summaryrefslogtreecommitdiffstats
path: root/app/actions/windows-actions.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--app/actions/windows-actions.c618
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);
+}