1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #ifndef CHROME_BROWSER_UI_GTK_GTK_CUSTOM_MENU_ITEM_H_
6 #define CHROME_BROWSER_UI_GTK_GTK_CUSTOM_MENU_ITEM_H_
8 // GtkCustomMenuItem is a GtkMenuItem subclass that has buttons in it and acts
9 // to support this. GtkCustomMenuItems only render properly when put in a
10 // GtkCustomMenu; there's a lot of collaboration between these two classes
11 // necessary to work around how gtk normally does menus.
13 // We can't rely on the normal event infrastructure. While a menu is up, the
14 // GtkMenu has a grab on all events. Instead of trying to pump events through
15 // the normal channels, we have the GtkCustomMenu selectively forward mouse
16 // motion through a back channel. The GtkCustomMenu only listens for button
17 // press information so it can block the effects of the click if the cursor
18 // isn't in a button in the menu item.
20 // A GtkCustomMenuItem doesn't try to take these signals and forward them to
21 // the buttons it owns. The GtkCustomMenu class keeps track of which button is
22 // selected (due to key events and mouse movement) and otherwise acts like a
23 // normal GtkItem. The buttons are only for sizing and rendering; they don't
24 // respond to events. Instead, when the GtkCustomMenuItem is activated by the
25 // GtkMenu, it uses which button was selected as a signal of what to do.
27 // Users should connect to the "button-pushed" signal to be notified when a
28 // button was pushed. We don't go through the normal "activate" signal because
29 // we need to communicate additional information, namely which button was
36 #define GTK_TYPE_CUSTOM_MENU_ITEM \
37 (gtk_custom_menu_item_get_type())
38 #define GTK_CUSTOM_MENU_ITEM(obj) \
39 (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_CUSTOM_MENU_ITEM, \
41 #define GTK_CUSTOM_MENU_ITEM_CLASS(klass) \
42 (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_CUSTOM_MENU_ITEM, \
43 GtkCustomMenuItemClass))
44 #define GTK_IS_CUSTOM_MENU_ITEM(obj) \
45 (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_CUSTOM_MENU_ITEM))
46 #define GTK_IS_CUSTOM_MENU_ITEM_CLASS(klass) \
47 (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_CUSTOM_MENU_ITEM))
48 #define GTK_CUSTOM_MENU_ITEM_GET_CLASS(obj) \
49 (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_CUSTOM_MENU_ITEM, \
50 GtkCustomMenuItemClass))
52 typedef struct _GtkCustomMenuItem GtkCustomMenuItem
;
53 typedef struct _GtkCustomMenuItemClass GtkCustomMenuItemClass
;
55 struct _GtkCustomMenuItem
{
56 GtkMenuItem menu_item
;
58 // Container for button widgets.
61 // Label on left side of menu item.
64 // List of all widgets we added. Used to find the leftmost and rightmost
65 // continuous buttons.
68 // Possible button widgets. Used for keyboard navigation.
69 GList
* button_widgets
;
71 // The widget that currently has highlight.
72 GtkWidget
* currently_selected_button
;
74 // The widget that was selected *before* |currently_selected_button|. Why do
75 // we hang on to this? Because the menu system sends us a deselect signal
76 // right before activating us. We need to listen to deselect since that's
77 // what we receive when the mouse cursor leaves us entirely.
78 GtkWidget
* previously_selected_button
;
81 struct _GtkCustomMenuItemClass
{
82 GtkMenuItemClass parent_class
;
85 GType
gtk_custom_menu_item_get_type(void) G_GNUC_CONST
;
86 GtkWidget
* gtk_custom_menu_item_new(const char* title
);
88 // Adds a button to our list of items in the |hbox|.
89 GtkWidget
* gtk_custom_menu_item_add_button(GtkCustomMenuItem
* menu_item
,
92 // Adds a button to our list of items in the |hbox|, but that isn't part of
93 // |button_widgets| to prevent it from being activatable.
94 GtkWidget
* gtk_custom_menu_item_add_button_label(GtkCustomMenuItem
* menu_item
,
97 // Adds a vertical space in the |hbox|.
98 void gtk_custom_menu_item_add_space(GtkCustomMenuItem
* menu_item
);
100 // Receives a motion event from the GtkCustomMenu that contains us. We can't
101 // just subscribe to motion-event or the individual widget enter/leave events
102 // because the top level GtkMenu has an event grab.
103 void gtk_custom_menu_item_receive_motion_event(GtkCustomMenuItem
* menu_item
,
104 gdouble x
, gdouble y
);
106 // Notification that the menu got a cursor key event. Used to move up/down
107 // within the menu buttons. Returns TRUE to stop the default signal handler
109 gboolean
gtk_custom_menu_item_handle_move(GtkCustomMenuItem
* menu_item
,
110 GtkMenuDirectionType direction
);
112 // Because we only get a generic "selected" signal when we've changed, we need
113 // to have a way for the GtkCustomMenu to tell us that we were just
115 void gtk_custom_menu_item_select_item_by_direction(
116 GtkCustomMenuItem
* menu_item
, GtkMenuDirectionType direction
);
118 // Whether we are currently hovering over a clickable region on the menu
119 // item. Used by GtkCustomMenu to determine whether it should discard click
121 gboolean
gtk_custom_menu_item_is_in_clickable_region(
122 GtkCustomMenuItem
* menu_item
);
124 // If the button is released while the |currently_selected_button| isn't
125 // supposed to dismiss the menu, this signals to our listeners that we want to
126 // run this command if it doesn't dismiss the menu. Returns TRUE if we acted
127 // on this button click (and should prevent the normal GtkMenu machinery from
128 // firing an "activate" signal).
129 gboolean
gtk_custom_menu_item_try_no_dismiss_command(
130 GtkCustomMenuItem
* menu_item
);
132 // Calls |callback| with every button and button-label in the container.
133 void gtk_custom_menu_item_foreach_button(GtkCustomMenuItem
* menu_item
,
134 GtkCallback callback
,
135 gpointer callback_data
);
139 #endif // CHROME_BROWSER_UI_GTK_GTK_CUSTOM_MENU_ITEM_H_