← Back to team overview

ayatana-commits team mailing list archive

[Merge] lp:~ted/indicator-appmenu/handle-event-errors into lp:indicator-appmenu

 

Ted Gould has proposed merging lp:~ted/indicator-appmenu/handle-event-errors into lp:indicator-appmenu.

Requested reviews:
  Indicator Applet Developers (indicator-applet-developers)


Allows the appmenu to handle errors in sent events and desensitize the items when there is an error'd state.
-- 
https://code.launchpad.net/~ted/indicator-appmenu/handle-event-errors/+merge/33964
Your team ayatana-commits is subscribed to branch lp:indicator-appmenu.
=== modified file 'src/indicator-appmenu.c'
--- src/indicator-appmenu.c	2010-08-17 16:51:58 +0000
+++ src/indicator-appmenu.c	2010-08-27 22:04:41 +0000
@@ -621,8 +621,12 @@
 	for (entries = entry_head; entries != NULL; entries = g_list_next(entries)) {
 		IndicatorObjectEntry * entry = (IndicatorObjectEntry *)entries->data;
 
-		if (entry->label != NULL) {
-			gtk_widget_show(GTK_WIDGET(entry->label));
+		if (iapp->default_app != NULL) {
+			window_menus_entry_restore(iapp->default_app, entry);
+		} else {
+			if (entry->label != NULL) {
+				gtk_widget_show(GTK_WIDGET(entry->label));
+			}
 		}
 
 		g_signal_emit(G_OBJECT(iapp), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED_ID, 0, entries->data, TRUE);

=== modified file 'src/window-menus.c'
--- src/window-menus.c	2010-06-29 19:07:13 +0000
+++ src/window-menus.c	2010-08-27 22:04:41 +0000
@@ -38,6 +38,19 @@
 	DbusmenuMenuitem * root;
 	DBusGProxy * props;
 	GArray * entries;
+	gboolean error_state;
+	guint   retry_timer;
+	gint    retry_id;
+	gchar * retry_name;
+	GValue  retry_data;
+	guint   retry_timestamp;
+};
+
+typedef struct _WMEntry WMEntry;
+struct _WMEntry {
+	IndicatorObjectEntry ioentry;
+	gboolean disabled;
+	gboolean hidden;
 };
 
 #define WINDOW_MENUS_GET_PRIVATE(o) \
@@ -49,6 +62,7 @@
 	ENTRY_ADDED,
 	ENTRY_REMOVED,
 	DESTROY,
+	ERROR_STATE,
 	LAST_SIGNAL
 };
 
@@ -102,6 +116,13 @@
 	                                      NULL, NULL,
 	                                      g_cclosure_marshal_VOID__VOID,
 	                                      G_TYPE_NONE, 0, G_TYPE_NONE);
+	signals[ERROR_STATE] =   g_signal_new(WINDOW_MENUS_SIGNAL_ERROR_STATE,
+	                                      G_TYPE_FROM_CLASS(klass),
+	                                      G_SIGNAL_RUN_LAST,
+	                                      G_STRUCT_OFFSET (WindowMenusClass, error_state),
+	                                      NULL, NULL,
+	                                      g_cclosure_marshal_VOID__BOOLEAN,
+	                                      G_TYPE_NONE, 1, G_TYPE_BOOLEAN, G_TYPE_NONE);
 
 	return;
 }
@@ -115,8 +136,9 @@
 	priv->client = NULL;
 	priv->props = NULL;
 	priv->root = NULL;
+	priv->error_state = FALSE;
 
-	priv->entries = g_array_new(FALSE, FALSE, sizeof(IndicatorObjectEntry *));
+	priv->entries = g_array_new(FALSE, FALSE, sizeof(WMEntry *));
 
 	return;
 }
@@ -144,6 +166,15 @@
 		priv->props = NULL;
 	}
 
+	if (priv->retry_timer != 0) {
+		g_source_remove(priv->retry_timer);
+		priv->retry_timer = 0;
+		g_value_unset(&priv->retry_data);
+		g_value_reset(&priv->retry_data);
+		g_free(priv->retry_name);
+		priv->retry_name = NULL;
+	}
+
 	G_OBJECT_CLASS (window_menus_parent_class)->dispose (object);
 	return;
 }
@@ -177,6 +208,93 @@
 	return;
 }
 
+/* Retry the event sending to the server to see if we can get things
+   working again. */
+static gboolean
+retry_event (gpointer user_data)
+{
+	g_debug("Retrying event");
+	g_return_val_if_fail(IS_WINDOW_MENUS(user_data), FALSE);
+	WindowMenusPrivate * priv = WINDOW_MENUS_GET_PRIVATE(user_data);
+
+	dbusmenu_client_send_event(DBUSMENU_CLIENT(priv->client), priv->retry_id, priv->retry_name, &priv->retry_data, priv->retry_timestamp);
+
+	priv->retry_timer = 0;
+	g_value_unset(&priv->retry_data);
+	g_value_reset(&priv->retry_data);
+	g_free(priv->retry_name);
+	priv->retry_name = NULL;
+
+	return FALSE;
+}
+
+/* Listen to whether our events are successfully sent */
+static void
+event_status (DbusmenuClient * client, DbusmenuMenuitem * mi, gchar * event, GValue * evdata, guint timestamp, GError * error, gpointer user_data)
+{
+	g_return_if_fail(IS_WINDOW_MENUS(user_data));
+	WindowMenusPrivate * priv = WINDOW_MENUS_GET_PRIVATE(user_data);
+
+	/* We don't care about status where there are no errors
+	   when we're in a happy state, just let them go. */
+	if (error == NULL && priv->error_state == FALSE) {
+		return;
+	}
+	int i;
+
+	/* Oh, things are working now! */
+	if (error == NULL) {
+		g_debug("Error state repaired");
+		priv->error_state = FALSE;
+		g_signal_emit(G_OBJECT(user_data), signals[ERROR_STATE], 0, priv->error_state, TRUE);
+
+		for (i = 0; i < priv->entries->len; i++) {
+			IndicatorObjectEntry * entry = g_array_index(priv->entries, IndicatorObjectEntry *, i);
+			window_menus_entry_restore(WINDOW_MENUS(user_data), entry);
+		}
+
+		if (priv->retry_timer != 0) {
+			g_source_remove(priv->retry_timer);
+			priv->retry_timer = 0;
+			g_value_unset(&priv->retry_data);
+			g_value_reset(&priv->retry_data);
+			g_free(priv->retry_name);
+			priv->retry_name = NULL;
+		}
+
+		return;
+	}
+
+	/* Uhg, means that events are breaking, now we need to
+	   try and handle that case. */
+	priv->error_state = TRUE;
+	g_signal_emit(G_OBJECT(user_data), signals[ERROR_STATE], 0, priv->error_state, TRUE);
+
+	for (i = 0; i < priv->entries->len; i++) {
+		IndicatorObjectEntry * entry = g_array_index(priv->entries, IndicatorObjectEntry *, i);
+
+		if (entry->label != NULL) {
+			gtk_widget_set_sensitive(GTK_WIDGET(entry->label), FALSE);
+		}
+		if (entry->image != NULL) {
+			gtk_widget_set_sensitive(GTK_WIDGET(entry->image), FALSE);
+		}
+	}
+
+	if (priv->retry_timer == 0) {
+		g_debug("Setting up retry timer");
+		priv->retry_timer = g_timeout_add_seconds(1, retry_event, user_data);
+
+		priv->retry_id = dbusmenu_menuitem_get_id(mi);
+		priv->retry_name = g_strdup(event);
+		g_value_init(&priv->retry_data, G_VALUE_TYPE(evdata));
+		g_value_copy(evdata, &priv->retry_data);
+		priv->retry_timestamp = timestamp;
+	}
+
+	return;
+}
+
 /* Build a new window menus object and attach to the signals to build
    up the representative menu. */
 WindowMenus *
@@ -214,6 +332,7 @@
 	dbusmenu_gtkclient_set_accel_group(priv->client, agroup);
 
 	g_signal_connect(G_OBJECT(priv->client), DBUSMENU_GTKCLIENT_SIGNAL_ROOT_CHANGED, G_CALLBACK(root_changed),   newmenu);
+	g_signal_connect(G_OBJECT(priv->client), DBUSMENU_CLIENT_SIGNAL_EVENT_RESULT, G_CALLBACK(event_status), newmenu);
 
 	DbusmenuMenuitem * root = dbusmenu_client_get_root(DBUSMENU_CLIENT(priv->client));
 	if (root != NULL) {
@@ -383,15 +502,19 @@
 menu_prop_changed (DbusmenuMenuitem * item, const gchar * property, const GValue * value, gpointer user_data)
 {
 	IndicatorObjectEntry * entry = (IndicatorObjectEntry *)user_data;
+	WMEntry * wmentry = (WMEntry *)user_data;
 
 	if (!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_VISIBLE)) {
 		if (g_value_get_boolean(value)) {
 			gtk_widget_show(GTK_WIDGET(entry->label));
+			wmentry->hidden = FALSE;
 		} else {
 			gtk_widget_hide(GTK_WIDGET(entry->label));
+			wmentry->hidden = TRUE;
 		}
 	} else if (!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_ENABLED)) {
 		gtk_widget_set_sensitive(GTK_WIDGET(entry->label), g_value_get_boolean(value));
+		wmentry->disabled = !g_value_get_boolean(value);
 	} else if (!g_strcmp0(property, DBUSMENU_MENUITEM_PROP_LABEL)) {
 		gtk_label_set_text(entry->label, g_value_get_string(value));
 	}
@@ -409,7 +532,8 @@
 	g_signal_handlers_disconnect_by_func(G_OBJECT(child), menu_child_realized, user_data);
 
 	WindowMenusPrivate * priv = WINDOW_MENUS_GET_PRIVATE((((gpointer *)user_data)[0]));
-	IndicatorObjectEntry * entry = g_new0(IndicatorObjectEntry, 1);
+	WMEntry * wmentry = g_new0(WMEntry, 1);
+	IndicatorObjectEntry * entry = &wmentry->ioentry;
 
 	entry->label = GTK_LABEL(gtk_label_new_with_mnemonic(dbusmenu_menuitem_property_get(newentry, DBUSMENU_MENUITEM_PROP_LABEL)));
 
@@ -429,15 +553,21 @@
 	g_signal_connect(G_OBJECT(newentry), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(menu_prop_changed), entry);
 
 	if (dbusmenu_menuitem_property_get_value(newentry, DBUSMENU_MENUITEM_PROP_VISIBLE) != NULL
-		&& dbusmenu_menuitem_property_get_bool(newentry, DBUSMENU_MENUITEM_PROP_VISIBLE) == FALSE)
+		&& dbusmenu_menuitem_property_get_bool(newentry, DBUSMENU_MENUITEM_PROP_VISIBLE) == FALSE) {
 		gtk_widget_hide(GTK_WIDGET(entry->label));
-	else
+		wmentry->hidden = TRUE;
+	} else {
 		gtk_widget_show(GTK_WIDGET(entry->label));
-
-	if (dbusmenu_menuitem_property_get_value (newentry, DBUSMENU_MENUITEM_PROP_ENABLED) != NULL)
-		gtk_widget_set_sensitive(GTK_WIDGET(entry->label), dbusmenu_menuitem_property_get_bool(newentry, DBUSMENU_MENUITEM_PROP_ENABLED));
-
-	g_array_append_val(priv->entries, entry);
+		wmentry->hidden = FALSE;
+	}
+
+	if (dbusmenu_menuitem_property_get_value (newentry, DBUSMENU_MENUITEM_PROP_ENABLED) != NULL) {
+		gboolean sensitive = dbusmenu_menuitem_property_get_bool(newentry, DBUSMENU_MENUITEM_PROP_ENABLED);
+		gtk_widget_set_sensitive(GTK_WIDGET(entry->label), sensitive);
+		wmentry->disabled = !sensitive;
+	}
+
+	g_array_append_val(priv->entries, wmentry);
 
 	g_signal_emit(G_OBJECT((((gpointer *)user_data)[0])), signals[ENTRY_ADDED], 0, entry, TRUE);
 
@@ -501,3 +631,41 @@
 	g_value_unset(&obj);
 	return retval;
 }
+
+/* Return whether we're in an error state or not */
+gboolean
+window_menus_get_error_state (WindowMenus * wm)
+{
+	g_return_val_if_fail(IS_WINDOW_MENUS(wm), TRUE);
+	WindowMenusPrivate * priv = WINDOW_MENUS_GET_PRIVATE(wm);
+	return priv->error_state;
+}
+
+/* Regain whether we're supposed to be hidden or disabled, we
+   want to keep that if that's the case, otherwise bring back
+   to the base state */
+void
+window_menus_entry_restore (WindowMenus * wm, IndicatorObjectEntry * entry)
+{
+	WMEntry * wmentry = (WMEntry *)entry;
+
+	if (entry->label != NULL) {
+		gtk_widget_set_sensitive(GTK_WIDGET(entry->label), !wmentry->disabled);
+		if (wmentry->hidden) {
+			gtk_widget_hide(GTK_WIDGET(entry->label));
+		} else {
+			gtk_widget_show(GTK_WIDGET(entry->label));
+		}
+	}
+
+	if (entry->image != NULL) {
+		gtk_widget_set_sensitive(GTK_WIDGET(entry->image), !wmentry->disabled);
+		if (wmentry->hidden) {
+			gtk_widget_hide(GTK_WIDGET(entry->image));
+		} else {
+			gtk_widget_show(GTK_WIDGET(entry->image));
+		}
+	}
+
+	return;
+}

=== modified file 'src/window-menus.h'
--- src/window-menus.h	2010-06-12 02:18:26 +0000
+++ src/window-menus.h	2010-08-27 22:04:41 +0000
@@ -38,6 +38,7 @@
 #define WINDOW_MENUS_SIGNAL_ENTRY_ADDED    "entry-added"
 #define WINDOW_MENUS_SIGNAL_ENTRY_REMOVED  "entry-removed"
 #define WINDOW_MENUS_SIGNAL_DESTROY        "destroy"
+#define WINDOW_MENUS_SIGNAL_ERROR_STATE    "error-state"
 
 typedef struct _WindowMenus      WindowMenus;
 typedef struct _WindowMenusClass WindowMenusClass;
@@ -50,6 +51,7 @@
 	void (*entry_removed) (WindowMenus * wm, IndicatorObjectEntry * entry, gpointer user_data);
 
 	void (*destroy)       (WindowMenus * wm, gpointer user_data);
+	void (*error_state)   (WindowMenus * wm, gboolean state, gpointer user_data);
 };
 
 struct _WindowMenus {
@@ -65,6 +67,9 @@
 gchar * window_menus_get_path (WindowMenus * wm);
 gchar * window_menus_get_address (WindowMenus * wm);
 
+gboolean window_menus_get_error_state (WindowMenus * wm);
+void window_menus_entry_restore (WindowMenus * wm, IndicatorObjectEntry * entry);
+
 G_END_DECLS
 
 #endif


Follow ups