gimp/app/widgets/gimpdockbook.c
Jehan 38d0abc026 app: prevent multiple registrations of a same action.
Pre-GIMP-3.0 code logics would re-allocate several GimpMenuFactory or
GimpUIManager for no good reason. While it was still working with old GtkAction
code, with our new GAction-based code, we were ending up overriding an action
with a new version of the same action, while keeping reference to old actions.
This made for discrepancies of the enabled or visible state of actions.

The new code keeps singleton of some objects and references to already
registered GimpUIManager or GimpActionGroups objects and make sure no actions
with the same name are created twice.
2023-04-12 22:07:09 +02:00

911 lines
29 KiB
C

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpdockbook.c
* Copyright (C) 2001-2007 Michael Natterer <mitch@gimp.org>
*
* 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 <string.h>
#include <gegl.h>
#undef GTK_DISABLE_DEPRECATED
#include <gtk/gtk.h>
#include "libgimpbase/gimpbase.h"
#include "libgimpwidgets/gimpwidgets.h"
#include "widgets-types.h"
#include "config/gimpguiconfig.h"
#include "core/gimp.h"
#include "core/gimpcontext.h"
#include "menus/menus.h"
#include "gimpactiongroup.h"
#include "gimpdialogfactory.h"
#include "gimpdnd.h"
#include "gimpdock.h"
#include "gimpdockable.h"
#include "gimpdockbook.h"
#include "gimpdocked.h"
#include "gimpdockcontainer.h"
#include "gimpdockwindow.h"
#include "gimphelp-ids.h"
#include "gimpmenufactory.h"
#include "gimppanedbox.h"
#include "gimpstringaction.h"
#include "gimpuimanager.h"
#include "gimpview.h"
#include "gimpwidgets-utils.h"
#include "gimp-log.h"
#include "gimp-intl.h"
#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"
enum
{
DOCKABLE_ADDED,
DOCKABLE_REMOVED,
DOCKABLE_REORDERED,
LAST_SIGNAL
};
typedef struct
{
GimpDockbookDragCallback callback;
gpointer data;
} GimpDockbookDragCallbackData;
struct _GimpDockbookPrivate
{
GimpDock *dock;
GimpUIManager *ui_manager;
guint tab_hover_timeout;
GimpDockable *tab_hover_dockable;
GimpPanedBox *drag_handler;
GtkWidget *menu_button;
};
static void gimp_dockbook_finalize (GObject *object);
static void gimp_dockbook_style_updated (GtkWidget *widget);
static void gimp_dockbook_drag_begin (GtkWidget *widget,
GdkDragContext *context);
static void gimp_dockbook_drag_end (GtkWidget *widget,
GdkDragContext *context);
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);
G_DEFINE_TYPE_WITH_PRIVATE (GimpDockbook, gimp_dockbook, GTK_TYPE_NOTEBOOK)
#define parent_class gimp_dockbook_parent_class
static guint dockbook_signals[LAST_SIGNAL] = { 0 };
static const GtkTargetEntry dialog_target_table[] = { GIMP_TARGET_NOTEBOOK_TAB };
static GList *drag_callbacks = NULL;
static void
gimp_dockbook_class_init (GimpDockbookClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass);
dockbook_signals[DOCKABLE_ADDED] =
g_signal_new ("dockable-added",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpDockbookClass, dockable_added),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
GIMP_TYPE_DOCKABLE);
dockbook_signals[DOCKABLE_REMOVED] =
g_signal_new ("dockable-removed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpDockbookClass, dockable_removed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
GIMP_TYPE_DOCKABLE);
dockbook_signals[DOCKABLE_REORDERED] =
g_signal_new ("dockable-reordered",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpDockbookClass, dockable_reordered),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
GIMP_TYPE_DOCKABLE);
object_class->finalize = gimp_dockbook_finalize;
widget_class->style_updated = gimp_dockbook_style_updated;
widget_class->drag_begin = gimp_dockbook_drag_begin;
widget_class->drag_end = gimp_dockbook_drag_end;
widget_class->drag_motion = gimp_dockbook_drag_motion;
widget_class->drag_drop = gimp_dockbook_drag_drop;
widget_class->popup_menu = gimp_dockbook_popup_menu;
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;
gtk_widget_class_install_style_property (widget_class,
g_param_spec_enum ("tab-icon-size",
NULL, NULL,
GTK_TYPE_ICON_SIZE,
DEFAULT_TAB_ICON_SIZE,
GIMP_PARAM_READABLE));
}
static void
gimp_dockbook_init (GimpDockbook *dockbook)
{
GtkNotebook *notebook = GTK_NOTEBOOK (dockbook);
GtkWidget *image;
dockbook->p = gimp_dockbook_get_instance_private (dockbook);
/* Various init */
gtk_notebook_popup_enable (notebook);
gtk_notebook_set_scrollable (notebook, TRUE);
gtk_notebook_set_show_border (notebook, FALSE);
gtk_notebook_set_show_tabs (notebook, TRUE);
gtk_notebook_set_group_name (notebook, "gimp-dockbook");
gtk_drag_dest_set (GTK_WIDGET (dockbook),
0,
dialog_target_table, G_N_ELEMENTS (dialog_target_table),
GDK_ACTION_MOVE);
/* 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);
gtk_notebook_set_action_widget (notebook,
dockbook->p->menu_button,
GTK_PACK_END);
gtk_widget_show (dockbook->p->menu_button);
image = gtk_image_new_from_icon_name (GIMP_ICON_MENU_LEFT,
GTK_ICON_SIZE_MENU);
gtk_image_set_pixel_size (GTK_IMAGE (image), 12);
gtk_image_set_from_icon_name (GTK_IMAGE (image), GIMP_ICON_MENU_LEFT,
GTK_ICON_SIZE_MENU);
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);
}
static void
gimp_dockbook_finalize (GObject *object)
{
GimpDockbook *dockbook = GIMP_DOCKBOOK (object);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_dockbook_style_updated (GtkWidget *widget)
{
GimpDockbook *dockbook = GIMP_DOCKBOOK (widget);
GimpContext *context;
GtkWidget *tab_widget;
GList *children;
GList *iter;
GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
if (! dockbook->p->dock ||
! (context = gimp_dock_get_context (dockbook->p->dock)))
return;
children = gtk_container_get_children (GTK_CONTAINER (dockbook));
for (iter = children; iter; iter = g_list_next (iter))
{
GimpDockable *dockable = GIMP_DOCKABLE (iter->data);
tab_widget = gimp_dockbook_create_tab_widget (dockbook, dockable);
gtk_notebook_set_tab_label (GTK_NOTEBOOK (dockbook),
GTK_WIDGET (dockable),
tab_widget);
}
g_list_free (children);
gimp_dock_invalidate_geometry (GIMP_DOCK (dockbook->p->dock));
}
static void
gimp_dockbook_drag_begin (GtkWidget *widget,
GdkDragContext *context)
{
GList *iter;
if (GTK_WIDGET_CLASS (parent_class)->drag_begin)
GTK_WIDGET_CLASS (parent_class)->drag_begin (widget, context);
iter = drag_callbacks;
while (iter)
{
GimpDockbookDragCallbackData *callback_data = iter->data;
iter = g_list_next (iter);
callback_data->callback (context, TRUE, callback_data->data);
}
}
static void
gimp_dockbook_drag_end (GtkWidget *widget,
GdkDragContext *context)
{
GList *iter;
iter = drag_callbacks;
while (iter)
{
GimpDockbookDragCallbackData *callback_data = iter->data;
iter = g_list_next (iter);
callback_data->callback (context, FALSE, callback_data->data);
}
if (GTK_WIDGET_CLASS (parent_class)->drag_end)
GTK_WIDGET_CLASS (parent_class)->drag_end (widget, context);
}
static gboolean
gimp_dockbook_drag_motion (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint time)
{
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;
}
return GTK_WIDGET_CLASS (parent_class)->drag_motion (widget, context,
x, y, time);
}
static gboolean
gimp_dockbook_drag_drop (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint time)
{
GimpDockbook *dockbook = GIMP_DOCKBOOK (widget);
if (gimp_paned_box_will_handle_drag (dockbook->p->drag_handler,
widget,
context,
x, y,
time))
{
return FALSE;
}
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);
/* 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;
}
return GTK_WIDGET_CLASS (parent_class)->drag_drop (widget, context,
x, y, time);
}
static gboolean
gimp_dockbook_popup_menu (GtkWidget *widget)
{
return gimp_dockbook_show_menu (GIMP_DOCKBOOK (widget));
}
static GtkNotebook *
gimp_dockbook_create_window (GtkNotebook *notebook,
GtkWidget *page,
gint x,
gint y)
{
GimpDockbook *dockbook = GIMP_DOCKBOOK (notebook);
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 = menus_get_global_menu_factory (gimp_dialog_factory_get_context (dialog_factory)->gimp);
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);
if (! gimp_dockable_get_locked (dockable))
{
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);
gtk_widget_show (child);
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)
{
}
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)
{
GimpUIManager *dockbook_ui_manager;
GimpUIManager *dialog_ui_manager;
const gchar *dialog_ui_path;
gpointer dialog_popup_data;
GimpDockable *dockable;
gint page_num;
dockbook_ui_manager = dockbook->p->ui_manager;
if (! dockbook_ui_manager)
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));
if (! dockable)
return FALSE;
dialog_ui_manager = gimp_dockable_get_menu (dockable,
&dialog_ui_path,
&dialog_popup_data);
/* 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_ui_popup_at_widget (dockbook_ui_manager,
"/dockable-popup",
dialog_ui_manager,
dialog_ui_path,
dockbook->p->menu_button,
GDK_GRAVITY_WEST,
GDK_GRAVITY_NORTH_EAST,
NULL,
(GDestroyNotify) gimp_dockbook_menu_end,
dockable);
return TRUE;
}
static void
gimp_dockbook_menu_end (GimpDockable *dockable)
{
/* release gimp_dockbook_show_menu()'s references */
g_object_set_data (G_OBJECT (dockable), GIMP_DOCKABLE_DETACH_REF_KEY, NULL);
g_object_unref (dockable);
}
/* public functions */
GtkWidget *
gimp_dockbook_new (GimpMenuFactory *menu_factory)
{
GimpDockbook *dockbook;
g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
dockbook = g_object_new (GIMP_TYPE_DOCKBOOK, NULL);
dockbook->p->ui_manager = gimp_menu_factory_get_manager (menu_factory,
"<Dockable>",
dockbook);
gimp_help_connect (GTK_WIDGET (dockbook), gimp_dockbook_help_func,
GIMP_HELP_DOCK, dockbook, NULL);
return GTK_WIDGET (dockbook);
}
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)
{
GimpContext *context;
g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
g_return_if_fail (dock == NULL || GIMP_IS_DOCK (dock));
if (dockbook->p->dock &&
(context = gimp_dock_get_context (dockbook->p->dock)) != NULL)
{
g_signal_handlers_disconnect_by_func (GIMP_GUI_CONFIG (context->gimp->config),
G_CALLBACK (gimp_dockbook_style_updated),
dockbook);
}
dockbook->p->dock = dock;
if (dockbook->p->dock &&
(context = gimp_dock_get_context (dockbook->p->dock)) != NULL)
{
g_signal_connect_object (GIMP_GUI_CONFIG (context->gimp->config),
"notify::theme",
G_CALLBACK (gimp_dockbook_style_updated),
dockbook, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
g_signal_connect_object (GIMP_GUI_CONFIG (context->gimp->config),
"notify::override-theme-icon-size",
G_CALLBACK (gimp_dockbook_style_updated),
dockbook, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
g_signal_connect_object (GIMP_GUI_CONFIG (context->gimp->config),
"notify::custom-icon-size",
G_CALLBACK (gimp_dockbook_style_updated),
dockbook, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
}
}
/**
* gimp_dockbook_add_from_dialog_factory:
* @dockbook: The #DockBook
* @identifiers: The dockable identifier(s)
*
* Add a dockable from the dialog factory associated with the dockbook.
**/
GtkWidget *
gimp_dockbook_add_from_dialog_factory (GimpDockbook *dockbook,
const gchar *identifiers)
{
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)))
gtk_notebook_append_page (GTK_NOTEBOOK (dockbook),
dockable, NULL);
return dockable;
}
/**
* 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));
GList *iter;
for (iter = children; iter; iter = g_list_next (iter))
{
GimpDockable *dockable = GIMP_DOCKABLE (iter->data);
gimp_dockable_set_context (dockable, context);
}
g_list_free (children);
}
GtkWidget *
gimp_dockbook_create_tab_widget (GimpDockbook *dockbook,
GimpDockable *dockable)
{
GtkWidget *tab_widget;
GimpDockWindow *dock_window;
GimpAction *action = NULL;
GtkIconSize tab_size = DEFAULT_TAB_ICON_SIZE;
gtk_widget_style_get (GTK_WIDGET (dockbook),
"tab-icon-size", &tab_size,
NULL);
tab_widget =
gimp_dockable_create_tab_widget (dockable,
gimp_dock_get_context (dockbook->p->dock),
gimp_dockable_get_tab_style (dockable),
tab_size);
if (GIMP_IS_VIEW (tab_widget))
{
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;
}
/* EEK */
dock_window = gimp_dock_window_from_dock (dockbook->p->dock);
if (dock_window &&
gimp_dock_container_get_ui_manager (GIMP_DOCK_CONTAINER (dock_window)))
{
const gchar *dialog_id;
dialog_id = g_object_get_data (G_OBJECT (dockable),
"gimp-dialog-identifier");
if (dialog_id)
{
GimpDockContainer *dock_container;
GimpActionGroup *group;
dock_container = GIMP_DOCK_CONTAINER (dock_window);
group = gimp_ui_manager_get_action_group
(gimp_dock_container_get_ui_manager (dock_container), "dialogs");
if (group)
{
GList *actions;
GList *list;
actions = gimp_action_group_list_actions (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
gimp_help_set_help_data (tab_widget,
gimp_dockable_get_blurb (dockable),
gimp_dockable_get_help_id (dockable));
return tab_widget;
}
/**
* 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;
}
void
gimp_dockbook_add_drag_callback (GimpDockbookDragCallback callback,
gpointer data)
{
GimpDockbookDragCallbackData *callback_data;
callback_data = g_slice_new (GimpDockbookDragCallbackData);
callback_data->callback = callback;
callback_data->data = data;
drag_callbacks = g_list_prepend (drag_callbacks, callback_data);
}
void
gimp_dockbook_remove_drag_callback (GimpDockbookDragCallback callback,
gpointer data)
{
GList *iter;
iter = drag_callbacks;
while (iter)
{
GimpDockbookDragCallbackData *callback_data = iter->data;
GList *next = g_list_next (iter);
if (callback_data->callback == callback &&
callback_data->data == data)
{
g_slice_free (GimpDockbookDragCallbackData, callback_data);
drag_callbacks = g_list_delete_link (drag_callbacks, iter);
}
iter = next;
}
}
/* private functions */
static void
gimp_dockbook_tab_locked_notify (GimpDockable *dockable,
GParamSpec *pspec,
GimpDockbook *dockbook)
{
gboolean locked = gimp_dockable_get_locked (dockable);
gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (dockbook),
GTK_WIDGET (dockable), ! locked);
gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (dockbook),
GTK_WIDGET (dockable), ! locked);
}
static void
gimp_dockbook_help_func (const gchar *help_id,
gpointer help_data)
{
GimpDockbook *dockbook = GIMP_DOCKBOOK (help_data);
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))
gimp_standard_help_func (gimp_dockable_get_help_id (GIMP_DOCKABLE (dockable)),
NULL);
else
gimp_standard_help_func (GIMP_HELP_DOCK, NULL);
}