1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpdialogfactory.c
5 * Copyright (C) 2001-2008 Michael Natterer <mitch@gimp.org>
6 *
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 3 of the License, or
10 * (at your option) any later version.
11 *
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.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <gegl.h>
27 #include <gtk/gtk.h>
28
29 #include "libgimpconfig/gimpconfig.h"
30 #include "libgimpwidgets/gimpwidgets.h"
31
32 #include "widgets-types.h"
33
34 #include "config/gimpguiconfig.h"
35
36 #include "core/gimp.h"
37 #include "core/gimpcontext.h"
38 #include "core/gimpmarshal.h"
39
40 #include "gimpcursor.h"
41 #include "gimpdialogfactory.h"
42 #include "gimpdock.h"
43 #include "gimpdockbook.h"
44 #include "gimpdockable.h"
45 #include "gimpdockcontainer.h"
46 #include "gimpdockwindow.h"
47 #include "gimpmenufactory.h"
48 #include "gimpsessioninfo.h"
49 #include "gimpwidgets-utils.h"
50
51 #include "gimp-log.h"
52
53
54 enum
55 {
56 DOCK_WINDOW_ADDED,
57 DOCK_WINDOW_REMOVED,
58 LAST_SIGNAL
59 };
60
61
62 struct _GimpDialogFactoryPrivate
63 {
64 GimpContext *context;
65 GimpMenuFactory *menu_factory;
66
67 GList *open_dialogs;
68 GList *session_infos;
69
70 GList *registered_dialogs;
71
72 GimpDialogsState dialog_state;
73 };
74
75
76 static void gimp_dialog_factory_dispose (GObject *object);
77 static void gimp_dialog_factory_finalize (GObject *object);
78 static GtkWidget * gimp_dialog_factory_constructor (GimpDialogFactory *factory,
79 GimpDialogFactoryEntry *entry,
80 GimpContext *context,
81 GimpUIManager *ui_manager,
82 gint view_size);
83 static void gimp_dialog_factory_config_notify (GimpDialogFactory *factory,
84 GParamSpec *pspec,
85 GimpGuiConfig *config);
86 static void gimp_dialog_factory_set_widget_data (GtkWidget *dialog,
87 GimpDialogFactory *factory,
88 GimpDialogFactoryEntry *entry);
89 static void gimp_dialog_factory_unset_widget_data (GtkWidget *dialog);
90 static gboolean gimp_dialog_factory_set_user_pos (GtkWidget *dialog,
91 GdkEventConfigure *cevent,
92 gpointer data);
93 static gboolean gimp_dialog_factory_dialog_configure (GtkWidget *dialog,
94 GdkEventConfigure *cevent,
95 GimpDialogFactory *factory);
96 static void gimp_dialog_factory_hide (GimpDialogFactory *factory);
97 static void gimp_dialog_factory_show (GimpDialogFactory *factory);
98
99
100 G_DEFINE_TYPE_WITH_PRIVATE (GimpDialogFactory, gimp_dialog_factory,
101 GIMP_TYPE_OBJECT)
102
103 #define parent_class gimp_dialog_factory_parent_class
104
105 static guint factory_signals[LAST_SIGNAL] = { 0 };
106
107
108 /* Is set by dialogs.c to a dialog factory initialized there.
109 *
110 * FIXME: The layer above should not do this kind of initialization of
111 * layers below.
112 */
113 static GimpDialogFactory *gimp_toplevel_factory = NULL;
114
115
116 static void
gimp_dialog_factory_class_init(GimpDialogFactoryClass * klass)117 gimp_dialog_factory_class_init (GimpDialogFactoryClass *klass)
118 {
119 GObjectClass *object_class = G_OBJECT_CLASS (klass);
120
121 object_class->dispose = gimp_dialog_factory_dispose;
122 object_class->finalize = gimp_dialog_factory_finalize;
123
124 factory_signals[DOCK_WINDOW_ADDED] =
125 g_signal_new ("dock-window-added",
126 G_TYPE_FROM_CLASS (klass),
127 G_SIGNAL_RUN_LAST,
128 G_STRUCT_OFFSET (GimpDialogFactoryClass, dock_window_added),
129 NULL, NULL,
130 gimp_marshal_VOID__OBJECT,
131 G_TYPE_NONE, 1,
132 GIMP_TYPE_DOCK_WINDOW);
133
134 factory_signals[DOCK_WINDOW_REMOVED] =
135 g_signal_new ("dock-window-removed",
136 G_TYPE_FROM_CLASS (klass),
137 G_SIGNAL_RUN_LAST,
138 G_STRUCT_OFFSET (GimpDialogFactoryClass, dock_window_removed),
139 NULL, NULL,
140 gimp_marshal_VOID__OBJECT,
141 G_TYPE_NONE, 1,
142 GIMP_TYPE_DOCK_WINDOW);
143 }
144
145 static void
gimp_dialog_factory_init(GimpDialogFactory * factory)146 gimp_dialog_factory_init (GimpDialogFactory *factory)
147 {
148 factory->p = gimp_dialog_factory_get_instance_private (factory);
149 factory->p->dialog_state = GIMP_DIALOGS_SHOWN;
150 }
151
152 static void
gimp_dialog_factory_dispose(GObject * object)153 gimp_dialog_factory_dispose (GObject *object)
154 {
155 GimpDialogFactory *factory = GIMP_DIALOG_FACTORY (object);
156 GList *list;
157
158 /* start iterating from the beginning each time we destroyed a
159 * toplevel because destroying a dock may cause lots of items
160 * to be removed from factory->p->open_dialogs
161 */
162 while (factory->p->open_dialogs)
163 {
164 for (list = factory->p->open_dialogs; list; list = g_list_next (list))
165 {
166 if (gtk_widget_is_toplevel (list->data))
167 {
168 gtk_widget_destroy (GTK_WIDGET (list->data));
169 break;
170 }
171 }
172
173 /* the list being non-empty without any toplevel is an error,
174 * so eek and chain up
175 */
176 if (! list)
177 {
178 g_warning ("%s: %d stale non-toplevel entries in factory->p->open_dialogs",
179 G_STRFUNC, g_list_length (factory->p->open_dialogs));
180 break;
181 }
182 }
183
184 if (factory->p->open_dialogs)
185 {
186 g_list_free (factory->p->open_dialogs);
187 factory->p->open_dialogs = NULL;
188 }
189
190 if (factory->p->session_infos)
191 {
192 g_list_free_full (factory->p->session_infos,
193 (GDestroyNotify) g_object_unref);
194 factory->p->session_infos = NULL;
195 }
196
197 G_OBJECT_CLASS (parent_class)->dispose (object);
198 }
199
200 static void
gimp_dialog_factory_finalize(GObject * object)201 gimp_dialog_factory_finalize (GObject *object)
202 {
203 GimpDialogFactory *factory = GIMP_DIALOG_FACTORY (object);
204 GList *list;
205
206 for (list = factory->p->registered_dialogs; list; list = g_list_next (list))
207 {
208 GimpDialogFactoryEntry *entry = list->data;
209
210 g_free (entry->identifier);
211 g_free (entry->name);
212 g_free (entry->blurb);
213 g_free (entry->icon_name);
214 g_free (entry->help_id);
215
216 g_slice_free (GimpDialogFactoryEntry, entry);
217 }
218
219 if (factory->p->registered_dialogs)
220 {
221 g_list_free (factory->p->registered_dialogs);
222 factory->p->registered_dialogs = NULL;
223 }
224
225 G_OBJECT_CLASS (parent_class)->finalize (object);
226 }
227
228 GimpDialogFactory *
gimp_dialog_factory_new(const gchar * name,GimpContext * context,GimpMenuFactory * menu_factory)229 gimp_dialog_factory_new (const gchar *name,
230 GimpContext *context,
231 GimpMenuFactory *menu_factory)
232 {
233 GimpDialogFactory *factory;
234 GimpGuiConfig *config;
235
236 g_return_val_if_fail (name != NULL, NULL);
237 g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL);
238 g_return_val_if_fail (! menu_factory || GIMP_IS_MENU_FACTORY (menu_factory),
239 NULL);
240
241 factory = g_object_new (GIMP_TYPE_DIALOG_FACTORY, NULL);
242
243 gimp_object_set_name (GIMP_OBJECT (factory), name);
244
245 config = GIMP_GUI_CONFIG (context->gimp->config);
246
247 factory->p->context = context;
248 factory->p->menu_factory = menu_factory;
249 factory->p->dialog_state = (config->hide_docks ?
250 GIMP_DIALOGS_HIDDEN_EXPLICITLY :
251 GIMP_DIALOGS_SHOWN);
252
253 g_signal_connect_object (config, "notify::hide-docks",
254 G_CALLBACK (gimp_dialog_factory_config_notify),
255 factory, G_CONNECT_SWAPPED);
256
257 return factory;
258 }
259
260 void
gimp_dialog_factory_register_entry(GimpDialogFactory * factory,const gchar * identifier,const gchar * name,const gchar * blurb,const gchar * icon_name,const gchar * help_id,GimpDialogNewFunc new_func,GimpDialogRestoreFunc restore_func,gint view_size,gboolean singleton,gboolean session_managed,gboolean remember_size,gboolean remember_if_open,gboolean hideable,gboolean image_window,gboolean dockable)261 gimp_dialog_factory_register_entry (GimpDialogFactory *factory,
262 const gchar *identifier,
263 const gchar *name,
264 const gchar *blurb,
265 const gchar *icon_name,
266 const gchar *help_id,
267 GimpDialogNewFunc new_func,
268 GimpDialogRestoreFunc restore_func,
269 gint view_size,
270 gboolean singleton,
271 gboolean session_managed,
272 gboolean remember_size,
273 gboolean remember_if_open,
274 gboolean hideable,
275 gboolean image_window,
276 gboolean dockable)
277 {
278 GimpDialogFactoryEntry *entry;
279
280 g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory));
281 g_return_if_fail (identifier != NULL);
282
283 entry = g_slice_new0 (GimpDialogFactoryEntry);
284
285 entry->identifier = g_strdup (identifier);
286 entry->name = g_strdup (name);
287 entry->blurb = g_strdup (blurb);
288 entry->icon_name = g_strdup (icon_name);
289 entry->help_id = g_strdup (help_id);
290 entry->new_func = new_func;
291 entry->restore_func = restore_func;
292 entry->view_size = view_size;
293 entry->singleton = singleton ? TRUE : FALSE;
294 entry->session_managed = session_managed ? TRUE : FALSE;
295 entry->remember_size = remember_size ? TRUE : FALSE;
296 entry->remember_if_open = remember_if_open ? TRUE : FALSE;
297 entry->hideable = hideable ? TRUE : FALSE;
298 entry->image_window = image_window ? TRUE : FALSE;
299 entry->dockable = dockable ? TRUE : FALSE;
300
301 factory->p->registered_dialogs = g_list_prepend (factory->p->registered_dialogs,
302 entry);
303 }
304
305 GimpDialogFactoryEntry *
gimp_dialog_factory_find_entry(GimpDialogFactory * factory,const gchar * identifier)306 gimp_dialog_factory_find_entry (GimpDialogFactory *factory,
307 const gchar *identifier)
308 {
309 GList *list;
310
311 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
312 g_return_val_if_fail (identifier != NULL, NULL);
313
314 for (list = factory->p->registered_dialogs; list; list = g_list_next (list))
315 {
316 GimpDialogFactoryEntry *entry = list->data;
317
318 if (! strcmp (identifier, entry->identifier))
319 return entry;
320 }
321
322 return NULL;
323 }
324
325 GimpSessionInfo *
gimp_dialog_factory_find_session_info(GimpDialogFactory * factory,const gchar * identifier)326 gimp_dialog_factory_find_session_info (GimpDialogFactory *factory,
327 const gchar *identifier)
328 {
329 GList *list;
330
331 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
332 g_return_val_if_fail (identifier != NULL, NULL);
333
334 for (list = factory->p->session_infos; list; list = g_list_next (list))
335 {
336 GimpSessionInfo *info = list->data;
337
338 if (gimp_session_info_get_factory_entry (info) &&
339 g_str_equal (identifier,
340 gimp_session_info_get_factory_entry (info)->identifier))
341 {
342 return info;
343 }
344 }
345
346 return NULL;
347 }
348
349 GtkWidget *
gimp_dialog_factory_find_widget(GimpDialogFactory * factory,const gchar * identifiers)350 gimp_dialog_factory_find_widget (GimpDialogFactory *factory,
351 const gchar *identifiers)
352 {
353 GtkWidget *widget = NULL;
354 gchar **ids;
355 gint i;
356
357 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
358 g_return_val_if_fail (identifiers != NULL, NULL);
359
360 ids = g_strsplit (identifiers, "|", 0);
361
362 for (i = 0; ids[i]; i++)
363 {
364 GimpSessionInfo *info;
365
366 info = gimp_dialog_factory_find_session_info (factory, ids[i]);
367
368 if (info)
369 {
370 widget = gimp_session_info_get_widget (info);
371
372 if (widget)
373 break;
374 }
375 }
376
377 g_strfreev (ids);
378
379 return widget;
380 }
381
382 /**
383 * gimp_dialog_factory_dialog_sane:
384 * @factory:
385 * @widget_factory:
386 * @widget_entry:
387 * @widget:
388 *
389 * Makes sure that the @widget with the given @widget_entry that was
390 * created by the given @widget_factory belongs to @efactory.
391 *
392 * Returns: %TRUE if that is the case, %FALSE otherwise.
393 **/
394 static gboolean
gimp_dialog_factory_dialog_sane(GimpDialogFactory * factory,GimpDialogFactory * widget_factory,GimpDialogFactoryEntry * widget_entry,GtkWidget * widget)395 gimp_dialog_factory_dialog_sane (GimpDialogFactory *factory,
396 GimpDialogFactory *widget_factory,
397 GimpDialogFactoryEntry *widget_entry,
398 GtkWidget *widget)
399 {
400 if (! widget_factory || ! widget_entry)
401 {
402 g_warning ("%s: dialog was not created by a GimpDialogFactory",
403 G_STRFUNC);
404 return FALSE;
405 }
406
407 if (widget_factory != factory)
408 {
409 g_warning ("%s: dialog was created by a different GimpDialogFactory",
410 G_STRFUNC);
411 return FALSE;
412 }
413
414 return TRUE;
415 }
416
417 /**
418 * gimp_dialog_factory_dialog_new_internal:
419 * @factory:
420 * @screen:
421 * @context:
422 * @ui_manager:
423 * @identifier:
424 * @view_size:
425 * @return_existing: If %TRUE, (or if the dialog is a singleton),
426 * don't create a new dialog if it exists, instead
427 * return the existing one
428 * @present: If %TRUE, the toplevel that contains the dialog (if any)
429 * will be gtk_window_present():ed
430 * @create_containers: If %TRUE, then containers for the
431 * dialog/dockable will be created as well. If you
432 * want to manage your own containers, pass %FALSE
433 *
434 * This is the lowest level dialog factory creation function.
435 *
436 * Returns: A created or existing #GtkWidget.
437 **/
438 static GtkWidget *
gimp_dialog_factory_dialog_new_internal(GimpDialogFactory * factory,GdkScreen * screen,gint monitor,GimpContext * context,GimpUIManager * ui_manager,const gchar * identifier,gint view_size,gboolean return_existing,gboolean present,gboolean create_containers)439 gimp_dialog_factory_dialog_new_internal (GimpDialogFactory *factory,
440 GdkScreen *screen,
441 gint monitor,
442 GimpContext *context,
443 GimpUIManager *ui_manager,
444 const gchar *identifier,
445 gint view_size,
446 gboolean return_existing,
447 gboolean present,
448 gboolean create_containers)
449 {
450 GimpDialogFactoryEntry *entry = NULL;
451 GtkWidget *dialog = NULL;
452 GtkWidget *toplevel = NULL;
453
454 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
455 g_return_val_if_fail (identifier != NULL, NULL);
456
457 entry = gimp_dialog_factory_find_entry (factory, identifier);
458
459 if (! entry)
460 {
461 g_warning ("%s: no entry registered for \"%s\"",
462 G_STRFUNC, identifier);
463 return NULL;
464 }
465
466 if (! entry->new_func)
467 {
468 g_warning ("%s: entry for \"%s\" has no constructor",
469 G_STRFUNC, identifier);
470 return NULL;
471 }
472
473 /* a singleton dialog is always returned if it already exists */
474 if (return_existing || entry->singleton)
475 {
476 dialog = gimp_dialog_factory_find_widget (factory, identifier);
477 }
478
479 /* create the dialog if it was not found */
480 if (! dialog)
481 {
482 GtkWidget *dock = NULL;
483 GtkWidget *dock_window = NULL;
484
485 /* What follows is special-case code for some entries. At some
486 * point we might want to abstract this block of code away.
487 */
488 if (create_containers)
489 {
490 if (entry->dockable)
491 {
492 GtkWidget *dockbook;
493
494 /* It doesn't make sense to have a dockable without a dock
495 * so create one. Create a new dock _before_ creating the
496 * dialog. We do this because the new dockable needs to be
497 * created in its dock's context.
498 */
499 dock = gimp_dock_with_window_new (factory,
500 screen,
501 monitor,
502 FALSE /*toolbox*/);
503 dockbook = gimp_dockbook_new (factory->p->menu_factory);
504
505 gimp_dock_add_book (GIMP_DOCK (dock),
506 GIMP_DOCKBOOK (dockbook),
507 0);
508 }
509 else if (strcmp ("gimp-toolbox", entry->identifier) == 0)
510 {
511 GimpDockContainer *dock_container;
512
513 dock_window = gimp_dialog_factory_dialog_new (factory,
514 screen,
515 monitor,
516 NULL /*ui_manager*/,
517 "gimp-toolbox-window",
518 -1 /*view_size*/,
519 FALSE /*present*/);
520
521 /* When we get a dock window, we also get a UI
522 * manager
523 */
524 dock_container = GIMP_DOCK_CONTAINER (dock_window);
525 ui_manager = gimp_dock_container_get_ui_manager (dock_container);
526 }
527 }
528
529 /* Create the new dialog in the appropriate context which is
530 * - the passed context if not NULL
531 * - the newly created dock's context if we just created it
532 * - the factory's context, which happens when raising a toplevel
533 * dialog was the original request.
534 */
535 if (view_size < GIMP_VIEW_SIZE_TINY)
536 view_size = entry->view_size;
537
538 if (context)
539 dialog = gimp_dialog_factory_constructor (factory, entry,
540 context,
541 ui_manager,
542 view_size);
543 else if (dock)
544 dialog = gimp_dialog_factory_constructor (factory, entry,
545 gimp_dock_get_context (GIMP_DOCK (dock)),
546 gimp_dock_get_ui_manager (GIMP_DOCK (dock)),
547 view_size);
548 else
549 dialog = gimp_dialog_factory_constructor (factory, entry,
550 factory->p->context,
551 ui_manager,
552 view_size);
553
554 if (dialog)
555 {
556 gimp_dialog_factory_set_widget_data (dialog, factory, entry);
557
558 /* If we created a dock before, the newly created dialog is
559 * supposed to be a GimpDockable.
560 */
561 if (dock)
562 {
563 if (GIMP_IS_DOCKABLE (dialog))
564 {
565 gimp_dock_add (GIMP_DOCK (dock), GIMP_DOCKABLE (dialog),
566 0, 0);
567
568 gtk_widget_show (dock);
569 }
570 else
571 {
572 g_warning ("%s: GimpDialogFactory is a dockable factory "
573 "but constructor for \"%s\" did not return a "
574 "GimpDockable",
575 G_STRFUNC, identifier);
576
577 gtk_widget_destroy (dialog);
578 gtk_widget_destroy (dock);
579
580 dialog = NULL;
581 dock = NULL;
582 }
583 }
584 else if (dock_window)
585 {
586 if (GIMP_IS_DOCK (dialog))
587 {
588 gimp_dock_window_add_dock (GIMP_DOCK_WINDOW (dock_window),
589 GIMP_DOCK (dialog),
590 -1 /*index*/);
591
592 gtk_widget_set_visible (dialog, present);
593 gtk_widget_set_visible (dock_window, present);
594 }
595 else
596 {
597 g_warning ("%s: GimpDialogFactory is a dock factory entry "
598 "but constructor for \"%s\" did not return a "
599 "GimpDock",
600 G_STRFUNC, identifier);
601
602 gtk_widget_destroy (dialog);
603 gtk_widget_destroy (dock_window);
604
605 dialog = NULL;
606 dock_window = NULL;
607 }
608 }
609 }
610 else if (dock)
611 {
612 g_warning ("%s: constructor for \"%s\" returned NULL",
613 G_STRFUNC, identifier);
614
615 gtk_widget_destroy (dock);
616
617 dock = NULL;
618 }
619
620 if (dialog)
621 gimp_dialog_factory_add_dialog (factory, dialog, screen, monitor);
622 }
623
624 /* Finally, if we found an existing dialog or created a new one, raise it.
625 */
626 if (! dialog)
627 return NULL;
628
629 if (gtk_widget_is_toplevel (dialog))
630 {
631 gtk_window_set_screen (GTK_WINDOW (dialog), screen);
632
633 toplevel = dialog;
634 }
635 else if (GIMP_IS_DOCK (dialog))
636 {
637 toplevel = gtk_widget_get_toplevel (dialog);
638 }
639 else if (GIMP_IS_DOCKABLE (dialog))
640 {
641 GimpDockable *dockable = GIMP_DOCKABLE (dialog);
642
643 if (gimp_dockable_get_dockbook (dockable) &&
644 gimp_dockbook_get_dock (gimp_dockable_get_dockbook (dockable)))
645 {
646 GtkNotebook *notebook = GTK_NOTEBOOK (gimp_dockable_get_dockbook (dockable));
647 gint num = gtk_notebook_page_num (notebook, dialog);
648
649 if (num != -1)
650 {
651 gtk_notebook_set_current_page (notebook, num);
652
653 gimp_widget_blink (dialog);
654 }
655 }
656
657 toplevel = gtk_widget_get_toplevel (dialog);
658 }
659
660 if (present && GTK_IS_WINDOW (toplevel))
661 {
662 /* Work around focus-stealing protection, or whatever makes the
663 * dock appear below the one where we clicked a button to open
664 * it. See bug #630173.
665 */
666 gtk_widget_show_now (toplevel);
667 gdk_window_raise (gtk_widget_get_window (toplevel));
668 }
669
670 return dialog;
671 }
672
673 /**
674 * gimp_dialog_factory_dialog_new:
675 * @factory: a #GimpDialogFactory
676 * @screen: the #GdkScreen the dialog should appear on
677 * @ui_manager: A #GimpUIManager, if applicable.
678 * @identifier: the identifier of the dialog as registered with
679 * gimp_dialog_factory_register_entry()
680 * @view_size: the initial preview size
681 * @present: whether gtk_window_present() should be called
682 *
683 * Creates a new toplevel dialog or a #GimpDockable, depending on whether
684 * %factory is a toplevel of dockable factory.
685 *
686 * Return value: the newly created dialog or an already existing singleton
687 * dialog.
688 **/
689 GtkWidget *
gimp_dialog_factory_dialog_new(GimpDialogFactory * factory,GdkScreen * screen,gint monitor,GimpUIManager * ui_manager,const gchar * identifier,gint view_size,gboolean present)690 gimp_dialog_factory_dialog_new (GimpDialogFactory *factory,
691 GdkScreen *screen,
692 gint monitor,
693 GimpUIManager *ui_manager,
694 const gchar *identifier,
695 gint view_size,
696 gboolean present)
697 {
698 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
699 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
700 g_return_val_if_fail (identifier != NULL, NULL);
701
702 return gimp_dialog_factory_dialog_new_internal (factory,
703 screen,
704 monitor,
705 factory->p->context,
706 ui_manager,
707 identifier,
708 view_size,
709 FALSE /*return_existing*/,
710 present,
711 FALSE /*create_containers*/);
712 }
713
714 GimpContext *
gimp_dialog_factory_get_context(GimpDialogFactory * factory)715 gimp_dialog_factory_get_context (GimpDialogFactory *factory)
716 {
717 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
718
719 return factory->p->context;
720 }
721
722 GimpMenuFactory *
gimp_dialog_factory_get_menu_factory(GimpDialogFactory * factory)723 gimp_dialog_factory_get_menu_factory (GimpDialogFactory *factory)
724 {
725 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
726
727 return factory->p->menu_factory;
728 }
729
730 GList *
gimp_dialog_factory_get_open_dialogs(GimpDialogFactory * factory)731 gimp_dialog_factory_get_open_dialogs (GimpDialogFactory *factory)
732 {
733 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
734
735 return factory->p->open_dialogs;
736 }
737
738 GList *
gimp_dialog_factory_get_session_infos(GimpDialogFactory * factory)739 gimp_dialog_factory_get_session_infos (GimpDialogFactory *factory)
740 {
741 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
742
743 return factory->p->session_infos;
744 }
745
746 void
gimp_dialog_factory_add_session_info(GimpDialogFactory * factory,GimpSessionInfo * info)747 gimp_dialog_factory_add_session_info (GimpDialogFactory *factory,
748 GimpSessionInfo *info)
749 {
750 g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory));
751 g_return_if_fail (GIMP_IS_SESSION_INFO (info));
752
753 /* We want to append rather than prepend so that the serialized
754 * order in sessionrc remains the same
755 */
756 factory->p->session_infos = g_list_append (factory->p->session_infos,
757 g_object_ref (info));
758 }
759
760 /**
761 * gimp_dialog_factory_dialog_raise:
762 * @factory: a #GimpDialogFactory
763 * @screen: the #GdkScreen the dialog should appear on
764 * @identifiers: a '|' separated list of identifiers of dialogs as
765 * registered with gimp_dialog_factory_register_entry()
766 * @view_size: the initial preview size if a dialog needs to be created
767 *
768 * Raises any of a list of already existing toplevel dialog or
769 * #GimpDockable if it was already created by this %facory.
770 *
771 * Implicitly creates the first dialog in the list if none of the dialogs
772 * were found.
773 *
774 * Return value: the raised or newly created dialog.
775 **/
776 GtkWidget *
gimp_dialog_factory_dialog_raise(GimpDialogFactory * factory,GdkScreen * screen,gint monitor,const gchar * identifiers,gint view_size)777 gimp_dialog_factory_dialog_raise (GimpDialogFactory *factory,
778 GdkScreen *screen,
779 gint monitor,
780 const gchar *identifiers,
781 gint view_size)
782 {
783 GtkWidget *dialog;
784 gchar **ids;
785 gint i;
786
787 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
788 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
789 g_return_val_if_fail (identifiers != NULL, NULL);
790
791 /* If the identifier is a list, try to find a matching dialog and
792 * raise it. If there's no match, use the first list item.
793 *
794 * (we split the identifier list manually here because we must pass
795 * a single identifier, not a list, to new_internal() below)
796 */
797 ids = g_strsplit (identifiers, "|", 0);
798 for (i = 0; ids[i]; i++)
799 {
800 if (gimp_dialog_factory_find_widget (factory, ids[i]))
801 break;
802 }
803
804 dialog = gimp_dialog_factory_dialog_new_internal (factory,
805 screen,
806 monitor,
807 NULL,
808 NULL,
809 ids[i] ? ids[i] : ids[0],
810 view_size,
811 TRUE /*return_existing*/,
812 TRUE /*present*/,
813 TRUE /*create_containers*/);
814 g_strfreev (ids);
815
816 return dialog;
817 }
818
819 /**
820 * gimp_dialog_factory_dockable_new:
821 * @factory: a #GimpDialogFactory
822 * @dock: a #GimpDock created by this %factory.
823 * @identifier: the identifier of the dialog as registered with
824 * gimp_dialog_factory_register_entry()
825 * @view_size:
826 *
827 * Creates a new #GimpDockable in the context of the #GimpDock it will be
828 * added to.
829 *
830 * Implicitly raises & returns an already existing singleton dockable,
831 * so callers should check that gimp_dockable_get_dockbook (dockable)
832 * is NULL before trying to add it to it's #GimpDockbook.
833 *
834 * Return value: the newly created #GimpDockable or an already existing
835 * singleton dockable.
836 **/
837 GtkWidget *
gimp_dialog_factory_dockable_new(GimpDialogFactory * factory,GimpDock * dock,const gchar * identifier,gint view_size)838 gimp_dialog_factory_dockable_new (GimpDialogFactory *factory,
839 GimpDock *dock,
840 const gchar *identifier,
841 gint view_size)
842 {
843 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
844 g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
845 g_return_val_if_fail (identifier != NULL, NULL);
846
847 return gimp_dialog_factory_dialog_new_internal (factory,
848 gtk_widget_get_screen (GTK_WIDGET (dock)),
849 0,
850 gimp_dock_get_context (dock),
851 gimp_dock_get_ui_manager (dock),
852 identifier,
853 view_size,
854 FALSE /*return_existing*/,
855 FALSE /*present*/,
856 FALSE /*create_containers*/);
857 }
858
859 void
gimp_dialog_factory_add_dialog(GimpDialogFactory * factory,GtkWidget * dialog,GdkScreen * screen,gint monitor)860 gimp_dialog_factory_add_dialog (GimpDialogFactory *factory,
861 GtkWidget *dialog,
862 GdkScreen *screen,
863 gint monitor)
864 {
865 GimpDialogFactory *dialog_factory = NULL;
866 GimpDialogFactoryEntry *entry = NULL;
867 GimpSessionInfo *info = NULL;
868 GList *list = NULL;
869 gboolean toplevel = FALSE;
870
871 g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory));
872 g_return_if_fail (GTK_IS_WIDGET (dialog));
873 g_return_if_fail (GDK_IS_SCREEN (screen));
874
875 if (g_list_find (factory->p->open_dialogs, dialog))
876 {
877 g_warning ("%s: dialog already registered", G_STRFUNC);
878 return;
879 }
880
881 dialog_factory = gimp_dialog_factory_from_widget (dialog, &entry);
882
883 if (! gimp_dialog_factory_dialog_sane (factory,
884 dialog_factory,
885 entry,
886 dialog))
887 return;
888
889 toplevel = gtk_widget_is_toplevel (dialog);
890
891 if (entry)
892 {
893 /* dialog is a toplevel (but not a GimpDockWindow) or a GimpDockable */
894
895 GIMP_LOG (DIALOG_FACTORY, "adding %s \"%s\"",
896 toplevel ? "toplevel" : "dockable",
897 entry->identifier);
898
899 for (list = factory->p->session_infos; list; list = g_list_next (list))
900 {
901 GimpSessionInfo *current_info = list->data;
902
903 if (gimp_session_info_get_factory_entry (current_info) == entry)
904 {
905 if (gimp_session_info_get_widget (current_info))
906 {
907 if (gimp_session_info_is_singleton (current_info))
908 {
909 g_warning ("%s: singleton dialog \"%s\" created twice",
910 G_STRFUNC, entry->identifier);
911
912 GIMP_LOG (DIALOG_FACTORY,
913 "corrupt session info: %p (widget %p)",
914 current_info,
915 gimp_session_info_get_widget (current_info));
916
917 return;
918 }
919
920 continue;
921 }
922
923 gimp_session_info_set_widget (current_info, dialog);
924
925 GIMP_LOG (DIALOG_FACTORY,
926 "updating session info %p (widget %p) for %s \"%s\"",
927 current_info,
928 gimp_session_info_get_widget (current_info),
929 toplevel ? "toplevel" : "dockable",
930 entry->identifier);
931
932 if (toplevel &&
933 gimp_session_info_is_session_managed (current_info) &&
934 ! gtk_widget_get_visible (dialog))
935 {
936 GimpGuiConfig *gui_config;
937
938 gui_config = GIMP_GUI_CONFIG (factory->p->context->gimp->config);
939
940 gimp_session_info_apply_geometry (current_info,
941 screen, monitor,
942 gui_config->restore_monitor);
943 }
944
945 info = current_info;
946 break;
947 }
948 }
949
950 if (! info)
951 {
952 info = gimp_session_info_new ();
953
954 gimp_session_info_set_widget (info, dialog);
955
956 GIMP_LOG (DIALOG_FACTORY,
957 "creating session info %p (widget %p) for %s \"%s\"",
958 info,
959 gimp_session_info_get_widget (info),
960 toplevel ? "toplevel" : "dockable",
961 entry->identifier);
962
963 gimp_session_info_set_factory_entry (info, entry);
964
965 if (gimp_session_info_is_session_managed (info))
966 {
967 /* Make the dialog show up at the user position the
968 * first time it is shown. After it has been shown the
969 * first time we don't want it to show at the mouse the
970 * next time. Think of the use cases "hide and show with
971 * tab" and "change virtual desktops"
972 */
973 GIMP_LOG (WM, "setting GTK_WIN_POS_MOUSE for %p (\"%s\")\n",
974 dialog, entry->identifier);
975
976 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
977 g_signal_connect (dialog, "configure-event",
978 G_CALLBACK (gimp_dialog_factory_set_user_pos),
979 NULL);
980 }
981
982 gimp_dialog_factory_add_session_info (factory, info);
983 g_object_unref (info);
984 }
985 }
986
987 /* Some special logic for dock windows */
988 if (GIMP_IS_DOCK_WINDOW (dialog))
989 {
990 g_signal_emit (factory, factory_signals[DOCK_WINDOW_ADDED], 0, dialog);
991 }
992
993 factory->p->open_dialogs = g_list_prepend (factory->p->open_dialogs, dialog);
994
995 g_signal_connect_object (dialog, "destroy",
996 G_CALLBACK (gimp_dialog_factory_remove_dialog),
997 factory,
998 G_CONNECT_SWAPPED);
999
1000 if (gimp_session_info_is_session_managed (info))
1001 g_signal_connect_object (dialog, "configure-event",
1002 G_CALLBACK (gimp_dialog_factory_dialog_configure),
1003 factory,
1004 0);
1005 }
1006
1007 void
gimp_dialog_factory_add_foreign(GimpDialogFactory * factory,const gchar * identifier,GtkWidget * dialog,GdkScreen * screen,gint monitor)1008 gimp_dialog_factory_add_foreign (GimpDialogFactory *factory,
1009 const gchar *identifier,
1010 GtkWidget *dialog,
1011 GdkScreen *screen,
1012 gint monitor)
1013 {
1014 GimpDialogFactory *dialog_factory;
1015 GimpDialogFactoryEntry *entry;
1016
1017 g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory));
1018 g_return_if_fail (identifier != NULL);
1019 g_return_if_fail (GTK_IS_WIDGET (dialog));
1020 g_return_if_fail (gtk_widget_is_toplevel (dialog));
1021 g_return_if_fail (GDK_IS_SCREEN (screen));
1022
1023 dialog_factory = gimp_dialog_factory_from_widget (dialog, &entry);
1024
1025 if (dialog_factory || entry)
1026 {
1027 g_warning ("%s: dialog was created by a GimpDialogFactory",
1028 G_STRFUNC);
1029 return;
1030 }
1031
1032 entry = gimp_dialog_factory_find_entry (factory, identifier);
1033
1034 if (! entry)
1035 {
1036 g_warning ("%s: no entry registered for \"%s\"",
1037 G_STRFUNC, identifier);
1038 return;
1039 }
1040
1041 if (entry->new_func)
1042 {
1043 g_warning ("%s: entry for \"%s\" has a constructor (is not foreign)",
1044 G_STRFUNC, identifier);
1045 return;
1046 }
1047
1048 gimp_dialog_factory_set_widget_data (dialog, factory, entry);
1049
1050 gimp_dialog_factory_add_dialog (factory, dialog, screen, monitor);
1051 }
1052
1053 /**
1054 * gimp_dialog_factory_position_dialog:
1055 * @factory:
1056 * @identifier:
1057 * @dialog:
1058 * @screen:
1059 * @monitor:
1060 *
1061 * We correctly position all newly created dialog via
1062 * gimp_dialog_factory_add_dialog(), but some dialogs (like various
1063 * color dialogs) are never destroyed but created only once per
1064 * session. On re-showing, whatever window managing magic kicks in and
1065 * the dialog sometimes goes where it shouldn't.
1066 *
1067 * This function correctly positions a dialog on re-showing so it
1068 * appears where it was before it was hidden.
1069 *
1070 * See https://gitlab.gnome.org/GNOME/gimp/issues/1093
1071 **/
1072 void
gimp_dialog_factory_position_dialog(GimpDialogFactory * factory,const gchar * identifier,GtkWidget * dialog,GdkScreen * screen,gint monitor)1073 gimp_dialog_factory_position_dialog (GimpDialogFactory *factory,
1074 const gchar *identifier,
1075 GtkWidget *dialog,
1076 GdkScreen *screen,
1077 gint monitor)
1078 {
1079 GimpSessionInfo *info;
1080 GimpGuiConfig *gui_config;
1081
1082 g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory));
1083 g_return_if_fail (identifier != NULL);
1084 g_return_if_fail (GTK_IS_WIDGET (dialog));
1085 g_return_if_fail (gtk_widget_is_toplevel (dialog));
1086 g_return_if_fail (GDK_IS_SCREEN (screen));
1087
1088 info = gimp_dialog_factory_find_session_info (factory, identifier);
1089
1090 if (! info)
1091 {
1092 g_warning ("%s: no session info found for \"%s\"",
1093 G_STRFUNC, identifier);
1094 return;
1095 }
1096
1097 if (gimp_session_info_get_widget (info) != dialog)
1098 {
1099 g_warning ("%s: session info for \"%s\" is for a different widget",
1100 G_STRFUNC, identifier);
1101 return;
1102 }
1103
1104 gui_config = GIMP_GUI_CONFIG (factory->p->context->gimp->config);
1105
1106 gimp_session_info_apply_geometry (info,
1107 screen, monitor,
1108 gui_config->restore_monitor);
1109 }
1110
1111 void
gimp_dialog_factory_remove_dialog(GimpDialogFactory * factory,GtkWidget * dialog)1112 gimp_dialog_factory_remove_dialog (GimpDialogFactory *factory,
1113 GtkWidget *dialog)
1114 {
1115 GimpDialogFactory *dialog_factory;
1116 GimpDialogFactoryEntry *entry;
1117 GList *list;
1118
1119 g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory));
1120 g_return_if_fail (GTK_IS_WIDGET (dialog));
1121
1122 if (! g_list_find (factory->p->open_dialogs, dialog))
1123 {
1124 g_warning ("%s: dialog not registered", G_STRFUNC);
1125 return;
1126 }
1127
1128 factory->p->open_dialogs = g_list_remove (factory->p->open_dialogs, dialog);
1129
1130 dialog_factory = gimp_dialog_factory_from_widget (dialog, &entry);
1131
1132 if (! gimp_dialog_factory_dialog_sane (factory,
1133 dialog_factory,
1134 entry,
1135 dialog))
1136 return;
1137
1138 GIMP_LOG (DIALOG_FACTORY, "removing \"%s\" (dialog = %p)",
1139 entry->identifier,
1140 dialog);
1141
1142 for (list = factory->p->session_infos; list; list = g_list_next (list))
1143 {
1144 GimpSessionInfo *session_info = list->data;
1145
1146 if (gimp_session_info_get_widget (session_info) == dialog)
1147 {
1148 GIMP_LOG (DIALOG_FACTORY,
1149 "clearing session info %p (widget %p) for \"%s\"",
1150 session_info, gimp_session_info_get_widget (session_info),
1151 entry->identifier);
1152
1153 gimp_session_info_set_widget (session_info, NULL);
1154
1155 gimp_dialog_factory_unset_widget_data (dialog);
1156
1157 g_signal_handlers_disconnect_by_func (dialog,
1158 gimp_dialog_factory_set_user_pos,
1159 NULL);
1160 g_signal_handlers_disconnect_by_func (dialog,
1161 gimp_dialog_factory_remove_dialog,
1162 factory);
1163
1164 if (gimp_session_info_is_session_managed (session_info))
1165 g_signal_handlers_disconnect_by_func (dialog,
1166 gimp_dialog_factory_dialog_configure,
1167 factory);
1168
1169 if (GIMP_IS_DOCK_WINDOW (dialog))
1170 {
1171 /* don't save session info for empty docks */
1172 factory->p->session_infos = g_list_remove (factory->p->session_infos,
1173 session_info);
1174 g_object_unref (session_info);
1175
1176 g_signal_emit (factory, factory_signals[DOCK_WINDOW_REMOVED], 0,
1177 dialog);
1178 }
1179
1180 break;
1181 }
1182 }
1183 }
1184
1185 void
gimp_dialog_factory_hide_dialog(GtkWidget * dialog)1186 gimp_dialog_factory_hide_dialog (GtkWidget *dialog)
1187 {
1188 GimpDialogFactory *factory = NULL;
1189
1190 g_return_if_fail (GTK_IS_WIDGET (dialog));
1191 g_return_if_fail (gtk_widget_is_toplevel (dialog));
1192
1193 if (! (factory = gimp_dialog_factory_from_widget (dialog, NULL)))
1194 {
1195 g_warning ("%s: dialog was not created by a GimpDialogFactory",
1196 G_STRFUNC);
1197 return;
1198 }
1199
1200 gtk_widget_hide (dialog);
1201
1202 if (factory->p->dialog_state != GIMP_DIALOGS_SHOWN)
1203 g_object_set_data (G_OBJECT (dialog), GIMP_DIALOG_VISIBILITY_KEY,
1204 GINT_TO_POINTER (GIMP_DIALOG_VISIBILITY_INVISIBLE));
1205 }
1206
1207 void
gimp_dialog_factory_set_state(GimpDialogFactory * factory,GimpDialogsState state)1208 gimp_dialog_factory_set_state (GimpDialogFactory *factory,
1209 GimpDialogsState state)
1210 {
1211 g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory));
1212
1213 factory->p->dialog_state = state;
1214
1215 if (state == GIMP_DIALOGS_SHOWN)
1216 {
1217 gimp_dialog_factory_show (factory);
1218 }
1219 else
1220 {
1221 gimp_dialog_factory_hide (factory);
1222 }
1223 }
1224
1225 GimpDialogsState
gimp_dialog_factory_get_state(GimpDialogFactory * factory)1226 gimp_dialog_factory_get_state (GimpDialogFactory *factory)
1227 {
1228 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), 0);
1229
1230 return factory->p->dialog_state;
1231 }
1232
1233 void
gimp_dialog_factory_show_with_display(GimpDialogFactory * factory)1234 gimp_dialog_factory_show_with_display (GimpDialogFactory *factory)
1235 {
1236 g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory));
1237
1238 if (factory->p->dialog_state == GIMP_DIALOGS_HIDDEN_WITH_DISPLAY)
1239 {
1240 gimp_dialog_factory_set_state (factory, GIMP_DIALOGS_SHOWN);
1241 }
1242 }
1243
1244 void
gimp_dialog_factory_hide_with_display(GimpDialogFactory * factory)1245 gimp_dialog_factory_hide_with_display (GimpDialogFactory *factory)
1246 {
1247 g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory));
1248
1249 if (factory->p->dialog_state == GIMP_DIALOGS_SHOWN)
1250 {
1251 gimp_dialog_factory_set_state (factory, GIMP_DIALOGS_HIDDEN_WITH_DISPLAY);
1252 }
1253 }
1254
1255 static GQuark gimp_dialog_factory_key = 0;
1256 static GQuark gimp_dialog_factory_entry_key = 0;
1257
1258 GimpDialogFactory *
gimp_dialog_factory_from_widget(GtkWidget * dialog,GimpDialogFactoryEntry ** entry)1259 gimp_dialog_factory_from_widget (GtkWidget *dialog,
1260 GimpDialogFactoryEntry **entry)
1261 {
1262 g_return_val_if_fail (GTK_IS_WIDGET (dialog), NULL);
1263
1264 if (! gimp_dialog_factory_key)
1265 {
1266 gimp_dialog_factory_key =
1267 g_quark_from_static_string ("gimp-dialog-factory");
1268
1269 gimp_dialog_factory_entry_key =
1270 g_quark_from_static_string ("gimp-dialog-factory-entry");
1271 }
1272
1273 if (entry)
1274 *entry = g_object_get_qdata (G_OBJECT (dialog),
1275 gimp_dialog_factory_entry_key);
1276
1277 return g_object_get_qdata (G_OBJECT (dialog), gimp_dialog_factory_key);
1278 }
1279
1280 #define GIMP_DIALOG_FACTORY_MIN_SIZE_KEY "gimp-dialog-factory-min-size"
1281
1282 void
gimp_dialog_factory_set_has_min_size(GtkWindow * window,gboolean has_min_size)1283 gimp_dialog_factory_set_has_min_size (GtkWindow *window,
1284 gboolean has_min_size)
1285 {
1286 g_return_if_fail (GTK_IS_WINDOW (window));
1287
1288 g_object_set_data (G_OBJECT (window), GIMP_DIALOG_FACTORY_MIN_SIZE_KEY,
1289 GINT_TO_POINTER (has_min_size ? TRUE : FALSE));
1290 }
1291
1292 gboolean
gimp_dialog_factory_get_has_min_size(GtkWindow * window)1293 gimp_dialog_factory_get_has_min_size (GtkWindow *window)
1294 {
1295 g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
1296
1297 return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (window),
1298 GIMP_DIALOG_FACTORY_MIN_SIZE_KEY));
1299 }
1300
1301
1302 /* private functions */
1303
1304 static GtkWidget *
gimp_dialog_factory_constructor(GimpDialogFactory * factory,GimpDialogFactoryEntry * entry,GimpContext * context,GimpUIManager * ui_manager,gint view_size)1305 gimp_dialog_factory_constructor (GimpDialogFactory *factory,
1306 GimpDialogFactoryEntry *entry,
1307 GimpContext *context,
1308 GimpUIManager *ui_manager,
1309 gint view_size)
1310 {
1311 GtkWidget *widget;
1312
1313 widget = entry->new_func (factory, context, ui_manager, view_size);
1314
1315 /* The entry is for a dockable, so we simply need to put the created
1316 * widget in a dockable
1317 */
1318 if (widget && entry->dockable)
1319 {
1320 GtkWidget *dockable = NULL;
1321
1322 dockable = gimp_dockable_new (entry->name, entry->blurb,
1323 entry->icon_name, entry->help_id);
1324 gtk_container_add (GTK_CONTAINER (dockable), widget);
1325 gtk_widget_show (widget);
1326
1327 /* EEK */
1328 g_object_set_data (G_OBJECT (dockable), "gimp-dialog-identifier",
1329 entry->identifier);
1330
1331 /* Return the dockable instead */
1332 widget = dockable;
1333 }
1334
1335 return widget;
1336 }
1337
1338 static void
gimp_dialog_factory_config_notify(GimpDialogFactory * factory,GParamSpec * pspec,GimpGuiConfig * config)1339 gimp_dialog_factory_config_notify (GimpDialogFactory *factory,
1340 GParamSpec *pspec,
1341 GimpGuiConfig *config)
1342 {
1343 GimpDialogsState state = gimp_dialog_factory_get_state (factory);
1344 GimpDialogsState new_state = state;
1345
1346 /* Make sure the state and config are in sync */
1347 if (config->hide_docks && state == GIMP_DIALOGS_SHOWN)
1348 new_state = GIMP_DIALOGS_HIDDEN_EXPLICITLY;
1349 else if (! config->hide_docks)
1350 new_state = GIMP_DIALOGS_SHOWN;
1351
1352 if (state != new_state)
1353 gimp_dialog_factory_set_state (factory, new_state);
1354 }
1355
1356 static void
gimp_dialog_factory_set_widget_data(GtkWidget * dialog,GimpDialogFactory * factory,GimpDialogFactoryEntry * entry)1357 gimp_dialog_factory_set_widget_data (GtkWidget *dialog,
1358 GimpDialogFactory *factory,
1359 GimpDialogFactoryEntry *entry)
1360 {
1361 g_return_if_fail (GTK_IS_WIDGET (dialog));
1362 g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory));
1363
1364 if (! gimp_dialog_factory_key)
1365 {
1366 gimp_dialog_factory_key =
1367 g_quark_from_static_string ("gimp-dialog-factory");
1368
1369 gimp_dialog_factory_entry_key =
1370 g_quark_from_static_string ("gimp-dialog-factory-entry");
1371 }
1372
1373 g_object_set_qdata (G_OBJECT (dialog), gimp_dialog_factory_key, factory);
1374
1375 if (entry)
1376 g_object_set_qdata (G_OBJECT (dialog), gimp_dialog_factory_entry_key,
1377 entry);
1378 }
1379
1380 static void
gimp_dialog_factory_unset_widget_data(GtkWidget * dialog)1381 gimp_dialog_factory_unset_widget_data (GtkWidget *dialog)
1382 {
1383 g_return_if_fail (GTK_IS_WIDGET (dialog));
1384
1385 if (! gimp_dialog_factory_key)
1386 return;
1387
1388 g_object_set_qdata (G_OBJECT (dialog), gimp_dialog_factory_key, NULL);
1389 g_object_set_qdata (G_OBJECT (dialog), gimp_dialog_factory_entry_key, NULL);
1390 }
1391
1392 static gboolean
gimp_dialog_factory_set_user_pos(GtkWidget * dialog,GdkEventConfigure * cevent,gpointer data)1393 gimp_dialog_factory_set_user_pos (GtkWidget *dialog,
1394 GdkEventConfigure *cevent,
1395 gpointer data)
1396 {
1397 GdkWindowHints geometry_mask;
1398
1399 /* Not only set geometry hints, also reset window position */
1400 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_NONE);
1401 g_signal_handlers_disconnect_by_func (dialog,
1402 gimp_dialog_factory_set_user_pos,
1403 data);
1404
1405 GIMP_LOG (WM, "setting GDK_HINT_USER_POS for %p\n", dialog);
1406 geometry_mask = GDK_HINT_USER_POS;
1407
1408 if (gimp_dialog_factory_get_has_min_size (GTK_WINDOW (dialog)))
1409 geometry_mask |= GDK_HINT_MIN_SIZE;
1410
1411 gtk_window_set_geometry_hints (GTK_WINDOW (dialog), NULL, NULL,
1412 geometry_mask);
1413
1414 return FALSE;
1415 }
1416
1417 static gboolean
gimp_dialog_factory_dialog_configure(GtkWidget * dialog,GdkEventConfigure * cevent,GimpDialogFactory * factory)1418 gimp_dialog_factory_dialog_configure (GtkWidget *dialog,
1419 GdkEventConfigure *cevent,
1420 GimpDialogFactory *factory)
1421 {
1422 GimpDialogFactory *dialog_factory;
1423 GimpDialogFactoryEntry *entry;
1424 GList *list;
1425
1426 if (! g_list_find (factory->p->open_dialogs, dialog))
1427 {
1428 g_warning ("%s: dialog not registered", G_STRFUNC);
1429 return FALSE;
1430 }
1431
1432 dialog_factory = gimp_dialog_factory_from_widget (dialog, &entry);
1433
1434 if (! gimp_dialog_factory_dialog_sane (factory,
1435 dialog_factory,
1436 entry,
1437 dialog))
1438 return FALSE;
1439
1440 for (list = factory->p->session_infos; list; list = g_list_next (list))
1441 {
1442 GimpSessionInfo *session_info = list->data;
1443
1444 if (gimp_session_info_get_widget (session_info) == dialog)
1445 {
1446 gimp_session_info_read_geometry (session_info, cevent);
1447
1448 GIMP_LOG (DIALOG_FACTORY,
1449 "updated session info for \"%s\" from window geometry "
1450 "(x=%d y=%d %dx%d)",
1451 entry->identifier,
1452 gimp_session_info_get_x (session_info),
1453 gimp_session_info_get_y (session_info),
1454 gimp_session_info_get_width (session_info),
1455 gimp_session_info_get_height (session_info));
1456
1457 break;
1458 }
1459 }
1460
1461 return FALSE;
1462 }
1463
1464 void
gimp_dialog_factory_save(GimpDialogFactory * factory,GimpConfigWriter * writer)1465 gimp_dialog_factory_save (GimpDialogFactory *factory,
1466 GimpConfigWriter *writer)
1467 {
1468 GList *infos;
1469
1470 for (infos = factory->p->session_infos; infos; infos = g_list_next (infos))
1471 {
1472 GimpSessionInfo *info = infos->data;
1473
1474 /* we keep session info entries for all toplevel dialogs created
1475 * by the factory but don't save them if they don't want to be
1476 * managed
1477 */
1478 if (! gimp_session_info_is_session_managed (info) ||
1479 gimp_session_info_get_factory_entry (info) == NULL)
1480 continue;
1481
1482 if (gimp_session_info_get_widget (info))
1483 gimp_session_info_get_info (info);
1484
1485 gimp_config_writer_open (writer, "session-info");
1486 gimp_config_writer_string (writer,
1487 gimp_object_get_name (factory));
1488
1489 GIMP_CONFIG_GET_INTERFACE (info)->serialize (GIMP_CONFIG (info),
1490 writer,
1491 NULL);
1492
1493 gimp_config_writer_close (writer);
1494
1495 if (gimp_session_info_get_widget (info))
1496 gimp_session_info_clear_info (info);
1497 }
1498 }
1499
1500 void
gimp_dialog_factory_restore(GimpDialogFactory * factory,GdkScreen * screen,gint monitor)1501 gimp_dialog_factory_restore (GimpDialogFactory *factory,
1502 GdkScreen *screen,
1503 gint monitor)
1504 {
1505 GList *infos;
1506
1507 for (infos = factory->p->session_infos; infos; infos = g_list_next (infos))
1508 {
1509 GimpSessionInfo *info = infos->data;
1510
1511 if (gimp_session_info_get_open (info))
1512 {
1513 gimp_session_info_restore (info, factory, screen, monitor);
1514 }
1515 else
1516 {
1517 GIMP_LOG (DIALOG_FACTORY,
1518 "skipping to restore session info %p, not open",
1519 info);
1520 }
1521 }
1522 }
1523
1524 static void
gimp_dialog_factory_hide(GimpDialogFactory * factory)1525 gimp_dialog_factory_hide (GimpDialogFactory *factory)
1526 {
1527 GList *list;
1528
1529 for (list = factory->p->open_dialogs; list; list = g_list_next (list))
1530 {
1531 GtkWidget *widget = list->data;
1532
1533 if (GTK_IS_WIDGET (widget) && gtk_widget_is_toplevel (widget))
1534 {
1535 GimpDialogFactoryEntry *entry = NULL;
1536 GimpDialogVisibilityState visibility = GIMP_DIALOG_VISIBILITY_UNKNOWN;
1537
1538 gimp_dialog_factory_from_widget (widget, &entry);
1539 if (! entry->hideable)
1540 continue;
1541
1542 if (gtk_widget_get_visible (widget))
1543 {
1544 gtk_widget_hide (widget);
1545 visibility = GIMP_DIALOG_VISIBILITY_HIDDEN;
1546
1547 GIMP_LOG (WM, "Hiding '%s' [%p]",
1548 gtk_window_get_title (GTK_WINDOW (widget)),
1549 widget);
1550 }
1551 else
1552 {
1553 visibility = GIMP_DIALOG_VISIBILITY_INVISIBLE;
1554 }
1555
1556 g_object_set_data (G_OBJECT (widget),
1557 GIMP_DIALOG_VISIBILITY_KEY,
1558 GINT_TO_POINTER (visibility));
1559 }
1560 }
1561 }
1562
1563 static void
gimp_dialog_factory_show(GimpDialogFactory * factory)1564 gimp_dialog_factory_show (GimpDialogFactory *factory)
1565 {
1566 GList *list;
1567
1568 for (list = factory->p->open_dialogs; list; list = g_list_next (list))
1569 {
1570 GtkWidget *widget = list->data;
1571
1572 if (GTK_IS_WIDGET (widget) && gtk_widget_is_toplevel (widget))
1573 {
1574 GimpDialogVisibilityState visibility;
1575
1576 visibility =
1577 GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
1578 GIMP_DIALOG_VISIBILITY_KEY));
1579
1580 if (! gtk_widget_get_visible (widget) &&
1581 visibility == GIMP_DIALOG_VISIBILITY_HIDDEN)
1582 {
1583 GIMP_LOG (WM, "Showing '%s' [%p]",
1584 gtk_window_get_title (GTK_WINDOW (widget)),
1585 widget);
1586
1587 /* Don't use gtk_window_present() here, we don't want the
1588 * keyboard focus to move.
1589 */
1590 gtk_widget_show (widget);
1591 g_object_set_data (G_OBJECT (widget),
1592 GIMP_DIALOG_VISIBILITY_KEY,
1593 GINT_TO_POINTER (GIMP_DIALOG_VISIBILITY_VISIBLE));
1594
1595 if (gtk_widget_get_visible (widget))
1596 gdk_window_raise (gtk_widget_get_window (widget));
1597 }
1598 }
1599 }
1600 }
1601
1602 void
gimp_dialog_factory_set_busy(GimpDialogFactory * factory)1603 gimp_dialog_factory_set_busy (GimpDialogFactory *factory)
1604 {
1605 GList *list;
1606
1607 if (! factory)
1608 return;
1609
1610 for (list = factory->p->open_dialogs; list; list = g_list_next (list))
1611 {
1612 GtkWidget *widget = list->data;
1613
1614 if (GTK_IS_WIDGET (widget) && gtk_widget_is_toplevel (widget))
1615 {
1616 GdkWindow *window = gtk_widget_get_window (widget);
1617
1618 if (window)
1619 {
1620 GdkCursor *cursor = gimp_cursor_new (window,
1621 GIMP_HANDEDNESS_RIGHT,
1622 (GimpCursorType) GDK_WATCH,
1623 GIMP_TOOL_CURSOR_NONE,
1624 GIMP_CURSOR_MODIFIER_NONE);
1625 gdk_window_set_cursor (window, cursor);
1626 gdk_cursor_unref (cursor);
1627 }
1628 }
1629 }
1630 }
1631
1632 void
gimp_dialog_factory_unset_busy(GimpDialogFactory * factory)1633 gimp_dialog_factory_unset_busy (GimpDialogFactory *factory)
1634 {
1635 GList *list;
1636
1637 if (! factory)
1638 return;
1639
1640 for (list = factory->p->open_dialogs; list; list = g_list_next (list))
1641 {
1642 GtkWidget *widget = list->data;
1643
1644 if (GTK_IS_WIDGET (widget) && gtk_widget_is_toplevel (widget))
1645 {
1646 GdkWindow *window = gtk_widget_get_window (widget);
1647
1648 if (window)
1649 gdk_window_set_cursor (window, NULL);
1650 }
1651 }
1652 }
1653
1654 /**
1655 * gimp_dialog_factory_get_singleton:
1656 *
1657 * Returns: The toplevel GimpDialogFactory instance.
1658 **/
1659 GimpDialogFactory *
gimp_dialog_factory_get_singleton(void)1660 gimp_dialog_factory_get_singleton (void)
1661 {
1662 g_return_val_if_fail (gimp_toplevel_factory != NULL, NULL);
1663
1664 return gimp_toplevel_factory;
1665 }
1666
1667 /**
1668 * gimp_dialog_factory_set_singleton:
1669 * @:
1670 *
1671 * Set the toplevel GimpDialogFactory instance. Must only be called by
1672 * dialogs_init()!.
1673 **/
1674 void
gimp_dialog_factory_set_singleton(GimpDialogFactory * factory)1675 gimp_dialog_factory_set_singleton (GimpDialogFactory *factory)
1676 {
1677 g_return_if_fail (gimp_toplevel_factory == NULL ||
1678 factory == NULL);
1679
1680 gimp_toplevel_factory = factory;
1681 }
1682