Merge lp:~charlesk/indicator-applet/lp-1045372 into lp:indicator-applet/12.10

Proposed by Charles Kerr
Status: Merged
Approved by: Lars Karlitski
Approved revision: 403
Merged at revision: 403
Proposed branch: lp:~charlesk/indicator-applet/lp-1045372
Merge into: lp:indicator-applet/12.10
Diff against target: 235 lines (+100/-68)
1 file modified
src/applet-main.c (+100/-68)
To merge this branch: bzr merge lp:~charlesk/indicator-applet/lp-1045372
Reviewer Review Type Date Requested Status
Lars Karlitski (community) Approve
jenkins continuous-integration Pending
Review via email: mp+123875@code.launchpad.net

Commit message

support hiding & re-showing IndicatorObjectEntries by caching their menuitems and using gtk_widget_hide / gtk_widget_show.

Description of the change

The cloak/decloak code existed to ensure that the IndicatorObjectEntry's widgets were not destroyed by client code on the "entry-removed" signal. Instead, let's fix the client code to understand that IOEs' visibility can be toggled and re-toggled.

See also: https://code.launchpad.net/~charlesk/libindicator/lp-1045372

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

Looks great.

I wouldn't have remembered fixing this applet, thanks :) Will we need a similar patch for unity-panel-service?

review: Approve
Revision history for this message
Charles Kerr (charlesk) wrote :

No, unity-panel-service works fine as-is.

I don't think that was the case back when this code was developed, but I'm not going to build this on 12.04 to confirm :)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/applet-main.c'
2--- src/applet-main.c 2012-04-04 16:30:42 +0000
3+++ src/applet-main.c 2012-09-12 02:55:21 +0000
4@@ -57,6 +57,7 @@
5
6 #define IO_DATA_NAME "indicator-name"
7 #define IO_DATA_ORDER_NUMBER "indicator-order-number"
8+#define IO_DATA_MENUITEM_LOOKUP "indicator-menuitem-lookup"
9
10 static gboolean applet_fill_cb (PanelApplet * applet, const gchar * iid, gpointer data);
11
12@@ -362,17 +363,16 @@
13 return;
14 }
15
16-static void
17-entry_added (IndicatorObject * io, IndicatorObjectEntry * entry, GtkWidget * menubar)
18+static GtkWidget*
19+create_menuitem (IndicatorObject * io, IndicatorObjectEntry * entry, GtkWidget * menubar)
20 {
21- const char *indicator_name = (const gchar *)g_object_get_data(G_OBJECT(io), IO_DATA_NAME);
22- g_debug("Signal: Entry Added from %s", indicator_name);
23- gboolean something_visible = FALSE;
24- gboolean something_sensitive = FALSE;
25+ GtkWidget * box;
26+ GtkWidget * menuitem;
27
28- GtkWidget * menuitem = gtk_menu_item_new();
29- GtkWidget * box = (packdirection == GTK_PACK_DIRECTION_LTR) ?
30- gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3) : gtk_box_new(GTK_ORIENTATION_VERTICAL, 3);
31+ menuitem = gtk_menu_item_new();
32+ box = (packdirection == GTK_PACK_DIRECTION_LTR)
33+ ? gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 3)
34+ : gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
35
36 gtk_widget_add_events(GTK_WIDGET(menuitem), GDK_SCROLL_MASK);
37
38@@ -389,18 +389,6 @@
39
40 if (entry->image != NULL) {
41 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(entry->image), FALSE, FALSE, 1);
42- if (gtk_widget_get_visible(GTK_WIDGET(entry->image))) {
43- something_visible = TRUE;
44- }
45-
46- if (gtk_widget_get_sensitive(GTK_WIDGET(entry->image))) {
47- something_sensitive = TRUE;
48- }
49-
50- g_signal_connect(G_OBJECT(entry->image), "show", G_CALLBACK(something_shown), menuitem);
51- g_signal_connect(G_OBJECT(entry->image), "hide", G_CALLBACK(something_hidden), menuitem);
52-
53- g_signal_connect(G_OBJECT(entry->image), "notify::sensitive", G_CALLBACK(sensitive_cb), menuitem);
54 }
55 if (entry->label != NULL) {
56 switch(packdirection) {
57@@ -416,19 +404,6 @@
58 break;
59 }
60 gtk_box_pack_start(GTK_BOX(box), GTK_WIDGET(entry->label), FALSE, FALSE, 1);
61-
62- if (gtk_widget_get_visible(GTK_WIDGET(entry->label))) {
63- something_visible = TRUE;
64- }
65-
66- if (gtk_widget_get_sensitive(GTK_WIDGET(entry->label))) {
67- something_sensitive = TRUE;
68- }
69-
70- g_signal_connect(G_OBJECT(entry->label), "show", G_CALLBACK(something_shown), menuitem);
71- g_signal_connect(G_OBJECT(entry->label), "hide", G_CALLBACK(something_hidden), menuitem);
72-
73- g_signal_connect(G_OBJECT(entry->label), "notify::sensitive", G_CALLBACK(sensitive_cb), menuitem);
74 }
75 gtk_container_add(GTK_CONTAINER(menuitem), box);
76 gtk_widget_show(box);
77@@ -439,6 +414,59 @@
78
79 place_in_menu(menubar, menuitem, io, entry);
80
81+ return menuitem;
82+}
83+
84+static void
85+entry_added (IndicatorObject * io, IndicatorObjectEntry * entry, GtkWidget * menubar)
86+{
87+ const gchar * name;
88+ GtkWidget * menuitem;
89+ GHashTable * menuitem_lookup;
90+ gboolean something_visible;
91+ gboolean something_sensitive;
92+
93+ name = g_object_get_data (G_OBJECT(io), IO_DATA_NAME);
94+ g_debug ("Signal: Entry Added from %s", name);
95+
96+ /* if the menuitem doesn't already exist, create it now */
97+ menuitem_lookup = g_object_get_data (G_OBJECT(io), IO_DATA_MENUITEM_LOOKUP);
98+ g_return_if_fail (menuitem_lookup != NULL);
99+ menuitem = g_hash_table_lookup (menuitem_lookup, entry);
100+ if (menuitem == NULL) {
101+ menuitem = create_menuitem (io, entry, menubar);
102+ g_hash_table_insert (menuitem_lookup, entry, menuitem);
103+ }
104+
105+ /* connect the callbacks */
106+ if (G_IS_OBJECT (entry->image)) {
107+ g_object_connect (entry->image,
108+ "signal::show", G_CALLBACK(something_shown), menuitem,
109+ "signal::hide", G_CALLBACK(something_hidden), menuitem,
110+ "signal::notify::sensitive", G_CALLBACK(sensitive_cb), menuitem,
111+ NULL);
112+ }
113+ if (G_IS_OBJECT (entry->label)) {
114+ g_object_connect (entry->label,
115+ "signal::show", G_CALLBACK(something_shown), menuitem,
116+ "signal::hide", G_CALLBACK(something_hidden), menuitem,
117+ "signal::notify::sensitive", G_CALLBACK(sensitive_cb), menuitem,
118+ NULL);
119+ }
120+
121+ /* refresh based on visibility & sensitivity */
122+ something_visible = FALSE;
123+ something_sensitive = FALSE;
124+ if (entry->image != NULL) {
125+ GtkWidget * w = GTK_WIDGET (entry->image);
126+ something_visible |= gtk_widget_get_visible (w);
127+ something_sensitive |= gtk_widget_get_sensitive (w);
128+ }
129+ if (entry->label != NULL) {
130+ GtkWidget * w = GTK_WIDGET (entry->label);
131+ something_visible |= gtk_widget_get_visible (w);
132+ something_sensitive |= gtk_widget_get_sensitive (w);
133+ }
134 if (something_visible) {
135 if (entry->accessible_desc != NULL) {
136 update_accessible_desc(entry, menuitem);
137@@ -451,37 +479,37 @@
138 }
139
140 static void
141-entry_removed_cb (GtkWidget * widget, gpointer userdata)
142-{
143- gpointer data = g_object_get_data(G_OBJECT(widget), MENU_DATA_INDICATOR_ENTRY);
144-
145- if (data != userdata) {
146- return;
147- }
148-
149- IndicatorObjectEntry * entry = (IndicatorObjectEntry *)data;
150- if (entry->label != NULL) {
151- g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(something_shown), widget);
152- g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(something_hidden), widget);
153- g_signal_handlers_disconnect_by_func(G_OBJECT(entry->label), G_CALLBACK(sensitive_cb), widget);
154- }
155- if (entry->image != NULL) {
156- g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(something_shown), widget);
157- g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(something_hidden), widget);
158- g_signal_handlers_disconnect_by_func(G_OBJECT(entry->image), G_CALLBACK(sensitive_cb), widget);
159- }
160-
161- gtk_widget_destroy(widget);
162- return;
163-}
164-
165-static void
166-entry_removed (IndicatorObject * io G_GNUC_UNUSED, IndicatorObjectEntry * entry,
167+entry_removed (IndicatorObject * io,
168+ IndicatorObjectEntry * entry,
169 gpointer user_data)
170 {
171+ GtkWidget * menuitem;
172+ GHashTable * menuitem_lookup;
173+
174 g_debug("Signal: Entry Removed");
175
176- gtk_container_foreach(GTK_CONTAINER(user_data), entry_removed_cb, entry);
177+ menuitem_lookup = g_object_get_data (G_OBJECT(io), IO_DATA_MENUITEM_LOOKUP);
178+ g_return_if_fail (menuitem_lookup != NULL);
179+ menuitem = g_hash_table_lookup (menuitem_lookup, entry);
180+ g_return_if_fail (menuitem != NULL);
181+
182+ /* disconnect the callbacks */
183+ if (G_IS_OBJECT (entry->label)) {
184+ g_object_disconnect (entry->label,
185+ "signal::show", G_CALLBACK(something_shown), menuitem,
186+ "signal::hide", G_CALLBACK(something_hidden), menuitem,
187+ "signal::notify::sensitive", G_CALLBACK(sensitive_cb), menuitem,
188+ NULL);
189+ }
190+ if (G_IS_OBJECT (entry->image)) {
191+ g_object_disconnect (entry->image,
192+ "signal::show", G_CALLBACK(something_shown), menuitem,
193+ "signal::hide", G_CALLBACK(something_hidden), menuitem,
194+ "signal::notify::sensitive", G_CALLBACK(sensitive_cb), menuitem,
195+ NULL);
196+ }
197+
198+ gtk_widget_hide (menuitem);
199
200 return;
201 }
202@@ -579,6 +607,8 @@
203 static gboolean
204 load_module (const gchar * name, GtkWidget * menubar)
205 {
206+ GObject * o;
207+
208 g_debug("Looking at Module: %s", name);
209 g_return_val_if_fail(name != NULL, FALSE);
210
211@@ -597,15 +627,17 @@
212 indicator_object_set_environment(io, (GStrv)indicator_env);
213
214 /* Attach the 'name' to the object */
215- g_object_set_data_full(G_OBJECT(io), IO_DATA_NAME, g_strdup(name), g_free);
216- g_object_set_data(G_OBJECT(io), IO_DATA_ORDER_NUMBER, GINT_TO_POINTER(name2order(name, NULL)));
217+ o = G_OBJECT (io);
218+ g_object_set_data_full(o, IO_DATA_MENUITEM_LOOKUP, g_hash_table_new (g_direct_hash, g_direct_equal), (GDestroyNotify)g_hash_table_destroy);
219+ g_object_set_data_full(o, IO_DATA_NAME, g_strdup(name), g_free);
220+ g_object_set_data(o, IO_DATA_ORDER_NUMBER, GINT_TO_POINTER(name2order(name, NULL)));
221
222 /* Connect to its signals */
223- g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED, G_CALLBACK(entry_added), menubar);
224- g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED, G_CALLBACK(entry_removed), menubar);
225- g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ENTRY_MOVED, G_CALLBACK(entry_moved), menubar);
226- g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_MENU_SHOW, G_CALLBACK(menu_show), menubar);
227- g_signal_connect(G_OBJECT(io), INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE, G_CALLBACK(accessible_desc_update), menubar);
228+ g_signal_connect(o, INDICATOR_OBJECT_SIGNAL_ENTRY_ADDED, G_CALLBACK(entry_added), menubar);
229+ g_signal_connect(o, INDICATOR_OBJECT_SIGNAL_ENTRY_REMOVED, G_CALLBACK(entry_removed), menubar);
230+ g_signal_connect(o, INDICATOR_OBJECT_SIGNAL_ENTRY_MOVED, G_CALLBACK(entry_moved), menubar);
231+ g_signal_connect(o, INDICATOR_OBJECT_SIGNAL_MENU_SHOW, G_CALLBACK(menu_show), menubar);
232+ g_signal_connect(o, INDICATOR_OBJECT_SIGNAL_ACCESSIBLE_DESC_UPDATE, G_CALLBACK(accessible_desc_update), menubar);
233
234 /* Work on the entries */
235 GList * entries = indicator_object_get_entries(io);

Subscribers

People subscribed via source and target branches