1
/* The GIMP -- an image manipulation program
2
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
5
* Copyright (C) 2001-2003 Michael Natterer <mitch@gimp.org>
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
#include "libgimpwidgets/gimpwidgets.h"
28
#include "widgets-types.h"
30
#include "config/gimpguiconfig.h"
32
#include "core/gimp.h"
33
#include "core/gimpcontext.h"
34
#include "core/gimpmarshal.h"
36
#include "gimpdialogfactory.h"
39
#include "gimpdockable.h"
40
#include "gimpdockbook.h"
41
#include "gimphelp-ids.h"
42
#include "gimpmessagebox.h"
43
#include "gimpmessagedialog.h"
44
#include "gimpwidgets-utils.h"
46
#include "gimp-intl.h"
49
#define DEFAULT_DOCK_HEIGHT 300
50
#define DEFAULT_SEPARATOR_HEIGHT 6
67
static void gimp_dock_class_init (GimpDockClass *klass);
68
static void gimp_dock_init (GimpDock *dock);
70
static GObject * gimp_dock_constructor (GType type,
72
GObjectConstructParam *params);
73
static void gimp_dock_set_property (GObject *object,
77
static void gimp_dock_get_property (GObject *object,
82
static void gimp_dock_destroy (GtkObject *object);
84
static gboolean gimp_dock_delete_event (GtkWidget *widget,
86
static gboolean gimp_dock_key_press_event (GtkWidget *widget,
89
static void gimp_dock_style_set (GtkWidget *widget,
90
GtkStyle *prev_style);
92
static void gimp_dock_real_book_added (GimpDock *dock,
93
GimpDockbook *dockbook);
94
static void gimp_dock_real_book_removed (GimpDock *dock,
95
GimpDockbook *dockbook);
97
static GtkWidget * gimp_dock_separator_new (GimpDock *dock);
98
static void gimp_dock_separator_drag_leave (GtkWidget *widget,
99
GdkDragContext *context,
102
static gboolean gimp_dock_separator_drag_motion (GtkWidget *widget,
103
GdkDragContext *context,
108
static gboolean gimp_dock_separator_drag_drop (GtkWidget *widget,
109
GdkDragContext *context,
116
static GtkWindowClass *parent_class = NULL;
117
static guint dock_signals[LAST_SIGNAL] = { 0 };
118
static GtkTargetEntry dialog_target_table[] =
125
gimp_dock_get_type (void)
127
static GType dock_type = 0;
131
static const GTypeInfo dock_info =
133
sizeof (GimpDockClass),
134
NULL, /* base_init */
135
NULL, /* base_finalize */
136
(GClassInitFunc) gimp_dock_class_init,
137
NULL, /* class_finalize */
138
NULL, /* class_data */
141
(GInstanceInitFunc) gimp_dock_init,
144
dock_type = g_type_register_static (GTK_TYPE_WINDOW,
153
gimp_dock_class_init (GimpDockClass *klass)
155
GObjectClass *object_class;
156
GtkObjectClass *gtk_object_class;
157
GtkWidgetClass *widget_class;
159
object_class = G_OBJECT_CLASS (klass);
160
gtk_object_class = GTK_OBJECT_CLASS (klass);
161
widget_class = GTK_WIDGET_CLASS (klass);
163
parent_class = g_type_class_peek_parent (klass);
165
dock_signals[BOOK_ADDED] =
166
g_signal_new ("book_added",
167
G_TYPE_FROM_CLASS (klass),
169
G_STRUCT_OFFSET (GimpDockClass, book_added),
171
gimp_marshal_VOID__OBJECT,
175
dock_signals[BOOK_REMOVED] =
176
g_signal_new ("book_removed",
177
G_TYPE_FROM_CLASS (klass),
179
G_STRUCT_OFFSET (GimpDockClass, book_removed),
181
gimp_marshal_VOID__OBJECT,
185
object_class->constructor = gimp_dock_constructor;
186
object_class->set_property = gimp_dock_set_property;
187
object_class->get_property = gimp_dock_get_property;
189
gtk_object_class->destroy = gimp_dock_destroy;
191
widget_class->delete_event = gimp_dock_delete_event;
192
widget_class->key_press_event = gimp_dock_key_press_event;
193
widget_class->style_set = gimp_dock_style_set;
196
klass->book_added = gimp_dock_real_book_added;
197
klass->book_removed = gimp_dock_real_book_removed;
199
g_object_class_install_property (object_class, PROP_CONTEXT,
200
g_param_spec_object ("context", NULL, NULL,
203
G_PARAM_CONSTRUCT_ONLY));
204
g_object_class_install_property (object_class, PROP_DIALOG_FACTORY,
205
g_param_spec_object ("dialog-factory", NULL, NULL,
206
GIMP_TYPE_DIALOG_FACTORY,
208
G_PARAM_CONSTRUCT_ONLY));
210
gtk_widget_class_install_style_property (widget_class,
211
g_param_spec_int ("default_height",
217
gtk_widget_class_install_style_property (widget_class,
218
g_param_spec_int ("separator_height",
222
DEFAULT_SEPARATOR_HEIGHT,
227
gimp_dock_init (GimpDock *dock)
229
GtkWidget *separator;
231
dock->context = NULL;
233
gtk_window_set_role (GTK_WINDOW (dock), "gimp-dock");
234
gtk_window_set_resizable (GTK_WINDOW (dock), TRUE);
236
dock->main_vbox = gtk_vbox_new (FALSE, 0);
237
gtk_container_add (GTK_CONTAINER (dock), dock->main_vbox);
238
gtk_widget_show (dock->main_vbox);
240
dock->vbox = gtk_vbox_new (FALSE, 0);
241
gtk_container_add (GTK_CONTAINER (dock->main_vbox), dock->vbox);
242
gtk_widget_show (dock->vbox);
244
separator = gimp_dock_separator_new (dock);
245
gtk_box_pack_start (GTK_BOX (dock->vbox), separator, FALSE, FALSE, 0);
246
gtk_widget_show (separator);
250
gimp_dock_set_property (GObject *object,
255
GimpDock *dock = GIMP_DOCK (object);
260
dock->context = GIMP_CONTEXT (g_value_dup_object (value));
262
case PROP_DIALOG_FACTORY:
263
dock->dialog_factory = GIMP_DIALOG_FACTORY (g_value_get_object (value));
266
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
272
gimp_dock_get_property (GObject *object,
277
GimpDock *dock = GIMP_DOCK (object);
282
g_value_set_object (value, dock->context);
284
case PROP_DIALOG_FACTORY:
285
g_value_set_object (value, dock->dialog_factory);
288
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
294
gimp_dock_constructor (GType type,
296
GObjectConstructParam *params)
300
GimpGuiConfig *config;
302
object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params);
304
dock = GIMP_DOCK (object);
306
g_assert (GIMP_IS_CONTEXT (dock->context));
307
g_assert (GIMP_IS_DIALOG_FACTORY (dock->dialog_factory));
309
config = GIMP_GUI_CONFIG (dock->context->gimp->config);
311
gimp_window_set_hint (GTK_WINDOW (dock), config->dock_window_hint);
317
gimp_dock_destroy (GtkObject *object)
319
GimpDock *dock = GIMP_DOCK (object);
321
while (dock->dockbooks)
322
gimp_dock_remove_book (dock, GIMP_DOCKBOOK (dock->dockbooks->data));
326
g_object_unref (dock->context);
327
dock->context = NULL;
330
GTK_OBJECT_CLASS (parent_class)->destroy (object);
334
gimp_dock_delete_event (GtkWidget *widget,
337
GimpDock *dock = GIMP_DOCK (widget);
339
gboolean retval = FALSE;
342
for (list = dock->dockbooks, n = 0; list; list = list->next)
343
n += gtk_notebook_get_n_pages (GTK_NOTEBOOK (list->data));
348
gimp_message_dialog_new (_("Close all tabs?"),
350
widget, GTK_DIALOG_MODAL,
353
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
354
_("Close all Tabs"), GTK_RESPONSE_OK,
358
gimp_message_box_set_primary_text (GIMP_MESSAGE_DIALOG (dialog)->box,
359
_("Close all tabs?"));
360
gimp_message_box_set_text (GIMP_MESSAGE_DIALOG (dialog)->box,
361
_("This window has %d tabs open. Closing the "
362
"window will also close all its tabs."), n);
364
retval = (gimp_dialog_run (GIMP_DIALOG (dialog)) != GTK_RESPONSE_OK);
366
gtk_widget_destroy (dialog);
373
gimp_dock_key_press_event (GtkWidget *widget,
376
GtkWindow *window = GTK_WINDOW (widget);
377
gboolean handled = FALSE;
379
/* we're overriding the GtkWindow implementation here to give
380
* the focus widget precedence over unmodified accelerators
381
* before the accelerator activation scheme.
384
/* invoke control/alt accelerators */
385
if (! handled && event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))
386
handled = gtk_window_activate_key (window, event);
388
/* invoke focus widget handlers */
390
handled = gtk_window_propagate_key_event (window, event);
392
/* invoke non-(control/alt) accelerators */
393
if (! handled && ! (event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)))
394
handled = gtk_window_activate_key (window, event);
396
/* chain up, bypassing gtk_window_key_press(), to invoke binding set */
398
handled = GTK_WIDGET_CLASS (g_type_class_peek (g_type_parent (GTK_TYPE_WINDOW)))->key_press_event (widget, event);
404
gimp_dock_style_set (GtkWidget *widget,
405
GtkStyle *prev_style)
411
gint separator_height;
413
dock = GIMP_DOCK (widget);
415
if (GTK_WIDGET_CLASS (parent_class)->style_set)
416
GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
418
gtk_widget_style_get (widget,
419
"default_height", &default_height,
420
"separator_height", &separator_height,
423
gtk_window_set_default_size (GTK_WINDOW (widget), -1, default_height);
425
children = gtk_container_get_children (GTK_CONTAINER (dock->vbox));
427
for (list = children; list; list = g_list_next (list))
429
if (GTK_IS_EVENT_BOX (list->data))
430
gtk_widget_set_size_request (GTK_WIDGET (list->data),
431
-1, separator_height);
434
g_list_free (children);
438
gimp_dock_real_book_added (GimpDock *dock,
439
GimpDockbook *dockbook)
444
gimp_dock_real_book_removed (GimpDock *dock,
445
GimpDockbook *dockbook)
447
if (dock->dockbooks == NULL)
448
gtk_widget_destroy (GTK_WIDGET (dock));
452
gimp_dock_separator_new (GimpDock *dock)
454
GtkWidget *event_box;
456
gint separator_height;
458
event_box = gtk_event_box_new ();
460
gtk_widget_set_name (event_box, "gimp-dock-separator");
462
gtk_widget_style_get (GTK_WIDGET (dock),
463
"separator_height", &separator_height,
466
gtk_widget_set_size_request (event_box, -1, separator_height);
468
frame = gtk_frame_new (NULL);
469
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
470
gtk_container_add (GTK_CONTAINER (event_box), frame);
471
gtk_widget_show (frame);
473
gimp_help_set_help_data (event_box,
474
_("You can drop dockable dialogs here."),
475
GIMP_HELP_DOCK_SEPARATOR);
477
gtk_drag_dest_set (GTK_WIDGET (event_box),
478
GTK_DEST_DEFAULT_ALL,
479
dialog_target_table, G_N_ELEMENTS (dialog_target_table),
482
g_signal_connect (event_box, "drag_leave",
483
G_CALLBACK (gimp_dock_separator_drag_leave),
485
g_signal_connect (event_box, "drag_motion",
486
G_CALLBACK (gimp_dock_separator_drag_motion),
488
g_signal_connect (event_box, "drag_drop",
489
G_CALLBACK (gimp_dock_separator_drag_drop),
496
gimp_dock_setup (GimpDock *dock,
497
const GimpDock *template)
499
g_return_if_fail (GIMP_IS_DOCK (dock));
500
g_return_if_fail (GIMP_IS_DOCK (template));
502
if (GIMP_DOCK_GET_CLASS (dock)->setup)
503
GIMP_DOCK_GET_CLASS (dock)->setup (dock, template);
507
gimp_dock_set_aux_info (GimpDock *dock,
510
g_return_if_fail (GIMP_IS_DOCK (dock));
512
if (GIMP_DOCK_GET_CLASS (dock)->set_aux_info)
513
GIMP_DOCK_GET_CLASS (dock)->set_aux_info (dock, aux_info);
517
gimp_dock_get_aux_info (GimpDock *dock)
519
g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
521
if (GIMP_DOCK_GET_CLASS (dock)->get_aux_info)
522
return GIMP_DOCK_GET_CLASS (dock)->get_aux_info (dock);
528
gimp_dock_add (GimpDock *dock,
529
GimpDockable *dockable,
533
GimpDockbook *dockbook;
535
g_return_if_fail (GIMP_IS_DOCK (dock));
536
g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
537
g_return_if_fail (dockable->dockbook == NULL);
539
dockbook = GIMP_DOCKBOOK (dock->dockbooks->data);
541
gimp_dockbook_add (dockbook, dockable, position);
545
gimp_dock_remove (GimpDock *dock,
546
GimpDockable *dockable)
548
g_return_if_fail (GIMP_IS_DOCK (dock));
549
g_return_if_fail (GIMP_IS_DOCKABLE (dockable));
550
g_return_if_fail (dockable->dockbook != NULL);
551
g_return_if_fail (dockable->dockbook->dock == dock);
553
gimp_dockbook_remove (dockable->dockbook, dockable);
557
gimp_dock_add_book (GimpDock *dock,
558
GimpDockbook *dockbook,
563
g_return_if_fail (GIMP_IS_DOCK (dock));
564
g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
565
g_return_if_fail (dockbook->dock == NULL);
567
old_length = g_list_length (dock->dockbooks);
569
if (index >= old_length || index < 0)
572
dockbook->dock = dock;
573
dock->dockbooks = g_list_insert (dock->dockbooks, dockbook, index);
577
GtkWidget *separator;
579
gtk_box_pack_start (GTK_BOX (dock->vbox), GTK_WIDGET (dockbook),
582
separator = gimp_dock_separator_new (dock);
583
gtk_box_pack_end (GTK_BOX (dock->vbox), separator, FALSE, FALSE, 0);
584
gtk_widget_show (separator);
593
old_book = g_list_nth_data (dock->dockbooks, index + 1);
595
old_book = g_list_nth_data (dock->dockbooks, index - 1);
597
parent = old_book->parent;
599
if ((old_length > 1) && (index > 0))
601
GtkWidget *grandparent;
603
grandparent = parent->parent;
606
parent = grandparent;
609
g_object_ref (old_book);
611
gtk_container_remove (GTK_CONTAINER (parent), old_book);
613
paned = gtk_vpaned_new ();
615
if (GTK_IS_VPANED (parent))
616
gtk_paned_pack1 (GTK_PANED (parent), paned, TRUE, FALSE);
618
gtk_box_pack_start (GTK_BOX (parent), paned, TRUE, TRUE, 0);
620
gtk_widget_show (paned);
624
gtk_paned_pack1 (GTK_PANED (paned), GTK_WIDGET (dockbook),
626
gtk_paned_pack2 (GTK_PANED (paned), old_book,
631
gtk_paned_pack1 (GTK_PANED (paned), old_book,
633
gtk_paned_pack2 (GTK_PANED (paned), GTK_WIDGET (dockbook),
637
g_object_unref (old_book);
640
gtk_widget_show (GTK_WIDGET (dockbook));
642
g_signal_emit (dock, dock_signals[BOOK_ADDED], 0, dockbook);
646
gimp_dock_remove_book (GimpDock *dock,
647
GimpDockbook *dockbook)
652
g_return_if_fail (GIMP_IS_DOCK (dock));
653
g_return_if_fail (GIMP_IS_DOCKBOOK (dockbook));
655
g_return_if_fail (dockbook->dock == dock);
657
old_length = g_list_length (dock->dockbooks);
658
index = g_list_index (dock->dockbooks, dockbook);
660
dockbook->dock = NULL;
661
dock->dockbooks = g_list_remove (dock->dockbooks, dockbook);
663
g_object_ref (dockbook);
667
GtkWidget *separator;
670
children = gtk_container_get_children (GTK_CONTAINER (dock->vbox));
672
separator = g_list_nth_data (children, 2);
674
gtk_container_remove (GTK_CONTAINER (dock->vbox), separator);
675
gtk_container_remove (GTK_CONTAINER (dock->vbox), GTK_WIDGET (dockbook));
677
g_list_free (children);
681
GtkWidget *other_book;
683
GtkWidget *grandparent;
685
parent = GTK_WIDGET (dockbook)->parent;
686
grandparent = parent->parent;
689
other_book = GTK_PANED (parent)->child2;
691
other_book = GTK_PANED (parent)->child1;
693
g_object_ref (other_book);
695
gtk_container_remove (GTK_CONTAINER (parent), other_book);
696
gtk_container_remove (GTK_CONTAINER (parent), GTK_WIDGET (dockbook));
698
gtk_container_remove (GTK_CONTAINER (grandparent), parent);
700
if (GTK_IS_VPANED (grandparent))
701
gtk_paned_pack1 (GTK_PANED (grandparent), other_book, TRUE, FALSE);
703
gtk_box_pack_start (GTK_BOX (dock->vbox), other_book, TRUE, TRUE, 0);
705
g_object_unref (other_book);
708
g_signal_emit (dock, dock_signals[BOOK_REMOVED], 0, dockbook);
710
g_object_unref (dockbook);
714
gimp_dock_separator_drag_leave (GtkWidget *widget,
715
GdkDragContext *context,
719
gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, NULL);
723
gimp_dock_separator_drag_motion (GtkWidget *widget,
724
GdkDragContext *context,
730
GdkColor *color = gtk_widget_get_style (widget)->bg + GTK_STATE_SELECTED;
732
gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, color);
738
gimp_dock_separator_drag_drop (GtkWidget *widget,
739
GdkDragContext *context,
745
GtkWidget *source = gtk_drag_get_source_widget (context);
749
GimpDockable *dockable;
751
if (GIMP_IS_DOCKABLE (source))
752
dockable = GIMP_DOCKABLE (source);
754
dockable = (GimpDockable *) g_object_get_data (G_OBJECT (source),
763
g_object_set_data (G_OBJECT (dockable),
764
"gimp-dock-drag-widget", NULL);
766
children = gtk_container_get_children (GTK_CONTAINER (widget->parent));
767
index = g_list_index (children, widget);
768
g_list_free (children);
775
/* if dropping to the same dock, take care that we don't try
776
* to reorder the *only* dockable in the dock
778
if (dockable->dockbook->dock == dock)
783
n_books = g_list_length (dock->dockbooks);
786
gtk_container_get_children (GTK_CONTAINER (dockable->dockbook));
787
n_dockables = g_list_length (children);
788
g_list_free (children);
790
if (n_books == 1 && n_dockables == 1)
791
return TRUE; /* successfully do nothing */
794
g_object_ref (dockable);
796
gimp_dockbook_remove (dockable->dockbook, dockable);
798
dockbook = gimp_dockbook_new (dock->dialog_factory->menu_factory);
799
gimp_dock_add_book (dock, GIMP_DOCKBOOK (dockbook), index);
801
gimp_dockbook_add (GIMP_DOCKBOOK (dockbook), dockable, -1);
803
g_object_unref (dockable);