diff options
Diffstat (limited to 'meta/packages/gtk+/gtk+-2.6.4-1.osso7/gtkmenu.c.diff')
-rw-r--r-- | meta/packages/gtk+/gtk+-2.6.4-1.osso7/gtkmenu.c.diff | 1223 |
1 files changed, 1223 insertions, 0 deletions
diff --git a/meta/packages/gtk+/gtk+-2.6.4-1.osso7/gtkmenu.c.diff b/meta/packages/gtk+/gtk+-2.6.4-1.osso7/gtkmenu.c.diff new file mode 100644 index 0000000000..16fac1b155 --- /dev/null +++ b/meta/packages/gtk+/gtk+-2.6.4-1.osso7/gtkmenu.c.diff | |||
@@ -0,0 +1,1223 @@ | |||
1 | --- gtk+-2.6.4/gtk/gtkmenu.c 2005-03-01 08:28:56.000000000 +0200 | ||
2 | +++ gtk+-2.6.4/gtk/gtkmenu.c 2005-04-06 16:19:36.921925376 +0300 | ||
3 | @@ -24,10 +24,16 @@ | ||
4 | * GTK+ at ftp://ftp.gtk.org/pub/gtk/. | ||
5 | */ | ||
6 | |||
7 | +/* Modified for Nokia Oyj during 2002-2005. See CHANGES file for list | ||
8 | + * of changes. | ||
9 | + */ | ||
10 | + | ||
11 | #define GTK_MENU_INTERNALS | ||
12 | |||
13 | #include <config.h> | ||
14 | #include <string.h> /* memset */ | ||
15 | +#include <math.h> | ||
16 | +#include <stdlib.h> | ||
17 | #include "gdk/gdkkeysyms.h" | ||
18 | #include "gtkalias.h" | ||
19 | #include "gtkaccellabel.h" | ||
20 | @@ -44,7 +50,11 @@ | ||
21 | #include "gtkvscrollbar.h" | ||
22 | #include "gtksettings.h" | ||
23 | #include "gtkintl.h" | ||
24 | +#include "gtkcombobox.h" | ||
25 | |||
26 | +/* Hildon : We need this to figure out if menu should have | ||
27 | + * corners etc. */ | ||
28 | +#include "gtkmenubar.h" | ||
29 | |||
30 | #define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_GET_CLASS (w) | ||
31 | |||
32 | @@ -55,16 +65,43 @@ | ||
33 | * extends below the submenu | ||
34 | */ | ||
35 | |||
36 | +/* HILDON: | ||
37 | + * Urgh, nasty thing to hard-code things like these :p | ||
38 | + * One should really do some rewriting here... | ||
39 | + */ | ||
40 | + | ||
41 | #define MENU_SCROLL_STEP1 8 | ||
42 | #define MENU_SCROLL_STEP2 15 | ||
43 | -#define MENU_SCROLL_ARROW_HEIGHT 16 | ||
44 | -#define MENU_SCROLL_FAST_ZONE 8 | ||
45 | +#define MENU_SCROLL_ARROW_HEIGHT 20 /* This used to be: 23; This hard-coding should be | ||
46 | + * changed. Add arrow_height style property into | ||
47 | + * commongtkrc and read it from there everywhere | ||
48 | + * where a reference to MENU_SCROLL_ARROW_HEIGHT | ||
49 | + * is made. | ||
50 | + * If these changes are made, please modify also | ||
51 | + * gtkcombobox.c. | ||
52 | + */ | ||
53 | +#define MENU_SCROLL_FAST_ZONE MENU_SCROLL_ARROW_HEIGHT /* Was originally 8 */ | ||
54 | #define MENU_SCROLL_TIMEOUT1 50 | ||
55 | #define MENU_SCROLL_TIMEOUT2 20 | ||
56 | |||
57 | #define ATTACH_INFO_KEY "gtk-menu-child-attach-info-key" | ||
58 | #define ATTACHED_MENUS "gtk-attached-menus" | ||
59 | |||
60 | +/* HILDON: */ | ||
61 | +#define HILDON_MENU_NAME_SHARP "menu_with_corners" | ||
62 | + | ||
63 | +/* needed to allow different themeing for first level menus */ | ||
64 | +#define HILDON_MENU_NAME_ROUND_FIRST_LEVEL "menu_without_corners_first_level" | ||
65 | +#define HILDON_MENU_NAME_ROUND "menu_without_corners" | ||
66 | +#define HILDON_MENU_NAME_FORCE_SHARP "menu_force_with_corners" | ||
67 | +#define HILDON_MENU_NAME_FORCE_ROUND "menu_force_without_corners" | ||
68 | + | ||
69 | +/* maximum sizes for menus when attached to comboboxes */ | ||
70 | +#define HILDON_MENU_COMBO_MAX_WIDTH 406 | ||
71 | +#define HILDON_MENU_COMBO_MIN_WIDTH 66 | ||
72 | +#define HILDON_MENU_COMBO_MAX_HEIGHT 305 | ||
73 | +#define HILDON_MENU_COMBO_MIN_HEIGHT 70 | ||
74 | + | ||
75 | typedef struct _GtkMenuAttachData GtkMenuAttachData; | ||
76 | typedef struct _GtkMenuPrivate GtkMenuPrivate; | ||
77 | |||
78 | @@ -92,6 +129,15 @@ | ||
79 | gboolean have_layout; | ||
80 | gint n_rows; | ||
81 | gint n_columns; | ||
82 | + | ||
83 | + /* Arrow states */ | ||
84 | + GtkStateType lower_arrow_state; | ||
85 | + GtkStateType upper_arrow_state; | ||
86 | + | ||
87 | + /* For context menu behavior */ | ||
88 | + gboolean context_menu; | ||
89 | + int popup_pointer_x; | ||
90 | + int popup_pointer_y; | ||
91 | }; | ||
92 | |||
93 | typedef struct | ||
94 | @@ -108,6 +154,7 @@ | ||
95 | |||
96 | enum { | ||
97 | MOVE_SCROLL, | ||
98 | + CLOSE_CURRENT, | ||
99 | LAST_SIGNAL | ||
100 | }; | ||
101 | |||
102 | @@ -191,7 +238,8 @@ | ||
103 | static void gtk_menu_handle_scrolling (GtkMenu *menu, | ||
104 | gint event_x, | ||
105 | gint event_y, | ||
106 | - gboolean enter); | ||
107 | + gboolean enter, | ||
108 | + gboolean motion); | ||
109 | static void gtk_menu_set_tearoff_hints (GtkMenu *menu, | ||
110 | gint width); | ||
111 | static void gtk_menu_style_set (GtkWidget *widget, | ||
112 | @@ -232,6 +280,9 @@ | ||
113 | guint signal_id); | ||
114 | static void _gtk_menu_refresh_accel_paths (GtkMenu *menu, | ||
115 | gboolean group_changed); | ||
116 | +static gboolean gtk_menu_check_name (GtkWidget *widget); | ||
117 | + | ||
118 | +static void _gtk_menu_close_current (GtkMenu *menu); | ||
119 | |||
120 | static GtkMenuShellClass *parent_class = NULL; | ||
121 | static const gchar attach_data_key[] = "gtk-menu-attach-data"; | ||
122 | @@ -496,7 +547,6 @@ | ||
123 | widget_class->hide_all = gtk_menu_hide_all; | ||
124 | widget_class->enter_notify_event = gtk_menu_enter_notify; | ||
125 | widget_class->leave_notify_event = gtk_menu_leave_notify; | ||
126 | - widget_class->motion_notify_event = gtk_menu_motion_notify; | ||
127 | widget_class->style_set = gtk_menu_style_set; | ||
128 | widget_class->focus = gtk_menu_focus; | ||
129 | widget_class->can_activate_accel = gtk_menu_real_can_activate_accel; | ||
130 | @@ -521,6 +571,15 @@ | ||
131 | _gtk_marshal_VOID__ENUM, | ||
132 | G_TYPE_NONE, 1, | ||
133 | GTK_TYPE_SCROLL_TYPE); | ||
134 | + | ||
135 | + menu_signals[CLOSE_CURRENT] = | ||
136 | + _gtk_binding_signal_new ("close_current", | ||
137 | + G_OBJECT_CLASS_TYPE (object_class), | ||
138 | + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, | ||
139 | + G_CALLBACK (_gtk_menu_close_current), | ||
140 | + NULL, NULL, | ||
141 | + _gtk_marshal_VOID__VOID, | ||
142 | + G_TYPE_NONE, 0); | ||
143 | |||
144 | g_object_class_install_property (gobject_class, | ||
145 | PROP_TEAROFF_TITLE, | ||
146 | @@ -606,6 +665,11 @@ | ||
147 | G_PARAM_READWRITE)); | ||
148 | |||
149 | binding_set = gtk_binding_set_by_class (class); | ||
150 | + /* Hildon : We moved handling of escape-key here because we need it to | ||
151 | + * work like closing a submenu, not closing all the menus. */ | ||
152 | + gtk_binding_entry_add_signal (binding_set, | ||
153 | + GDK_Escape, 0, | ||
154 | + "close_current", 0); | ||
155 | gtk_binding_entry_add_signal (binding_set, | ||
156 | GDK_Up, 0, | ||
157 | "move_current", 1, | ||
158 | @@ -709,6 +773,25 @@ | ||
159 | DEFAULT_POPDOWN_DELAY, | ||
160 | G_PARAM_READWRITE)); | ||
161 | |||
162 | + /* Hildon addition : border width was | ||
163 | + replaced with horizontal-padding and | ||
164 | + vertical-padding (which already is an style | ||
165 | + property for GtkMenu). */ | ||
166 | + gtk_widget_class_install_style_property (widget_class, | ||
167 | + g_param_spec_int ("horizontal-padding", | ||
168 | + P_("Horizontal Padding"), | ||
169 | + P_("Extra space at the left and right edges of the menu"), | ||
170 | + 0, | ||
171 | + G_MAXINT, | ||
172 | + 0, /* 1, */ | ||
173 | + G_PARAM_READABLE)); | ||
174 | + | ||
175 | + gtk_widget_class_install_style_property (widget_class, | ||
176 | + g_param_spec_boolean ("double_arrows", | ||
177 | + P_("Double Arrows"), | ||
178 | + P_("When scrolling, always show both arrows."), | ||
179 | + FALSE, | ||
180 | + G_PARAM_READABLE)); | ||
181 | } | ||
182 | |||
183 | |||
184 | @@ -884,13 +967,14 @@ | ||
185 | menu->toggle_size = 0; | ||
186 | |||
187 | menu->toplevel = g_object_connect (g_object_new (GTK_TYPE_WINDOW, | ||
188 | - "type", GTK_WINDOW_POPUP, | ||
189 | - "child", menu, | ||
190 | - NULL), | ||
191 | + "type", GTK_WINDOW_POPUP, | ||
192 | + "child", menu, | ||
193 | + NULL), | ||
194 | "signal::event", gtk_menu_window_event, menu, | ||
195 | "signal::size_request", gtk_menu_window_size_request, menu, | ||
196 | "signal::destroy", gtk_widget_destroyed, &menu->toplevel, | ||
197 | NULL); | ||
198 | + | ||
199 | gtk_window_set_resizable (GTK_WINDOW (menu->toplevel), FALSE); | ||
200 | gtk_window_set_mnemonic_modifier (GTK_WINDOW (menu->toplevel), 0); | ||
201 | |||
202 | @@ -919,6 +1003,15 @@ | ||
203 | menu->lower_arrow_visible = FALSE; | ||
204 | menu->upper_arrow_prelight = FALSE; | ||
205 | menu->lower_arrow_prelight = FALSE; | ||
206 | + | ||
207 | + /* <Hildon> */ | ||
208 | + priv->upper_arrow_state = GTK_STATE_NORMAL; | ||
209 | + priv->lower_arrow_state = GTK_STATE_NORMAL; | ||
210 | + | ||
211 | + priv->context_menu = FALSE; | ||
212 | + priv->popup_pointer_x = -1; | ||
213 | + priv->popup_pointer_y = -1; | ||
214 | + /* </hildon */ | ||
215 | |||
216 | priv->have_layout = FALSE; | ||
217 | } | ||
218 | @@ -1220,7 +1313,8 @@ | ||
219 | |||
220 | static gboolean | ||
221 | popup_grab_on_window (GdkWindow *window, | ||
222 | - guint32 activate_time) | ||
223 | + guint32 activate_time, | ||
224 | + gboolean grab_keyboard) | ||
225 | { | ||
226 | if ((gdk_pointer_grab (window, TRUE, | ||
227 | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | | ||
228 | @@ -1228,7 +1322,8 @@ | ||
229 | GDK_POINTER_MOTION_MASK, | ||
230 | NULL, NULL, activate_time) == 0)) | ||
231 | { | ||
232 | - if (gdk_keyboard_grab (window, TRUE, | ||
233 | + if (!grab_keyboard || | ||
234 | + gdk_keyboard_grab (window, TRUE, | ||
235 | activate_time) == 0) | ||
236 | return TRUE; | ||
237 | else | ||
238 | @@ -1282,6 +1377,7 @@ | ||
239 | GtkWidget *parent; | ||
240 | GdkEvent *current_event; | ||
241 | GtkMenuShell *menu_shell; | ||
242 | + gboolean grab_keyboard; | ||
243 | GtkMenuPrivate *priv = gtk_menu_get_private (menu); | ||
244 | |||
245 | g_return_if_fail (GTK_IS_MENU (menu)); | ||
246 | @@ -1333,10 +1429,28 @@ | ||
247 | * probably could just leave the grab on the other window, with a | ||
248 | * little reorganization of the code in gtkmenu*). | ||
249 | */ | ||
250 | + | ||
251 | + grab_keyboard = gtk_menu_shell_get_take_focus (menu_shell); | ||
252 | + gtk_window_set_accept_focus (GTK_WINDOW (menu->toplevel), grab_keyboard); | ||
253 | + | ||
254 | if (xgrab_shell && xgrab_shell != widget) | ||
255 | { | ||
256 | - if (popup_grab_on_window (xgrab_shell->window, activate_time)) | ||
257 | + if (popup_grab_on_window (xgrab_shell->window, activate_time, grab_keyboard)) | ||
258 | GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE; | ||
259 | + | ||
260 | + /* HILDON: | ||
261 | + * Check wheter parent is GtkMenuBar. If so, | ||
262 | + * then we need sharp upper corners for this menu. | ||
263 | + */ | ||
264 | + if (gtk_menu_check_name (widget)) | ||
265 | + { | ||
266 | + if (GTK_IS_MENU_BAR (parent_menu_shell)) | ||
267 | + gtk_widget_set_name (widget, HILDON_MENU_NAME_SHARP); | ||
268 | + else if (GTK_IS_MENU (parent_menu_shell)) | ||
269 | + gtk_widget_set_name( widget, HILDON_MENU_NAME_ROUND); | ||
270 | + else | ||
271 | + gtk_widget_set_name (widget, HILDON_MENU_NAME_ROUND_FIRST_LEVEL); | ||
272 | + } | ||
273 | } | ||
274 | else | ||
275 | { | ||
276 | @@ -1344,8 +1458,14 @@ | ||
277 | |||
278 | xgrab_shell = widget; | ||
279 | transfer_window = menu_grab_transfer_window_get (menu); | ||
280 | - if (popup_grab_on_window (transfer_window, activate_time)) | ||
281 | + if (popup_grab_on_window (transfer_window, activate_time, grab_keyboard)) | ||
282 | GTK_MENU_SHELL (xgrab_shell)->have_xgrab = TRUE; | ||
283 | + | ||
284 | + /* HILDON: | ||
285 | + * We want this menu to have round corners (Used by default) | ||
286 | + */ | ||
287 | + if (gtk_menu_check_name (widget)) | ||
288 | + gtk_widget_set_name (widget, HILDON_MENU_NAME_ROUND_FIRST_LEVEL); | ||
289 | } | ||
290 | |||
291 | if (!GTK_MENU_SHELL (xgrab_shell)->have_xgrab) | ||
292 | @@ -1409,6 +1529,23 @@ | ||
293 | |||
294 | /* Position the menu, possibly changing the size request | ||
295 | */ | ||
296 | + if (GTK_IS_COMBO_BOX (gtk_menu_get_attach_widget (menu))) | ||
297 | + { | ||
298 | + /* Hildon - limit the size if the menu is attached to a ComboBox */ | ||
299 | + GtkRequisition req; | ||
300 | + gint width, height; | ||
301 | + | ||
302 | + gtk_widget_set_size_request (widget, -1, -1); | ||
303 | + gtk_widget_size_request (widget, &req); | ||
304 | + | ||
305 | + width = MAX (MIN (req.width, HILDON_MENU_COMBO_MAX_WIDTH), | ||
306 | + HILDON_MENU_COMBO_MIN_WIDTH); | ||
307 | + height = MAX (MIN (req.height, HILDON_MENU_COMBO_MAX_HEIGHT), | ||
308 | + HILDON_MENU_COMBO_MIN_HEIGHT); | ||
309 | + | ||
310 | + gtk_widget_set_size_request (widget, width, height); | ||
311 | + } | ||
312 | + | ||
313 | gtk_menu_position (menu); | ||
314 | |||
315 | /* Compute the size of the toplevel and realize it so we | ||
316 | @@ -1430,13 +1567,29 @@ | ||
317 | |||
318 | gtk_menu_scroll_to (menu, menu->scroll_offset); | ||
319 | |||
320 | + if (priv->context_menu) | ||
321 | + { | ||
322 | + /* Save position of the pointer during popup */ | ||
323 | + /* currently not-multihead safe */ | ||
324 | + GdkScreen *screen; | ||
325 | + GdkDisplay *display; | ||
326 | + | ||
327 | + screen = gtk_widget_get_screen (widget); | ||
328 | + display = gdk_screen_get_display (screen); | ||
329 | + | ||
330 | + gdk_display_get_pointer (display, NULL, | ||
331 | + &priv->popup_pointer_x, | ||
332 | + &priv->popup_pointer_y, | ||
333 | + NULL); | ||
334 | + } | ||
335 | + | ||
336 | /* Once everything is set up correctly, map the toplevel window on | ||
337 | the screen. | ||
338 | */ | ||
339 | gtk_widget_show (menu->toplevel); | ||
340 | |||
341 | if (xgrab_shell == widget) | ||
342 | - popup_grab_on_window (widget->window, activate_time); /* Should always succeed */ | ||
343 | + popup_grab_on_window (widget->window, activate_time, grab_keyboard); /* Should always succeed */ | ||
344 | gtk_grab_add (GTK_WIDGET (menu)); | ||
345 | } | ||
346 | |||
347 | @@ -1996,6 +2149,7 @@ | ||
348 | GtkWidget *child; | ||
349 | GList *children; | ||
350 | guint vertical_padding; | ||
351 | + guint horizontal_padding; | ||
352 | |||
353 | g_return_if_fail (GTK_IS_MENU (widget)); | ||
354 | |||
355 | @@ -2025,9 +2179,10 @@ | ||
356 | |||
357 | gtk_widget_style_get (GTK_WIDGET (menu), | ||
358 | "vertical-padding", &vertical_padding, | ||
359 | + "horizontal-padding", &horizontal_padding, | ||
360 | NULL); | ||
361 | |||
362 | - attributes.x = border_width + widget->style->xthickness; | ||
363 | + attributes.x = border_width + widget->style->xthickness + horizontal_padding; | ||
364 | attributes.y = border_width + widget->style->ythickness + vertical_padding; | ||
365 | attributes.width = MAX (1, widget->allocation.width - attributes.x * 2); | ||
366 | attributes.height = MAX (1, widget->allocation.height - attributes.y * 2); | ||
367 | @@ -2040,11 +2195,14 @@ | ||
368 | if (menu->lower_arrow_visible) | ||
369 | attributes.height -= MENU_SCROLL_ARROW_HEIGHT; | ||
370 | |||
371 | + attributes.window_type = GDK_WINDOW_CHILD; | ||
372 | + | ||
373 | menu->view_window = gdk_window_new (widget->window, &attributes, attributes_mask); | ||
374 | gdk_window_set_user_data (menu->view_window, menu); | ||
375 | |||
376 | attributes.x = 0; | ||
377 | attributes.y = 0; | ||
378 | + attributes.width = MAX (1, widget->requisition.width - (border_width + widget->style->xthickness + horizontal_padding) * 2); | ||
379 | attributes.height = MAX (1, widget->requisition.height - (border_width + widget->style->ythickness + vertical_padding) * 2); | ||
380 | |||
381 | menu->bin_window = gdk_window_new (menu->view_window, &attributes, attributes_mask); | ||
382 | @@ -2164,6 +2322,10 @@ | ||
383 | guint vertical_padding; | ||
384 | GtkRequisition child_requisition; | ||
385 | GtkMenuPrivate *priv; | ||
386 | + guint horizontal_padding; | ||
387 | + GdkScreen *screen; | ||
388 | + GdkRectangle monitor; | ||
389 | + gint monitor_num; | ||
390 | |||
391 | g_return_if_fail (GTK_IS_MENU (widget)); | ||
392 | g_return_if_fail (requisition != NULL); | ||
393 | @@ -2182,6 +2344,16 @@ | ||
394 | priv->heights = g_new0 (guint, gtk_menu_get_n_rows (menu)); | ||
395 | priv->heights_length = gtk_menu_get_n_rows (menu); | ||
396 | |||
397 | +/* Hildon addition to find out the monitor width */ | ||
398 | + screen = gtk_widget_get_screen (widget); | ||
399 | + if (widget->window != NULL) | ||
400 | + monitor_num = gdk_screen_get_monitor_at_window (screen, widget->window); | ||
401 | + else | ||
402 | + monitor_num = 0; | ||
403 | + if (monitor_num < 0) | ||
404 | + monitor_num = 0; | ||
405 | + gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); | ||
406 | + | ||
407 | children = menu_shell->children; | ||
408 | while (children) | ||
409 | { | ||
410 | @@ -2223,15 +2395,18 @@ | ||
411 | |||
412 | requisition->width += max_toggle_size + max_accel_width; | ||
413 | requisition->width *= gtk_menu_get_n_columns (menu); | ||
414 | - requisition->width += (GTK_CONTAINER (menu)->border_width + | ||
415 | - widget->style->xthickness) * 2; | ||
416 | |||
417 | gtk_widget_style_get (GTK_WIDGET (menu), | ||
418 | + "horizontal-padding", &horizontal_padding, | ||
419 | "vertical-padding", &vertical_padding, | ||
420 | NULL); | ||
421 | + requisition->width += (GTK_CONTAINER (menu)->border_width + horizontal_padding + | ||
422 | + widget->style->xthickness) * 2; | ||
423 | requisition->height += (GTK_CONTAINER (menu)->border_width + vertical_padding + | ||
424 | widget->style->ythickness) * 2; | ||
425 | |||
426 | +/* Hildon addition to not make the menu too wide for the screen. */ | ||
427 | + requisition->width = MIN (requisition->width, monitor.width); | ||
428 | menu->toggle_size = max_toggle_size; | ||
429 | |||
430 | /* Don't resize the tearoff if it is not active, because it won't redraw (it is only a background pixmap). | ||
431 | @@ -2253,6 +2428,7 @@ | ||
432 | GList *children; | ||
433 | gint x, y; | ||
434 | gint width, height; | ||
435 | + guint horizontal_padding; | ||
436 | guint vertical_padding; | ||
437 | |||
438 | g_return_if_fail (GTK_IS_MENU (widget)); | ||
439 | @@ -2266,10 +2442,11 @@ | ||
440 | gtk_widget_get_child_requisition (GTK_WIDGET (menu), &child_requisition); | ||
441 | |||
442 | gtk_widget_style_get (GTK_WIDGET (menu), | ||
443 | + "horizontal-padding", &horizontal_padding, | ||
444 | "vertical-padding", &vertical_padding, | ||
445 | NULL); | ||
446 | |||
447 | - x = GTK_CONTAINER (menu)->border_width + widget->style->xthickness; | ||
448 | + x = GTK_CONTAINER (menu)->border_width + widget->style->xthickness + horizontal_padding; | ||
449 | y = GTK_CONTAINER (menu)->border_width + widget->style->ythickness + vertical_padding; | ||
450 | |||
451 | width = MAX (1, allocation->width - x * 2); | ||
452 | @@ -2407,27 +2584,32 @@ | ||
453 | GdkEventExpose *event) | ||
454 | { | ||
455 | GtkMenu *menu; | ||
456 | - gint width, height; | ||
457 | - gint border_x, border_y; | ||
458 | - guint vertical_padding; | ||
459 | |||
460 | g_return_if_fail (GTK_IS_MENU (widget)); | ||
461 | |||
462 | menu = GTK_MENU (widget); | ||
463 | |||
464 | - gtk_widget_style_get (GTK_WIDGET (menu), | ||
465 | - "vertical-padding", &vertical_padding, | ||
466 | - NULL); | ||
467 | - | ||
468 | - border_x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness; | ||
469 | - border_y = GTK_CONTAINER (widget)->border_width + widget->style->ythickness + vertical_padding; | ||
470 | - gdk_drawable_get_size (widget->window, &width, &height); | ||
471 | - | ||
472 | if (event->window == widget->window) | ||
473 | { | ||
474 | + gint width, height; | ||
475 | + gint border_x, border_y; | ||
476 | + guint vertical_padding; | ||
477 | + guint horizontal_padding; | ||
478 | + GtkMenuPrivate *priv; | ||
479 | gint arrow_space = MENU_SCROLL_ARROW_HEIGHT - 2 * widget->style->ythickness; | ||
480 | gint arrow_size = 0.7 * arrow_space; | ||
481 | |||
482 | + priv = gtk_menu_get_private (menu); | ||
483 | + | ||
484 | + gtk_widget_style_get (GTK_WIDGET (menu), | ||
485 | + "vertical-padding", &vertical_padding, | ||
486 | + "horizontal-padding", &horizontal_padding, | ||
487 | + NULL); | ||
488 | + | ||
489 | + border_x = GTK_CONTAINER (widget)->border_width + widget->style->xthickness + horizontal_padding; | ||
490 | + border_y = GTK_CONTAINER (widget)->border_width + widget->style->ythickness + vertical_padding; | ||
491 | + gdk_drawable_get_size (widget->window, &width, &height); | ||
492 | + | ||
493 | gtk_paint_box (widget->style, | ||
494 | widget->window, | ||
495 | GTK_STATE_NORMAL, | ||
496 | @@ -2436,21 +2618,9 @@ | ||
497 | 0, 0, -1, -1); | ||
498 | if (menu->upper_arrow_visible && !menu->tearoff_active) | ||
499 | { | ||
500 | - gtk_paint_box (widget->style, | ||
501 | - widget->window, | ||
502 | - menu->upper_arrow_prelight ? | ||
503 | - GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, | ||
504 | - GTK_SHADOW_OUT, | ||
505 | - NULL, widget, "menu", | ||
506 | - border_x, | ||
507 | - border_y, | ||
508 | - width - 2 * border_x, | ||
509 | - MENU_SCROLL_ARROW_HEIGHT); | ||
510 | - | ||
511 | gtk_paint_arrow (widget->style, | ||
512 | widget->window, | ||
513 | - menu->upper_arrow_prelight ? | ||
514 | - GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, | ||
515 | + priv->upper_arrow_state, | ||
516 | GTK_SHADOW_OUT, | ||
517 | NULL, widget, "menu_scroll_arrow_up", | ||
518 | GTK_ARROW_UP, | ||
519 | @@ -2462,21 +2632,9 @@ | ||
520 | |||
521 | if (menu->lower_arrow_visible && !menu->tearoff_active) | ||
522 | { | ||
523 | - gtk_paint_box (widget->style, | ||
524 | - widget->window, | ||
525 | - menu->lower_arrow_prelight ? | ||
526 | - GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, | ||
527 | - GTK_SHADOW_OUT, | ||
528 | - NULL, widget, "menu", | ||
529 | - border_x, | ||
530 | - height - border_y - MENU_SCROLL_ARROW_HEIGHT, | ||
531 | - width - 2*border_x, | ||
532 | - MENU_SCROLL_ARROW_HEIGHT); | ||
533 | - | ||
534 | gtk_paint_arrow (widget->style, | ||
535 | widget->window, | ||
536 | - menu->lower_arrow_prelight ? | ||
537 | - GTK_STATE_PRELIGHT : GTK_STATE_NORMAL, | ||
538 | + priv->lower_arrow_state, | ||
539 | GTK_SHADOW_OUT, | ||
540 | NULL, widget, "menu_scroll_arrow_down", | ||
541 | GTK_ARROW_DOWN, | ||
542 | @@ -2516,18 +2674,82 @@ | ||
543 | GTK_WIDGET_CLASS (parent_class)->show (widget); | ||
544 | } | ||
545 | |||
546 | +static GtkWidget * | ||
547 | +find_active_menu_item (GdkEventButton *event) | ||
548 | +{ | ||
549 | + GtkWidget *menu_item; | ||
550 | + | ||
551 | + menu_item = gtk_get_event_widget ((GdkEvent*) event); | ||
552 | + while (menu_item && !GTK_IS_MENU_ITEM (menu_item)) | ||
553 | + menu_item = menu_item->parent; | ||
554 | + | ||
555 | + return menu_item; | ||
556 | +} | ||
557 | + | ||
558 | +static gboolean | ||
559 | +pointer_in_menu_tree (GtkWidget *widget) | ||
560 | +{ | ||
561 | + GtkMenuShell *mshell; | ||
562 | + int width, height, x, y; | ||
563 | + | ||
564 | + mshell = GTK_MENU_SHELL (widget); | ||
565 | + | ||
566 | + gdk_window_get_pointer (widget->window, &x, &y, NULL); | ||
567 | + gdk_drawable_get_size (widget->window, &width, &height); | ||
568 | + | ||
569 | + if ((x <= width) && (x >= 0) && (y <= height) && (y >= 0)) | ||
570 | + return TRUE; | ||
571 | + | ||
572 | + if ((mshell->parent_menu_shell != NULL) && | ||
573 | + GTK_IS_MENU (mshell->parent_menu_shell)) | ||
574 | + return pointer_in_menu_tree (mshell->parent_menu_shell); | ||
575 | + | ||
576 | + return FALSE; | ||
577 | +} | ||
578 | + | ||
579 | +static int | ||
580 | +distance_traveled (GtkWidget *widget) | ||
581 | +{ | ||
582 | + GtkMenuPrivate *priv; | ||
583 | + GdkScreen *screen; | ||
584 | + GdkDisplay *display; | ||
585 | + int x, y, dx, dy; | ||
586 | + | ||
587 | + priv = gtk_menu_get_private (GTK_MENU (widget)); | ||
588 | + | ||
589 | + screen = gtk_widget_get_screen (widget); | ||
590 | + display = gdk_screen_get_display (screen); | ||
591 | + | ||
592 | + gdk_display_get_pointer (display, NULL, &x, &y, NULL); | ||
593 | + | ||
594 | + dx = (priv->popup_pointer_x - x); | ||
595 | + dy = (priv->popup_pointer_y - y); | ||
596 | + | ||
597 | + return abs ((int) sqrt ((double) (dx * dx + dy * dy))); | ||
598 | +} | ||
599 | + | ||
600 | static gboolean | ||
601 | gtk_menu_button_press (GtkWidget *widget, | ||
602 | - GdkEventButton *event) | ||
603 | + GdkEventButton *event) | ||
604 | { | ||
605 | - /* Don't pop down the menu for releases over scroll arrows | ||
606 | - */ | ||
607 | - if (GTK_IS_MENU (widget)) | ||
608 | + GtkWidget *menu_item; | ||
609 | + | ||
610 | + menu_item = find_active_menu_item (event); | ||
611 | + if (menu_item == NULL) | ||
612 | { | ||
613 | GtkMenu *menu = GTK_MENU (widget); | ||
614 | |||
615 | - if (menu->upper_arrow_prelight || menu->lower_arrow_prelight) | ||
616 | - return TRUE; | ||
617 | + if (menu->upper_arrow_prelight || menu->lower_arrow_prelight) | ||
618 | + { | ||
619 | + gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE, FALSE); | ||
620 | + | ||
621 | + return TRUE; | ||
622 | + } | ||
623 | + | ||
624 | + /* Don't pass down to menu shell if a non-menuitem part | ||
625 | + * of the menu was clicked. */ | ||
626 | + if (pointer_in_menu_tree (widget)) | ||
627 | + return TRUE; | ||
628 | } | ||
629 | |||
630 | return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event); | ||
631 | @@ -2537,14 +2759,44 @@ | ||
632 | gtk_menu_button_release (GtkWidget *widget, | ||
633 | GdkEventButton *event) | ||
634 | { | ||
635 | - /* Don't pop down the menu for releases over scroll arrows | ||
636 | - */ | ||
637 | - if (GTK_IS_MENU (widget)) | ||
638 | + GtkMenuPrivate *priv; | ||
639 | + GtkWidget *menu_item; | ||
640 | + | ||
641 | + priv = gtk_menu_get_private (GTK_MENU (widget)); | ||
642 | + | ||
643 | + menu_item = find_active_menu_item (event); | ||
644 | + if (menu_item == NULL) | ||
645 | { | ||
646 | GtkMenu *menu = GTK_MENU (widget); | ||
647 | |||
648 | - if (menu->upper_arrow_prelight || menu->lower_arrow_prelight) | ||
649 | - return TRUE; | ||
650 | + if (menu->upper_arrow_prelight || menu->lower_arrow_prelight) | ||
651 | + { | ||
652 | + gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, FALSE, FALSE); | ||
653 | + | ||
654 | + return TRUE; | ||
655 | + } | ||
656 | + | ||
657 | + if (priv->context_menu && | ||
658 | + (priv->popup_pointer_x >= 0) && | ||
659 | + (priv->popup_pointer_y >= 0)) | ||
660 | + { | ||
661 | + int distance; | ||
662 | + | ||
663 | + distance = distance_traveled (widget); | ||
664 | + | ||
665 | + priv->popup_pointer_x = -1; | ||
666 | + priv->popup_pointer_y = -1; | ||
667 | + | ||
668 | + /* Don't popdown if we traveled less than 20px since popup point, | ||
669 | + * as per the specs. */ | ||
670 | + if (distance < 20) | ||
671 | + return TRUE; | ||
672 | + } | ||
673 | + | ||
674 | + /* Don't pass down to menu shell if a non-menuitem part | ||
675 | + * of the menu was clicked. */ | ||
676 | + if (pointer_in_menu_tree (widget)) | ||
677 | + return TRUE; | ||
678 | } | ||
679 | |||
680 | return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event); | ||
681 | @@ -2765,7 +3017,7 @@ | ||
682 | gboolean need_enter; | ||
683 | |||
684 | if (GTK_IS_MENU (widget)) | ||
685 | - gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE); | ||
686 | + gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE, TRUE); | ||
687 | |||
688 | /* We received the event for one of two reasons: | ||
689 | * | ||
690 | @@ -2779,7 +3031,27 @@ | ||
691 | menu_item = gtk_get_event_widget ((GdkEvent*) event); | ||
692 | if (!menu_item || !GTK_IS_MENU_ITEM (menu_item) || | ||
693 | !GTK_IS_MENU (menu_item->parent)) | ||
694 | - return FALSE; | ||
695 | + { | ||
696 | + GtkMenuPrivate *priv; | ||
697 | + | ||
698 | + priv = gtk_menu_get_private (GTK_MENU (widget)); | ||
699 | + | ||
700 | + if (priv->context_menu) | ||
701 | + { | ||
702 | + /* Context menu mode. If we dragged out of the menu, | ||
703 | + * close the menu, as by the specs. */ | ||
704 | + if (!pointer_in_menu_tree (widget) && | ||
705 | + (distance_traveled (widget) >= 20) && | ||
706 | + (event->state & GDK_BUTTON1_MASK)) | ||
707 | + { | ||
708 | + gtk_menu_deactivate (GTK_MENU_SHELL (widget)); | ||
709 | + | ||
710 | + return TRUE; | ||
711 | + } | ||
712 | + } | ||
713 | + | ||
714 | + return FALSE; | ||
715 | + } | ||
716 | |||
717 | menu_shell = GTK_MENU_SHELL (menu_item->parent); | ||
718 | menu = GTK_MENU (menu_shell); | ||
719 | @@ -2795,6 +3067,11 @@ | ||
720 | */ | ||
721 | if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root)) | ||
722 | return TRUE; | ||
723 | +/* HILDON MOD. | ||
724 | + * Close the submenus that are two levels down from the currently selected. | ||
725 | + * This ensures that the focus is correct all the time.*/ | ||
726 | + if (GTK_MENU_ITEM(menu_item)->submenu != NULL) | ||
727 | + gtk_menu_shell_deselect (GTK_MENU_SHELL(&(GTK_MENU(GTK_MENU_ITEM(menu_item)->submenu)->menu_shell))); | ||
728 | |||
729 | /* Make sure we pop down if we enter a non-selectable menu item, so we | ||
730 | * don't show a submenu when the cursor is outside the stay-up triangle. | ||
731 | @@ -2828,6 +3105,7 @@ | ||
732 | send_event->crossing.y_root = event->y_root; | ||
733 | send_event->crossing.x = event->x; | ||
734 | send_event->crossing.y = event->y; | ||
735 | + send_event->crossing.state = event->state; | ||
736 | |||
737 | /* We send the event to 'widget', the currently active menu, | ||
738 | * instead of 'menu', the menu that the pointer is in. This | ||
739 | @@ -2852,17 +3130,24 @@ | ||
740 | GtkWidget *widget; | ||
741 | gint offset; | ||
742 | gint view_width, view_height; | ||
743 | + gboolean double_arrows; | ||
744 | |||
745 | widget = GTK_WIDGET (menu); | ||
746 | offset = menu->scroll_offset + step; | ||
747 | |||
748 | + /* get double_arrows style property */ | ||
749 | + gtk_widget_style_get (widget, | ||
750 | + "double_arrows", &double_arrows, | ||
751 | + NULL); | ||
752 | + | ||
753 | /* If we scroll upward and the non-visible top part | ||
754 | * is smaller than the scroll arrow it would be | ||
755 | * pretty stupid to show the arrow and taking more | ||
756 | * screen space than just scrolling to the top. | ||
757 | */ | ||
758 | - if ((step < 0) && (offset < MENU_SCROLL_ARROW_HEIGHT)) | ||
759 | - offset = 0; | ||
760 | + if (!double_arrows) | ||
761 | + if ((step < 0) && (offset < MENU_SCROLL_ARROW_HEIGHT)) | ||
762 | + offset = 0; | ||
763 | |||
764 | /* Don't scroll over the top if we weren't before: */ | ||
765 | if ((menu->scroll_offset >= 0) && (offset < 0)) | ||
766 | @@ -2874,6 +3159,12 @@ | ||
767 | if (menu->scroll_offset > 0) | ||
768 | view_height -= MENU_SCROLL_ARROW_HEIGHT; | ||
769 | |||
770 | + /* When both arrows are always shown, reduce | ||
771 | + * view height even more. | ||
772 | + */ | ||
773 | + if (double_arrows) | ||
774 | + view_height -= MENU_SCROLL_ARROW_HEIGHT; | ||
775 | + | ||
776 | if ((menu->scroll_offset + view_height <= widget->requisition.height) && | ||
777 | (offset + view_height > widget->requisition.height)) | ||
778 | offset = widget->requisition.height - view_height; | ||
779 | @@ -2922,18 +3213,21 @@ | ||
780 | gtk_menu_handle_scrolling (GtkMenu *menu, | ||
781 | gint x, | ||
782 | gint y, | ||
783 | - gboolean enter) | ||
784 | + gboolean enter, | ||
785 | + gboolean motion) | ||
786 | { | ||
787 | GtkMenuShell *menu_shell; | ||
788 | + GtkMenuPrivate *priv; | ||
789 | gint width, height; | ||
790 | gint border; | ||
791 | GdkRectangle rect; | ||
792 | - gboolean in_arrow; | ||
793 | gboolean scroll_fast = FALSE; | ||
794 | guint vertical_padding; | ||
795 | gint top_x, top_y; | ||
796 | gint win_x, win_y; | ||
797 | |||
798 | + priv = gtk_menu_get_private (menu); | ||
799 | + | ||
800 | menu_shell = GTK_MENU_SHELL (menu); | ||
801 | |||
802 | gdk_drawable_get_size (GTK_WIDGET (menu)->window, &width, &height); | ||
803 | @@ -2946,10 +3240,11 @@ | ||
804 | GTK_WIDGET (menu)->style->ythickness + vertical_padding; | ||
805 | |||
806 | gdk_window_get_position (menu->toplevel->window, &top_x, &top_y); | ||
807 | + x -= top_x; | ||
808 | + y -= top_y; | ||
809 | + | ||
810 | gdk_window_get_position (GTK_WIDGET (menu)->window, &win_x, &win_y); | ||
811 | - win_x += top_x; | ||
812 | - win_y += top_y; | ||
813 | - | ||
814 | + | ||
815 | if (menu->upper_arrow_visible && !menu->tearoff_active) | ||
816 | { | ||
817 | rect.x = win_x; | ||
818 | @@ -2957,35 +3252,49 @@ | ||
819 | rect.width = width; | ||
820 | rect.height = MENU_SCROLL_ARROW_HEIGHT + border; | ||
821 | |||
822 | - in_arrow = FALSE; | ||
823 | + menu->upper_arrow_prelight = FALSE; | ||
824 | if ((x >= rect.x) && (x < rect.x + rect.width) && | ||
825 | (y >= rect.y) && (y < rect.y + rect.height)) | ||
826 | - { | ||
827 | - in_arrow = TRUE; | ||
828 | - scroll_fast = (y < rect.y + MENU_SCROLL_FAST_ZONE); | ||
829 | - } | ||
830 | - | ||
831 | - if (enter && in_arrow && | ||
832 | - (!menu->upper_arrow_prelight || menu->scroll_fast != scroll_fast)) | ||
833 | - { | ||
834 | - menu->upper_arrow_prelight = TRUE; | ||
835 | - menu->scroll_fast = scroll_fast; | ||
836 | - gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE); | ||
837 | - | ||
838 | - /* Deselect the active item so that any submenus are poped down */ | ||
839 | - gtk_menu_shell_deselect (menu_shell); | ||
840 | + menu->upper_arrow_prelight = TRUE; | ||
841 | |||
842 | - gtk_menu_remove_scroll_timeout (menu); | ||
843 | - menu->scroll_step = (scroll_fast) ? -MENU_SCROLL_STEP2 : -MENU_SCROLL_STEP1; | ||
844 | - menu->timeout_id = g_timeout_add ((scroll_fast) ? MENU_SCROLL_TIMEOUT2 : MENU_SCROLL_TIMEOUT1, | ||
845 | - gtk_menu_scroll_timeout, | ||
846 | - menu); | ||
847 | - } | ||
848 | - else if (!enter && !in_arrow && menu->upper_arrow_prelight) | ||
849 | + if (priv->upper_arrow_state != GTK_STATE_INSENSITIVE) | ||
850 | { | ||
851 | - gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE); | ||
852 | - | ||
853 | - gtk_menu_stop_scrolling (menu); | ||
854 | + if (enter && menu->upper_arrow_prelight && | ||
855 | + (menu->timeout_id == 0 || menu->scroll_fast != scroll_fast)) | ||
856 | + { | ||
857 | + menu->scroll_fast = scroll_fast; | ||
858 | + | ||
859 | + /* Deselect the active item so that any submenus are poped down */ | ||
860 | + gtk_menu_shell_deselect (menu_shell); | ||
861 | + | ||
862 | + gtk_menu_remove_scroll_timeout (menu); | ||
863 | + menu->scroll_step = (scroll_fast) ? -MENU_SCROLL_STEP2 : -MENU_SCROLL_STEP1; | ||
864 | + | ||
865 | + if (!motion) | ||
866 | + { | ||
867 | + /* Only do stuff on click. */ | ||
868 | + GtkSettings *settings; | ||
869 | + guint timeout; | ||
870 | + | ||
871 | + settings = gtk_settings_get_default (); | ||
872 | + g_object_get (settings, "gtk-update-timeout", &timeout, NULL); | ||
873 | + | ||
874 | + menu->timeout_id = g_timeout_add (timeout / 2, gtk_menu_scroll_timeout, menu); | ||
875 | + | ||
876 | + priv->upper_arrow_state = GTK_STATE_ACTIVE; | ||
877 | + } | ||
878 | + | ||
879 | + gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE); | ||
880 | + } | ||
881 | + else if (!enter) | ||
882 | + { | ||
883 | + gtk_menu_stop_scrolling (menu); | ||
884 | + | ||
885 | + priv->upper_arrow_state = menu->upper_arrow_prelight ? | ||
886 | + GTK_STATE_PRELIGHT : GTK_STATE_NORMAL; | ||
887 | + | ||
888 | + gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE); | ||
889 | + } | ||
890 | } | ||
891 | } | ||
892 | |||
893 | @@ -2996,36 +3305,50 @@ | ||
894 | rect.width = width; | ||
895 | rect.height = MENU_SCROLL_ARROW_HEIGHT + border; | ||
896 | |||
897 | - in_arrow = FALSE; | ||
898 | + menu->lower_arrow_prelight = FALSE; | ||
899 | if ((x >= rect.x) && (x < rect.x + rect.width) && | ||
900 | (y >= rect.y) && (y < rect.y + rect.height)) | ||
901 | - { | ||
902 | - in_arrow = TRUE; | ||
903 | - scroll_fast = (y > rect.y + rect.height - MENU_SCROLL_FAST_ZONE); | ||
904 | - } | ||
905 | + menu->lower_arrow_prelight = TRUE; | ||
906 | |||
907 | - if (enter && in_arrow && | ||
908 | - (!menu->lower_arrow_prelight || menu->scroll_fast != scroll_fast)) | ||
909 | + if (priv->lower_arrow_state != GTK_STATE_INSENSITIVE) | ||
910 | { | ||
911 | - menu->lower_arrow_prelight = TRUE; | ||
912 | - menu->scroll_fast = scroll_fast; | ||
913 | - gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE); | ||
914 | + if (enter && menu->lower_arrow_prelight && | ||
915 | + (menu->timeout_id == 0 || menu->scroll_fast != scroll_fast)) | ||
916 | + { | ||
917 | + menu->scroll_fast = scroll_fast; | ||
918 | |||
919 | - /* Deselect the active item so that any submenus are poped down */ | ||
920 | - gtk_menu_shell_deselect (menu_shell); | ||
921 | + /* Deselect the active item so that any submenus are poped down */ | ||
922 | + gtk_menu_shell_deselect (menu_shell); | ||
923 | |||
924 | - gtk_menu_remove_scroll_timeout (menu); | ||
925 | - menu->scroll_step = (scroll_fast) ? MENU_SCROLL_STEP2 : MENU_SCROLL_STEP1; | ||
926 | - menu->timeout_id = g_timeout_add ((scroll_fast) ? MENU_SCROLL_TIMEOUT2 : MENU_SCROLL_TIMEOUT1, | ||
927 | - gtk_menu_scroll_timeout, | ||
928 | - menu); | ||
929 | - } | ||
930 | - else if (!enter && !in_arrow && menu->lower_arrow_prelight) | ||
931 | - { | ||
932 | - gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE); | ||
933 | - | ||
934 | - gtk_menu_stop_scrolling (menu); | ||
935 | - } | ||
936 | + gtk_menu_remove_scroll_timeout (menu); | ||
937 | + menu->scroll_step = (scroll_fast) ? MENU_SCROLL_STEP2 : MENU_SCROLL_STEP1; | ||
938 | + | ||
939 | + if (!motion) | ||
940 | + { | ||
941 | + /* Only do stuff on click. */ | ||
942 | + GtkSettings *settings; | ||
943 | + guint timeout; | ||
944 | + | ||
945 | + settings = gtk_settings_get_default (); | ||
946 | + g_object_get (settings, "gtk-update-timeout", &timeout, NULL); | ||
947 | + | ||
948 | + menu->timeout_id = g_timeout_add (timeout / 2, gtk_menu_scroll_timeout, menu); | ||
949 | + | ||
950 | + priv->lower_arrow_state = GTK_STATE_ACTIVE; | ||
951 | + } | ||
952 | + | ||
953 | + gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE); | ||
954 | + } | ||
955 | + else if (!enter) | ||
956 | + { | ||
957 | + gtk_menu_stop_scrolling (menu); | ||
958 | + | ||
959 | + priv->lower_arrow_state = menu->lower_arrow_prelight ? | ||
960 | + GTK_STATE_PRELIGHT : GTK_STATE_NORMAL; | ||
961 | + | ||
962 | + gdk_window_invalidate_rect (GTK_WIDGET (menu)->window, &rect, FALSE); | ||
963 | + } | ||
964 | + } | ||
965 | } | ||
966 | } | ||
967 | |||
968 | @@ -3041,7 +3364,7 @@ | ||
969 | GtkMenuShell *menu_shell = GTK_MENU_SHELL (widget); | ||
970 | |||
971 | if (!menu_shell->ignore_enter) | ||
972 | - gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE); | ||
973 | + gtk_menu_handle_scrolling (GTK_MENU (widget), event->x_root, event->y_root, TRUE, TRUE); | ||
974 | } | ||
975 | |||
976 | if (menu_item && GTK_IS_MENU_ITEM (menu_item)) | ||
977 | @@ -3106,7 +3429,7 @@ | ||
978 | if (gtk_menu_navigating_submenu (menu, event->x_root, event->y_root)) | ||
979 | return TRUE; | ||
980 | |||
981 | - gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE); | ||
982 | + gtk_menu_handle_scrolling (menu, event->x_root, event->y_root, FALSE, TRUE); | ||
983 | |||
984 | event_widget = gtk_get_event_widget ((GdkEvent*) event); | ||
985 | |||
986 | @@ -3611,7 +3934,13 @@ | ||
987 | requisition.width, requisition.height); | ||
988 | } | ||
989 | |||
990 | - menu->scroll_offset = scroll_offset; | ||
991 | + /* Hildon hack for menu in comboboxes: | ||
992 | + * in case the menu in attached to a ComboBox, the scroll_offset is | ||
993 | + * calculated in the positioning function so we dont't overwrite it | ||
994 | + * with the value calculated above (in this function) */ | ||
995 | + if ( !GTK_IS_COMBO_BOX(gtk_menu_get_attach_widget(menu)) ) | ||
996 | + menu->scroll_offset = scroll_offset; | ||
997 | + | ||
998 | } | ||
999 | |||
1000 | static void | ||
1001 | @@ -3628,9 +3957,6 @@ | ||
1002 | gtk_menu_stop_scrolling (GtkMenu *menu) | ||
1003 | { | ||
1004 | gtk_menu_remove_scroll_timeout (menu); | ||
1005 | - | ||
1006 | - menu->upper_arrow_prelight = FALSE; | ||
1007 | - menu->lower_arrow_prelight = FALSE; | ||
1008 | } | ||
1009 | |||
1010 | static void | ||
1011 | @@ -3644,6 +3970,8 @@ | ||
1012 | gboolean last_visible; | ||
1013 | gint menu_height; | ||
1014 | guint vertical_padding; | ||
1015 | + guint horizontal_padding; | ||
1016 | + gboolean double_arrows; | ||
1017 | |||
1018 | widget = GTK_WIDGET (menu); | ||
1019 | |||
1020 | @@ -3663,19 +3991,93 @@ | ||
1021 | |||
1022 | gtk_widget_style_get (GTK_WIDGET (menu), | ||
1023 | "vertical-padding", &vertical_padding, | ||
1024 | + "horizontal-padding", &horizontal_padding, | ||
1025 | + "double_arrows", &double_arrows, | ||
1026 | NULL); | ||
1027 | |||
1028 | border_width = GTK_CONTAINER (menu)->border_width; | ||
1029 | - view_width -= (border_width + widget->style->xthickness) * 2; | ||
1030 | + view_width -= (border_width + widget->style->xthickness + horizontal_padding) * 2; | ||
1031 | view_height -= (border_width + widget->style->ythickness + vertical_padding) * 2; | ||
1032 | menu_height = widget->requisition.height - | ||
1033 | (border_width + widget->style->ythickness + vertical_padding) * 2; | ||
1034 | |||
1035 | - x = border_width + widget->style->xthickness; | ||
1036 | + x = border_width + widget->style->xthickness + horizontal_padding; | ||
1037 | y = border_width + widget->style->ythickness + vertical_padding; | ||
1038 | |||
1039 | + if (double_arrows && !menu->tearoff_active && (view_height < menu_height)) | ||
1040 | + { | ||
1041 | + GtkMenuPrivate *priv; | ||
1042 | + GtkStateType upper_arrow_previous_state, lower_arrow_previous_state; | ||
1043 | + | ||
1044 | + priv = gtk_menu_get_private (menu); | ||
1045 | + | ||
1046 | + upper_arrow_previous_state = priv->upper_arrow_state; | ||
1047 | + lower_arrow_previous_state = priv->lower_arrow_state; | ||
1048 | + | ||
1049 | + if (!menu->upper_arrow_visible || !menu->lower_arrow_visible) | ||
1050 | + gtk_widget_queue_draw (GTK_WIDGET (menu)); | ||
1051 | + | ||
1052 | + view_height -= 2*MENU_SCROLL_ARROW_HEIGHT; | ||
1053 | + y += MENU_SCROLL_ARROW_HEIGHT; | ||
1054 | + | ||
1055 | + menu->upper_arrow_visible = menu->lower_arrow_visible = TRUE; | ||
1056 | + if (priv->upper_arrow_state == GTK_STATE_INSENSITIVE) | ||
1057 | + { | ||
1058 | + priv->upper_arrow_state = menu->upper_arrow_prelight ? | ||
1059 | + GTK_STATE_PRELIGHT : GTK_STATE_NORMAL; | ||
1060 | + } | ||
1061 | + if (priv->lower_arrow_state == GTK_STATE_INSENSITIVE) | ||
1062 | + { | ||
1063 | + priv->lower_arrow_state = menu->lower_arrow_prelight ? | ||
1064 | + GTK_STATE_PRELIGHT : GTK_STATE_NORMAL; | ||
1065 | + } | ||
1066 | + | ||
1067 | + if (offset <= 0) | ||
1068 | + { | ||
1069 | + offset = 0; | ||
1070 | + priv->upper_arrow_state = GTK_STATE_INSENSITIVE; | ||
1071 | + } | ||
1072 | + if (offset >= menu_height - view_height) | ||
1073 | + { | ||
1074 | + offset = menu_height - view_height; | ||
1075 | + priv->lower_arrow_state = GTK_STATE_INSENSITIVE; | ||
1076 | + } | ||
1077 | + | ||
1078 | + if ((priv->upper_arrow_state != upper_arrow_previous_state) || | ||
1079 | + (priv->lower_arrow_state != lower_arrow_previous_state)) | ||
1080 | + gtk_widget_queue_draw (GTK_WIDGET (menu)); | ||
1081 | + | ||
1082 | + if (upper_arrow_previous_state != GTK_STATE_INSENSITIVE && | ||
1083 | + priv->upper_arrow_state == GTK_STATE_INSENSITIVE) | ||
1084 | + { | ||
1085 | + /* If we hid the upper arrow, possibly remove timeout */ | ||
1086 | + if (menu->scroll_step < 0) | ||
1087 | + { | ||
1088 | + gtk_menu_stop_scrolling (menu); | ||
1089 | + gtk_widget_queue_draw (GTK_WIDGET (menu)); | ||
1090 | + } | ||
1091 | + } | ||
1092 | + | ||
1093 | + if (lower_arrow_previous_state != GTK_STATE_INSENSITIVE && | ||
1094 | + priv->lower_arrow_state == GTK_STATE_INSENSITIVE) | ||
1095 | + { | ||
1096 | + /* If we hid the lower arrow, possibly remove timeout */ | ||
1097 | + if (menu->scroll_step > 0) | ||
1098 | + { | ||
1099 | + gtk_menu_stop_scrolling (menu); | ||
1100 | + gtk_widget_queue_draw (GTK_WIDGET (menu)); | ||
1101 | + } | ||
1102 | + } | ||
1103 | + } | ||
1104 | + else | ||
1105 | if (!menu->tearoff_active) | ||
1106 | { | ||
1107 | + if (offset <= 0) | ||
1108 | + offset = 0; | ||
1109 | + | ||
1110 | + if (offset >= menu_height - view_height) | ||
1111 | + offset = menu_height - view_height; | ||
1112 | + | ||
1113 | last_visible = menu->upper_arrow_visible; | ||
1114 | menu->upper_arrow_visible = offset > 0; | ||
1115 | |||
1116 | @@ -3685,8 +4087,6 @@ | ||
1117 | if ( (last_visible != menu->upper_arrow_visible) && | ||
1118 | !menu->upper_arrow_visible) | ||
1119 | { | ||
1120 | - menu->upper_arrow_prelight = FALSE; | ||
1121 | - | ||
1122 | /* If we hid the upper arrow, possibly remove timeout */ | ||
1123 | if (menu->scroll_step < 0) | ||
1124 | { | ||
1125 | @@ -3704,8 +4104,6 @@ | ||
1126 | if ( (last_visible != menu->lower_arrow_visible) && | ||
1127 | !menu->lower_arrow_visible) | ||
1128 | { | ||
1129 | - menu->lower_arrow_prelight = FALSE; | ||
1130 | - | ||
1131 | /* If we hid the lower arrow, possibly remove timeout */ | ||
1132 | if (menu->scroll_step > 0) | ||
1133 | { | ||
1134 | @@ -3792,12 +4190,14 @@ | ||
1135 | &child_offset, &child_height, &last_child)) | ||
1136 | { | ||
1137 | guint vertical_padding; | ||
1138 | + gboolean double_arrows; | ||
1139 | |||
1140 | y = menu->scroll_offset; | ||
1141 | gdk_drawable_get_size (GTK_WIDGET (menu)->window, &width, &height); | ||
1142 | |||
1143 | gtk_widget_style_get (GTK_WIDGET (menu), | ||
1144 | "vertical-padding", &vertical_padding, | ||
1145 | + "double_arrows", &double_arrows, | ||
1146 | NULL); | ||
1147 | |||
1148 | height -= 2*GTK_CONTAINER (menu)->border_width + 2*GTK_WIDGET (menu)->style->ythickness + 2*vertical_padding; | ||
1149 | @@ -3820,11 +4220,11 @@ | ||
1150 | if (child_offset + child_height > y + height - arrow_height) | ||
1151 | { | ||
1152 | arrow_height = 0; | ||
1153 | - if (!last_child && !menu->tearoff_active) | ||
1154 | + if ((!last_child && !menu->tearoff_active) || (double_arrows)) | ||
1155 | arrow_height += MENU_SCROLL_ARROW_HEIGHT; | ||
1156 | |||
1157 | y = child_offset + child_height - height + arrow_height; | ||
1158 | - if ((y > 0) && !menu->tearoff_active) | ||
1159 | + if (((y > 0) && !menu->tearoff_active) || (double_arrows)) | ||
1160 | { | ||
1161 | /* Need upper arrow */ | ||
1162 | arrow_height += MENU_SCROLL_ARROW_HEIGHT; | ||
1163 | @@ -4374,3 +4774,60 @@ | ||
1164 | return list; | ||
1165 | } | ||
1166 | |||
1167 | +/* Little help function for making some sanity tests on this menu. | ||
1168 | + * Checks that given widget really is a menu and that it has no name | ||
1169 | + * assigned to it yet. | ||
1170 | + * Names used to do hildon theming: | ||
1171 | + * HILDON_MENU_NAME_SHARP for menu with sharp upper corners | ||
1172 | + * HILDON_MENU_NAME_ROUND for menu with round corners | ||
1173 | + */ | ||
1174 | +static gboolean | ||
1175 | +gtk_menu_check_name (GtkWidget *widget) | ||
1176 | +{ | ||
1177 | + gboolean legal_name = FALSE; | ||
1178 | + gchar **tmp = NULL; | ||
1179 | + const gchar *name = NULL; | ||
1180 | + static gchar *menu_names[] = { "GtkMenu", | ||
1181 | + HILDON_MENU_NAME_SHARP, | ||
1182 | + HILDON_MENU_NAME_ROUND, | ||
1183 | + HILDON_MENU_NAME_ROUND_FIRST_LEVEL, | ||
1184 | + NULL }; | ||
1185 | + if (GTK_IS_MENU (widget) && | ||
1186 | + (name = gtk_widget_get_name (widget))) | ||
1187 | + { | ||
1188 | + if (!g_ascii_strcasecmp (name, HILDON_MENU_NAME_FORCE_SHARP) || !g_ascii_strcasecmp (name, HILDON_MENU_NAME_FORCE_ROUND)) | ||
1189 | + return FALSE; | ||
1190 | + for (tmp = menu_names; *tmp; tmp++) | ||
1191 | + if (!g_ascii_strcasecmp (name, *tmp )) | ||
1192 | + { | ||
1193 | + legal_name = TRUE; | ||
1194 | + break; | ||
1195 | + } | ||
1196 | + } | ||
1197 | + | ||
1198 | + return legal_name; | ||
1199 | +} | ||
1200 | + | ||
1201 | +/* A function called when esc-key is pressed. */ | ||
1202 | +static void | ||
1203 | +_gtk_menu_close_current (GtkMenu * menu) | ||
1204 | +{ | ||
1205 | + GtkMenuShell * shell = GTK_MENU_SHELL (menu); | ||
1206 | + | ||
1207 | + /* Check is a submenu of current menu item is visible. | ||
1208 | + * If it is, close that first. */ | ||
1209 | + if (shell->active_menu_item && (GTK_MENU_ITEM (shell->active_menu_item)->submenu) && GTK_WIDGET_VISIBLE (GTK_MENU_ITEM (shell->active_menu_item)->submenu)) | ||
1210 | + gtk_menu_popdown (GTK_MENU (GTK_MENU_ITEM (shell->active_menu_item)->submenu)); | ||
1211 | + else | ||
1212 | + gtk_menu_popdown (menu); | ||
1213 | + | ||
1214 | +} | ||
1215 | + | ||
1216 | +/* Hildon function to make context menus behave according to spec */ | ||
1217 | +void | ||
1218 | +_gtk_menu_enable_context_menu_behavior (GtkMenu *menu) | ||
1219 | +{ | ||
1220 | + GtkMenuPrivate *priv = gtk_menu_get_private (menu); | ||
1221 | + | ||
1222 | + priv->context_menu = TRUE; | ||
1223 | +} | ||