2006-12-10 05:33:38 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
2001-04-11 00:03:40 +08:00
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
|
|
|
* gimpdockbook.c
|
2007-09-17 23:40:01 +08:00
|
|
|
* Copyright (C) 2001-2007 Michael Natterer <mitch@gimp.org>
|
2001-04-11 00:03:40 +08:00
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
2001-04-11 00:03:40 +08:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2009-01-18 06:28:01 +08:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2001-04-11 00:03:40 +08:00
|
|
|
* (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
|
2018-07-12 05:27:07 +08:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2001-04-11 00:03:40 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2001-11-24 00:25:01 +08:00
|
|
|
#include <string.h>
|
|
|
|
|
2012-03-30 01:19:01 +08:00
|
|
|
#include <gegl.h>
|
2012-02-02 03:32:22 +08:00
|
|
|
#undef GTK_DISABLE_DEPRECATED
|
2001-04-11 00:03:40 +08:00
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
|
|
|
|
2001-05-08 11:48:54 +08:00
|
|
|
#include "widgets-types.h"
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2017-03-10 13:04:20 +08:00
|
|
|
#include "config/gimpguiconfig.h"
|
|
|
|
|
|
|
|
#include "core/gimp.h"
|
2003-01-11 01:55:53 +08:00
|
|
|
#include "core/gimpcontext.h"
|
2003-05-03 19:59:44 +08:00
|
|
|
#include "core/gimpmarshal.h"
|
2003-01-11 01:55:53 +08:00
|
|
|
|
2011-07-03 22:36:38 +08:00
|
|
|
#include "gimpdialogfactory.h"
|
2001-05-08 11:48:54 +08:00
|
|
|
#include "gimpdnd.h"
|
2009-09-13 15:31:21 +08:00
|
|
|
#include "gimpdock.h"
|
2001-04-11 00:03:40 +08:00
|
|
|
#include "gimpdockable.h"
|
|
|
|
#include "gimpdockbook.h"
|
2008-05-20 05:11:03 +08:00
|
|
|
#include "gimpdocked.h"
|
2011-05-14 00:56:03 +08:00
|
|
|
#include "gimpdockcontainer.h"
|
2009-09-15 13:58:14 +08:00
|
|
|
#include "gimpdockwindow.h"
|
2003-08-26 18:07:01 +08:00
|
|
|
#include "gimphelp-ids.h"
|
2003-01-11 01:55:53 +08:00
|
|
|
#include "gimpmenufactory.h"
|
2009-10-25 00:52:48 +08:00
|
|
|
#include "gimppanedbox.h"
|
2005-10-31 02:41:18 +08:00
|
|
|
#include "gimpstringaction.h"
|
|
|
|
#include "gimpuimanager.h"
|
2004-08-25 01:16:46 +08:00
|
|
|
#include "gimpview.h"
|
2018-05-02 20:53:56 +08:00
|
|
|
#include "gimpwidgets-utils.h"
|
2001-11-24 00:25:01 +08:00
|
|
|
|
app: Use a GdkWindow instead of GimpDockSeparators for dockable DND
Make drag-and-drop rearrangement of dockables happen directly in the
existing widget hierarchy so we don't have to use special, ugly
widgets (read GimpDockSeparator:s) for that.
More specifically, make edges of dockables and dockbooks have the same
semantics as the GimpDockSeparators had. We put a highlight colored
GdkWindow on top of the widget in question to highlight these special
drop areas. This GdkWindow is not taken into consideration in the GTK+
drag-and-drop code, so it does not interupt the DND interaction.
To achive this, there is a problem we must solve: Drag events in GTK+
are propagated inwards and out, but we sometimes want ancenstor
widgets to take care of drop events. We solve this by introducing the
concept of "drag handlers". A drag handler is asked if it will handle
a given drag event, and if it will, a client will let the drag event
be propagated upwards in the widget hierarchy. Right now, the
GimpPanedBox is the only "drag handler". The code could be generalized
more but it doesn't feel worth it at this point.
The size of the special drop area is 5px, the same size as the default
GtkPaned handles. This is because the plan is to later use these
handles as drop areas too.
Other changes of interest are:
* We need to take care of "drag-motion", "drag-drop" and widget
highlightning ourselves. We can not use the GtkDestDefaults
conveniences with gtk_drag_dest_set() any longer since we need more
control.
* Make the drop callback pass the insert index directly instead of a
GimpDockSeparator
* Add some GIMP_LOG() debug output for DND
* Disable the GimpDockSeparator code in GimpToolbox
2009-11-30 01:22:12 +08:00
|
|
|
#include "gimp-log.h"
|
2010-05-27 00:10:31 +08:00
|
|
|
#include "gimp-intl.h"
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2012-02-02 03:32:22 +08:00
|
|
|
|
2010-05-27 00:10:31 +08:00
|
|
|
#define DEFAULT_TAB_ICON_SIZE GTK_ICON_SIZE_BUTTON
|
|
|
|
#define DND_WIDGET_ICON_SIZE GTK_ICON_SIZE_BUTTON
|
|
|
|
#define MENU_WIDGET_SPACING 4
|
|
|
|
#define TAB_HOVER_TIMEOUT 500
|
|
|
|
#define GIMP_DOCKABLE_DETACH_REF_KEY "gimp-dockable-detach-ref"
|
2001-05-07 00:14:34 +08:00
|
|
|
|
|
|
|
|
2003-05-03 19:59:44 +08:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
DOCKABLE_ADDED,
|
|
|
|
DOCKABLE_REMOVED,
|
|
|
|
DOCKABLE_REORDERED,
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
2012-02-02 03:38:10 +08:00
|
|
|
|
2009-09-13 22:30:09 +08:00
|
|
|
struct _GimpDockbookPrivate
|
|
|
|
{
|
2010-06-12 05:18:49 +08:00
|
|
|
GimpDock *dock;
|
|
|
|
GimpUIManager *ui_manager;
|
2009-09-13 22:30:09 +08:00
|
|
|
|
2010-06-12 05:18:49 +08:00
|
|
|
guint tab_hover_timeout;
|
|
|
|
GimpDockable *tab_hover_dockable;
|
app: Use a GdkWindow instead of GimpDockSeparators for dockable DND
Make drag-and-drop rearrangement of dockables happen directly in the
existing widget hierarchy so we don't have to use special, ugly
widgets (read GimpDockSeparator:s) for that.
More specifically, make edges of dockables and dockbooks have the same
semantics as the GimpDockSeparators had. We put a highlight colored
GdkWindow on top of the widget in question to highlight these special
drop areas. This GdkWindow is not taken into consideration in the GTK+
drag-and-drop code, so it does not interupt the DND interaction.
To achive this, there is a problem we must solve: Drag events in GTK+
are propagated inwards and out, but we sometimes want ancenstor
widgets to take care of drop events. We solve this by introducing the
concept of "drag handlers". A drag handler is asked if it will handle
a given drag event, and if it will, a client will let the drag event
be propagated upwards in the widget hierarchy. Right now, the
GimpPanedBox is the only "drag handler". The code could be generalized
more but it doesn't feel worth it at this point.
The size of the special drop area is 5px, the same size as the default
GtkPaned handles. This is because the plan is to later use these
handles as drop areas too.
Other changes of interest are:
* We need to take care of "drag-motion", "drag-drop" and widget
highlightning ourselves. We can not use the GtkDestDefaults
conveniences with gtk_drag_dest_set() any longer since we need more
control.
* Make the drop callback pass the insert index directly instead of a
GimpDockSeparator
* Add some GIMP_LOG() debug output for DND
* Disable the GimpDockSeparator code in GimpToolbox
2009-11-30 01:22:12 +08:00
|
|
|
|
2010-06-12 05:18:49 +08:00
|
|
|
GimpPanedBox *drag_handler;
|
|
|
|
|
|
|
|
GtkWidget *menu_button;
|
2009-09-13 22:30:09 +08:00
|
|
|
};
|
|
|
|
|
2003-05-03 19:59:44 +08:00
|
|
|
|
2018-06-08 08:40:31 +08:00
|
|
|
static void gimp_dockbook_finalize (GObject *object);
|
|
|
|
|
|
|
|
static gboolean gimp_dockbook_drag_motion (GtkWidget *widget,
|
|
|
|
GdkDragContext *context,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
guint time);
|
|
|
|
static gboolean gimp_dockbook_drag_drop (GtkWidget *widget,
|
|
|
|
GdkDragContext *context,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
guint time);
|
|
|
|
static gboolean gimp_dockbook_popup_menu (GtkWidget *widget);
|
|
|
|
|
|
|
|
static GtkNotebook *gimp_dockbook_create_window (GtkNotebook *notebook,
|
|
|
|
GtkWidget *page,
|
|
|
|
gint x,
|
|
|
|
gint y);
|
|
|
|
static void gimp_dockbook_page_added (GtkNotebook *notebook,
|
|
|
|
GtkWidget *child,
|
|
|
|
guint page_num);
|
|
|
|
static void gimp_dockbook_page_removed (GtkNotebook *notebook,
|
|
|
|
GtkWidget *child,
|
|
|
|
guint page_num);
|
|
|
|
static void gimp_dockbook_page_reordered (GtkNotebook *notebook,
|
|
|
|
GtkWidget *child,
|
|
|
|
guint page_num);
|
|
|
|
|
|
|
|
static gboolean gimp_dockbook_menu_button_press (GimpDockbook *dockbook,
|
|
|
|
GdkEventButton *bevent,
|
|
|
|
GtkWidget *button);
|
|
|
|
static gboolean gimp_dockbook_show_menu (GimpDockbook *dockbook);
|
|
|
|
static void gimp_dockbook_menu_end (GimpDockable *dockable);
|
|
|
|
static void gimp_dockbook_tab_locked_notify (GimpDockable *dockable,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
GimpDockbook *dockbook);
|
|
|
|
static void gimp_dockbook_help_func (const gchar *help_id,
|
|
|
|
gpointer help_data);
|
2017-03-10 13:04:20 +08:00
|
|
|
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2006-05-15 17:46:31 +08:00
|
|
|
G_DEFINE_TYPE (GimpDockbook, gimp_dockbook, GTK_TYPE_NOTEBOOK)
|
2005-12-20 06:37:49 +08:00
|
|
|
|
|
|
|
#define parent_class gimp_dockbook_parent_class
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2005-12-20 06:37:49 +08:00
|
|
|
static guint dockbook_signals[LAST_SIGNAL] = { 0 };
|
2003-05-03 19:59:44 +08:00
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
static const GtkTargetEntry dialog_target_table[] = { GIMP_TARGET_NOTEBOOK_TAB };
|
2001-04-11 00:03:40 +08:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dockbook_class_init (GimpDockbookClass *klass)
|
|
|
|
{
|
2018-06-08 07:37:19 +08:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass);
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2003-05-03 19:59:44 +08:00
|
|
|
dockbook_signals[DOCKABLE_ADDED] =
|
2005-05-27 21:05:26 +08:00
|
|
|
g_signal_new ("dockable-added",
|
2004-08-25 01:16:46 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpDockbookClass, dockable_added),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__OBJECT,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
GIMP_TYPE_DOCKABLE);
|
2003-05-03 19:59:44 +08:00
|
|
|
|
|
|
|
dockbook_signals[DOCKABLE_REMOVED] =
|
2005-05-27 21:05:26 +08:00
|
|
|
g_signal_new ("dockable-removed",
|
2004-08-25 01:16:46 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpDockbookClass, dockable_removed),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__OBJECT,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
GIMP_TYPE_DOCKABLE);
|
2003-05-03 19:59:44 +08:00
|
|
|
|
|
|
|
dockbook_signals[DOCKABLE_REORDERED] =
|
2005-05-27 21:05:26 +08:00
|
|
|
g_signal_new ("dockable-reordered",
|
2004-08-25 01:16:46 +08:00
|
|
|
G_TYPE_FROM_CLASS (klass),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (GimpDockbookClass, dockable_reordered),
|
|
|
|
NULL, NULL,
|
|
|
|
gimp_marshal_VOID__OBJECT,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
GIMP_TYPE_DOCKABLE);
|
2003-05-03 19:59:44 +08:00
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
object_class->finalize = gimp_dockbook_finalize;
|
2003-05-03 19:59:44 +08:00
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
widget_class->drag_motion = gimp_dockbook_drag_motion;
|
|
|
|
widget_class->drag_drop = gimp_dockbook_drag_drop;
|
|
|
|
widget_class->popup_menu = gimp_dockbook_popup_menu;
|
2003-05-03 19:59:44 +08:00
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
notebook_class->create_window = gimp_dockbook_create_window;
|
|
|
|
notebook_class->page_added = gimp_dockbook_page_added;
|
|
|
|
notebook_class->page_removed = gimp_dockbook_page_removed;
|
|
|
|
notebook_class->page_reordered = gimp_dockbook_page_reordered;
|
|
|
|
|
|
|
|
klass->dockable_added = NULL;
|
|
|
|
klass->dockable_removed = NULL;
|
|
|
|
klass->dockable_reordered = NULL;
|
2001-11-30 00:44:51 +08:00
|
|
|
|
2002-03-19 03:34:06 +08:00
|
|
|
gtk_widget_class_install_style_property (widget_class,
|
2005-05-27 21:05:26 +08:00
|
|
|
g_param_spec_enum ("tab-icon-size",
|
2002-05-10 22:50:27 +08:00
|
|
|
NULL, NULL,
|
|
|
|
GTK_TYPE_ICON_SIZE,
|
2003-03-22 03:18:52 +08:00
|
|
|
DEFAULT_TAB_ICON_SIZE,
|
2006-01-19 04:29:40 +08:00
|
|
|
GIMP_PARAM_READABLE));
|
2009-09-13 22:30:09 +08:00
|
|
|
|
|
|
|
g_type_class_add_private (klass, sizeof (GimpDockbookPrivate));
|
2001-04-11 00:03:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dockbook_init (GimpDockbook *dockbook)
|
|
|
|
{
|
2010-02-01 03:22:24 +08:00
|
|
|
GtkNotebook *notebook = GTK_NOTEBOOK (dockbook);
|
2018-05-26 22:28:58 +08:00
|
|
|
GtkWidget *image;
|
2010-02-01 03:22:24 +08:00
|
|
|
|
2009-09-13 22:30:09 +08:00
|
|
|
dockbook->p = G_TYPE_INSTANCE_GET_PRIVATE (dockbook,
|
|
|
|
GIMP_TYPE_DOCKBOOK,
|
|
|
|
GimpDockbookPrivate);
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2010-05-27 00:10:31 +08:00
|
|
|
/* Various init */
|
2010-02-01 03:22:24 +08:00
|
|
|
gtk_notebook_popup_enable (notebook);
|
|
|
|
gtk_notebook_set_scrollable (notebook, TRUE);
|
|
|
|
gtk_notebook_set_show_border (notebook, FALSE);
|
2010-05-27 00:10:31 +08:00
|
|
|
gtk_notebook_set_show_tabs (notebook, TRUE);
|
2018-06-08 07:37:19 +08:00
|
|
|
gtk_notebook_set_group_name (notebook, "gimp-dockbook");
|
2001-04-11 00:03:40 +08:00
|
|
|
|
|
|
|
gtk_drag_dest_set (GTK_WIDGET (dockbook),
|
app: Use a GdkWindow instead of GimpDockSeparators for dockable DND
Make drag-and-drop rearrangement of dockables happen directly in the
existing widget hierarchy so we don't have to use special, ugly
widgets (read GimpDockSeparator:s) for that.
More specifically, make edges of dockables and dockbooks have the same
semantics as the GimpDockSeparators had. We put a highlight colored
GdkWindow on top of the widget in question to highlight these special
drop areas. This GdkWindow is not taken into consideration in the GTK+
drag-and-drop code, so it does not interupt the DND interaction.
To achive this, there is a problem we must solve: Drag events in GTK+
are propagated inwards and out, but we sometimes want ancenstor
widgets to take care of drop events. We solve this by introducing the
concept of "drag handlers". A drag handler is asked if it will handle
a given drag event, and if it will, a client will let the drag event
be propagated upwards in the widget hierarchy. Right now, the
GimpPanedBox is the only "drag handler". The code could be generalized
more but it doesn't feel worth it at this point.
The size of the special drop area is 5px, the same size as the default
GtkPaned handles. This is because the plan is to later use these
handles as drop areas too.
Other changes of interest are:
* We need to take care of "drag-motion", "drag-drop" and widget
highlightning ourselves. We can not use the GtkDestDefaults
conveniences with gtk_drag_dest_set() any longer since we need more
control.
* Make the drop callback pass the insert index directly instead of a
GimpDockSeparator
* Add some GIMP_LOG() debug output for DND
* Disable the GimpDockSeparator code in GimpToolbox
2009-11-30 01:22:12 +08:00
|
|
|
0,
|
2001-10-17 19:33:43 +08:00
|
|
|
dialog_target_table, G_N_ELEMENTS (dialog_target_table),
|
2001-04-11 00:03:40 +08:00
|
|
|
GDK_ACTION_MOVE);
|
2010-05-27 00:10:31 +08:00
|
|
|
|
|
|
|
/* Menu button */
|
|
|
|
dockbook->p->menu_button = gtk_button_new ();
|
|
|
|
gtk_widget_set_can_focus (dockbook->p->menu_button, FALSE);
|
|
|
|
gtk_button_set_relief (GTK_BUTTON (dockbook->p->menu_button),
|
|
|
|
GTK_RELIEF_NONE);
|
2011-11-17 07:17:46 +08:00
|
|
|
gtk_notebook_set_action_widget (notebook,
|
|
|
|
dockbook->p->menu_button,
|
|
|
|
GTK_PACK_END);
|
2010-05-27 00:10:31 +08:00
|
|
|
gtk_widget_show (dockbook->p->menu_button);
|
|
|
|
|
2017-03-05 23:01:59 +08:00
|
|
|
image = gtk_image_new_from_icon_name (GIMP_ICON_MENU_LEFT,
|
|
|
|
GTK_ICON_SIZE_MENU);
|
2014-05-07 21:30:38 +08:00
|
|
|
gtk_image_set_pixel_size (GTK_IMAGE (image), 12);
|
2017-03-05 23:01:59 +08:00
|
|
|
gtk_image_set_from_icon_name (GTK_IMAGE (image), GIMP_ICON_MENU_LEFT,
|
|
|
|
GTK_ICON_SIZE_MENU);
|
2010-05-27 00:10:31 +08:00
|
|
|
gtk_container_add (GTK_CONTAINER (dockbook->p->menu_button), image);
|
|
|
|
gtk_widget_show (image);
|
|
|
|
|
|
|
|
gimp_help_set_help_data (dockbook->p->menu_button, _("Configure this tab"),
|
|
|
|
GIMP_HELP_DOCK_TAB_MENU);
|
|
|
|
|
|
|
|
g_signal_connect_swapped (dockbook->p->menu_button, "button-press-event",
|
|
|
|
G_CALLBACK (gimp_dockbook_menu_button_press),
|
|
|
|
dockbook);
|
2001-04-11 00:03:40 +08:00
|
|
|
}
|
|
|
|
|
2003-01-11 01:55:53 +08:00
|
|
|
static void
|
|
|
|
gimp_dockbook_finalize (GObject *object)
|
|
|
|
{
|
2003-10-06 01:26:21 +08:00
|
|
|
GimpDockbook *dockbook = GIMP_DOCKBOOK (object);
|
2003-01-11 01:55:53 +08:00
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&dockbook->p->ui_manager);
|
|
|
|
|
2003-01-11 01:55:53 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
app: Use a GdkWindow instead of GimpDockSeparators for dockable DND
Make drag-and-drop rearrangement of dockables happen directly in the
existing widget hierarchy so we don't have to use special, ugly
widgets (read GimpDockSeparator:s) for that.
More specifically, make edges of dockables and dockbooks have the same
semantics as the GimpDockSeparators had. We put a highlight colored
GdkWindow on top of the widget in question to highlight these special
drop areas. This GdkWindow is not taken into consideration in the GTK+
drag-and-drop code, so it does not interupt the DND interaction.
To achive this, there is a problem we must solve: Drag events in GTK+
are propagated inwards and out, but we sometimes want ancenstor
widgets to take care of drop events. We solve this by introducing the
concept of "drag handlers". A drag handler is asked if it will handle
a given drag event, and if it will, a client will let the drag event
be propagated upwards in the widget hierarchy. Right now, the
GimpPanedBox is the only "drag handler". The code could be generalized
more but it doesn't feel worth it at this point.
The size of the special drop area is 5px, the same size as the default
GtkPaned handles. This is because the plan is to later use these
handles as drop areas too.
Other changes of interest are:
* We need to take care of "drag-motion", "drag-drop" and widget
highlightning ourselves. We can not use the GtkDestDefaults
conveniences with gtk_drag_dest_set() any longer since we need more
control.
* Make the drop callback pass the insert index directly instead of a
GimpDockSeparator
* Add some GIMP_LOG() debug output for DND
* Disable the GimpDockSeparator code in GimpToolbox
2009-11-30 01:22:12 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_dockbook_drag_motion (GtkWidget *widget,
|
|
|
|
GdkDragContext *context,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
guint time)
|
|
|
|
{
|
2015-02-20 04:18:21 +08:00
|
|
|
GimpDockbook *dockbook = GIMP_DOCKBOOK (widget);
|
|
|
|
|
|
|
|
if (gimp_paned_box_will_handle_drag (dockbook->p->drag_handler,
|
|
|
|
widget,
|
|
|
|
context,
|
|
|
|
x, y,
|
|
|
|
time))
|
|
|
|
{
|
|
|
|
gdk_drag_status (context, 0, time);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
return GTK_WIDGET_CLASS (parent_class)->drag_motion (widget, context,
|
|
|
|
x, y, time);
|
app: Use a GdkWindow instead of GimpDockSeparators for dockable DND
Make drag-and-drop rearrangement of dockables happen directly in the
existing widget hierarchy so we don't have to use special, ugly
widgets (read GimpDockSeparator:s) for that.
More specifically, make edges of dockables and dockbooks have the same
semantics as the GimpDockSeparators had. We put a highlight colored
GdkWindow on top of the widget in question to highlight these special
drop areas. This GdkWindow is not taken into consideration in the GTK+
drag-and-drop code, so it does not interupt the DND interaction.
To achive this, there is a problem we must solve: Drag events in GTK+
are propagated inwards and out, but we sometimes want ancenstor
widgets to take care of drop events. We solve this by introducing the
concept of "drag handlers". A drag handler is asked if it will handle
a given drag event, and if it will, a client will let the drag event
be propagated upwards in the widget hierarchy. Right now, the
GimpPanedBox is the only "drag handler". The code could be generalized
more but it doesn't feel worth it at this point.
The size of the special drop area is 5px, the same size as the default
GtkPaned handles. This is because the plan is to later use these
handles as drop areas too.
Other changes of interest are:
* We need to take care of "drag-motion", "drag-drop" and widget
highlightning ourselves. We can not use the GtkDestDefaults
conveniences with gtk_drag_dest_set() any longer since we need more
control.
* Make the drop callback pass the insert index directly instead of a
GimpDockSeparator
* Add some GIMP_LOG() debug output for DND
* Disable the GimpDockSeparator code in GimpToolbox
2009-11-30 01:22:12 +08:00
|
|
|
}
|
|
|
|
|
2001-04-11 00:03:40 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_dockbook_drag_drop (GtkWidget *widget,
|
2004-08-25 01:16:46 +08:00
|
|
|
GdkDragContext *context,
|
|
|
|
gint x,
|
|
|
|
gint y,
|
|
|
|
guint time)
|
2001-04-11 00:03:40 +08:00
|
|
|
{
|
app: Use a GdkWindow instead of GimpDockSeparators for dockable DND
Make drag-and-drop rearrangement of dockables happen directly in the
existing widget hierarchy so we don't have to use special, ugly
widgets (read GimpDockSeparator:s) for that.
More specifically, make edges of dockables and dockbooks have the same
semantics as the GimpDockSeparators had. We put a highlight colored
GdkWindow on top of the widget in question to highlight these special
drop areas. This GdkWindow is not taken into consideration in the GTK+
drag-and-drop code, so it does not interupt the DND interaction.
To achive this, there is a problem we must solve: Drag events in GTK+
are propagated inwards and out, but we sometimes want ancenstor
widgets to take care of drop events. We solve this by introducing the
concept of "drag handlers". A drag handler is asked if it will handle
a given drag event, and if it will, a client will let the drag event
be propagated upwards in the widget hierarchy. Right now, the
GimpPanedBox is the only "drag handler". The code could be generalized
more but it doesn't feel worth it at this point.
The size of the special drop area is 5px, the same size as the default
GtkPaned handles. This is because the plan is to later use these
handles as drop areas too.
Other changes of interest are:
* We need to take care of "drag-motion", "drag-drop" and widget
highlightning ourselves. We can not use the GtkDestDefaults
conveniences with gtk_drag_dest_set() any longer since we need more
control.
* Make the drop callback pass the insert index directly instead of a
GimpDockSeparator
* Add some GIMP_LOG() debug output for DND
* Disable the GimpDockSeparator code in GimpToolbox
2009-11-30 01:22:12 +08:00
|
|
|
GimpDockbook *dockbook = GIMP_DOCKBOOK (widget);
|
|
|
|
|
|
|
|
if (gimp_paned_box_will_handle_drag (dockbook->p->drag_handler,
|
|
|
|
widget,
|
|
|
|
context,
|
|
|
|
x, y,
|
|
|
|
time))
|
|
|
|
{
|
2015-02-20 04:18:21 +08:00
|
|
|
return FALSE;
|
app: Use a GdkWindow instead of GimpDockSeparators for dockable DND
Make drag-and-drop rearrangement of dockables happen directly in the
existing widget hierarchy so we don't have to use special, ugly
widgets (read GimpDockSeparator:s) for that.
More specifically, make edges of dockables and dockbooks have the same
semantics as the GimpDockSeparators had. We put a highlight colored
GdkWindow on top of the widget in question to highlight these special
drop areas. This GdkWindow is not taken into consideration in the GTK+
drag-and-drop code, so it does not interupt the DND interaction.
To achive this, there is a problem we must solve: Drag events in GTK+
are propagated inwards and out, but we sometimes want ancenstor
widgets to take care of drop events. We solve this by introducing the
concept of "drag handlers". A drag handler is asked if it will handle
a given drag event, and if it will, a client will let the drag event
be propagated upwards in the widget hierarchy. Right now, the
GimpPanedBox is the only "drag handler". The code could be generalized
more but it doesn't feel worth it at this point.
The size of the special drop area is 5px, the same size as the default
GtkPaned handles. This is because the plan is to later use these
handles as drop areas too.
Other changes of interest are:
* We need to take care of "drag-motion", "drag-drop" and widget
highlightning ourselves. We can not use the GtkDestDefaults
conveniences with gtk_drag_dest_set() any longer since we need more
control.
* Make the drop callback pass the insert index directly instead of a
GimpDockSeparator
* Add some GIMP_LOG() debug output for DND
* Disable the GimpDockSeparator code in GimpToolbox
2009-11-30 01:22:12 +08:00
|
|
|
}
|
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
if (widget == gtk_drag_get_source_widget (context))
|
|
|
|
{
|
|
|
|
GList *children = gtk_container_get_children (GTK_CONTAINER (widget));
|
|
|
|
gint n_children = g_list_length (children);
|
|
|
|
|
|
|
|
g_list_free (children);
|
app: Use a GdkWindow instead of GimpDockSeparators for dockable DND
Make drag-and-drop rearrangement of dockables happen directly in the
existing widget hierarchy so we don't have to use special, ugly
widgets (read GimpDockSeparator:s) for that.
More specifically, make edges of dockables and dockbooks have the same
semantics as the GimpDockSeparators had. We put a highlight colored
GdkWindow on top of the widget in question to highlight these special
drop areas. This GdkWindow is not taken into consideration in the GTK+
drag-and-drop code, so it does not interupt the DND interaction.
To achive this, there is a problem we must solve: Drag events in GTK+
are propagated inwards and out, but we sometimes want ancenstor
widgets to take care of drop events. We solve this by introducing the
concept of "drag handlers". A drag handler is asked if it will handle
a given drag event, and if it will, a client will let the drag event
be propagated upwards in the widget hierarchy. Right now, the
GimpPanedBox is the only "drag handler". The code could be generalized
more but it doesn't feel worth it at this point.
The size of the special drop area is 5px, the same size as the default
GtkPaned handles. This is because the plan is to later use these
handles as drop areas too.
Other changes of interest are:
* We need to take care of "drag-motion", "drag-drop" and widget
highlightning ourselves. We can not use the GtkDestDefaults
conveniences with gtk_drag_dest_set() any longer since we need more
control.
* Make the drop callback pass the insert index directly instead of a
GimpDockSeparator
* Add some GIMP_LOG() debug output for DND
* Disable the GimpDockSeparator code in GimpToolbox
2009-11-30 01:22:12 +08:00
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
/* we dragged the only tab, and want to drop it back on the same
|
|
|
|
* notebook, this would remove and add the page, causing the
|
|
|
|
* dockbook to be destroyed in the process because it becomes
|
|
|
|
* empty
|
|
|
|
*/
|
|
|
|
if (n_children == 1)
|
|
|
|
return FALSE;
|
|
|
|
}
|
2015-02-20 04:18:21 +08:00
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
return GTK_WIDGET_CLASS (parent_class)->drag_drop (widget, context,
|
|
|
|
x, y, time);
|
2003-10-06 01:26:21 +08:00
|
|
|
}
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2010-05-27 00:10:31 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_dockbook_popup_menu (GtkWidget *widget)
|
|
|
|
{
|
|
|
|
return gimp_dockbook_show_menu (GIMP_DOCKBOOK (widget));
|
|
|
|
}
|
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
static GtkNotebook *
|
|
|
|
gimp_dockbook_create_window (GtkNotebook *notebook,
|
|
|
|
GtkWidget *page,
|
|
|
|
gint x,
|
|
|
|
gint y)
|
|
|
|
{
|
|
|
|
GimpDockbook *dockbook = GIMP_DOCKBOOK (notebook);
|
|
|
|
GimpDockable *dockable = GIMP_DOCKABLE (page);
|
|
|
|
GimpDialogFactory *dialog_factory;
|
|
|
|
GimpMenuFactory *menu_factory;
|
|
|
|
GimpDockWindow *src_dock_window;
|
|
|
|
GimpDock *src_dock;
|
|
|
|
GtkWidget *new_dock;
|
|
|
|
GimpDockWindow *new_dock_window;
|
|
|
|
GtkWidget *new_dockbook;
|
|
|
|
|
|
|
|
src_dock = gimp_dockbook_get_dock (dockbook);
|
|
|
|
src_dock_window = gimp_dock_window_from_dock (src_dock);
|
|
|
|
|
|
|
|
dialog_factory = gimp_dock_get_dialog_factory (src_dock);
|
|
|
|
menu_factory = gimp_dialog_factory_get_menu_factory (dialog_factory);
|
|
|
|
|
|
|
|
new_dock = gimp_dock_with_window_new (dialog_factory,
|
|
|
|
gimp_widget_get_monitor (page),
|
|
|
|
FALSE);
|
|
|
|
|
|
|
|
new_dock_window = gimp_dock_window_from_dock (GIMP_DOCK (new_dock));
|
|
|
|
gtk_window_set_position (GTK_WINDOW (new_dock_window), GTK_WIN_POS_MOUSE);
|
|
|
|
if (src_dock_window)
|
|
|
|
gimp_dock_window_setup (new_dock_window, src_dock_window);
|
|
|
|
|
|
|
|
new_dockbook = gimp_dockbook_new (menu_factory);
|
|
|
|
|
|
|
|
gimp_dock_add_book (GIMP_DOCK (new_dock), GIMP_DOCKBOOK (new_dockbook), 0);
|
|
|
|
|
|
|
|
gtk_widget_show (GTK_WIDGET (new_dock_window));
|
|
|
|
gtk_widget_show (new_dock);
|
|
|
|
|
|
|
|
return GTK_NOTEBOOK (new_dockbook);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dockbook_page_added (GtkNotebook *notebook,
|
|
|
|
GtkWidget *child,
|
|
|
|
guint page_num)
|
|
|
|
{
|
|
|
|
GimpDockbook *dockbook = GIMP_DOCKBOOK (notebook);
|
|
|
|
GimpDockable *dockable = GIMP_DOCKABLE (child);
|
|
|
|
GtkWidget *tab_widget;
|
|
|
|
GtkWidget *menu_widget;
|
|
|
|
|
|
|
|
GIMP_LOG (DND, "GimpDockable %p added to GimpDockbook %p",
|
|
|
|
dockable, dockbook);
|
|
|
|
|
|
|
|
tab_widget = gimp_dockbook_create_tab_widget (dockbook, dockable);
|
|
|
|
|
|
|
|
/* For the notebook right-click menu, always use the icon style */
|
|
|
|
menu_widget =
|
|
|
|
gimp_dockable_create_tab_widget (dockable,
|
|
|
|
gimp_dock_get_context (dockbook->p->dock),
|
|
|
|
GIMP_TAB_STYLE_ICON_BLURB,
|
|
|
|
GTK_ICON_SIZE_MENU);
|
|
|
|
|
|
|
|
gtk_notebook_set_tab_label (notebook, child, tab_widget);
|
|
|
|
gtk_notebook_set_menu_label (notebook, child, menu_widget);
|
|
|
|
|
2018-06-08 07:53:46 +08:00
|
|
|
if (! gimp_dockable_get_locked (dockable))
|
2018-06-08 07:37:19 +08:00
|
|
|
{
|
|
|
|
gtk_notebook_set_tab_reorderable (notebook, child, TRUE);
|
|
|
|
gtk_notebook_set_tab_detachable (notebook, child, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_dockable_set_dockbook (dockable, dockbook);
|
|
|
|
|
|
|
|
gimp_dockable_set_context (dockable,
|
|
|
|
gimp_dock_get_context (dockbook->p->dock));
|
|
|
|
|
|
|
|
g_signal_connect (dockable, "notify::locked",
|
|
|
|
G_CALLBACK (gimp_dockbook_tab_locked_notify),
|
|
|
|
dockbook);
|
|
|
|
|
2018-06-17 21:14:15 +08:00
|
|
|
gtk_widget_show (child);
|
2018-06-08 07:37:19 +08:00
|
|
|
gtk_notebook_set_current_page (notebook, page_num);
|
|
|
|
|
|
|
|
g_signal_emit (dockbook, dockbook_signals[DOCKABLE_ADDED], 0, dockable);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dockbook_page_removed (GtkNotebook *notebook,
|
|
|
|
GtkWidget *child,
|
|
|
|
guint page_num)
|
|
|
|
{
|
|
|
|
GimpDockbook *dockbook = GIMP_DOCKBOOK (notebook);
|
|
|
|
GimpDockable *dockable = GIMP_DOCKABLE (child);
|
|
|
|
|
|
|
|
GIMP_LOG (DND, "GimpDockable removed %p from GimpDockbook %p",
|
|
|
|
dockable, dockbook);
|
|
|
|
|
|
|
|
g_signal_handlers_disconnect_by_func (dockable,
|
|
|
|
G_CALLBACK (gimp_dockbook_tab_locked_notify),
|
|
|
|
dockbook);
|
|
|
|
|
|
|
|
gimp_dockable_set_dockbook (dockable, NULL);
|
|
|
|
|
|
|
|
gimp_dockable_set_context (dockable, NULL);
|
|
|
|
|
|
|
|
g_signal_emit (dockbook, dockbook_signals[DOCKABLE_REMOVED], 0, dockable);
|
|
|
|
|
|
|
|
if (dockbook->p->dock)
|
|
|
|
{
|
|
|
|
GList *children = gtk_container_get_children (GTK_CONTAINER (dockbook));
|
|
|
|
|
|
|
|
if (! children)
|
|
|
|
gimp_dock_remove_book (dockbook->p->dock, dockbook);
|
|
|
|
|
|
|
|
g_list_free (children);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dockbook_page_reordered (GtkNotebook *notebook,
|
|
|
|
GtkWidget *child,
|
|
|
|
guint page_num)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2010-05-27 00:10:31 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_dockbook_menu_button_press (GimpDockbook *dockbook,
|
|
|
|
GdkEventButton *bevent,
|
|
|
|
GtkWidget *button)
|
|
|
|
{
|
|
|
|
gboolean handled = FALSE;
|
|
|
|
|
|
|
|
if (bevent->button == 1 && bevent->type == GDK_BUTTON_PRESS)
|
|
|
|
handled = gimp_dockbook_show_menu (dockbook);
|
|
|
|
|
|
|
|
return handled;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_dockbook_show_menu (GimpDockbook *dockbook)
|
|
|
|
{
|
2018-05-26 22:28:58 +08:00
|
|
|
GimpUIManager *dockbook_ui_manager;
|
|
|
|
GimpUIManager *dialog_ui_manager;
|
|
|
|
const gchar *dialog_ui_path;
|
|
|
|
gpointer dialog_popup_data;
|
|
|
|
GtkWidget *parent_menu_widget;
|
|
|
|
GtkAction *parent_menu_action;
|
|
|
|
GimpDockable *dockable;
|
|
|
|
gint page_num;
|
2010-05-27 00:10:31 +08:00
|
|
|
|
2010-06-13 00:45:02 +08:00
|
|
|
dockbook_ui_manager = gimp_dockbook_get_ui_manager (dockbook);
|
2010-05-27 00:10:31 +08:00
|
|
|
|
|
|
|
if (! dockbook_ui_manager)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
parent_menu_widget =
|
|
|
|
gtk_ui_manager_get_widget (GTK_UI_MANAGER (dockbook_ui_manager),
|
|
|
|
"/dockable-popup/dockable-menu");
|
|
|
|
parent_menu_action =
|
|
|
|
gtk_ui_manager_get_action (GTK_UI_MANAGER (dockbook_ui_manager),
|
|
|
|
"/dockable-popup/dockable-menu");
|
|
|
|
|
|
|
|
if (! parent_menu_widget || ! parent_menu_action)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (dockbook));
|
|
|
|
dockable = GIMP_DOCKABLE (gtk_notebook_get_nth_page (GTK_NOTEBOOK (dockbook),
|
|
|
|
page_num));
|
|
|
|
|
2010-06-13 00:45:02 +08:00
|
|
|
if (! dockable)
|
2010-05-27 00:10:31 +08:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
dialog_ui_manager = gimp_dockable_get_menu (dockable,
|
|
|
|
&dialog_ui_path,
|
|
|
|
&dialog_popup_data);
|
|
|
|
|
|
|
|
if (dialog_ui_manager && dialog_ui_path)
|
|
|
|
{
|
2010-06-13 00:45:02 +08:00
|
|
|
GtkWidget *child_menu_widget;
|
|
|
|
GtkAction *child_menu_action;
|
|
|
|
gchar *label;
|
2010-05-27 00:10:31 +08:00
|
|
|
|
|
|
|
child_menu_widget =
|
|
|
|
gtk_ui_manager_get_widget (GTK_UI_MANAGER (dialog_ui_manager),
|
|
|
|
dialog_ui_path);
|
|
|
|
|
|
|
|
if (! child_menu_widget)
|
|
|
|
{
|
2016-10-29 05:09:44 +08:00
|
|
|
g_warning ("%s: UI manager '%s' has no widget at path '%s'",
|
2010-05-27 00:10:31 +08:00
|
|
|
G_STRFUNC, dialog_ui_manager->name, dialog_ui_path);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
child_menu_action =
|
|
|
|
gtk_ui_manager_get_action (GTK_UI_MANAGER (dialog_ui_manager),
|
|
|
|
dialog_ui_path);
|
|
|
|
|
|
|
|
if (! child_menu_action)
|
|
|
|
{
|
|
|
|
g_warning ("%s: UI manager '%s' has no action at path '%s'",
|
|
|
|
G_STRFUNC, dialog_ui_manager->name, dialog_ui_path);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_get (child_menu_action,
|
|
|
|
"label", &label,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
g_object_set (parent_menu_action,
|
2014-05-07 21:30:38 +08:00
|
|
|
"label", label,
|
|
|
|
"icon-name", gimp_dockable_get_icon_name (dockable),
|
|
|
|
"visible", TRUE,
|
2010-05-27 00:10:31 +08:00
|
|
|
NULL);
|
|
|
|
|
2010-06-13 00:45:02 +08:00
|
|
|
g_free (label);
|
|
|
|
|
2010-05-27 00:10:31 +08:00
|
|
|
if (! GTK_IS_MENU (child_menu_widget))
|
|
|
|
{
|
|
|
|
g_warning ("%s: child_menu_widget (%p) is not a GtkMenu",
|
|
|
|
G_STRFUNC, child_menu_widget);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
GtkWidget *image = gimp_dockable_get_icon (dockable,
|
|
|
|
GTK_ICON_SIZE_MENU);
|
2018-05-02 20:53:56 +08:00
|
|
|
gimp_menu_item_set_image (GTK_MENU_ITEM (parent_menu_widget), image);
|
2010-05-27 00:10:31 +08:00
|
|
|
gtk_widget_show (image);
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_menu_item_set_submenu (GTK_MENU_ITEM (parent_menu_widget),
|
|
|
|
child_menu_widget);
|
|
|
|
|
|
|
|
gimp_ui_manager_update (dialog_ui_manager, dialog_popup_data);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_object_set (parent_menu_action, "visible", FALSE, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* an action callback may destroy both dockable and dockbook, so
|
|
|
|
* reference them for gimp_dockbook_menu_end()
|
|
|
|
*/
|
|
|
|
g_object_ref (dockable);
|
|
|
|
g_object_set_data_full (G_OBJECT (dockable), GIMP_DOCKABLE_DETACH_REF_KEY,
|
|
|
|
g_object_ref (dockbook),
|
|
|
|
g_object_unref);
|
|
|
|
|
|
|
|
gimp_ui_manager_update (dockbook_ui_manager, dockable);
|
2018-05-02 06:44:38 +08:00
|
|
|
|
|
|
|
gimp_ui_manager_ui_popup_at_widget (dockbook_ui_manager,
|
|
|
|
"/dockable-popup",
|
|
|
|
dockbook->p->menu_button,
|
|
|
|
GDK_GRAVITY_WEST,
|
|
|
|
GDK_GRAVITY_NORTH_EAST,
|
|
|
|
NULL,
|
|
|
|
(GDestroyNotify) gimp_dockbook_menu_end,
|
|
|
|
dockable);
|
2010-05-27 00:10:31 +08:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dockbook_menu_end (GimpDockable *dockable)
|
|
|
|
{
|
2010-06-13 00:45:02 +08:00
|
|
|
GimpUIManager *dialog_ui_manager;
|
|
|
|
const gchar *dialog_ui_path;
|
|
|
|
gpointer dialog_popup_data;
|
2010-05-27 00:10:31 +08:00
|
|
|
|
|
|
|
dialog_ui_manager = gimp_dockable_get_menu (dockable,
|
|
|
|
&dialog_ui_path,
|
|
|
|
&dialog_popup_data);
|
|
|
|
|
|
|
|
if (dialog_ui_manager && dialog_ui_path)
|
|
|
|
{
|
|
|
|
GtkWidget *child_menu_widget =
|
|
|
|
gtk_ui_manager_get_widget (GTK_UI_MANAGER (dialog_ui_manager),
|
|
|
|
dialog_ui_path);
|
|
|
|
|
|
|
|
if (child_menu_widget)
|
|
|
|
gtk_menu_detach (GTK_MENU (child_menu_widget));
|
|
|
|
}
|
|
|
|
|
2010-06-13 00:45:02 +08:00
|
|
|
/* release gimp_dockbook_show_menu()'s references */
|
2010-05-27 00:10:31 +08:00
|
|
|
g_object_set_data (G_OBJECT (dockable), GIMP_DOCKABLE_DETACH_REF_KEY, NULL);
|
|
|
|
g_object_unref (dockable);
|
|
|
|
}
|
|
|
|
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
/* public functions */
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2003-10-06 01:26:21 +08:00
|
|
|
GtkWidget *
|
|
|
|
gimp_dockbook_new (GimpMenuFactory *menu_factory)
|
|
|
|
{
|
|
|
|
GimpDockbook *dockbook;
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2003-10-06 01:26:21 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2003-10-06 01:26:21 +08:00
|
|
|
dockbook = g_object_new (GIMP_TYPE_DOCKBOOK, NULL);
|
2001-04-11 00:03:40 +08:00
|
|
|
|
2009-09-13 22:30:09 +08:00
|
|
|
dockbook->p->ui_manager = gimp_menu_factory_manager_new (menu_factory,
|
2016-11-23 14:01:41 +08:00
|
|
|
"<Dockable>",
|
2018-05-14 06:34:16 +08:00
|
|
|
dockbook);
|
2004-04-23 01:14:22 +08:00
|
|
|
|
2003-10-06 01:26:21 +08:00
|
|
|
gimp_help_connect (GTK_WIDGET (dockbook), gimp_dockbook_help_func,
|
|
|
|
GIMP_HELP_DOCK, dockbook);
|
|
|
|
|
|
|
|
return GTK_WIDGET (dockbook);
|
2001-04-11 00:03:40 +08:00
|
|
|
}
|
|
|
|
|
2009-09-13 22:30:09 +08:00
|
|
|
GimpDock *
|
|
|
|
gimp_dockbook_get_dock (GimpDockbook *dockbook)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DOCKBOOK (dockbook), NULL);
|
|
|
|
|
|
|
|
return dockbook->p->dock;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gimp_dockbook_set_dock (GimpDockbook *dockbook,
|
|
|
|
GimpDock *dock)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
|
|
|
|
g_return_if_fail (dock == NULL || GIMP_IS_DOCK (dock));
|
|
|
|
|
|
|
|
dockbook->p->dock = dock;
|
|
|
|
}
|
|
|
|
|
|
|
|
GimpUIManager *
|
|
|
|
gimp_dockbook_get_ui_manager (GimpDockbook *dockbook)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_DOCKBOOK (dockbook), NULL);
|
|
|
|
|
|
|
|
return dockbook->p->ui_manager;
|
|
|
|
}
|
|
|
|
|
2011-07-03 22:36:38 +08:00
|
|
|
/**
|
|
|
|
* gimp_dockbook_add_from_dialog_factory:
|
|
|
|
* @dockbook: The #DockBook
|
|
|
|
* @identifiers: The dockable identifier(s)
|
|
|
|
*
|
2018-03-25 04:49:01 +08:00
|
|
|
* Add a dockable from the dialog factory associated with the dockbook.
|
2011-07-03 22:36:38 +08:00
|
|
|
**/
|
|
|
|
GtkWidget *
|
|
|
|
gimp_dockbook_add_from_dialog_factory (GimpDockbook *dockbook,
|
2018-06-08 08:40:31 +08:00
|
|
|
const gchar *identifiers)
|
2011-07-03 22:36:38 +08:00
|
|
|
{
|
|
|
|
GtkWidget *dockable;
|
|
|
|
GimpDock *dock;
|
|
|
|
gchar *identifier;
|
|
|
|
gchar *p;
|
|
|
|
|
|
|
|
g_return_val_if_fail (GIMP_IS_DOCKBOOK (dockbook), NULL);
|
|
|
|
g_return_val_if_fail (identifiers != NULL, NULL);
|
|
|
|
|
|
|
|
identifier = g_strdup (identifiers);
|
|
|
|
|
|
|
|
p = strchr (identifier, '|');
|
|
|
|
|
|
|
|
if (p)
|
|
|
|
*p = '\0';
|
|
|
|
|
|
|
|
dock = gimp_dockbook_get_dock (dockbook);
|
|
|
|
dockable = gimp_dialog_factory_dockable_new (gimp_dock_get_dialog_factory (dock),
|
|
|
|
dock,
|
|
|
|
identifier, -1);
|
|
|
|
|
|
|
|
g_free (identifier);
|
|
|
|
|
|
|
|
/* Maybe gimp_dialog_factory_dockable_new() returned an already
|
|
|
|
* existing singleton dockable, so check if it already is
|
|
|
|
* attached to a dockbook.
|
|
|
|
*/
|
|
|
|
if (dockable && ! gimp_dockable_get_dockbook (GIMP_DOCKABLE (dockable)))
|
2018-06-08 08:40:31 +08:00
|
|
|
gtk_notebook_append_page (GTK_NOTEBOOK (dockbook),
|
|
|
|
dockable, NULL);
|
2011-07-03 22:36:38 +08:00
|
|
|
|
|
|
|
return dockable;
|
|
|
|
}
|
|
|
|
|
2010-01-06 20:33:47 +08:00
|
|
|
/**
|
|
|
|
* gimp_dockbook_update_with_context:
|
|
|
|
* @dockbook:
|
|
|
|
* @context:
|
|
|
|
*
|
|
|
|
* Set @context on all dockables in @dockbook.
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
gimp_dockbook_update_with_context (GimpDockbook *dockbook,
|
|
|
|
GimpContext *context)
|
|
|
|
{
|
|
|
|
GList *children = gtk_container_get_children (GTK_CONTAINER (dockbook));
|
2018-05-26 22:28:58 +08:00
|
|
|
GList *iter;
|
2010-01-06 20:33:47 +08:00
|
|
|
|
2018-05-26 22:28:58 +08:00
|
|
|
for (iter = children; iter; iter = g_list_next (iter))
|
2010-01-06 20:33:47 +08:00
|
|
|
{
|
|
|
|
GimpDockable *dockable = GIMP_DOCKABLE (iter->data);
|
|
|
|
|
|
|
|
gimp_dockable_set_context (dockable, context);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free (children);
|
|
|
|
}
|
|
|
|
|
2003-07-08 23:07:56 +08:00
|
|
|
GtkWidget *
|
2008-05-20 05:11:03 +08:00
|
|
|
gimp_dockbook_create_tab_widget (GimpDockbook *dockbook,
|
|
|
|
GimpDockable *dockable)
|
2002-03-20 20:57:59 +08:00
|
|
|
{
|
2009-09-15 13:58:14 +08:00
|
|
|
GtkWidget *tab_widget;
|
|
|
|
GimpDockWindow *dock_window;
|
2010-05-23 18:36:24 +08:00
|
|
|
GtkAction *action = NULL;
|
2018-05-31 08:59:05 +08:00
|
|
|
GtkIconSize tab_size = DEFAULT_TAB_ICON_SIZE;
|
2002-03-20 20:57:59 +08:00
|
|
|
|
2018-05-31 08:59:05 +08:00
|
|
|
gtk_widget_style_get (GTK_WIDGET (dockbook),
|
|
|
|
"tab-icon-size", &tab_size,
|
|
|
|
NULL);
|
2010-04-18 23:42:26 +08:00
|
|
|
tab_widget =
|
2018-05-26 22:28:58 +08:00
|
|
|
gimp_dockable_create_tab_widget (dockable,
|
|
|
|
gimp_dock_get_context (dockbook->p->dock),
|
|
|
|
gimp_dockable_get_tab_style (dockable),
|
2018-05-31 08:59:05 +08:00
|
|
|
tab_size);
|
2018-05-26 22:28:58 +08:00
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
if (GIMP_IS_VIEW (tab_widget))
|
2018-05-26 22:28:58 +08:00
|
|
|
{
|
|
|
|
GtkWidget *event_box;
|
|
|
|
|
|
|
|
event_box = gtk_event_box_new ();
|
|
|
|
gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE);
|
|
|
|
gtk_event_box_set_above_child (GTK_EVENT_BOX (event_box), TRUE);
|
|
|
|
gtk_container_add (GTK_CONTAINER (event_box), tab_widget);
|
|
|
|
gtk_widget_show (tab_widget);
|
|
|
|
|
|
|
|
tab_widget = event_box;
|
|
|
|
}
|
2002-03-20 20:57:59 +08:00
|
|
|
|
2005-10-31 02:41:18 +08:00
|
|
|
/* EEK */
|
2009-09-15 13:58:14 +08:00
|
|
|
dock_window = gimp_dock_window_from_dock (dockbook->p->dock);
|
2011-05-14 00:56:03 +08:00
|
|
|
if (dock_window &&
|
|
|
|
gimp_dock_container_get_ui_manager (GIMP_DOCK_CONTAINER (dock_window)))
|
2005-10-31 02:41:18 +08:00
|
|
|
{
|
|
|
|
const gchar *dialog_id;
|
|
|
|
|
|
|
|
dialog_id = g_object_get_data (G_OBJECT (dockable),
|
|
|
|
"gimp-dialog-identifier");
|
|
|
|
|
|
|
|
if (dialog_id)
|
|
|
|
{
|
2011-05-14 00:56:03 +08:00
|
|
|
GimpDockContainer *dock_container;
|
|
|
|
GimpActionGroup *group;
|
|
|
|
|
|
|
|
dock_container = GIMP_DOCK_CONTAINER (dock_window);
|
2005-10-31 02:41:18 +08:00
|
|
|
|
|
|
|
group = gimp_ui_manager_get_action_group
|
2011-05-14 00:56:03 +08:00
|
|
|
(gimp_dock_container_get_ui_manager (dock_container), "dialogs");
|
2005-10-31 02:41:18 +08:00
|
|
|
|
|
|
|
if (group)
|
|
|
|
{
|
|
|
|
GList *actions;
|
|
|
|
GList *list;
|
|
|
|
|
|
|
|
actions = gtk_action_group_list_actions (GTK_ACTION_GROUP (group));
|
|
|
|
|
|
|
|
for (list = actions; list; list = g_list_next (list))
|
|
|
|
{
|
|
|
|
if (GIMP_IS_STRING_ACTION (list->data) &&
|
|
|
|
strstr (GIMP_STRING_ACTION (list->data)->value,
|
|
|
|
dialog_id))
|
|
|
|
{
|
|
|
|
action = list->data;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_list_free (actions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action)
|
|
|
|
gimp_widget_set_accel_help (tab_widget, action);
|
|
|
|
else
|
2010-01-05 07:30:10 +08:00
|
|
|
gimp_help_set_help_data (tab_widget,
|
|
|
|
gimp_dockable_get_blurb (dockable),
|
|
|
|
gimp_dockable_get_help_id (dockable));
|
2002-03-20 20:57:59 +08:00
|
|
|
|
|
|
|
return tab_widget;
|
|
|
|
}
|
|
|
|
|
app: Use a GdkWindow instead of GimpDockSeparators for dockable DND
Make drag-and-drop rearrangement of dockables happen directly in the
existing widget hierarchy so we don't have to use special, ugly
widgets (read GimpDockSeparator:s) for that.
More specifically, make edges of dockables and dockbooks have the same
semantics as the GimpDockSeparators had. We put a highlight colored
GdkWindow on top of the widget in question to highlight these special
drop areas. This GdkWindow is not taken into consideration in the GTK+
drag-and-drop code, so it does not interupt the DND interaction.
To achive this, there is a problem we must solve: Drag events in GTK+
are propagated inwards and out, but we sometimes want ancenstor
widgets to take care of drop events. We solve this by introducing the
concept of "drag handlers". A drag handler is asked if it will handle
a given drag event, and if it will, a client will let the drag event
be propagated upwards in the widget hierarchy. Right now, the
GimpPanedBox is the only "drag handler". The code could be generalized
more but it doesn't feel worth it at this point.
The size of the special drop area is 5px, the same size as the default
GtkPaned handles. This is because the plan is to later use these
handles as drop areas too.
Other changes of interest are:
* We need to take care of "drag-motion", "drag-drop" and widget
highlightning ourselves. We can not use the GtkDestDefaults
conveniences with gtk_drag_dest_set() any longer since we need more
control.
* Make the drop callback pass the insert index directly instead of a
GimpDockSeparator
* Add some GIMP_LOG() debug output for DND
* Disable the GimpDockSeparator code in GimpToolbox
2009-11-30 01:22:12 +08:00
|
|
|
/**
|
|
|
|
* gimp_dockable_set_drag_handler:
|
|
|
|
* @dockable:
|
|
|
|
* @handler:
|
|
|
|
*
|
|
|
|
* Set a drag handler that will be asked if it will handle drag events
|
|
|
|
* before the dockbook handles the event itself.
|
|
|
|
**/
|
|
|
|
void
|
|
|
|
gimp_dockbook_set_drag_handler (GimpDockbook *dockbook,
|
|
|
|
GimpPanedBox *drag_handler)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
|
|
|
|
|
|
|
|
dockbook->p->drag_handler = drag_handler;
|
|
|
|
}
|
|
|
|
|
2018-05-26 22:28:58 +08:00
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
/* private functions */
|
2007-09-17 23:40:01 +08:00
|
|
|
|
2008-05-20 05:11:03 +08:00
|
|
|
static void
|
|
|
|
gimp_dockbook_tab_locked_notify (GimpDockable *dockable,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
GimpDockbook *dockbook)
|
|
|
|
{
|
2018-06-08 07:53:46 +08:00
|
|
|
gboolean locked = gimp_dockable_get_locked (dockable);
|
2008-05-20 05:11:03 +08:00
|
|
|
|
2018-06-08 07:37:19 +08:00
|
|
|
gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (dockbook),
|
|
|
|
GTK_WIDGET (dockable), ! locked);
|
|
|
|
gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (dockbook),
|
|
|
|
GTK_WIDGET (dockable), ! locked);
|
2008-05-20 05:11:03 +08:00
|
|
|
}
|
|
|
|
|
2003-08-26 18:07:01 +08:00
|
|
|
static void
|
|
|
|
gimp_dockbook_help_func (const gchar *help_id,
|
|
|
|
gpointer help_data)
|
|
|
|
{
|
2008-05-20 05:11:03 +08:00
|
|
|
GimpDockbook *dockbook = GIMP_DOCKBOOK (help_data);
|
2003-08-26 18:07:01 +08:00
|
|
|
GtkWidget *dockable;
|
|
|
|
gint page_num;
|
|
|
|
|
|
|
|
page_num = gtk_notebook_get_current_page (GTK_NOTEBOOK (dockbook));
|
|
|
|
|
|
|
|
dockable = gtk_notebook_get_nth_page (GTK_NOTEBOOK (dockbook), page_num);
|
|
|
|
|
|
|
|
if (GIMP_IS_DOCKABLE (dockable))
|
2010-01-05 07:30:10 +08:00
|
|
|
gimp_standard_help_func (gimp_dockable_get_help_id (GIMP_DOCKABLE (dockable)),
|
|
|
|
NULL);
|
2003-08-26 18:07:01 +08:00
|
|
|
else
|
|
|
|
gimp_standard_help_func (GIMP_HELP_DOCK, NULL);
|
|
|
|
}
|