Merge lp:~desrt/indicator-appmenu/hud-awareness into lp:indicator-appmenu/12.10

Proposed by Allison Karlitskaya
Status: Merged
Approved by: Charles Kerr
Approved revision: 213
Merge reported by: Lars Karlitski
Merged at revision: not available
Proposed branch: lp:~desrt/indicator-appmenu/hud-awareness
Merge into: lp:indicator-appmenu/12.10
Diff against target: 270 lines (+136/-25)
1 file modified
src/hudmenumodelcollector.c (+136/-25)
To merge this branch: bzr merge lp:~desrt/indicator-appmenu/hud-awareness
Reviewer Review Type Date Requested Status
Lars Karlitski (community) Approve
Review via email: mp+127937@code.launchpad.net

Description of the change

HudMenuModelCollector: implement the GMenuModel hud-awareness protocol

This is an efficient way of notifying applications with about-to-show
actions for their menus that the HUD is active and that all of their
menus should be brought up to date.

To post a comment you must log in.
Revision history for this message
Lars Karlitski (larsu) wrote :

Looks good.

I still find the protocol to be slightly ... weird ;)

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/hudmenumodelcollector.c'
2--- src/hudmenumodelcollector.c 2012-10-01 13:59:17 +0000
3+++ src/hudmenumodelcollector.c 2012-10-04 06:27:21 +0000
4@@ -60,22 +60,67 @@
5 {
6 GObject parent_instance;
7
8- GSList *models;
9- guint refresh_id;
10- /* stuff... */
11- GDBusMenuModel *app_menu;
12- GDBusMenuModel *menubar;
13+ /* Cancelled on finalize */
14+ GCancellable *cancellable;
15+
16+ /* GDBus shared session bus and D-Bus name of the app/indicator */
17+ GDBusConnection *session;
18+ gchar *unique_bus_name;
19+
20+ /* If this is an application, is_application will be set and
21+ * 'application' and 'window' will contain the two action groups for
22+ * the window that we are collecting.
23+ *
24+ * If this is an indicator, is_application will be false and the
25+ * (singular) action group for the indicator will be in 'application'.
26+ */
27 GDBusActionGroup *application;
28 GDBusActionGroup *window;
29-
30 gboolean is_application;
31
32+ /* The GMenuModel for the app menu.
33+ *
34+ * If this is an indicator, the indicator menu is stored here.
35+ *
36+ * app_menu_is_hud_aware is TRUE if we should send HudActiveChanged
37+ * calls to app_menu_object_path when our use_count goes above 0.
38+ */
39+ GDBusMenuModel *app_menu;
40+ gchar *app_menu_object_path;
41+ gboolean app_menu_is_hud_aware;
42+
43+ /* Ditto for the menubar.
44+ *
45+ * If this is an indicator then these will all be unset.
46+ */
47+ GDBusMenuModel *menubar;
48+ gchar *menubar_object_path;
49+ gboolean menubar_is_hud_aware;
50+
51+ /* Boring details about the app/indicator we are showing. */
52 gchar *prefix;
53 gchar *desktop_file;
54 gchar *icon;
55+ guint penalty;
56+
57+ /* Each time we see a new menumodel added we add it to 'models', start
58+ * watching it for changes and add its contents to 'items', possibly
59+ * finding more menumodels to do the same to.
60+ *
61+ * Each time an item is removed, we schedule an idle (in 'refresh_id')
62+ * to wipe out all the 'items', disconnect signals from each model in
63+ * 'models' and add them all back again.
64+ *
65+ * Searching just iterates over 'items'.
66+ */
67 GPtrArray *items;
68+ GSList *models;
69+ guint refresh_id;
70+
71+ /* Keep track of our use_count in order to send signals to HUD-aware
72+ * apps and indicators.
73+ */
74 gint use_count;
75- guint penalty;
76 };
77
78 typedef struct
79@@ -151,9 +196,6 @@
80 return context;
81 }
82
83-
84-
85-
86 G_DEFINE_TYPE (HudModelItem, hud_model_item, HUD_TYPE_ITEM)
87
88 static void
89@@ -432,10 +474,28 @@
90 }
91
92 static void
93+hud_menu_model_collector_active_changed (HudMenuModelCollector *collector,
94+ gboolean active)
95+{
96+ if (collector->app_menu_is_hud_aware)
97+ g_dbus_connection_call (collector->session, collector->unique_bus_name, collector->app_menu_object_path,
98+ "com.canonical.hud.Awareness", "HudActiveChanged", g_variant_new ("(b)", active),
99+ NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
100+
101+ if (collector->menubar_is_hud_aware)
102+ g_dbus_connection_call (collector->session, collector->unique_bus_name, collector->app_menu_object_path,
103+ "com.canonical.hud.Awareness", "HudActiveChanged", g_variant_new ("(b)", active),
104+ NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
105+}
106+
107+static void
108 hud_menu_model_collector_use (HudSource *source)
109 {
110 HudMenuModelCollector *collector = HUD_MENU_MODEL_COLLECTOR (source);
111
112+ if (collector->use_count == 0)
113+ hud_menu_model_collector_active_changed (collector, TRUE);
114+
115 collector->use_count++;
116 }
117
118@@ -445,6 +505,9 @@
119 HudMenuModelCollector *collector = HUD_MENU_MODEL_COLLECTOR (source);
120
121 collector->use_count--;
122+
123+ if (collector->use_count == 0)
124+ hud_menu_model_collector_active_changed (collector, FALSE);
125 }
126
127 static void
128@@ -474,6 +537,9 @@
129 {
130 HudMenuModelCollector *collector = HUD_MENU_MODEL_COLLECTOR (object);
131
132+ g_cancellable_cancel (collector->cancellable);
133+ g_object_unref (collector->cancellable);
134+
135 if (collector->refresh_id)
136 g_source_remove (collector->refresh_id);
137
138@@ -483,6 +549,10 @@
139 g_clear_object (&collector->application);
140 g_clear_object (&collector->window);
141
142+ g_object_unref (collector->session);
143+ g_free (collector->unique_bus_name);
144+ g_free (collector->app_menu_object_path);
145+ g_free (collector->menubar_object_path);
146 g_free (collector->prefix);
147 g_free (collector->desktop_file);
148 g_free (collector->icon);
149@@ -497,6 +567,7 @@
150 hud_menu_model_collector_init (HudMenuModelCollector *collector)
151 {
152 collector->items = g_ptr_array_new_with_free_func (g_object_unref);
153+ collector->cancellable = g_cancellable_new ();
154 }
155
156 static void
157@@ -513,6 +584,40 @@
158 class->finalize = hud_menu_model_collector_finalize;
159 }
160
161+static void
162+hud_menu_model_collector_hud_awareness_cb (GObject *source,
163+ GAsyncResult *result,
164+ gpointer user_data)
165+{
166+ GVariant *reply;
167+
168+ /* The goal of this function is to set either the
169+ * app_menu_is_hud_aware or menubar_is_hud_aware flag (which we have a
170+ * pointer to in user_data) to TRUE in the case that the remote
171+ * appears to support the com.canonical.hud.Awareness protocol.
172+ *
173+ * If it supports it, the async call will be successful. In that
174+ * case, we want to set *(gboolean *) user_data = TRUE;
175+ *
176+ * There are two cases that we don't want to do that write. The first
177+ * is the event that the remote doesn't support the protocol. In that
178+ * case, we will see an error when we inspect the result. The other
179+ * is the case in which the flag to which user_data points no longer
180+ * exists (ie: collector has been finalized). In this case, the
181+ * cancellable will have been cancelled and we will also see an error.
182+ *
183+ * Long story short: If we get any error, just do nothing.
184+ */
185+
186+ reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, NULL);
187+
188+ if (reply)
189+ {
190+ *(gboolean *) user_data = TRUE;
191+ g_variant_unref (reply);
192+ }
193+}
194+
195 /**
196 * hud_menu_model_collector_get:
197 * @window: a #BamfWindow
198@@ -533,12 +638,15 @@
199 {
200 HudMenuModelCollector *collector;
201 gchar *unique_bus_name;
202- gchar *app_menu_object_path;
203- gchar *menubar_object_path;
204 gchar *application_object_path;
205 gchar *window_object_path;
206 GDBusConnection *session;
207
208+ session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
209+
210+ if (!session)
211+ return NULL;
212+
213 unique_bus_name = bamf_window_get_utf8_prop (window, "_GTK_UNIQUE_BUS_NAME");
214
215 if (!unique_bus_name)
216@@ -546,24 +654,32 @@
217 return NULL;
218
219 collector = g_object_new (HUD_TYPE_MENU_MODEL_COLLECTOR, NULL);
220+ collector->session = session;
221+ collector->unique_bus_name = unique_bus_name;
222
223- app_menu_object_path = bamf_window_get_utf8_prop (window, "_GTK_APP_MENU_OBJECT_PATH");
224- menubar_object_path = bamf_window_get_utf8_prop (window, "_GTK_MENUBAR_OBJECT_PATH");
225+ collector->app_menu_object_path = bamf_window_get_utf8_prop (window, "_GTK_APP_MENU_OBJECT_PATH");
226+ collector->menubar_object_path = bamf_window_get_utf8_prop (window, "_GTK_MENUBAR_OBJECT_PATH");
227 application_object_path = bamf_window_get_utf8_prop (window, "_GTK_APPLICATION_OBJECT_PATH");
228 window_object_path = bamf_window_get_utf8_prop (window, "_GTK_WINDOW_OBJECT_PATH");
229
230- session = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
231-
232- if (app_menu_object_path)
233+ if (collector->app_menu_object_path)
234 {
235- collector->app_menu = g_dbus_menu_model_get (session, unique_bus_name, app_menu_object_path);
236+ collector->app_menu = g_dbus_menu_model_get (session, unique_bus_name, collector->app_menu_object_path);
237 hud_menu_model_collector_add_model (collector, G_MENU_MODEL (collector->app_menu), NULL, NULL, NULL);
238+ g_dbus_connection_call (session, unique_bus_name, collector->app_menu_object_path,
239+ "com.canonical.hud.Awareness", "CheckAwareness",
240+ NULL, G_VARIANT_TYPE_UNIT, G_DBUS_CALL_FLAGS_NONE, -1, collector->cancellable,
241+ hud_menu_model_collector_hud_awareness_cb, &collector->app_menu_is_hud_aware);
242 }
243
244- if (menubar_object_path)
245+ if (collector->menubar_object_path)
246 {
247- collector->menubar = g_dbus_menu_model_get (session, unique_bus_name, menubar_object_path);
248+ collector->menubar = g_dbus_menu_model_get (session, unique_bus_name, collector->menubar_object_path);
249 hud_menu_model_collector_add_model (collector, G_MENU_MODEL (collector->menubar), NULL, NULL, NULL);
250+ g_dbus_connection_call (session, unique_bus_name, collector->app_menu_object_path,
251+ "com.canonical.hud.Awareness", "CheckAwareness",
252+ NULL, G_VARIANT_TYPE_UNIT, G_DBUS_CALL_FLAGS_NONE, -1, collector->cancellable,
253+ hud_menu_model_collector_hud_awareness_cb, &collector->menubar_is_hud_aware);
254 }
255
256 if (application_object_path)
257@@ -580,14 +696,9 @@
258 * enabled/disabled. how to deal with that?
259 */
260
261- g_free (unique_bus_name);
262- g_free (app_menu_object_path);
263- g_free (menubar_object_path);
264 g_free (application_object_path);
265 g_free (window_object_path);
266
267- g_object_unref (session);
268-
269 return collector;
270 }
271

Subscribers

People subscribed via source and target branches