From 2f8881f532e21c8b43fe90d70ddde76ed81e2889 Mon Sep 17 00:00:00 2001 From: Alexander Schwinn Date: Sun, 17 May 2020 02:36:26 +0200 Subject: Introduced widget thunar-menu in order to unify the way menus are build in thunar, and used it for the context menu (Bug #16654) --- po/POTFILES.in | 1 + thunar/Makefile.am | 2 + thunar/thunar-menu.c | 347 ++++++++++++++++++++++++++++++++++++++++++ thunar/thunar-menu.h | 74 +++++++++ thunar/thunar-standard-view.c | 45 +++++- 5 files changed, 461 insertions(+), 8 deletions(-) create mode 100644 thunar/thunar-menu.c create mode 100644 thunar/thunar-menu.h diff --git a/po/POTFILES.in b/po/POTFILES.in index 63cc7e66..ac935ea2 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -46,6 +46,7 @@ thunar/thunar-location-bar.c thunar/thunar-location-button.c thunar/thunar-location-buttons.c thunar/thunar-location-entry.c +thunar/thunar-menu.c thunar/thunar-notify.c thunar/thunar-navigator.c thunar/thunar-pango-extensions.c diff --git a/thunar/Makefile.am b/thunar/Makefile.am index cff7b495..1ab27536 100644 --- a/thunar/Makefile.am +++ b/thunar/Makefile.am @@ -142,6 +142,8 @@ thunar_SOURCES = \ thunar-location-buttons.h \ thunar-location-entry.c \ thunar-location-entry.h \ + thunar-menu.c \ + thunar-menu.h \ thunar-menu-util.c \ thunar-menu-util.h \ thunar-notify.c \ diff --git a/thunar/thunar-menu.c b/thunar/thunar-menu.c new file mode 100644 index 00000000..5271d049 --- /dev/null +++ b/thunar/thunar-menu.c @@ -0,0 +1,347 @@ +/*- + * Copyright (c) 2020 Alexander Schwinn + * + * 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 of the License, 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include + +/* property identifiers */ +enum +{ + PROP_0, + PROP_MENU_TYPE, + PROP_LAUNCHER, + PROP_FORCE_SECTION_OPEN, + PROP_TAB_SUPPORT_DISABLED, + PROP_CHANGE_DIRECTORY_SUPPORT_DISABLED, +}; + +static void thunar_menu_finalize (GObject *object); +static void thunar_menu_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void thunar_menu_set_property (GObject *object, + guint prop_uid, + const GValue *value, + GParamSpec *pspec); + +struct _ThunarMenuClass +{ + GtkMenuClass __parent__; +}; + +struct _ThunarMenu +{ + GtkMenu __parent__; + ThunarLauncher *launcher; + + /* true, if the 'open' section should be forced */ + gboolean force_section_open; + + /* true, if 'open as new tab' should not be shown */ + gboolean tab_support_disabled; + + /* true, if 'open' for folders, which would result in changing the directory, should not be shown */ + gboolean change_directory_support_disabled; + + /* detailed type of the thunar menu */ + ThunarMenuType type; +}; + + + +static GQuark thunar_menu_handler_quark; + +G_DEFINE_TYPE (ThunarMenu, thunar_menu, GTK_TYPE_MENU) + + + +static void +thunar_menu_class_init (ThunarMenuClass *klass) +{ + GObjectClass *gobject_class; + + /* determine the "thunar-menu-handler" quark */ + thunar_menu_handler_quark = g_quark_from_static_string ("thunar-menu-handler"); + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = thunar_menu_finalize; + gobject_class->get_property = thunar_menu_get_property; + gobject_class->set_property = thunar_menu_set_property; + + g_object_class_install_property (gobject_class, + PROP_MENU_TYPE, + g_param_spec_int ("menu-type", + "menu-type", + "menu-type", + 0, 1, 0, // min, max, default + G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (gobject_class, + PROP_LAUNCHER, + g_param_spec_object ("launcher", + "launcher", + "launcher", + THUNAR_TYPE_LAUNCHER, + G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (gobject_class, + PROP_FORCE_SECTION_OPEN, + g_param_spec_boolean ("force-section-open", + "force-section-open", + "force-section-open", + FALSE, + G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (gobject_class, + PROP_TAB_SUPPORT_DISABLED, + g_param_spec_boolean ("tab-support-disabled", + "tab-support-disabled", + "tab-support-disabled", + FALSE, + G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT_ONLY)); + + g_object_class_install_property (gobject_class, + PROP_CHANGE_DIRECTORY_SUPPORT_DISABLED, + g_param_spec_boolean ("change_directory-support-disabled", + "change_directory-support-disabled", + "change_directory-support-disabled", + FALSE, + G_PARAM_WRITABLE + | G_PARAM_CONSTRUCT_ONLY)); +} + + + +static void +thunar_menu_init (ThunarMenu *menu) +{ + menu->force_section_open = FALSE; + menu->type = FALSE; + menu->tab_support_disabled = FALSE; + menu->change_directory_support_disabled = FALSE; +} + + + +static void +thunar_menu_finalize (GObject *object) +{ + ThunarMenu *menu = THUNAR_MENU (object); + + g_object_unref (menu->launcher); + + (*G_OBJECT_CLASS (thunar_menu_parent_class)->finalize) (object); +} + + + +static void +thunar_menu_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +static void +thunar_menu_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ThunarMenu *menu = THUNAR_MENU (object); + + switch (prop_id) + { + case PROP_MENU_TYPE: + menu->type = g_value_get_int (value); + break; + + case PROP_LAUNCHER: + menu->launcher = g_value_dup_object (value); + g_object_ref (G_OBJECT (menu->launcher)); + break; + + case PROP_FORCE_SECTION_OPEN: + menu->force_section_open = g_value_get_boolean (value); + break; + + case PROP_TAB_SUPPORT_DISABLED: + menu->tab_support_disabled = g_value_get_boolean (value); + break; + + case PROP_CHANGE_DIRECTORY_SUPPORT_DISABLED: + menu->change_directory_support_disabled = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +/** + * thunar_menu_add_sections: + * @menu : a #ThunarMenu instance + * @menu_sections : bit enumeration of #ThunarMenuSections which should be added to the #ThunarMenu + * + * Method to add different sections of #GtkMenuItems to the #ThunarMenu, + * according to the selected #ThunarMenuSections + * + * Return value: TRUE if any #GtkMenuItem was added + **/ +gboolean +thunar_menu_add_sections (ThunarMenu *menu, + ThunarMenuSections menu_sections) +{ + GtkWidget *window; + gboolean item_added; + gboolean is_window_menu = menu->type == THUNAR_MENU_TYPE_WINDOW; + + _thunar_return_val_if_fail (THUNAR_IS_MENU (menu), FALSE); + + if (menu_sections & THUNAR_MENU_SECTION_OPEN) + { + if (thunar_launcher_append_open_section (menu->launcher, GTK_MENU_SHELL (menu), !menu->tab_support_disabled, !menu->change_directory_support_disabled, menu->force_section_open)) + xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu)); + } + + if (menu_sections & THUNAR_MENU_SECTION_SENDTO) + { + item_added = thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_SENDTO_MENU, FALSE) != NULL; + if (item_added) + xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu)); + } + if (menu_sections & THUNAR_MENU_SECTION_CREATE_NEW_FILES) + { + item_added = FALSE; + item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_CREATE_FOLDER, is_window_menu) != NULL); + // TODO: Create Document + if (item_added) + xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu)); + } + item_added = FALSE; + if (menu_sections & THUNAR_MENU_SECTION_CUT) + item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_CUT, is_window_menu) != NULL); + if (menu_sections & THUNAR_MENU_SECTION_COPY_PASTE) + { + item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_COPY, is_window_menu) != NULL); + item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_PASTE, is_window_menu) != NULL); + } + if (item_added) + xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu)); + + if (menu_sections & THUNAR_MENU_SECTION_TRASH_DELETE) + { + item_added = FALSE; + item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_MOVE_TO_TRASH, is_window_menu) != NULL); + item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_DELETE, is_window_menu) != NULL); + if (item_added) + xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu)); + } + if (menu_sections & THUNAR_MENU_SECTION_EMPTY_TRASH) + { + if (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_EMPTY_TRASH, FALSE) != NULL ) + xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu)); + } + if (menu_sections & THUNAR_MENU_SECTION_RESTORE) + { + if (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_RESTORE, FALSE) != NULL) + xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu)); + } + + item_added = FALSE; + if (menu_sections & THUNAR_MENU_SECTION_DUPLICATE) + item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_DUPLICATE, is_window_menu) != NULL); + if (menu_sections & THUNAR_MENU_SECTION_MAKELINK) + item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_MAKE_LINK, is_window_menu) != NULL); + if (menu_sections & THUNAR_MENU_SECTION_RENAME) + item_added |= (thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_RENAME, is_window_menu) != NULL); + if (item_added) + xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (menu)); + + if (menu_sections & THUNAR_MENU_SECTION_CUSTOM_ACTIONS) + { + // TODO + } + + if (menu_sections & THUNAR_MENU_SECTION_ZOOM) + { + // TODO + } + + if (menu_sections & THUNAR_MENU_SECTION_PROPERTIES) + thunar_launcher_append_menu_item (menu->launcher, GTK_MENU_SHELL (menu), THUNAR_LAUNCHER_ACTION_PROPERTIES, FALSE); + + return TRUE; +} + + + +/** + * thunar_menu_get_launcher: + * @menu : a #ThunarMenu instance + * + * Return value: (transfer none): The launcher of this #ThunarMenu instance + **/ +GtkWidget* +thunar_menu_get_launcher (ThunarMenu *menu) +{ + _thunar_return_val_if_fail (THUNAR_IS_MENU (menu), NULL); + return GTK_WIDGET (menu->launcher); +} + + + +/** + * thunar_menu_hide_accel_labels: + * @menu : a #ThunarMenu instance + * + * Will hide the accel_labels of all menu items of this menu + **/ +void +thunar_menu_hide_accel_labels (ThunarMenu *menu) +{ + _thunar_return_if_fail (THUNAR_IS_MENU (menu)); + + for (GList* lp = gtk_container_get_children (GTK_CONTAINER (menu)); lp != NULL; lp = lp->next) + xfce_gtk_menu_item_set_accel_label (lp->data, NULL); +} diff --git a/thunar/thunar-menu.h b/thunar/thunar-menu.h new file mode 100644 index 00000000..16272592 --- /dev/null +++ b/thunar/thunar-menu.h @@ -0,0 +1,74 @@ +/*- + * Copyright (c) 2020 Alexander Schwinn + * + * 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 of the License, 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., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef __THUNAR_MENU_H__ +#define __THUNAR_MENU_H__ + +#include + +#include + +G_BEGIN_DECLS; + +typedef struct _ThunarMenuClass ThunarMenuClass; +typedef struct _ThunarMenu ThunarMenu; + +#define THUNAR_TYPE_MENU (thunar_menu_get_type ()) +#define THUNAR_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_MENU, ThunarMenu)) +#define THUNAR_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_MENU, ThunarMenuClass)) +#define THUNAR_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_MENU)) +#define THUNAR_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_MENU)) +#define THUNAR_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_MENU, ThunarMenu)) + +/* For window menu, some items are shown insensitive, instead of hidden */ +typedef enum +{ + THUNAR_MENU_TYPE_WINDOW, + THUNAR_MENU_TYPE_CONTEXT, +} ThunarMenuType; + +/* Bundles of #GtkMenuItems, which can be created by this widget */ +typedef enum +{ + THUNAR_MENU_SECTION_OPEN = 1 << 0, + THUNAR_MENU_SECTION_SENDTO = 1 << 1, + THUNAR_MENU_SECTION_CREATE_NEW_FILES = 1 << 2, + THUNAR_MENU_SECTION_CUT = 1 << 3, + THUNAR_MENU_SECTION_COPY_PASTE = 1 << 4, + THUNAR_MENU_SECTION_TRASH_DELETE = 1 << 5, + THUNAR_MENU_SECTION_EMPTY_TRASH = 1 << 6, + THUNAR_MENU_SECTION_RESTORE = 1 << 7, + THUNAR_MENU_SECTION_DUPLICATE = 1 << 8, + THUNAR_MENU_SECTION_MAKELINK = 1 << 9, + THUNAR_MENU_SECTION_RENAME = 1 << 10, + THUNAR_MENU_SECTION_CUSTOM_ACTIONS = 1 << 11, + THUNAR_MENU_SECTION_ZOOM = 1 << 12, + THUNAR_MENU_SECTION_PROPERTIES = 1 << 13, + +} ThunarMenuSections; + + +GType thunar_menu_get_type (void) G_GNUC_CONST; + +gboolean thunar_menu_add_sections (ThunarMenu *menu, + ThunarMenuSections menu_sections); +GtkWidget* thunar_menu_get_launcher (ThunarMenu *menu); +void thunar_menu_hide_accel_labels (ThunarMenu *menu); + +G_END_DECLS; + +#endif /* !__THUNAR_CONTEXT_MENU_H__ */ diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c index 6538eed3..c2b926ab 100644 --- a/thunar/thunar-standard-view.c +++ b/thunar/thunar-standard-view.c @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -3589,28 +3590,56 @@ thunar_standard_view_size_allocate (ThunarStandardView *standard_view, void thunar_standard_view_context_menu (ThunarStandardView *standard_view) { - GtkWidget *menu; - GList *selected_items; + GtkWidget *window; + ThunarMenu *context_menu; + GList *selected_items; _thunar_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view)); /* grab an additional reference on the view */ g_object_ref (G_OBJECT (standard_view)); - /* run the menu (figuring out whether to use the file or the folder context menu) */ selected_items = (*THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->get_selected_items) (standard_view); -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - menu = gtk_ui_manager_get_widget (standard_view->ui_manager, (selected_items != NULL) ? "/file-context-menu" : "/folder-context-menu"); -G_GNUC_END_IGNORE_DEPRECATIONS + + window = gtk_widget_get_toplevel (GTK_WIDGET (standard_view)); + + context_menu = g_object_new (THUNAR_TYPE_MENU, "menu-type", THUNAR_MENU_TYPE_CONTEXT, + "launcher", thunar_window_get_launcher (THUNAR_WINDOW (window)), NULL); + if (selected_items != NULL) + { + thunar_menu_add_sections (context_menu, THUNAR_MENU_SECTION_OPEN + | THUNAR_MENU_SECTION_SENDTO + | THUNAR_MENU_SECTION_CUT + | THUNAR_MENU_SECTION_COPY_PASTE + | THUNAR_MENU_SECTION_TRASH_DELETE + | THUNAR_MENU_SECTION_EMPTY_TRASH + | THUNAR_MENU_SECTION_RESTORE + | THUNAR_MENU_SECTION_RENAME + | THUNAR_MENU_SECTION_CUSTOM_ACTIONS + | THUNAR_MENU_SECTION_PROPERTIES); + } + else /* right click on some empty space */ + { + thunar_menu_add_sections (context_menu, THUNAR_MENU_SECTION_CREATE_NEW_FILES + | THUNAR_MENU_SECTION_COPY_PASTE + | THUNAR_MENU_SECTION_EMPTY_TRASH + | THUNAR_MENU_SECTION_CUSTOM_ACTIONS); + xfce_gtk_menu_append_seperator (GTK_MENU_SHELL (context_menu)); + thunar_menu_add_sections (context_menu, THUNAR_MENU_SECTION_ZOOM + | THUNAR_MENU_SECTION_PROPERTIES); + } + thunar_menu_hide_accel_labels (context_menu); + gtk_widget_show_all (GTK_WIDGET (context_menu)); + /* if there is a drag_timer_event (long press), we use it */ if (standard_view->priv->drag_timer_event != NULL) { - thunar_gtk_menu_run_at_event (GTK_MENU (menu), standard_view->priv->drag_timer_event); + thunar_gtk_menu_run_at_event (GTK_MENU (context_menu), standard_view->priv->drag_timer_event); gdk_event_free (standard_view->priv->drag_timer_event); standard_view->priv->drag_timer_event = NULL; } else - thunar_gtk_menu_run (GTK_MENU (menu)); + thunar_gtk_menu_run (GTK_MENU (context_menu)); g_list_free_full (selected_items, (GDestroyNotify) gtk_tree_path_free); -- cgit v1.2.1