1 --- gtk+-2.6.4/gtk/gtkmenuitem.c 2004-12-28 09:39:31.000000000 +0200
2 +++ gtk+-2.6.4/gtk/gtkmenuitem.c 2005-04-06 16:19:36.973917472 +0300
4 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
7 +/* Modified for Nokia Oyj during 2002-2003. See CHANGES file for list
11 #define GTK_MENU_INTERNALS
15 #include "gtkmenuitem.h"
16 #include "gtkseparatormenuitem.h"
18 +#define HILDON_HEIGHT_INCREMENT 1
19 +#define HILDON_ARROW_SPACE 6
21 #define MENU_ITEM_CLASS(w) GTK_MENU_ITEM_CLASS (GTK_OBJECT (w)->klass)
28 +static void _gtk_menu_item_activate_submenus (GtkMenuItem *item);
30 static GtkItemClass *parent_class;
31 static guint menu_item_signals[LAST_SIGNAL] = { 0 };
34 item_class->select = gtk_real_menu_item_select;
35 item_class->deselect = gtk_real_menu_item_deselect;
37 - klass->activate = NULL;
38 + /* Hildon addition : Added this to catch the
39 + * activation of meuuitems with submenus. */
40 + klass->activate = _gtk_menu_item_activate_submenus;
41 klass->activate_item = gtk_real_menu_item_activate_item;
42 klass->toggle_size_request = gtk_real_menu_item_toggle_size_request;
43 klass->toggle_size_allocate = gtk_real_menu_item_toggle_size_allocate;
49 + /* Hildon modification - allow themeing of separator height */
50 + gtk_widget_class_install_style_property (widget_class,
51 + g_param_spec_int ("separator_height",
53 + "Draw a separator graphics with height of x pixels.",
62 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
64 gtk_item_select (GTK_ITEM (menu_item));
65 + /* HILDON MOD. This is required as changed focus isn't drawn automatically
66 + * and drawing it must be requested. */
67 + if ((GTK_WIDGET(menu_item)->parent) && GTK_IS_MENU (GTK_WIDGET(menu_item)->parent))
69 + GtkMenu *menu = GTK_MENU (GTK_WIDGET(menu_item)->parent);
70 + if (menu->parent_menu_item) gtk_widget_queue_draw(GTK_WIDGET(menu->parent_menu_item));
76 g_return_if_fail (GTK_IS_MENU_ITEM (menu_item));
78 gtk_item_deselect (GTK_ITEM (menu_item));
79 + /* HILDON MOD. This is required as changed focus isn't drawn automatically
80 + * and drawing it must be requested. */
81 + if ((GTK_WIDGET(menu_item)->parent) && GTK_IS_MENU (GTK_WIDGET(menu_item)->parent))
83 + GtkMenu *menu = GTK_MENU (GTK_WIDGET(menu_item)->parent);
84 + if (menu->parent_menu_item) gtk_widget_queue_draw(GTK_WIDGET(menu->parent_menu_item));
90 "arrow_spacing", &arrow_spacing,
93 - requisition->width += child_requisition.height;
94 + requisition->width += child_requisition.height + HILDON_ARROW_SPACE;
95 requisition->width += arrow_spacing;
97 requisition->width = MAX (requisition->width, get_minimum_width (widget));
99 requisition->height += 4;
102 + /* We get correct focus size if we make the widget a bit bigger.
103 + * (If the increment would be big, we should probably adjust the text
104 + * position aswell.)
106 + requisition->height += HILDON_HEIGHT_INCREMENT;
109 gtk_container_foreach (GTK_CONTAINER (menu_item),
110 gtk_menu_item_accel_width_foreach,
113 if (direction == GTK_TEXT_DIR_RTL)
114 child_allocation.x += child_requisition.height;
115 - child_allocation.width -= child_requisition.height;
116 + /* HILDON Modification. */
117 + child_allocation.width -= child_requisition.height + HILDON_ARROW_SPACE;
120 if (child_allocation.width < 1)
122 GtkShadowType shadow_type, selected_shadow_type;
126 gint border_width = GTK_CONTAINER (widget)->border_width;
128 if (GTK_WIDGET_DRAWABLE (widget))
129 @@ -704,10 +747,56 @@
130 if ((state_type == GTK_STATE_PRELIGHT) &&
131 (GTK_BIN (menu_item)->child))
134 + gint focus_width = width;
135 gtk_widget_style_get (widget,
136 "selected_shadow_type", &selected_shadow_type,
138 - gtk_paint_box (widget->style,
140 + if (menu_item->submenu && menu_item->show_submenu_indicator)
142 + GtkRequisition child_requisition;
144 + /* gint arrow_extent; */
145 + gtk_widget_get_child_requisition (GTK_BIN (menu_item)->child,
146 + &child_requisition);
148 + arrow_size = child_requisition.height - 2 * widget->style->ythickness;
149 + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) {
150 + focus_width = x + width - arrow_size - 2 - HILDON_ARROW_SPACE;
153 + focus_x = x + arrow_size + 2 + HILDON_ARROW_SPACE;
158 + * Hildon modification:
159 + * This draws different focus depending on if it's the toplevel
160 + * focused menu item. All items that have submenus that in turn
161 + * have an item selected will be drawn with SELECTED - state focus.
162 + * If this isn't the case, PRELIGHT - state focus is used. */
163 + if (menu_item->submenu)
166 + msi = GTK_MENU_ITEM(GTK_MENU_SHELL(&((GTK_MENU(menu_item->submenu))->menu_shell))->active_menu_item);
167 + if ((msi == NULL) || (GTK_WIDGET (msi)->state == 0))
168 + gtk_paint_box (widget->style,
170 + GTK_STATE_PRELIGHT,
171 + selected_shadow_type,
172 + area, widget, "menuitem",
173 + focus_x, y, focus_width, height);
175 + gtk_paint_box (widget->style,
177 + GTK_STATE_SELECTED,
178 + selected_shadow_type,
179 + area, widget, "menuitem",
180 + focus_x, y, focus_width, height);
183 + gtk_paint_box (widget->style,
186 selected_shadow_type,
188 arrow_extent = arrow_size * 0.8;
190 shadow_type = GTK_SHADOW_OUT;
191 - if (state_type == GTK_STATE_PRELIGHT)
192 - shadow_type = GTK_SHADOW_IN;
193 + /*Hildon: only show the pressed arrow if the submenu is visible*/
194 + if (state_type == GTK_STATE_PRELIGHT
195 + && GTK_WIDGET_VISIBLE( menu_item->submenu))
197 + shadow_type = GTK_SHADOW_IN;
200 if (direction == GTK_TEXT_DIR_LTR)
204 arrow_y = y + (height - arrow_extent) / 2;
206 +/* HILDON modification to correct focus drawing with submenu arrow */
207 + arrow_x = arrow_x - 4;
209 gtk_paint_arrow (widget->style, widget->window,
210 state_type, shadow_type,
211 area, widget, "menuitem",
212 @@ -772,18 +868,20 @@
214 else if (!GTK_BIN (menu_item)->child)
216 - guint horizontal_padding;
217 + guint horizontal_padding, separator_height;
219 gtk_widget_style_get (widget,
220 "horizontal_padding", &horizontal_padding,
221 + "separator_height", &separator_height,
224 - gtk_paint_hline (widget->style, widget->window, GTK_STATE_NORMAL,
225 - area, widget, "menuitem",
226 - widget->allocation.x + horizontal_padding + widget->style->xthickness,
227 - widget->allocation.x + widget->allocation.width - horizontal_padding - widget->style->xthickness - 1,
228 - widget->allocation.y + (widget->allocation.height -
229 - widget->style->ythickness) / 2);
230 + /* themable menuitem for menu separators */
231 + gtk_paint_box (widget->style, widget->window, GTK_STATE_NORMAL, GTK_SHADOW_NONE,
232 + area, widget, "separator",
233 + widget->allocation.x + horizontal_padding + widget->style->xthickness,
234 + widget->allocation.y + (widget->allocation.height - widget->style->ythickness) / 2,
235 + widget->allocation.x + widget->allocation.width - horizontal_padding - widget->style->xthickness - 1,
241 (!GTK_WIDGET_MAPPED (menu_item->submenu) ||
242 GTK_MENU (menu_item->submenu)->tearoff_active))
244 + GdkEvent *event = gtk_get_current_event ();
247 if (menu_item->timer)
248 @@ -851,26 +950,40 @@
249 popup_delay = get_popup_delay (menu_item);
253 - GdkEvent *event = gtk_get_current_event ();
255 - menu_item->timer = g_timeout_add (popup_delay,
256 - gtk_menu_item_select_timeout,
259 - event->type != GDK_BUTTON_PRESS &&
260 - event->type != GDK_ENTER_NOTIFY)
261 - menu_item->timer_from_keypress = TRUE;
263 - menu_item->timer_from_keypress = FALSE;
266 - gdk_event_free (event);
269 + /* OK, Here comes the contender for the 2003 Ugly Award
270 + * The popup delay is set small enough to be unnoticable, but high enough to not
271 + * notice the flickering which occurs when we close all the deepest menu's Gtk+ helpfully
272 + * expands but are not needed
273 + * This does not fix the mouse navigation yet (bug 18) but should take care of 442
274 + * NOTE: test the delay factor on different CPU speeds
277 + /* Hildon: Disabling the automatic opening of submenus. */
280 + event->type != GDK_BUTTON_PRESS &&
281 + event->type != GDK_ENTER_NOTIFY &&
282 + event->type != GDK_MOTION_NOTIFY) /*hildon: for some reason, the event is sometimes this and not enter!*/
283 + menu_item->timer_from_keypress = TRUE;
286 + /* mouse/pen events */
287 + /* here is a problem -- when a menu item with sub menus gets a mouse event,
288 + another event is generated for the submenu (and further its submenu etc.)
289 + This leads to a behaviour which does not comply to the hildon spec. */
290 + menu_item->timer_from_keypress = FALSE;
292 + else /* does this really happen? */
293 + menu_item->timer_from_keypress = FALSE;
296 - _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item));
297 + _gtk_menu_item_popup_submenu (menu_item);
300 + gdk_event_free (event);
304 gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_PRELIGHT);
305 gtk_widget_queue_draw (GTK_WIDGET (menu_item));
307 @@ -878,25 +991,16 @@
309 gtk_real_menu_item_deselect (GtkItem *item)
311 - GtkMenuItem *menu_item;
312 + GtkWidget *menu_item;
314 g_return_if_fail (GTK_IS_MENU_ITEM (item));
316 - menu_item = GTK_MENU_ITEM (item);
317 + menu_item = GTK_WIDGET (item);
319 - if (menu_item->submenu)
321 - if (menu_item->timer)
323 - g_source_remove (menu_item->timer);
324 - menu_item->timer = 0;
327 - gtk_menu_popdown (GTK_MENU (menu_item->submenu));
329 + _gtk_menu_item_popdown_submenu (menu_item);
331 - gtk_widget_set_state (GTK_WIDGET (menu_item), GTK_STATE_NORMAL);
332 - gtk_widget_queue_draw (GTK_WIDGET (menu_item));
333 + gtk_widget_set_state (menu_item, GTK_STATE_NORMAL);
334 + gtk_widget_queue_draw (menu_item);
338 @@ -941,10 +1045,7 @@
339 _gtk_menu_shell_activate (menu_shell);
341 gtk_menu_shell_select_item (GTK_MENU_SHELL (widget->parent), widget);
342 - _gtk_menu_item_popup_submenu (widget);
344 - gtk_menu_shell_select_first (GTK_MENU_SHELL (menu_item->submenu), TRUE);
345 - submenu = GTK_MENU_SHELL (menu_item->submenu);
346 + /* Hildon mod: automatic submenu opening has been removed */
352 _gtk_menu_item_popup_submenu (GTK_WIDGET (menu_item));
353 if (menu_item->timer_from_keypress && menu_item->submenu)
354 - GTK_MENU_SHELL (menu_item->submenu)->ignore_enter = TRUE;
355 + GTK_MENU_SHELL (menu_item->submenu)->ignore_enter = TRUE;
358 GDK_THREADS_LEAVE ();
359 @@ -1002,7 +1103,16 @@
360 g_source_remove (menu_item->timer);
361 menu_item->timer = 0;
363 + /* HILDON MOD. This is required as changed submenu arrow isn't drawn automatically
364 + * and drawing it must be requested. */
365 + gtk_widget_queue_draw (widget);
367 if (GTK_WIDGET_IS_SENSITIVE (menu_item->submenu))
369 + gboolean take_focus;
370 + take_focus = gtk_menu_shell_get_take_focus (GTK_MENU_SHELL (widget->parent));
371 + gtk_menu_shell_set_take_focus (GTK_MENU_SHELL (menu_item->submenu),take_focus);
373 gtk_menu_popup (GTK_MENU (menu_item->submenu),
376 @@ -1010,6 +1120,28 @@
378 GTK_MENU_SHELL (widget->parent)->button,
384 +_gtk_menu_item_popdown_submenu (GtkWidget *widget)
386 + GtkMenuItem *menu_item;
388 + menu_item = GTK_MENU_ITEM (widget);
390 + if (menu_item->submenu)
392 + if (menu_item->timer)
394 + g_source_remove (menu_item->timer);
395 + menu_item->timer = 0;
398 + gtk_menu_popdown (GTK_MENU (menu_item->submenu));
401 + gtk_widget_queue_draw (widget);
405 @@ -1092,14 +1224,17 @@
406 tx += widget->allocation.width - twidth;
409 +/* HILDON modifications
410 + * Here we make the submenu of an menubar appear under the menubar.
411 + * The only exception is when the resulting menu would be under 100 pixels
412 + * high. In that case, the menu is made 100 pixels high.
414 if ((ty + widget->allocation.height + theight) <= monitor.y + monitor.height)
415 ty += widget->allocation.height;
416 - else if ((ty - theight) >= monitor.y)
418 - else if (monitor.y + monitor.height - (ty + widget->allocation.height) > ty)
419 + else if ((ty + widget->allocation.height) < monitor.y + monitor.height - 120)
420 ty += widget->allocation.height;
423 + ty = monitor.y + monitor.height - 120;
427 @@ -1404,3 +1539,30 @@
432 +/* Hildon modification :
433 + * This function exists only for opening submenus on
436 +_gtk_menu_item_activate_submenus (GtkMenuItem *item)
440 + g_return_if_fail (GTK_IS_MENU_ITEM (item));
442 + if (!GTK_IS_MENU (item->submenu) ||
443 + GTK_WIDGET_VISIBLE (item->submenu))
446 + event = gtk_get_current_event ();
447 + _gtk_menu_item_popup_submenu (item);
449 + /* We don't want to select first item if the submenu
450 + * is opened with mouse release because the selection
451 + * would move straigh back under the cursor. */
452 + if ((event == NULL) || (event->type != GDK_BUTTON_RELEASE))
453 + gtk_menu_shell_select_first (GTK_MENU_SHELL (item->submenu), TRUE);
456 + gdk_event_free (event);