2 * Copyright (C) 2003, 2004 Marco Pesenti Gritti
3 * Copyright (C) 2003, 2004 Christian Persch
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "ev-navigation-action-widget.h"
23 #include <glib/gi18n.h>
26 static void ev_navigation_action_widget_init (EvNavigationActionWidget *action_widget);
27 static void ev_navigation_action_widget_class_init (EvNavigationActionWidgetClass *action_widget);
28 static void ev_navigation_action_widget_toggled (GtkToggleToolButton *toggle);
29 static gboolean ev_navigation_action_widget_button_press_event (GtkWidget *widget,
30 GdkEventButton *event,
33 G_DEFINE_TYPE (EvNavigationActionWidget, ev_navigation_action_widget, GTK_TYPE_TOGGLE_TOOL_BUTTON)
41 static gint signals[LAST_SIGNAL];
44 ev_navigation_action_widget_init (EvNavigationActionWidget *action_widget)
46 GtkWidget *toggle_button;
48 /* It's rather dirty hack but we need a child to connect to
52 toggle_button = gtk_bin_get_child (GTK_BIN (action_widget));
54 g_signal_connect (toggle_button, "button-press-event",
55 G_CALLBACK (ev_navigation_action_widget_button_press_event),
61 ev_navigation_action_widget_class_init (EvNavigationActionWidgetClass *klass)
63 GtkToggleToolButtonClass *toggle_tool_button_class = GTK_TOGGLE_TOOL_BUTTON_CLASS (klass);
65 toggle_tool_button_class->toggled = ev_navigation_action_widget_toggled;
68 g_signal_new ("show-menu",
69 G_OBJECT_CLASS_TYPE (klass),
71 G_STRUCT_OFFSET (EvNavigationActionWidgetClass, show_menu),
73 g_cclosure_marshal_VOID__VOID,
78 menu_deactivate_cb (GtkMenuShell *menu_shell,
79 EvNavigationActionWidget *widget)
81 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (widget), FALSE);
86 menu_detacher (GtkWidget *widget,
89 EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (widget);
90 g_return_if_fail (button->menu == menu);
95 ev_navigation_action_widget_set_menu(EvNavigationActionWidget *button, GtkWidget *menu)
98 if (button->menu == GTK_MENU (menu))
101 if (button->menu && gtk_widget_get_visible (GTK_WIDGET (button->menu)))
102 gtk_menu_shell_deactivate (GTK_MENU_SHELL (button->menu));
105 g_signal_handlers_disconnect_by_func (button->menu,
108 gtk_menu_detach (button->menu);
111 button->menu = GTK_MENU (menu);
114 gtk_menu_attach_to_widget (button->menu, GTK_WIDGET (button),
116 g_signal_connect (button->menu, "deactivate",
117 G_CALLBACK (menu_deactivate_cb), button);
122 menu_position_func (GtkMenu *menu,
126 EvNavigationActionWidget *button)
128 GtkWidget *widget = GTK_WIDGET (button);
129 GtkRequisition menu_req;
130 GtkAllocation allocation;
131 GtkTextDirection direction;
132 GdkWindow *gdk_window;
133 GdkRectangle monitor;
137 gtk_widget_get_preferred_size (GTK_WIDGET (button->menu), &menu_req, NULL);
138 direction = gtk_widget_get_direction (widget);
139 screen = gtk_widget_get_screen (GTK_WIDGET (menu));
141 gdk_window = gtk_widget_get_window (widget);
142 monitor_num = gdk_screen_get_monitor_at_window (screen, gdk_window);
145 gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
147 gdk_window_get_origin (gdk_window, x, y);
148 gtk_widget_get_allocation (widget, &allocation);
152 if (direction == GTK_TEXT_DIR_LTR)
153 *x += MAX (allocation.width - menu_req.width, 0);
154 else if (menu_req.width > allocation.width)
155 *x -= menu_req.width - allocation.width;
157 if ((*y + allocation.height + menu_req.height) <= monitor.y + monitor.height)
158 *y += allocation.height;
159 else if ((*y - menu_req.height) >= monitor.y)
160 *y -= menu_req.height;
161 else if (monitor.y + monitor.height - (*y + allocation.height) > *y)
162 *y += allocation.height;
164 *y -= menu_req.height;
170 popup_menu_under_arrow (EvNavigationActionWidget *button,
171 GdkEventButton *event)
173 g_signal_emit (button, signals[SHOW_MENU], 0);
178 gtk_menu_popup (button->menu, NULL, NULL,
179 (GtkMenuPositionFunc) menu_position_func,
181 event ? event->button : 0,
182 event ? event->time : gtk_get_current_event_time ());
186 ev_navigation_action_widget_toggled (GtkToggleToolButton *toggle)
188 EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (toggle);
192 if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button)) &&
193 !gtk_widget_get_visible (GTK_WIDGET (button->menu))) {
194 /* we get here only when the menu is activated by a key
195 * press, so that we can select the first menu item */
196 popup_menu_under_arrow (button, NULL);
197 gtk_menu_shell_select_first (GTK_MENU_SHELL (button->menu), FALSE);
202 ev_navigation_action_widget_button_press_event (GtkWidget *widget,
203 GdkEventButton *event,
206 EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (data);
208 if (event->button == 1) {
209 popup_menu_under_arrow (button, event);
210 gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (button), TRUE);