diff options
Diffstat (limited to 'app/actions/windows-actions.c')
-rw-r--r-- | app/actions/windows-actions.c | 618 |
1 files changed, 618 insertions, 0 deletions
diff --git a/app/actions/windows-actions.c b/app/actions/windows-actions.c new file mode 100644 index 0000000..52b2a9c --- /dev/null +++ b/app/actions/windows-actions.c @@ -0,0 +1,618 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * 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 3 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, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> +#include <gtk/gtk.h> +#include <gdk/gdkkeysyms.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpwidgets/gimpwidgets.h" + +#include "actions-types.h" + +#include "config/gimpdisplayconfig.h" +#include "config/gimpguiconfig.h" + +#include "core/gimp.h" +#include "core/gimpimage.h" +#include "core/gimplist.h" + +#include "widgets/gimpaction.h" +#include "widgets/gimpactiongroup.h" +#include "widgets/gimpdialogfactory.h" +#include "widgets/gimpdock.h" +#include "widgets/gimpdockwindow.h" +#include "widgets/gimphelp-ids.h" + +#include "display/gimpdisplay.h" +#include "display/gimpdisplayshell.h" + +#include "dialogs/dialogs.h" + +#include "windows-actions.h" +#include "windows-commands.h" + +#include "gimp-intl.h" + + +static void windows_actions_display_add (GimpContainer *container, + GimpDisplay *display, + GimpActionGroup *group); +static void windows_actions_display_remove (GimpContainer *container, + GimpDisplay *display, + GimpActionGroup *group); +static void windows_actions_display_reorder (GimpContainer *container, + GimpDisplay *display, + gint position, + GimpActionGroup *group); +static void windows_actions_image_notify (GimpDisplay *display, + const GParamSpec *unused, + GimpActionGroup *group); +static void windows_actions_title_notify (GimpDisplayShell *shell, + const GParamSpec *unused, + GimpActionGroup *group); +static void windows_actions_update_display_accels (GimpActionGroup *group); + +static void windows_actions_dock_window_added (GimpDialogFactory *factory, + GimpDockWindow *dock_window, + GimpActionGroup *group); +static void windows_actions_dock_window_removed (GimpDialogFactory *factory, + GimpDockWindow *dock_window, + GimpActionGroup *group); +static void windows_actions_dock_window_notify (GimpDockWindow *dock, + const GParamSpec *pspec, + GimpActionGroup *group); +static void windows_actions_recent_add (GimpContainer *container, + GimpSessionInfo *info, + GimpActionGroup *group); +static void windows_actions_recent_remove (GimpContainer *container, + GimpSessionInfo *info, + GimpActionGroup *group); +static void windows_actions_single_window_mode_notify (GimpDisplayConfig *config, + GParamSpec *pspec, + GimpActionGroup *group); + + +/* The only reason we have "Tab" in the action entries below is to + * give away the hardcoded keyboard shortcut. If the user changes the + * shortcut to something else, both that shortcut and Tab will + * work. The reason we have the shortcut hardcoded is because + * gtk_accelerator_valid() returns FALSE for GDK_tab. + */ + +static const GimpActionEntry windows_actions[] = +{ + { "windows-menu", NULL, NC_("windows-action", + "_Windows") }, + { "windows-docks-menu", NULL, NC_("windows-action", + "_Recently Closed Docks") }, + { "windows-dialogs-menu", NULL, NC_("windows-action", + "_Dockable Dialogs") }, + + { "windows-show-display-next", NULL, + NC_("windows-action", "Next Image"), "<alt>Tab", + NC_("windows-action", "Switch to the next image"), + windows_show_display_next_cmd_callback, + NULL }, + + { "windows-show-display-previous", NULL, + NC_("windows-action", "Previous Image"), "<alt><shift>Tab", + NC_("windows-action", "Switch to the previous image"), + windows_show_display_previous_cmd_callback, + NULL }, + + { "windows-tab-position", NULL, NC_("windows-action", + "_Tabs Position") }, +}; + +static const GimpToggleActionEntry windows_toggle_actions[] = +{ + { "windows-hide-docks", NULL, + NC_("windows-action", "_Hide Docks"), "Tab", + NC_("windows-action", "When enabled, docks and other dialogs are hidden, leaving only image windows."), + windows_hide_docks_cmd_callback, + FALSE, + GIMP_HELP_WINDOWS_HIDE_DOCKS }, + + { "windows-show-tabs", NULL, + NC_("windows-action", "_Show Tabs"), NULL, + NC_("windows-action", "When enabled, the image tabs bar is shown."), + windows_show_tabs_cmd_callback, + FALSE, + GIMP_HELP_WINDOWS_SHOW_TABS }, + + { "windows-use-single-window-mode", NULL, + NC_("windows-action", "Single-Window _Mode"), NULL, + NC_("windows-action", "When enabled, GIMP is in a single-window mode."), + windows_use_single_window_mode_cmd_callback, + FALSE, + GIMP_HELP_WINDOWS_USE_SINGLE_WINDOW_MODE } +}; + +static const GimpRadioActionEntry windows_tabs_position_actions[] = +{ + { "windows-tabs-position-top", GIMP_ICON_GO_TOP, + NC_("windows-tabs-position-action", "_Top"), NULL, + NC_("windows-tabs-position-action", "Position the tabs on the top"), + GIMP_POSITION_TOP, GIMP_HELP_WINDOWS_TABS_POSITION }, + + { "windows-tabs-position-bottom", GIMP_ICON_GO_BOTTOM, + NC_("windows-tabs-position-action", "_Bottom"), NULL, + NC_("windows-tabs-position-action", "Position the tabs on the bottom"), + GIMP_POSITION_BOTTOM, GIMP_HELP_WINDOWS_TABS_POSITION }, + + { "windows-tabs-position-left", GIMP_ICON_GO_FIRST, + NC_("windows-tabs-position-action", "_Left"), NULL, + NC_("windows-tabs-position-action", "Position the tabs on the left"), + GIMP_POSITION_LEFT, GIMP_HELP_WINDOWS_TABS_POSITION }, + + { "windows-tabs-position-right", GIMP_ICON_GO_LAST, + NC_("windows-tabs-position-action", "_Right"), NULL, + NC_("windows-tabs-position-action", "Position the tabs on the right"), + GIMP_POSITION_RIGHT, GIMP_HELP_WINDOWS_TABS_POSITION }, +}; + +void +windows_actions_setup (GimpActionGroup *group) +{ + GList *list; + + gimp_action_group_add_actions (group, "windows-action", + windows_actions, + G_N_ELEMENTS (windows_actions)); + + gimp_action_group_add_toggle_actions (group, "windows-action", + windows_toggle_actions, + G_N_ELEMENTS (windows_toggle_actions)); + + gimp_action_group_add_radio_actions (group, "windows-tabs-position-action", + windows_tabs_position_actions, + G_N_ELEMENTS (windows_tabs_position_actions), + NULL, 0, + windows_set_tabs_position_cmd_callback); + + gimp_action_group_set_action_hide_empty (group, "windows-docks-menu", FALSE); + + g_signal_connect_object (group->gimp->displays, "add", + G_CALLBACK (windows_actions_display_add), + group, 0); + g_signal_connect_object (group->gimp->displays, "remove", + G_CALLBACK (windows_actions_display_remove), + group, 0); + g_signal_connect_object (group->gimp->displays, "reorder", + G_CALLBACK (windows_actions_display_reorder), + group, 0); + + for (list = gimp_get_display_iter (group->gimp); + list; + list = g_list_next (list)) + { + GimpDisplay *display = list->data; + + windows_actions_display_add (group->gimp->displays, display, group); + } + + g_signal_connect_object (gimp_dialog_factory_get_singleton (), "dock-window-added", + G_CALLBACK (windows_actions_dock_window_added), + group, 0); + g_signal_connect_object (gimp_dialog_factory_get_singleton (), "dock-window-removed", + G_CALLBACK (windows_actions_dock_window_removed), + group, 0); + + for (list = gimp_dialog_factory_get_open_dialogs (gimp_dialog_factory_get_singleton ()); + list; + list = g_list_next (list)) + { + GimpDockWindow *dock_window = list->data; + + if (GIMP_IS_DOCK_WINDOW (dock_window)) + windows_actions_dock_window_added (gimp_dialog_factory_get_singleton (), + dock_window, + group); + } + + g_signal_connect_object (global_recent_docks, "add", + G_CALLBACK (windows_actions_recent_add), + group, 0); + g_signal_connect_object (global_recent_docks, "remove", + G_CALLBACK (windows_actions_recent_remove), + group, 0); + + for (list = GIMP_LIST (global_recent_docks)->queue->head; + list; + list = g_list_next (list)) + { + GimpSessionInfo *info = list->data; + + windows_actions_recent_add (global_recent_docks, info, group); + } + + g_signal_connect_object (group->gimp->config, "notify::single-window-mode", + G_CALLBACK (windows_actions_single_window_mode_notify), + group, 0); +} + +void +windows_actions_update (GimpActionGroup *group, + gpointer data) +{ + GimpGuiConfig *config = GIMP_GUI_CONFIG (group->gimp->config); + const gchar *action = NULL; + +#define SET_ACTIVE(action,condition) \ + gimp_action_group_set_action_active (group, action, (condition) != 0) + + SET_ACTIVE ("windows-use-single-window-mode", config->single_window_mode); + SET_ACTIVE ("windows-hide-docks", config->hide_docks); + SET_ACTIVE ("windows-show-tabs", config->show_tabs); + + switch (config->tabs_position) + { + case GIMP_POSITION_TOP: + action = "windows-tabs-position-top"; + break; + case GIMP_POSITION_BOTTOM: + action = "windows-tabs-position-bottom"; + break; + case GIMP_POSITION_LEFT: + action = "windows-tabs-position-left"; + break; + case GIMP_POSITION_RIGHT: + action = "windows-tabs-position-right"; + break; + default: + action = "windows-tabs-position-top"; + break; + } + + gimp_action_group_set_action_active (group, action, TRUE); + gimp_action_group_set_action_sensitive (group, "windows-tab-position", config->single_window_mode); + gimp_action_group_set_action_sensitive (group, "windows-show-tabs", config->single_window_mode); + +#undef SET_ACTIVE +} + +gchar * +windows_actions_dock_window_to_action_name (GimpDockWindow *dock_window) +{ + return g_strdup_printf ("windows-dock-%04d", + gimp_dock_window_get_id (dock_window)); +} + + +/* private functions */ + +static void +windows_actions_display_add (GimpContainer *container, + GimpDisplay *display, + GimpActionGroup *group) +{ + GimpDisplayShell *shell = gimp_display_get_shell (display); + + g_signal_connect_object (display, "notify::image", + G_CALLBACK (windows_actions_image_notify), + group, 0); + + g_signal_connect_object (shell, "notify::title", + G_CALLBACK (windows_actions_title_notify), + group, 0); + + windows_actions_image_notify (display, NULL, group); +} + +static void +windows_actions_display_remove (GimpContainer *container, + GimpDisplay *display, + GimpActionGroup *group) +{ + GimpDisplayShell *shell = gimp_display_get_shell (display); + GimpAction *action; + gchar *action_name; + + if (shell) + g_signal_handlers_disconnect_by_func (shell, + windows_actions_title_notify, + group); + + action_name = gimp_display_get_action_name (display); + action = gimp_action_group_get_action (group, action_name); + g_free (action_name); + + if (action) + gimp_action_group_remove_action_and_accel (group, action); + + windows_actions_update_display_accels (group); +} + +static void +windows_actions_display_reorder (GimpContainer *container, + GimpDisplay *display, + gint new_index, + GimpActionGroup *group) +{ + windows_actions_update_display_accels (group); +} + +static void +windows_actions_image_notify (GimpDisplay *display, + const GParamSpec *unused, + GimpActionGroup *group) +{ + GimpImage *image = gimp_display_get_image (display); + GimpAction *action; + gchar *action_name; + + action_name = gimp_display_get_action_name (display); + + action = gimp_action_group_get_action (group, action_name); + + if (! action) + { + GimpActionEntry entry; + + entry.name = action_name; + entry.icon_name = GIMP_ICON_IMAGE; + entry.label = ""; + entry.accelerator = NULL; + entry.tooltip = NULL; + entry.callback = windows_show_display_cmd_callback; + entry.help_id = NULL; + + gimp_action_group_add_actions (group, NULL, &entry, 1); + + gimp_action_group_set_action_always_show_image (group, action_name, + TRUE); + action = gimp_action_group_get_action (group, action_name); + + g_object_set_data (G_OBJECT (action), "display", display); + } + + g_free (action_name); + + if (image) + { + const gchar *display_name; + gchar *escaped; + gchar *title; + + display_name = gimp_image_get_display_name (image); + escaped = gimp_escape_uline (display_name); + + title = g_strdup_printf ("%s-%d.%d", escaped, + gimp_image_get_ID (image), + gimp_display_get_instance (display)); + g_free (escaped); + + g_object_set (action, + "visible", TRUE, + "label", title, + "tooltip", gimp_image_get_display_path (image), + "viewable", image, + "context", gimp_get_user_context (group->gimp), + NULL); + + g_free (title); + + windows_actions_update_display_accels (group); + } + else + { + g_object_set (action, + "visible", FALSE, + "viewable", NULL, + NULL); + } +} + +static void +windows_actions_title_notify (GimpDisplayShell *shell, + const GParamSpec *unused, + GimpActionGroup *group) +{ + windows_actions_image_notify (shell->display, NULL, group); +} + +static void +windows_actions_update_display_accels (GimpActionGroup *group) +{ + GList *list; + gint i; + + for (list = gimp_get_display_iter (group->gimp), i = 0; + list && i < 10; + list = g_list_next (list), i++) + { + GimpDisplay *display = list->data; + GimpAction *action; + gchar *action_name; + + if (! gimp_display_get_image (display)) + break; + + action_name = gimp_display_get_action_name (display); + + action = gimp_action_group_get_action (group, action_name); + g_free (action_name); + + if (action) + { + const gchar *accel_path; + guint accel_key; + + accel_path = gimp_action_get_accel_path (action); + + if (i < 9) + accel_key = GDK_KEY_1 + i; + else + accel_key = GDK_KEY_0; + + gtk_accel_map_change_entry (accel_path, + accel_key, GDK_MOD1_MASK, + TRUE); + } + } +} + +static void +windows_actions_dock_window_added (GimpDialogFactory *factory, + GimpDockWindow *dock_window, + GimpActionGroup *group) +{ + GimpAction *action; + GimpActionEntry entry; + gchar *action_name = windows_actions_dock_window_to_action_name (dock_window); + + entry.name = action_name; + entry.icon_name = NULL; + entry.label = ""; + entry.accelerator = NULL; + entry.tooltip = NULL; + entry.callback = windows_show_dock_cmd_callback; + entry.help_id = GIMP_HELP_WINDOWS_SHOW_DOCK; + + gimp_action_group_add_actions (group, NULL, &entry, 1); + + action = gimp_action_group_get_action (group, action_name); + + g_object_set (action, + "ellipsize", PANGO_ELLIPSIZE_END, + NULL); + + g_object_set_data (G_OBJECT (action), "dock-window", dock_window); + + g_free (action_name); + + g_signal_connect_object (dock_window, "notify::title", + G_CALLBACK (windows_actions_dock_window_notify), + group, 0); + + if (gtk_window_get_title (GTK_WINDOW (dock_window))) + windows_actions_dock_window_notify (dock_window, NULL, group); +} + +static void +windows_actions_dock_window_removed (GimpDialogFactory *factory, + GimpDockWindow *dock_window, + GimpActionGroup *group) +{ + GimpAction *action; + gchar *action_name; + + action_name = windows_actions_dock_window_to_action_name (dock_window); + action = gimp_action_group_get_action (group, action_name); + g_free (action_name); + + if (action) + gimp_action_group_remove_action_and_accel (group, action); +} + +static void +windows_actions_dock_window_notify (GimpDockWindow *dock_window, + const GParamSpec *pspec, + GimpActionGroup *group) +{ + GimpAction *action; + gchar *action_name; + + action_name = windows_actions_dock_window_to_action_name (dock_window); + action = gimp_action_group_get_action (group, action_name); + g_free (action_name); + + if (action) + g_object_set (action, + "label", gtk_window_get_title (GTK_WINDOW (dock_window)), + "tooltip", gtk_window_get_title (GTK_WINDOW (dock_window)), + NULL); +} + +static void +windows_actions_recent_add (GimpContainer *container, + GimpSessionInfo *info, + GimpActionGroup *group) +{ + GimpAction *action; + GimpActionEntry entry; + gint info_id; + static gint info_id_counter = 1; + gchar *action_name; + + info_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (info), + "recent-action-id")); + + if (! info_id) + { + info_id = info_id_counter++; + + g_object_set_data (G_OBJECT (info), "recent-action-id", + GINT_TO_POINTER (info_id)); + } + + action_name = g_strdup_printf ("windows-recent-%04d", info_id); + + entry.name = action_name; + entry.icon_name = NULL; + entry.label = gimp_object_get_name (info); + entry.accelerator = NULL; + entry.tooltip = gimp_object_get_name (info); + entry.callback = windows_open_recent_cmd_callback; + entry.help_id = GIMP_HELP_WINDOWS_OPEN_RECENT_DOCK; + + gimp_action_group_add_actions (group, NULL, &entry, 1); + + action = gimp_action_group_get_action (group, action_name); + + g_object_set (action, + "ellipsize", PANGO_ELLIPSIZE_END, + "max-width-chars", 30, + NULL); + + g_object_set_data (G_OBJECT (action), "info", info); + + g_free (action_name); +} + +static void +windows_actions_recent_remove (GimpContainer *container, + GimpSessionInfo *info, + GimpActionGroup *group) +{ + GimpAction *action; + gint info_id; + gchar *action_name; + + info_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (info), + "recent-action-id")); + + action_name = g_strdup_printf ("windows-recent-%04d", info_id); + action = gimp_action_group_get_action (group, action_name); + g_free (action_name); + + if (action) + gimp_action_group_remove_action_and_accel (group, action); +} + +static void +windows_actions_single_window_mode_notify (GimpDisplayConfig *config, + GParamSpec *pspec, + GimpActionGroup *group) +{ + gimp_action_group_set_action_active (group, + "windows-use-single-window-mode", + GIMP_GUI_CONFIG (config)->single_window_mode); +} |