diff options
Diffstat (limited to 'shell/ev-navigation-action-widget.c')
-rw-r--r-- | shell/ev-navigation-action-widget.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/shell/ev-navigation-action-widget.c b/shell/ev-navigation-action-widget.c new file mode 100644 index 00000000..95c7fdff --- /dev/null +++ b/shell/ev-navigation-action-widget.c @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2003, 2004 Marco Pesenti Gritti + * Copyright (C) 2003, 2004 Christian Persch + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "ev-navigation-action-widget.h" + +#include <glib/gi18n.h> +#include <string.h> + +static void ev_navigation_action_widget_init (EvNavigationActionWidget *action_widget); +static void ev_navigation_action_widget_class_init (EvNavigationActionWidgetClass *action_widget); +static void ev_navigation_action_widget_toggled (GtkToggleToolButton *toggle); +static gboolean ev_navigation_action_widget_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer data); + +G_DEFINE_TYPE (EvNavigationActionWidget, ev_navigation_action_widget, GTK_TYPE_TOGGLE_TOOL_BUTTON) + +enum +{ + SHOW_MENU, + LAST_SIGNAL +}; + +static gint signals[LAST_SIGNAL]; + +static void +ev_navigation_action_widget_init (EvNavigationActionWidget *action_widget) +{ + GtkWidget *toggle_button; + + /* It's rather dirty hack but we need a child to connect to + * button press event + */ + + toggle_button = gtk_bin_get_child (GTK_BIN (action_widget)); + + g_signal_connect (toggle_button, "button-press-event", + G_CALLBACK (ev_navigation_action_widget_button_press_event), + action_widget); + return; +} + +static void +ev_navigation_action_widget_class_init (EvNavigationActionWidgetClass *klass) +{ + GtkToggleToolButtonClass *toggle_tool_button_class = GTK_TOGGLE_TOOL_BUTTON_CLASS (klass); + + toggle_tool_button_class->toggled = ev_navigation_action_widget_toggled; + + signals[SHOW_MENU] = + g_signal_new ("show-menu", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EvNavigationActionWidgetClass, show_menu), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static int +menu_deactivate_cb (GtkMenuShell *menu_shell, + EvNavigationActionWidget *widget) +{ + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (widget), FALSE); + return TRUE; +} + +static void +menu_detacher (GtkWidget *widget, + GtkMenu *menu) +{ + EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (widget); + g_return_if_fail (button->menu == menu); + button->menu = NULL; +} + +void +ev_navigation_action_widget_set_menu(EvNavigationActionWidget *button, GtkWidget *menu) +{ + + if (button->menu == GTK_MENU (menu)) + return; + + if (button->menu && gtk_widget_get_visible (GTK_WIDGET (button->menu))) + gtk_menu_shell_deactivate (GTK_MENU_SHELL (button->menu)); + + if (button->menu) { + g_signal_handlers_disconnect_by_func (button->menu, + menu_deactivate_cb, + button); + gtk_menu_detach (button->menu); + } + + button->menu = GTK_MENU (menu); + + if (button->menu) { + gtk_menu_attach_to_widget (button->menu, GTK_WIDGET (button), + menu_detacher); + g_signal_connect (button->menu, "deactivate", + G_CALLBACK (menu_deactivate_cb), button); + } +} + +static void +menu_position_func (GtkMenu *menu, + int *x, + int *y, + gboolean *push_in, + EvNavigationActionWidget *button) +{ + GtkWidget *widget = GTK_WIDGET (button); + GtkRequisition menu_req; + GtkAllocation allocation; + GtkTextDirection direction; + GdkWindow *gdk_window; + GdkRectangle monitor; + gint monitor_num; + GdkScreen *screen; + + gtk_widget_size_request (GTK_WIDGET (button->menu), &menu_req); + direction = gtk_widget_get_direction (widget); + screen = gtk_widget_get_screen (GTK_WIDGET (menu)); + + gdk_window = gtk_widget_get_window (widget); + monitor_num = gdk_screen_get_monitor_at_window (screen, gdk_window); + if (monitor_num < 0) + monitor_num = 0; + gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor); + + gdk_window_get_origin (gdk_window, x, y); + gtk_widget_get_allocation (widget, &allocation); + *x += allocation.x; + *y += allocation.y; + + if (direction == GTK_TEXT_DIR_LTR) + *x += MAX (allocation.width - menu_req.width, 0); + else if (menu_req.width > allocation.width) + *x -= menu_req.width - allocation.width; + + if ((*y + allocation.height + menu_req.height) <= monitor.y + monitor.height) + *y += allocation.height; + else if ((*y - menu_req.height) >= monitor.y) + *y -= menu_req.height; + else if (monitor.y + monitor.height - (*y + allocation.height) > *y) + *y += allocation.height; + else + *y -= menu_req.height; + + *push_in = FALSE; +} + +static void +popup_menu_under_arrow (EvNavigationActionWidget *button, + GdkEventButton *event) +{ + g_signal_emit (button, signals[SHOW_MENU], 0); + + if (!button->menu) + return; + + gtk_menu_popup (button->menu, NULL, NULL, + (GtkMenuPositionFunc) menu_position_func, + button, + event ? event->button : 0, + event ? event->time : gtk_get_current_event_time ()); +} + +static void +ev_navigation_action_widget_toggled (GtkToggleToolButton *toggle) +{ + EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (toggle); + if (!button->menu) + return; + + if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (button)) && + !gtk_widget_get_visible (GTK_WIDGET (button->menu))) { + /* we get here only when the menu is activated by a key + * press, so that we can select the first menu item */ + popup_menu_under_arrow (button, NULL); + gtk_menu_shell_select_first (GTK_MENU_SHELL (button->menu), FALSE); + } +} + +static gboolean +ev_navigation_action_widget_button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer data) +{ + EvNavigationActionWidget *button = EV_NAVIGATION_ACTION_WIDGET (data); + + if (event->button == 1) { + popup_menu_under_arrow (button, event); + gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (button), TRUE); + return TRUE; + } + return FALSE; +} |