Skip to content

Commit

Permalink
Merge pull request #70 from hartlottery/fix_timer
Browse files Browse the repository at this point in the history
An old problem is that the plugin cannot work normally if the i3wm starts before xfce4-panel as in #62, here we're using a timer to handle the ipc resources' acquisition.

May still have some segfault there.

Tested in archlinux with latest xfce4-panel (v4.18.4).

Investigating an error that causing the .xsession-errors during restart i3wm twice or more, crashed in g_io_channel_read_chars: and channel->is_readable.

Backtrace seems indicates an error of i3ipc-glib.

The problem is caused by an unhandled error status code from glib, submitted a PR to altdesktop/i3ipc-glib#41, but may not get merged due to unmaintained.
  • Loading branch information
denesb authored Jul 14, 2023
2 parents 14e4532 + c2bab64 commit 427f165
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 32 deletions.
104 changes: 72 additions & 32 deletions panel-plugin/i3w-plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ static void
on_ipc_shutdown(gpointer i3_w);

static void
recover_from_disconnect(i3WorkspacesPlugin *i3_workspaces);
reconnect_i3wm_timer(i3WorkspacesPlugin *i3_workspaces);

static void
handle_change_output(i3WorkspacesPlugin* i3_workspaces);
Expand Down Expand Up @@ -187,6 +187,8 @@ construct_workspaces(XfcePanelPlugin *plugin)

i3WorkspacesPlugin *i3_workspaces;
GtkOrientation orientation;
fprintf(stderr, "xfce4_i3_workspaces: construct_workspace, plugin=%p\n",
plugin);

/* allocate memory for the plugin structure */
i3_workspaces = g_slice_new0(i3WorkspacesPlugin);
Expand Down Expand Up @@ -226,24 +228,16 @@ construct_workspaces(XfcePanelPlugin *plugin)

i3_workspaces->workspace_buttons = g_hash_table_new(g_direct_hash, g_direct_equal);

/* Add a label for the binding mode */
i3_workspaces->mode_label = gtk_label_new(NULL);
/* Add a label for the binding mode */
i3_workspaces->mode_label = gtk_label_new(NULL);
GtkStyleContext *mode_label_context = gtk_widget_get_style_context(
GTK_WIDGET(i3_workspaces->mode_label));
gtk_style_context_add_class(mode_label_context, "binding-mode");
gtk_box_pack_end(GTK_BOX(i3_workspaces->hvbox), i3_workspaces->mode_label, FALSE, FALSE, 0);
gtk_widget_show(i3_workspaces->mode_label);
gtk_box_pack_end(GTK_BOX(i3_workspaces->hvbox), i3_workspaces->mode_label, FALSE, FALSE, 0);
gtk_widget_show(i3_workspaces->mode_label);

GError *err = NULL;
i3_workspaces->i3wm = i3wm_construct(&err);
if (NULL != err)
{
recover_from_disconnect(i3_workspaces);
}

connect_callbacks(i3_workspaces);

add_workspaces(i3_workspaces);
/* Setup a timer to connect to the i3wm until success. */
reconnect_i3wm_timer(i3_workspaces);

return i3_workspaces;
}
Expand Down Expand Up @@ -302,8 +296,17 @@ destruct(XfcePanelPlugin *plugin, i3WorkspacesPlugin *i3_workspaces)
/* destroy the panel widgets */
gtk_widget_destroy(i3_workspaces->hvbox);

/* cancel the timer */
if (i3_workspaces->timeout) {
g_source_remove(i3_workspaces->timeout);
i3_workspaces->timeout = 0;
}

/* destroy the i3wm delegate */
i3wm_destruct(i3_workspaces->i3wm);
if (i3_workspaces->i3wm) {
i3wm_destruct(i3_workspaces->i3wm);
i3_workspaces->i3wm = NULL;
}

/* free the plugin structure */
g_slice_free(i3WorkspacesPlugin, i3_workspaces);
Expand Down Expand Up @@ -395,6 +398,7 @@ config_changed(gpointer cb_data)
static void
add_workspaces(i3WorkspacesPlugin *i3_workspaces)
{
g_assert(i3_workspaces->i3wm);
GSList *wlist = i3wm_get_workspaces(i3_workspaces->i3wm);

GSList *witem;
Expand Down Expand Up @@ -599,10 +603,14 @@ static void
on_workspace_clicked(GtkWidget *button, gpointer data)
{
i3WorkspacesPlugin *i3_workspaces = (i3WorkspacesPlugin *)data;
GSList *wlist = i3wm_get_workspaces(i3_workspaces->i3wm);
GSList *wlist, *witem;
i3workspace *workspace = NULL;

GSList *witem;
if (!i3_workspaces->i3wm) {
return;
}

wlist = i3wm_get_workspaces(i3_workspaces->i3wm);
for (witem = wlist; witem != NULL; witem = witem->next)
{
workspace = (i3workspace *) witem->data;
Expand Down Expand Up @@ -635,6 +643,12 @@ on_workspace_scrolled(GtkWidget *ebox, GdkEventScroll *ev, gpointer data)
{
i3WorkspacesPlugin *i3_workspaces = (i3WorkspacesPlugin *)data;

if (!i3_workspaces->i3wm) {
/* Hasn't connected, so stop the event. Once connected the workspace
* is ensured to be updated. */
return TRUE;
}

GList *wlist = g_hash_table_get_keys(i3_workspaces->workspace_buttons);
wlist = g_list_sort(wlist, (GCompareFunc) i3wm_workspace_cmp);

Expand Down Expand Up @@ -676,29 +690,55 @@ static void
on_ipc_shutdown(gpointer i3_w)
{
i3WorkspacesPlugin *i3_workspaces = (i3WorkspacesPlugin *) i3_w;
fprintf(stderr, "xfce4_i3_workspaces: on_ipc_shutdown, i3_w=%p\n", i3_w);

/* Remove previous resources */
remove_workspaces(i3_workspaces);
i3wm_destruct(i3_workspaces->i3wm);
i3_workspaces->i3wm = NULL;

recover_from_disconnect(i3_workspaces);

connect_callbacks(i3_workspaces);
if (i3_workspaces->i3wm) {
i3wm_destruct(i3_workspaces->i3wm);
i3_workspaces->i3wm = NULL;
}

add_workspaces(i3_workspaces);
/* When shutdown, wake up the timer try to reconnect */
reconnect_i3wm_timer(i3_workspaces);
}

static void
recover_from_disconnect(i3WorkspacesPlugin *i3_workspaces)
static gboolean
reconnect_i3wm_callback(gpointer data)
{
i3WorkspacesPlugin *i3_workspaces = (i3WorkspacesPlugin *) data;
GError *err = NULL;

if (i3_workspaces->i3wm) {
// maybe already initialized by other timers?
fprintf(stderr, "warn: other timer already reconnected?\n");
return G_SOURCE_REMOVE;
}

fprintf(stderr, "Connecting to i3 workspace manager...\n");
i3_workspaces->i3wm = i3wm_construct(&err);
while (NULL != err)
{
fprintf(stderr, "Cannot connect to the i3 window manager: %s\n", err->message);
if (err != NULL) {
fprintf(stderr, "Still waiting for i3 window manager: %s\n",
err->message);
g_error_free(err);
err = NULL;
i3_workspaces->i3wm = i3wm_construct(&err);
return G_SOURCE_CONTINUE;
}

// connected, doing the init things; todo: is memory barrier needed?
// don't know whether the timer is sync or not
connect_callbacks(i3_workspaces);
add_workspaces(i3_workspaces);

i3_workspaces->timeout = 0;
return G_SOURCE_REMOVE;
}

static void
reconnect_i3wm_timer(i3WorkspacesPlugin *i3_workspaces)
{
guint id = g_timeout_add_seconds(1, reconnect_i3wm_callback, i3_workspaces);
if (id == 0) {
fprintf(stderr, "Timer broken! Plugin will no longer works.\n");
}
i3_workspaces->timeout = id;
}
1 change: 1 addition & 0 deletions panel-plugin/i3w-plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ typedef struct
i3WorkspacesConfig *config;

i3windowManager *i3wm;
guint timeout;
}
i3WorkspacesPlugin;

Expand Down

0 comments on commit 427f165

Please sign in to comment.