>From 9b0ed3f2e6d1c4e65f2706de4cd338515aa1de02 Mon Sep 17 00:00:00 2001 From: Yosef Or Boczko Date: Sun, 30 Jun 2013 13:48:44 +0300 Subject: Port GtkToolbar to GtkHeaderBar --- src/Makefile.am | 4 +- src/nautilus-header-bar.c | 628 +++++++++++++++++++++++++++++++++++++++++ src/nautilus-header-bar.h | 75 +++++ src/nautilus-toolbar.c | 642 ------------------------------------------ src/nautilus-toolbar.h | 77 ----- src/nautilus-window-private.h | 2 +- src/nautilus-window-slot.c | 2 +- src/nautilus-window.c | 40 +-- 8 files changed, 727 insertions(+), 743 deletions(-) create mode 100644 src/nautilus-header-bar.c create mode 100644 src/nautilus-header-bar.h delete mode 100644 src/nautilus-toolbar.c delete mode 100644 src/nautilus-toolbar.h diff --git a/src/Makefile.am b/src/Makefile.am index 651fccc..61909e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -185,8 +185,8 @@ nautilus_SOURCES = \ nautilus-shell-search-provider.c \ nautilus-special-location-bar.c \ nautilus-special-location-bar.h \ - nautilus-toolbar.c \ - nautilus-toolbar.h \ + nautilus-header-bar.c \ + nautilus-header-bar.h \ nautilus-trash-bar.c \ nautilus-trash-bar.h \ nautilus-view.c \ diff --git a/src/nautilus-header-bar.c b/src/nautilus-header-bar.c new file mode 100644 index 0000000..2eadbd7 --- /dev/null +++ b/src/nautilus-header-bar.c @@ -0,0 +1,628 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* + * Nautilus + * + * Copyright (C) 2011, Red Hat, Inc. + * + * Nautilus 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 of the + * License, or (at your option) any later version. + * + * Nautilus 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: Cosimo Cecchi + * + */ + +#include + +#include "nautilus-header-bar.h" + +#include "nautilus-location-entry.h" +#include "nautilus-pathbar.h" +#include "nautilus-actions.h" + +#include +#include + +#include +#include + +typedef enum { + NAUTILUS_NAVIGATION_DIRECTION_NONE, + NAUTILUS_NAVIGATION_DIRECTION_BACK, + NAUTILUS_NAVIGATION_DIRECTION_FORWARD +} NautilusNavigationDirection; + +struct _NautilusHeaderBarPriv { + GtkWidget *header_bar; + NautilusWindow *window; + + GtkWidget *path_bar; + GtkWidget *location_entry; + + GtkToolItem *back_forward; + + gboolean show_location_entry; + + guint popup_timeout_id; +}; + +enum { + PROP_WINDOW = 1, + PROP_SHOW_LOCATION_ENTRY, + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; + +G_DEFINE_TYPE (NautilusHeaderBar, nautilus_header_bar, GTK_TYPE_BOX); + +static void unschedule_menu_popup_timeout (NautilusHeaderBar *self); + +static void +header_bar_update_appearance (NautilusHeaderBar *self) +{ + gboolean show_location_entry; + + show_location_entry = self->priv->show_location_entry || + g_settings_get_boolean (nautilus_preferences, NAUTILUS_PREFERENCES_ALWAYS_USE_LOCATION_ENTRY); + + gtk_widget_set_visible (self->priv->location_entry, + show_location_entry); + gtk_widget_set_visible (self->priv->path_bar, + !show_location_entry); +} + +static gint +get_icon_margin (NautilusHeaderBar *self) +{ + GtkIconSize toolbar_size; + gint toolbar_size_px, menu_size_px; + + g_object_get (gtk_settings_get_default (), "gtk-toolbar-icon-size", &toolbar_size, NULL); + /* toolbar_size = GTK_ICON_SIZE_SMALL_TOOLBAR; */ + + gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &menu_size_px, NULL); + gtk_icon_size_lookup (toolbar_size, &toolbar_size_px, NULL); + + return (gint) floor ((toolbar_size_px - menu_size_px) / 2.0); +} + +static GtkWidget * +header_bar_create_toolbutton (NautilusHeaderBar *self, + gboolean create_menu, + gboolean create_toggle, + const gchar *name, + const gchar *tooltip) +{ + GtkWidget *button, *image; + GtkActionGroup *action_group; + GtkAction *action; + + action_group = nautilus_window_get_main_action_group (self->priv->window); + + if (create_menu) { + button = gtk_menu_button_new (); + } else if (create_toggle) { + button = gtk_toggle_button_new (); + } else { + button = gtk_button_new (); + } + + image = gtk_image_new (); + g_object_set (image, "margin", get_icon_margin (self), NULL); + + gtk_button_set_image (GTK_BUTTON (button), image); + + if (create_menu) { + gtk_image_set_from_icon_name (GTK_IMAGE (image), name, + GTK_ICON_SIZE_MENU); + gtk_widget_set_tooltip_text (button, tooltip); + } else { + action = gtk_action_group_get_action (action_group, name); + gtk_activatable_set_related_action (GTK_ACTIVATABLE (button), action); + gtk_button_set_label (GTK_BUTTON (button), NULL); + gtk_widget_set_tooltip_text (button, gtk_action_get_tooltip (action)); + } + + return button; +} + +static void +activate_back_or_forward_menu_item (GtkMenuItem *menu_item, + NautilusWindow *window, + gboolean back) +{ + int index; + + g_assert (GTK_IS_MENU_ITEM (menu_item)); + + index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu_item), "user_data")); + + nautilus_window_back_or_forward (window, back, index, nautilus_event_get_window_open_flags ()); +} + +static void +activate_back_menu_item_callback (GtkMenuItem *menu_item, + NautilusWindow *window) +{ + activate_back_or_forward_menu_item (menu_item, window, TRUE); +} + +static void +activate_forward_menu_item_callback (GtkMenuItem *menu_item, NautilusWindow *window) +{ + activate_back_or_forward_menu_item (menu_item, window, FALSE); +} + +static void +fill_menu (NautilusWindow *window, + GtkWidget *menu, + gboolean back) +{ + NautilusWindowSlot *slot; + GtkWidget *menu_item; + int index; + GList *list; + + slot = nautilus_window_get_active_slot (window); + list = back ? nautilus_window_slot_get_back_history (slot) : + nautilus_window_slot_get_forward_history (slot); + + index = 0; + while (list != NULL) { + menu_item = nautilus_bookmark_menu_item_new (NAUTILUS_BOOKMARK (list->data)); + g_object_set_data (G_OBJECT (menu_item), "user_data", GINT_TO_POINTER (index)); + gtk_widget_show (GTK_WIDGET (menu_item)); + g_signal_connect_object (menu_item, "activate", + back + ? G_CALLBACK (activate_back_menu_item_callback) + : G_CALLBACK (activate_forward_menu_item_callback), + window, 0); + + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + list = g_list_next (list); + ++index; + } +} + +/* adapted from gtk/gtkmenubutton.c */ +static void +menu_position_func (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + GtkWidget *widget) +{ + GtkWidget *toplevel; + GtkRequisition menu_req; + GdkRectangle monitor; + gint monitor_num; + GdkScreen *screen; + GdkWindow *window; + GtkAllocation allocation; + + /* Set the dropdown menu hint on the toplevel, so the WM can omit the top side + * of the shadows. + */ + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menu)); + gtk_window_set_type_hint (GTK_WINDOW (toplevel), GDK_WINDOW_TYPE_HINT_DROPDOWN_MENU); + + window = gtk_widget_get_window (widget); + screen = gtk_widget_get_screen (GTK_WIDGET (menu)); + monitor_num = gdk_screen_get_monitor_at_window (screen, window); + if (monitor_num < 0) { + monitor_num = 0; + } + + gdk_screen_get_monitor_workarea (screen, monitor_num, &monitor); + gtk_widget_get_preferred_size (GTK_WIDGET (menu), &menu_req, NULL); + gtk_widget_get_allocation (widget, &allocation); + gdk_window_get_origin (window, x, y); + + *x += allocation.x; + *y += allocation.y; + + if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) { + *x -= MAX (menu_req.width - allocation.width, 0); + } else { + *x += MAX (allocation.width - menu_req.width, 0); + } + + 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 +show_menu (NautilusHeaderBar *self, + GtkWidget *widget, + guint button, + guint32 event_time) +{ + NautilusWindow *window; + GtkWidget *menu; + NautilusNavigationDirection direction; + + window = self->priv->window; + menu = gtk_menu_new (); + + direction = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (widget), + "nav-direction")); + + switch (direction) { + case NAUTILUS_NAVIGATION_DIRECTION_FORWARD: + fill_menu (window, menu, FALSE); + break; + case NAUTILUS_NAVIGATION_DIRECTION_BACK: + fill_menu (window, menu, TRUE); + break; + default: + g_assert_not_reached (); + break; + } + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, + (GtkMenuPositionFunc) menu_position_func, widget, + button, event_time); +} + +#define MENU_POPUP_TIMEOUT 1200 + +typedef struct { + NautilusHeaderBar *self; + GtkWidget *widget; +} ScheduleMenuData; + +static void +schedule_menu_data_free (ScheduleMenuData *data) +{ + g_slice_free (ScheduleMenuData, data); +} + +static gboolean +popup_menu_timeout_cb (gpointer user_data) +{ + ScheduleMenuData *data = user_data; + + show_menu (data->self, data->widget, + 1, gtk_get_current_event_time ()); + + return FALSE; +} + +static void +unschedule_menu_popup_timeout (NautilusHeaderBar *self) +{ + if (self->priv->popup_timeout_id != 0) { + g_source_remove (self->priv->popup_timeout_id); + self->priv->popup_timeout_id = 0; + } +} + +static void +schedule_menu_popup_timeout (NautilusHeaderBar *self, + GtkWidget *widget) +{ + ScheduleMenuData *data; + + /* unschedule any previous timeouts */ + unschedule_menu_popup_timeout (self); + + data = g_slice_new0 (ScheduleMenuData); + data->self = self; + data->widget = widget; + + self->priv->popup_timeout_id = + g_timeout_add_full (G_PRIORITY_DEFAULT, MENU_POPUP_TIMEOUT, + popup_menu_timeout_cb, data, + (GDestroyNotify) schedule_menu_data_free); +} + +static gboolean +tool_button_press_cb (GtkButton *button, + GdkEventButton *event, + gpointer user_data) +{ + NautilusHeaderBar *self = user_data; + + if (event->button == 3) { + /* right click */ + show_menu (self, GTK_WIDGET (button), event->button, event->time); + return TRUE; + } + + if (event->button == 1) { + schedule_menu_popup_timeout (self, GTK_WIDGET (button)); + } + + return FALSE; +} + +static gboolean +tool_button_release_cb (GtkButton *button, + GdkEventButton *event, + gpointer user_data) +{ + NautilusHeaderBar *self = user_data; + + unschedule_menu_popup_timeout (self); + + return FALSE; +} + +static void +navigation_button_setup_menu (NautilusHeaderBar *self, + GtkWidget *button, + NautilusNavigationDirection direction) +{ + g_object_set_data (G_OBJECT (button), "nav-direction", GUINT_TO_POINTER (direction)); + + g_signal_connect (button, "button-press-event", + G_CALLBACK (tool_button_press_cb), self); + g_signal_connect (button, "button-release-event", + G_CALLBACK (tool_button_release_cb), self); +} + +static gboolean +gear_menu_key_press (GtkWidget *widget, + GdkEventKey *event, + gpointer user_data) +{ + GdkModifierType mask = gtk_accelerator_get_default_mod_mask (); + + if ((event->state & mask) == 0 && (event->keyval == GDK_KEY_F10)) { + gtk_menu_shell_deactivate (GTK_MENU_SHELL (widget)); + return TRUE; + } + + return FALSE; +} + +static void +nautilus_header_bar_constructed (GObject *obj) +{ + NautilusHeaderBar *self = NAUTILUS_HEADER_BAR (obj); + GtkWidget *box, *hbox, *header_bar; + GtkWidget *tool_button; + GtkWidget *menu; + GtkWidget *back_forward; + GtkUIManager *ui_manager; + + G_OBJECT_CLASS (nautilus_header_bar_parent_class)->constructed (obj); + + ui_manager = nautilus_window_get_ui_manager (self->priv->window); + + gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (self)), + GTK_JUNCTION_BOTTOM); + + header_bar = gtk_header_bar_new (); + self->priv->header_bar = header_bar; + + gtk_box_pack_start (GTK_BOX (self), self->priv->header_bar, TRUE, TRUE, 0); + //~ gtk_window_set_titlebar (GTK_WINDOW (self->priv->window), self->priv->header_bar); + gtk_widget_show_all