Merge lp:~3v1n0/unity/panel-service-menus-deactivation-discard into lp:unity

Proposed by Marco Trevisan (Treviño)
Status: Merged
Approved by: Andrea Azzarone
Approved revision: no longer in the source branch.
Merged at revision: 4189
Proposed branch: lp:~3v1n0/unity/panel-service-menus-deactivation-discard
Merge into: lp:unity
Diff against target: 204 lines (+78/-10)
1 file modified
services/panel-service.c (+78/-10)
To merge this branch: bzr merge lp:~3v1n0/unity/panel-service-menus-deactivation-discard
Reviewer Review Type Date Requested Status
Andrea Azzarone (community) Approve
Review via email: mp+303549@code.launchpad.net

Commit message

PanelService: don't allow to deactivate menus if they've been opened too shortly

This could be caused by some random events while doing fast scrubbing.

To post a comment you must log in.
Revision history for this message
Andrea Azzarone (azzar1) wrote :

+1

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'services/panel-service.c'
2--- services/panel-service.c 2015-11-02 13:29:42 +0000
3+++ services/panel-service.c 2016-08-22 12:32:55 +0000
4@@ -80,6 +80,7 @@
5 gint last_right;
6 gint last_bottom;
7 guint32 last_menu_button;
8+ guint64 last_open_time;
9
10 GSettings *gsettings;
11 KeyBinding menu_toggle;
12@@ -92,6 +93,7 @@
13
14 /* Globals */
15 static gboolean suppress_signals = FALSE;
16+static void (*default_menu_shell_deactivate) (GtkMenuShell *menu_shell);
17
18 enum
19 {
20@@ -138,6 +140,7 @@
21 static void notify_object (IndicatorObject *object);
22 static void update_keybinding (GSettings *, const gchar *, gpointer);
23 static void emit_upstart_event (const gchar *);
24+static void menu_shell_deactivate_override (GtkMenuShell *menu_shell);
25 static gchar * get_indicator_entry_id_by_entry (IndicatorObjectEntry *entry);
26 static IndicatorObjectEntry * get_indicator_entry_by_id (PanelService *self, const gchar *entry_id);
27 static GdkFilterReturn event_filter (GdkXEvent *, GdkEvent *, PanelService *);
28@@ -161,7 +164,7 @@
29 if (GTK_IS_WIDGET (priv->last_menu) &&
30 gtk_widget_get_realized (GTK_WIDGET (priv->last_menu)))
31 {
32- gtk_menu_popdown (GTK_MENU (priv->last_menu));
33+ panel_service_close_active_entry (PANEL_SERVICE (self));
34 g_signal_handlers_disconnect_by_data (priv->last_menu, self);
35 priv->last_menu = NULL;
36 }
37@@ -435,6 +438,25 @@
38 return entry;
39 }
40
41+static const gchar *
42+get_indicator_entry_id_by_menu (PanelService *self, GtkMenu *menu)
43+{
44+ GHashTableIter iter;
45+ IndicatorObjectEntry* entry;
46+ gchar *id;
47+
48+ g_hash_table_iter_init (&iter, self->priv->id2entry_hash);
49+ while (g_hash_table_iter_next (&iter, (gpointer*) &id, (gpointer*) &entry))
50+ {
51+ if (entry && entry->menu == menu)
52+ {
53+ return id;
54+ }
55+ }
56+
57+ return NULL;
58+}
59+
60 static void
61 ensure_entry_menu_is_closed (PanelService *self,
62 const gchar *panel_id,
63@@ -446,7 +468,9 @@
64 if (GTK_IS_MENU (priv->last_menu) && priv->last_menu == entry->menu)
65 {
66 if (!priv->last_panel || !panel_id || g_strcmp0 (priv->last_panel, panel_id) == 0)
67- gtk_menu_popdown (entry->menu);
68+ {
69+ panel_service_close_active_entry (self);
70+ }
71 }
72 }
73
74@@ -590,17 +614,15 @@
75 event_matches_keybinding (event->mods.base, keysym, &priv->show_dash) ||
76 event_matches_keybinding (event->mods.base, keysym, &priv->show_hud))
77 {
78- if (GTK_IS_MENU (priv->last_menu))
79- gtk_menu_popdown (GTK_MENU (priv->last_menu));
80-
81+ panel_service_close_active_entry (self);
82 ret = GDK_FILTER_REMOVE;
83 }
84 else if (event->mods.base != GDK_CONTROL_MASK)
85 {
86 if (!IsModifierKey (keysym) && (event->mods.base != 0 || is_allowed_keysym (keysym)))
87 {
88- if (GTK_IS_MENU (priv->last_menu) && !is_control_keysym (keysym))
89- gtk_menu_popdown (GTK_MENU (priv->last_menu));
90+ if (!is_control_keysym (keysym))
91+ panel_service_close_active_entry (self);
92
93 reinject_key_event_to_root_window (event);
94 ret = GDK_FILTER_REMOVE;
95@@ -1370,9 +1392,7 @@
96
97 if (!entry)
98 {
99- if (GTK_IS_MENU (self->priv->last_menu))
100- gtk_menu_popdown (GTK_MENU (self->priv->last_menu));
101-
102+ panel_service_close_active_entry (self);
103 return;
104 }
105
106@@ -1840,8 +1860,16 @@
107 on_active_menu_hidden (GtkMenu *menu, PanelService *self)
108 {
109 PanelServicePrivate *priv = self->priv;
110+ GtkMenuShellClass *menu_shell_class = GTK_MENU_SHELL_GET_CLASS (priv->last_menu);
111+
112 g_signal_handlers_disconnect_by_data (priv->last_menu, self);
113
114+ if (menu_shell_class && default_menu_shell_deactivate &&
115+ menu_shell_class->deactivate != default_menu_shell_deactivate)
116+ {
117+ menu_shell_class->deactivate = default_menu_shell_deactivate;
118+ }
119+
120 priv->last_x = 0;
121 priv->last_y = 0;
122 priv->last_menu_button = 0;
123@@ -1853,6 +1881,7 @@
124 priv->last_right = 0;
125 priv->last_top = 0;
126 priv->last_bottom = 0;
127+ priv->last_open_time = 0;
128
129 priv->use_event = FALSE;
130 priv->pressed_entry = NULL;
131@@ -2270,6 +2299,34 @@
132 }
133
134 static void
135+menu_shell_deactivate_override (GtkMenuShell *menu_shell)
136+{
137+ PanelService *self = panel_service_get_default ();
138+ const gchar *entry_id;
139+
140+ if (gtk_get_current_event () && GTK_MENU (menu_shell) == self->priv->last_menu)
141+ {
142+ guint64 ms_open = (g_get_monotonic_time () - self->priv->last_open_time) / 1000;
143+
144+ if (ms_open < 50)
145+ {
146+ /* If the menu shell deactivation was requested by an event, we ensure this
147+ * didn't happen too early to activation, or there could be a race causing
148+ * no menu to appear. Also since the item is now marked as inactive, we should
149+ * manually highlight it. */
150+ entry_id = get_indicator_entry_id_by_menu (self, self->priv->last_menu);
151+
152+ if (entry_id)
153+ g_signal_emit (self, _service_signals[ENTRY_ACTIVATE_REQUEST], 0, entry_id);
154+
155+ return;
156+ }
157+ }
158+
159+ default_menu_shell_deactivate (menu_shell);
160+}
161+
162+static void
163 panel_service_show_entry_common (PanelService *self,
164 IndicatorObject *object,
165 IndicatorObjectEntry *entry,
166@@ -2281,6 +2338,7 @@
167 {
168 PanelServicePrivate *priv;
169 GtkWidget *last_menu;
170+ GtkMenuShellClass *menu_shell_class;
171
172 g_return_if_fail (PANEL_IS_SERVICE (self));
173 g_return_if_fail (INDICATOR_IS_OBJECT (object));
174@@ -2350,6 +2408,14 @@
175 g_signal_connect_after (priv->last_menu, "move-current",
176 G_CALLBACK (on_active_menu_move_current), self);
177
178+ /* Override the menu deactivation in order to prevent it to close too early */
179+ menu_shell_class = GTK_MENU_SHELL_GET_CLASS (priv->last_menu);
180+ if (menu_shell_class && menu_shell_class->deactivate != menu_shell_deactivate_override)
181+ {
182+ default_menu_shell_deactivate = menu_shell_class->deactivate;
183+ menu_shell_class->deactivate = menu_shell_deactivate_override;
184+ }
185+
186 gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (priv->last_menu), TRUE);
187 gtk_menu_popup (priv->last_menu, NULL, NULL, positon_menu, self, button, CurrentTime);
188 gboolean visible = gtk_widget_is_visible (GTK_WIDGET (priv->last_menu));
189@@ -2382,6 +2448,7 @@
190 priv->last_right = left + width -1;
191 priv->last_top = top;
192 priv->last_bottom = top + height -1;
193+ priv->last_open_time = g_get_monotonic_time ();
194 }
195 else
196 {
197@@ -2626,6 +2693,7 @@
198
199 if (GTK_IS_MENU (self->priv->last_menu))
200 {
201+ self->priv->last_open_time = 0;
202 gtk_menu_popdown (GTK_MENU (self->priv->last_menu));
203 }
204 }