1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <math.h>
21
22 #include <gegl.h>
23 #include <gtk/gtk.h>
24
25 #ifdef G_OS_WIN32
26 #include <windef.h>
27 #include <winbase.h>
28 #include <windows.h>
29 #endif
30
31 #ifdef GDK_WINDOWING_QUARTZ
32 #import <AppKit/AppKit.h>
33 #include <gdk/gdkquartz.h>
34 #endif /* !GDK_WINDOWING_QUARTZ */
35
36 #include "libgimpmath/gimpmath.h"
37 #include "libgimpcolor/gimpcolor.h"
38 #include "libgimpwidgets/gimpwidgets.h"
39
40 #include "display-types.h"
41
42 #include "config/gimpguiconfig.h"
43
44 #include "core/gimp.h"
45 #include "core/gimpcontext.h"
46 #include "core/gimpimage.h"
47 #include "core/gimpprogress.h"
48 #include "core/gimpcontainer.h"
49
50 #include "widgets/gimpactiongroup.h"
51 #include "widgets/gimpdialogfactory.h"
52 #include "widgets/gimpdock.h"
53 #include "widgets/gimpdockbook.h"
54 #include "widgets/gimpdockcolumns.h"
55 #include "widgets/gimpdockcontainer.h"
56 #include "widgets/gimphelp-ids.h"
57 #include "widgets/gimpmenufactory.h"
58 #include "widgets/gimpsessioninfo.h"
59 #include "widgets/gimpsessioninfo-aux.h"
60 #include "widgets/gimpsessionmanaged.h"
61 #include "widgets/gimpsessioninfo-dock.h"
62 #include "widgets/gimptoolbox.h"
63 #include "widgets/gimpuimanager.h"
64 #include "widgets/gimpview.h"
65 #include "widgets/gimpviewrenderer.h"
66 #include "widgets/gimpwidgets-utils.h"
67
68 #include "gimpdisplay.h"
69 #include "gimpdisplay-foreach.h"
70 #include "gimpdisplayshell.h"
71 #include "gimpdisplayshell-appearance.h"
72 #include "gimpdisplayshell-close.h"
73 #include "gimpdisplayshell-scale.h"
74 #include "gimpdisplayshell-scroll.h"
75 #include "gimpdisplayshell-tool-events.h"
76 #include "gimpdisplayshell-transform.h"
77 #include "gimpimagewindow.h"
78 #include "gimpstatusbar.h"
79
80 #include "gimp-log.h"
81 #include "gimp-priorities.h"
82
83 #include "gimp-intl.h"
84
85
86 #define GIMP_EMPTY_IMAGE_WINDOW_ENTRY_ID "gimp-empty-image-window"
87 #define GIMP_SINGLE_IMAGE_WINDOW_ENTRY_ID "gimp-single-image-window"
88
89 /* The width of the left and right dock areas */
90 #define GIMP_IMAGE_WINDOW_LEFT_DOCKS_WIDTH "left-docks-width"
91 #define GIMP_IMAGE_WINDOW_RIGHT_DOCKS_WIDTH "right-docks-width"
92
93 /* deprecated property: GtkPaned position of the right docks area */
94 #define GIMP_IMAGE_WINDOW_RIGHT_DOCKS_POS "right-docks-position"
95
96 /* Whether the window's maximized or not */
97 #define GIMP_IMAGE_WINDOW_MAXIMIZED "maximized"
98
99 #if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
100 #define NSWindowCollectionBehaviorFullScreenAuxiliary (1 << 8)
101 #endif
102
103
104 enum
105 {
106 PROP_0,
107 PROP_GIMP,
108 PROP_DIALOG_FACTORY,
109 PROP_INITIAL_SCREEN,
110 PROP_INITIAL_MONITOR
111 };
112
113
114 typedef struct _GimpImageWindowPrivate GimpImageWindowPrivate;
115
116 struct _GimpImageWindowPrivate
117 {
118 Gimp *gimp;
119 GimpUIManager *menubar_manager;
120 GimpDialogFactory *dialog_factory;
121
122 GList *shells;
123 GimpDisplayShell *active_shell;
124
125 GtkWidget *main_vbox;
126 GtkWidget *menubar;
127 GtkWidget *hbox;
128 GtkWidget *left_hpane;
129 GtkWidget *left_docks;
130 GtkWidget *right_hpane;
131 GtkWidget *notebook;
132 GtkWidget *right_docks;
133
134 GdkWindowState window_state;
135
136 const gchar *entry_id;
137
138 GdkScreen *initial_screen;
139 gint initial_monitor;
140
141 gint suspend_keep_pos;
142
143 gint update_ui_manager_idle_id;
144 };
145
146 typedef struct
147 {
148 gint canvas_x;
149 gint canvas_y;
150 gint window_x;
151 gint window_y;
152 } PosCorrectionData;
153
154
155 #define GIMP_IMAGE_WINDOW_GET_PRIVATE(window) \
156 ((GimpImageWindowPrivate *) gimp_image_window_get_instance_private ((GimpImageWindow *) (window)))
157
158
159 /* local function prototypes */
160
161 static void gimp_image_window_dock_container_iface_init
162 (GimpDockContainerInterface
163 *iface);
164 static void gimp_image_window_session_managed_iface_init
165 (GimpSessionManagedInterface
166 *iface);
167 static void gimp_image_window_constructed (GObject *object);
168 static void gimp_image_window_dispose (GObject *object);
169 static void gimp_image_window_finalize (GObject *object);
170 static void gimp_image_window_set_property (GObject *object,
171 guint property_id,
172 const GValue *value,
173 GParamSpec *pspec);
174 static void gimp_image_window_get_property (GObject *object,
175 guint property_id,
176 GValue *value,
177 GParamSpec *pspec);
178
179 static void gimp_image_window_map (GtkWidget *widget);
180 static gboolean gimp_image_window_delete_event (GtkWidget *widget,
181 GdkEventAny *event);
182 static gboolean gimp_image_window_configure_event (GtkWidget *widget,
183 GdkEventConfigure *event);
184 static gboolean gimp_image_window_window_state_event (GtkWidget *widget,
185 GdkEventWindowState *event);
186 static void gimp_image_window_style_set (GtkWidget *widget,
187 GtkStyle *prev_style);
188
189 static void gimp_image_window_monitor_changed (GimpWindow *window,
190 GdkScreen *screen,
191 gint monitor);
192
193 static GList * gimp_image_window_get_docks (GimpDockContainer *dock_container);
194 static GimpDialogFactory *
195 gimp_image_window_dock_container_get_dialog_factory
196 (GimpDockContainer *dock_container);
197 static GimpUIManager *
198 gimp_image_window_dock_container_get_ui_manager
199 (GimpDockContainer *dock_container);
200 static void gimp_image_window_add_dock (GimpDockContainer *dock_container,
201 GimpDock *dock,
202 GimpSessionInfoDock *dock_info);
203 static GimpAlignmentType
204 gimp_image_window_get_dock_side (GimpDockContainer *dock_container,
205 GimpDock *dock);
206 static GList * gimp_image_window_get_aux_info (GimpSessionManaged *session_managed);
207 static void gimp_image_window_set_aux_info (GimpSessionManaged *session_managed,
208 GList *aux_info);
209
210 static void gimp_image_window_config_notify (GimpImageWindow *window,
211 GParamSpec *pspec,
212 GimpGuiConfig *config);
213 static void gimp_image_window_session_clear (GimpImageWindow *window);
214 static void gimp_image_window_session_apply (GimpImageWindow *window,
215 const gchar *entry_id,
216 GdkScreen *screen,
217 gint monitor);
218 static void gimp_image_window_session_update (GimpImageWindow *window,
219 GimpDisplay *new_display,
220 const gchar *new_entry_id,
221 GdkScreen *screen,
222 gint monitor);
223 static const gchar *
224 gimp_image_window_config_to_entry_id (GimpGuiConfig *config);
225 static void gimp_image_window_show_tooltip (GimpUIManager *manager,
226 const gchar *tooltip,
227 GimpImageWindow *window);
228 static void gimp_image_window_hide_tooltip (GimpUIManager *manager,
229 GimpImageWindow *window);
230 static gboolean gimp_image_window_update_ui_manager_idle
231 (GimpImageWindow *window);
232 static void gimp_image_window_update_ui_manager (GimpImageWindow *window);
233
234 static void gimp_image_window_shell_size_allocate (GimpDisplayShell *shell,
235 GtkAllocation *allocation,
236 PosCorrectionData *data);
237 static gboolean gimp_image_window_shell_events (GtkWidget *widget,
238 GdkEvent *event,
239 GimpImageWindow *window);
240
241 static void gimp_image_window_switch_page (GtkNotebook *notebook,
242 gpointer page,
243 gint page_num,
244 GimpImageWindow *window);
245 static void gimp_image_window_page_removed (GtkNotebook *notebook,
246 GtkWidget *widget,
247 gint page_num,
248 GimpImageWindow *window);
249 static void gimp_image_window_page_reordered (GtkNotebook *notebook,
250 GtkWidget *widget,
251 gint page_num,
252 GimpImageWindow *window);
253 static void gimp_image_window_disconnect_from_active_shell
254 (GimpImageWindow *window);
255
256 static void gimp_image_window_image_notify (GimpDisplay *display,
257 const GParamSpec *pspec,
258 GimpImageWindow *window);
259 static void gimp_image_window_shell_scaled (GimpDisplayShell *shell,
260 GimpImageWindow *window);
261 static void gimp_image_window_shell_rotated (GimpDisplayShell *shell,
262 GimpImageWindow *window);
263 static void gimp_image_window_shell_title_notify (GimpDisplayShell *shell,
264 const GParamSpec *pspec,
265 GimpImageWindow *window);
266 static void gimp_image_window_shell_icon_notify (GimpDisplayShell *shell,
267 const GParamSpec *pspec,
268 GimpImageWindow *window);
269 static GtkWidget *
270 gimp_image_window_create_tab_label (GimpImageWindow *window,
271 GimpDisplayShell *shell);
272 static void gimp_image_window_update_tab_labels (GimpImageWindow *window);
273
274
275 G_DEFINE_TYPE_WITH_CODE (GimpImageWindow, gimp_image_window, GIMP_TYPE_WINDOW,
276 G_ADD_PRIVATE (GimpImageWindow)
277 G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCK_CONTAINER,
278 gimp_image_window_dock_container_iface_init)
279 G_IMPLEMENT_INTERFACE (GIMP_TYPE_SESSION_MANAGED,
280 gimp_image_window_session_managed_iface_init))
281
282 #define parent_class gimp_image_window_parent_class
283
284
285 static const gchar image_window_rc_style[] =
286 "style \"fullscreen-menubar-style\"\n"
287 "{\n"
288 " GtkMenuBar::shadow-type = none\n"
289 " GtkMenuBar::internal-padding = 0\n"
290 "}\n"
291 "widget \"*.gimp-menubar-fullscreen\" style \"fullscreen-menubar-style\"\n";
292
293 static void
gimp_image_window_class_init(GimpImageWindowClass * klass)294 gimp_image_window_class_init (GimpImageWindowClass *klass)
295 {
296 GObjectClass *object_class = G_OBJECT_CLASS (klass);
297 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
298 GimpWindowClass *window_class = GIMP_WINDOW_CLASS (klass);
299
300 object_class->constructed = gimp_image_window_constructed;
301 object_class->dispose = gimp_image_window_dispose;
302 object_class->finalize = gimp_image_window_finalize;
303 object_class->set_property = gimp_image_window_set_property;
304 object_class->get_property = gimp_image_window_get_property;
305
306 widget_class->map = gimp_image_window_map;
307 widget_class->delete_event = gimp_image_window_delete_event;
308 widget_class->configure_event = gimp_image_window_configure_event;
309 widget_class->window_state_event = gimp_image_window_window_state_event;
310 widget_class->style_set = gimp_image_window_style_set;
311
312 window_class->monitor_changed = gimp_image_window_monitor_changed;
313
314 g_object_class_install_property (object_class, PROP_GIMP,
315 g_param_spec_object ("gimp",
316 NULL, NULL,
317 GIMP_TYPE_GIMP,
318 GIMP_PARAM_WRITABLE |
319 G_PARAM_CONSTRUCT_ONLY));
320
321 g_object_class_install_property (object_class, PROP_DIALOG_FACTORY,
322 g_param_spec_object ("dialog-factory",
323 NULL, NULL,
324 GIMP_TYPE_DIALOG_FACTORY,
325 GIMP_PARAM_READWRITE |
326 G_PARAM_CONSTRUCT_ONLY));
327
328 g_object_class_install_property (object_class, PROP_INITIAL_SCREEN,
329 g_param_spec_object ("initial-screen",
330 NULL, NULL,
331 GDK_TYPE_SCREEN,
332 GIMP_PARAM_READWRITE |
333 G_PARAM_CONSTRUCT_ONLY));
334 g_object_class_install_property (object_class, PROP_INITIAL_MONITOR,
335 g_param_spec_int ("initial-monitor",
336 NULL, NULL,
337 0, 16, 0,
338 GIMP_PARAM_READWRITE |
339 G_PARAM_CONSTRUCT_ONLY));
340
341 gtk_rc_parse_string (image_window_rc_style);
342 }
343
344 static void
gimp_image_window_init(GimpImageWindow * window)345 gimp_image_window_init (GimpImageWindow *window)
346 {
347 static gint role_serial = 1;
348 gchar *role;
349
350 role = g_strdup_printf ("gimp-image-window-%d", role_serial++);
351 gtk_window_set_role (GTK_WINDOW (window), role);
352 g_free (role);
353
354 gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
355 }
356
357 static void
gimp_image_window_dock_container_iface_init(GimpDockContainerInterface * iface)358 gimp_image_window_dock_container_iface_init (GimpDockContainerInterface *iface)
359 {
360 iface->get_docks = gimp_image_window_get_docks;
361 iface->get_dialog_factory = gimp_image_window_dock_container_get_dialog_factory;
362 iface->get_ui_manager = gimp_image_window_dock_container_get_ui_manager;
363 iface->add_dock = gimp_image_window_add_dock;
364 iface->get_dock_side = gimp_image_window_get_dock_side;
365 }
366
367 static void
gimp_image_window_session_managed_iface_init(GimpSessionManagedInterface * iface)368 gimp_image_window_session_managed_iface_init (GimpSessionManagedInterface *iface)
369 {
370 iface->get_aux_info = gimp_image_window_get_aux_info;
371 iface->set_aux_info = gimp_image_window_set_aux_info;
372 }
373
374 static void
gimp_image_window_constructed(GObject * object)375 gimp_image_window_constructed (GObject *object)
376 {
377 GimpImageWindow *window = GIMP_IMAGE_WINDOW (object);
378 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
379 GimpMenuFactory *menu_factory;
380 GimpGuiConfig *config;
381
382 G_OBJECT_CLASS (parent_class)->constructed (object);
383
384 gimp_assert (GIMP_IS_GIMP (private->gimp));
385 gimp_assert (GIMP_IS_DIALOG_FACTORY (private->dialog_factory));
386
387 menu_factory = gimp_dialog_factory_get_menu_factory (private->dialog_factory);
388
389 private->menubar_manager = gimp_menu_factory_manager_new (menu_factory,
390 "<Image>",
391 window,
392 FALSE);
393
394 g_signal_connect_object (private->dialog_factory, "dock-window-added",
395 G_CALLBACK (gimp_image_window_update_ui_manager),
396 window, G_CONNECT_SWAPPED);
397 g_signal_connect_object (private->dialog_factory, "dock-window-removed",
398 G_CALLBACK (gimp_image_window_update_ui_manager),
399 window, G_CONNECT_SWAPPED);
400
401 gtk_window_add_accel_group (GTK_WINDOW (window),
402 gimp_ui_manager_get_accel_group (private->menubar_manager));
403
404 g_signal_connect (private->menubar_manager, "show-tooltip",
405 G_CALLBACK (gimp_image_window_show_tooltip),
406 window);
407 g_signal_connect (private->menubar_manager, "hide-tooltip",
408 G_CALLBACK (gimp_image_window_hide_tooltip),
409 window);
410
411 config = GIMP_GUI_CONFIG (private->gimp->config);
412
413 /* Create the window toplevel container */
414 private->main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
415 gtk_container_add (GTK_CONTAINER (window), private->main_vbox);
416 gtk_widget_show (private->main_vbox);
417
418 /* Create the menubar */
419 #ifndef GDK_WINDOWING_QUARTZ
420 private->menubar = gimp_ui_manager_get_widget (private->menubar_manager,
421 "/image-menubar");
422 #endif /* !GDK_WINDOWING_QUARTZ */
423 if (private->menubar)
424 {
425 gtk_box_pack_start (GTK_BOX (private->main_vbox),
426 private->menubar, FALSE, FALSE, 0);
427
428 /* make sure we can activate accels even if the menubar is invisible
429 * (see https://bugzilla.gnome.org/show_bug.cgi?id=137151)
430 */
431 g_signal_connect (private->menubar, "can-activate-accel",
432 G_CALLBACK (gtk_true),
433 NULL);
434
435 /* active display callback */
436 g_signal_connect (private->menubar, "button-press-event",
437 G_CALLBACK (gimp_image_window_shell_events),
438 window);
439 g_signal_connect (private->menubar, "button-release-event",
440 G_CALLBACK (gimp_image_window_shell_events),
441 window);
442 g_signal_connect (private->menubar, "key-press-event",
443 G_CALLBACK (gimp_image_window_shell_events),
444 window);
445 }
446
447 /* Create the hbox that contains docks and images */
448 private->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
449 gtk_box_pack_start (GTK_BOX (private->main_vbox), private->hbox,
450 TRUE, TRUE, 0);
451 gtk_widget_show (private->hbox);
452
453 /* Create the left pane */
454 private->left_hpane = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
455 gtk_box_pack_start (GTK_BOX (private->hbox), private->left_hpane,
456 TRUE, TRUE, 0);
457 gtk_widget_show (private->left_hpane);
458
459 /* Create the left dock columns widget */
460 private->left_docks =
461 gimp_dock_columns_new (gimp_get_user_context (private->gimp),
462 private->dialog_factory,
463 private->menubar_manager);
464 gtk_paned_pack1 (GTK_PANED (private->left_hpane), private->left_docks,
465 FALSE, FALSE);
466 gtk_widget_set_visible (private->left_docks, config->single_window_mode);
467
468 /* Create the right pane */
469 private->right_hpane = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
470 gtk_paned_pack2 (GTK_PANED (private->left_hpane), private->right_hpane,
471 TRUE, FALSE);
472 gtk_widget_show (private->right_hpane);
473
474 /* Create notebook that contains images */
475 private->notebook = gtk_notebook_new ();
476 gtk_notebook_set_scrollable (GTK_NOTEBOOK (private->notebook), TRUE);
477 gtk_notebook_set_show_border (GTK_NOTEBOOK (private->notebook), FALSE);
478 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (private->notebook), FALSE);
479 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (private->notebook), GTK_POS_TOP);
480
481 gtk_paned_pack1 (GTK_PANED (private->right_hpane), private->notebook,
482 TRUE, TRUE);
483
484 g_signal_connect (private->notebook, "switch-page",
485 G_CALLBACK (gimp_image_window_switch_page),
486 window);
487 g_signal_connect (private->notebook, "page-removed",
488 G_CALLBACK (gimp_image_window_page_removed),
489 window);
490 g_signal_connect (private->notebook, "page-reordered",
491 G_CALLBACK (gimp_image_window_page_reordered),
492 window);
493 gtk_widget_show (private->notebook);
494
495 /* Create the right dock columns widget */
496 private->right_docks =
497 gimp_dock_columns_new (gimp_get_user_context (private->gimp),
498 private->dialog_factory,
499 private->menubar_manager);
500 gtk_paned_pack2 (GTK_PANED (private->right_hpane), private->right_docks,
501 FALSE, FALSE);
502 gtk_widget_set_visible (private->right_docks, config->single_window_mode);
503
504 g_signal_connect_object (config, "notify::single-window-mode",
505 G_CALLBACK (gimp_image_window_config_notify),
506 window, G_CONNECT_SWAPPED);
507 g_signal_connect_object (config, "notify::show-tabs",
508 G_CALLBACK (gimp_image_window_config_notify),
509 window, G_CONNECT_SWAPPED);
510 g_signal_connect_object (config, "notify::hide-docks",
511 G_CALLBACK (gimp_image_window_config_notify),
512 window, G_CONNECT_SWAPPED);
513 g_signal_connect_object (config, "notify::tabs-position",
514 G_CALLBACK (gimp_image_window_config_notify),
515 window, G_CONNECT_SWAPPED);
516
517 gimp_image_window_session_update (window,
518 NULL /*new_display*/,
519 gimp_image_window_config_to_entry_id (config),
520 private->initial_screen,
521 private->initial_monitor);
522 }
523
524 static void
gimp_image_window_dispose(GObject * object)525 gimp_image_window_dispose (GObject *object)
526 {
527 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (object);
528
529 if (private->dialog_factory)
530 {
531 g_signal_handlers_disconnect_by_func (private->dialog_factory,
532 gimp_image_window_update_ui_manager,
533 object);
534 private->dialog_factory = NULL;
535 }
536
537 g_clear_object (&private->menubar_manager);
538
539 if (private->update_ui_manager_idle_id)
540 {
541 g_source_remove (private->update_ui_manager_idle_id);
542 private->update_ui_manager_idle_id = 0;
543 }
544
545 G_OBJECT_CLASS (parent_class)->dispose (object);
546 }
547
548 static void
gimp_image_window_finalize(GObject * object)549 gimp_image_window_finalize (GObject *object)
550 {
551 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (object);
552
553 if (private->shells)
554 {
555 g_list_free (private->shells);
556 private->shells = NULL;
557 }
558
559 G_OBJECT_CLASS (parent_class)->finalize (object);
560 }
561
562 static void
gimp_image_window_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)563 gimp_image_window_set_property (GObject *object,
564 guint property_id,
565 const GValue *value,
566 GParamSpec *pspec)
567 {
568 GimpImageWindow *window = GIMP_IMAGE_WINDOW (object);
569 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
570
571 switch (property_id)
572 {
573 case PROP_GIMP:
574 private->gimp = g_value_get_object (value);
575 break;
576 case PROP_DIALOG_FACTORY:
577 private->dialog_factory = g_value_get_object (value);
578 break;
579 case PROP_INITIAL_SCREEN:
580 private->initial_screen = g_value_get_object (value);
581 break;
582 case PROP_INITIAL_MONITOR:
583 private->initial_monitor = g_value_get_int (value);
584 break;
585
586 default:
587 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
588 break;
589 }
590 }
591
592 static void
gimp_image_window_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)593 gimp_image_window_get_property (GObject *object,
594 guint property_id,
595 GValue *value,
596 GParamSpec *pspec)
597 {
598 GimpImageWindow *window = GIMP_IMAGE_WINDOW (object);
599 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
600
601 switch (property_id)
602 {
603 case PROP_GIMP:
604 g_value_set_object (value, private->gimp);
605 break;
606 case PROP_DIALOG_FACTORY:
607 g_value_set_object (value, private->dialog_factory);
608 break;
609 case PROP_INITIAL_SCREEN:
610 g_value_set_object (value, private->initial_screen);
611 break;
612 case PROP_INITIAL_MONITOR:
613 g_value_set_int (value, private->initial_monitor);
614 break;
615
616 default:
617 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
618 break;
619 }
620 }
621
622 static void
gimp_image_window_map(GtkWidget * widget)623 gimp_image_window_map (GtkWidget *widget)
624 {
625 #ifdef GDK_WINDOWING_QUARTZ
626 GdkWindow *gdk_window;
627 NSWindow *ns_window;
628 #endif /* !GDK_WINDOWING_QUARTZ */
629
630 GTK_WIDGET_CLASS (parent_class)->map (widget);
631
632 #ifdef GDK_WINDOWING_QUARTZ
633 gdk_window = gtk_widget_get_window (GTK_WIDGET (widget));
634 ns_window = gdk_quartz_window_get_nswindow (gdk_window);
635
636 /* Disable the new-style full screen mode. For now only the "old-style"
637 * full screen mode, via the "View" menu, is supported. In the future, and
638 * as soon as GTK+ has proper support for this, we will migrate to the
639 * new-style full screen mode.
640 */
641 ns_window.collectionBehavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
642 #endif /* !GDK_WINDOWING_QUARTZ */
643 }
644
645 static gboolean
gimp_image_window_delete_event(GtkWidget * widget,GdkEventAny * event)646 gimp_image_window_delete_event (GtkWidget *widget,
647 GdkEventAny *event)
648 {
649 GimpImageWindow *window = GIMP_IMAGE_WINDOW (widget);
650 GimpDisplayShell *shell = gimp_image_window_get_active_shell (window);
651 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
652 GimpGuiConfig *config = GIMP_GUI_CONFIG (private->gimp->config);
653
654 if (config->single_window_mode)
655 gimp_ui_manager_activate_action (gimp_image_window_get_ui_manager (window),
656 "file", "file-quit");
657 else if (shell)
658 gimp_display_shell_close (shell, FALSE);
659
660 return TRUE;
661 }
662
663 static gboolean
gimp_image_window_configure_event(GtkWidget * widget,GdkEventConfigure * event)664 gimp_image_window_configure_event (GtkWidget *widget,
665 GdkEventConfigure *event)
666 {
667 GimpImageWindow *window = GIMP_IMAGE_WINDOW (widget);
668 GtkAllocation allocation;
669 gint current_width;
670 gint current_height;
671
672 gtk_widget_get_allocation (widget, &allocation);
673
674 /* Grab the size before we run the parent implementation */
675 current_width = allocation.width;
676 current_height = allocation.height;
677
678 /* Run the parent implementation */
679 if (GTK_WIDGET_CLASS (parent_class)->configure_event)
680 GTK_WIDGET_CLASS (parent_class)->configure_event (widget, event);
681
682 /* If the window size has changed, make sure additoinal logic is run
683 * in the display shell's size-allocate
684 */
685 if (event->width != current_width ||
686 event->height != current_height)
687 {
688 /* FIXME multiple shells */
689 GimpDisplayShell *shell = gimp_image_window_get_active_shell (window);
690
691 if (shell && gimp_display_get_image (shell->display))
692 shell->size_allocate_from_configure_event = TRUE;
693 }
694
695 return TRUE;
696 }
697
698 static gboolean
gimp_image_window_window_state_event(GtkWidget * widget,GdkEventWindowState * event)699 gimp_image_window_window_state_event (GtkWidget *widget,
700 GdkEventWindowState *event)
701 {
702 GimpImageWindow *window = GIMP_IMAGE_WINDOW (widget);
703 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
704 GimpDisplayShell *shell = gimp_image_window_get_active_shell (window);
705
706 if (! shell)
707 return FALSE;
708
709 private->window_state = event->new_window_state;
710
711 if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
712 {
713 gboolean fullscreen = gimp_image_window_get_fullscreen (window);
714
715 GIMP_LOG (WM, "Image window '%s' [%p] set fullscreen %s",
716 gtk_window_get_title (GTK_WINDOW (widget)),
717 widget,
718 fullscreen ? "TRUE" : "FALSE");
719
720 if (private->menubar)
721 gtk_widget_set_name (private->menubar,
722 fullscreen ? "gimp-menubar-fullscreen" : NULL);
723
724 gimp_image_window_suspend_keep_pos (window);
725 gimp_display_shell_appearance_update (shell);
726 gimp_image_window_resume_keep_pos (window);
727 }
728
729 if (event->changed_mask & GDK_WINDOW_STATE_ICONIFIED)
730 {
731 GimpStatusbar *statusbar = gimp_display_shell_get_statusbar (shell);
732 gboolean iconified = gimp_image_window_is_iconified (window);
733
734 GIMP_LOG (WM, "Image window '%s' [%p] set %s",
735 gtk_window_get_title (GTK_WINDOW (widget)),
736 widget,
737 iconified ? "iconified" : "uniconified");
738
739 if (iconified)
740 {
741 if (gimp_displays_get_num_visible (private->gimp) == 0)
742 {
743 GIMP_LOG (WM, "No displays visible any longer");
744
745 gimp_dialog_factory_hide_with_display (private->dialog_factory);
746 }
747 }
748 else
749 {
750 gimp_dialog_factory_show_with_display (private->dialog_factory);
751 }
752
753 if (gimp_progress_is_active (GIMP_PROGRESS (statusbar)))
754 {
755 if (iconified)
756 gimp_statusbar_override_window_title (statusbar);
757 else
758 gtk_window_set_title (GTK_WINDOW (window), shell->title);
759 }
760 }
761
762 return FALSE;
763 }
764
765 static void
gimp_image_window_style_set(GtkWidget * widget,GtkStyle * prev_style)766 gimp_image_window_style_set (GtkWidget *widget,
767 GtkStyle *prev_style)
768 {
769 GimpImageWindow *window = GIMP_IMAGE_WINDOW (widget);
770 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
771 GimpDisplayShell *shell = gimp_image_window_get_active_shell (window);
772 GimpStatusbar *statusbar = NULL;
773 GtkRequisition requisition = { 0, };
774 GdkGeometry geometry = { 0, };
775 GdkWindowHints geometry_mask = 0;
776
777 GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
778
779 if (! shell)
780 return;
781
782 statusbar = gimp_display_shell_get_statusbar (shell);
783
784 gtk_widget_size_request (GTK_WIDGET (statusbar), &requisition);
785
786 geometry.min_height = 23;
787
788 geometry.min_width = requisition.width;
789 geometry.min_height += requisition.height;
790
791 if (private->menubar)
792 {
793 gtk_widget_size_request (private->menubar, &requisition);
794
795 geometry.min_height += requisition.height;
796 }
797
798 geometry_mask = GDK_HINT_MIN_SIZE;
799
800 /* Only set user pos on the empty display because it gets a pos
801 * set by gimp. All other displays should be placed by the window
802 * manager. See https://bugzilla.gnome.org/show_bug.cgi?id=559580
803 */
804 if (! gimp_display_get_image (shell->display))
805 geometry_mask |= GDK_HINT_USER_POS;
806
807 gtk_window_set_geometry_hints (GTK_WINDOW (widget), NULL,
808 &geometry, geometry_mask);
809
810 gimp_dialog_factory_set_has_min_size (GTK_WINDOW (widget), TRUE);
811 }
812
813 static void
gimp_image_window_monitor_changed(GimpWindow * window,GdkScreen * screen,gint monitor)814 gimp_image_window_monitor_changed (GimpWindow *window,
815 GdkScreen *screen,
816 gint monitor)
817 {
818 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
819 GList *list;
820
821 for (list = private->shells; list; list = g_list_next (list))
822 {
823 /* hack, this should live here, and screen_changed call
824 * monitor_changed
825 */
826 g_signal_emit_by_name (list->data, "screen-changed",
827 gtk_widget_get_screen (list->data));
828
829 /* make it fetch the new monitor's resolution */
830 gimp_display_shell_scale_update (GIMP_DISPLAY_SHELL (list->data));
831
832 /* make it fetch the right monitor profile */
833 gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (list->data));
834 }
835 }
836
837 static GList *
gimp_image_window_get_docks(GimpDockContainer * dock_container)838 gimp_image_window_get_docks (GimpDockContainer *dock_container)
839 {
840 GimpImageWindowPrivate *private;
841 GList *iter;
842 GList *all_docks = NULL;
843
844 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (dock_container), FALSE);
845
846 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (dock_container);
847
848 for (iter = gimp_dock_columns_get_docks (GIMP_DOCK_COLUMNS (private->left_docks));
849 iter;
850 iter = g_list_next (iter))
851 {
852 all_docks = g_list_append (all_docks, GIMP_DOCK (iter->data));
853 }
854
855 for (iter = gimp_dock_columns_get_docks (GIMP_DOCK_COLUMNS (private->right_docks));
856 iter;
857 iter = g_list_next (iter))
858 {
859 all_docks = g_list_append (all_docks, GIMP_DOCK (iter->data));
860 }
861
862 return all_docks;
863 }
864
865 static GimpDialogFactory *
gimp_image_window_dock_container_get_dialog_factory(GimpDockContainer * dock_container)866 gimp_image_window_dock_container_get_dialog_factory (GimpDockContainer *dock_container)
867 {
868 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (dock_container);
869
870 return private->dialog_factory;
871 }
872
873 static GimpUIManager *
gimp_image_window_dock_container_get_ui_manager(GimpDockContainer * dock_container)874 gimp_image_window_dock_container_get_ui_manager (GimpDockContainer *dock_container)
875 {
876 GimpImageWindow *window = GIMP_IMAGE_WINDOW (dock_container);
877
878 return gimp_image_window_get_ui_manager (window);
879 }
880
881 void
gimp_image_window_add_dock(GimpDockContainer * dock_container,GimpDock * dock,GimpSessionInfoDock * dock_info)882 gimp_image_window_add_dock (GimpDockContainer *dock_container,
883 GimpDock *dock,
884 GimpSessionInfoDock *dock_info)
885 {
886 GimpImageWindow *window;
887 GimpDisplayShell *active_shell;
888 GimpImageWindowPrivate *private;
889
890 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (dock_container));
891
892 window = GIMP_IMAGE_WINDOW (dock_container);
893 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
894
895 if (dock_info->side == GIMP_ALIGN_LEFT)
896 {
897 gimp_dock_columns_add_dock (GIMP_DOCK_COLUMNS (private->left_docks),
898 dock,
899 -1 /*index*/);
900 }
901 else
902 {
903 gimp_dock_columns_add_dock (GIMP_DOCK_COLUMNS (private->right_docks),
904 dock,
905 -1 /*index*/);
906 }
907
908 active_shell = gimp_image_window_get_active_shell (window);
909 if (active_shell)
910 gimp_display_shell_appearance_update (active_shell);
911 }
912
913 static GimpAlignmentType
gimp_image_window_get_dock_side(GimpDockContainer * dock_container,GimpDock * dock)914 gimp_image_window_get_dock_side (GimpDockContainer *dock_container,
915 GimpDock *dock)
916 {
917 GimpAlignmentType side = -1;
918 GimpImageWindowPrivate *private;
919 GList *iter;
920
921 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (dock_container), FALSE);
922
923 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (dock_container);
924
925 for (iter = gimp_dock_columns_get_docks (GIMP_DOCK_COLUMNS (private->left_docks));
926 iter && side == -1;
927 iter = g_list_next (iter))
928 {
929 GimpDock *dock_iter = GIMP_DOCK (iter->data);
930
931 if (dock_iter == dock)
932 side = GIMP_ALIGN_LEFT;
933 }
934
935 for (iter = gimp_dock_columns_get_docks (GIMP_DOCK_COLUMNS (private->right_docks));
936 iter && side == -1;
937 iter = g_list_next (iter))
938 {
939 GimpDock *dock_iter = GIMP_DOCK (iter->data);
940
941 if (dock_iter == dock)
942 side = GIMP_ALIGN_RIGHT;
943 }
944
945 return side;
946 }
947
948 static GList *
gimp_image_window_get_aux_info(GimpSessionManaged * session_managed)949 gimp_image_window_get_aux_info (GimpSessionManaged *session_managed)
950 {
951 GList *aux_info = NULL;
952 GimpImageWindowPrivate *private;
953 GimpGuiConfig *config;
954
955 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (session_managed), NULL);
956
957 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (session_managed);
958 config = GIMP_GUI_CONFIG (private->gimp->config);
959
960 if (config->single_window_mode)
961 {
962 GimpSessionInfoAux *aux;
963 GtkAllocation allocation;
964 gchar widthbuf[128];
965
966 g_snprintf (widthbuf, sizeof (widthbuf), "%d",
967 gtk_paned_get_position (GTK_PANED (private->left_hpane)));
968 aux = gimp_session_info_aux_new (GIMP_IMAGE_WINDOW_LEFT_DOCKS_WIDTH,
969 widthbuf);
970 aux_info = g_list_append (aux_info, aux);
971
972 gtk_widget_get_allocation (private->right_hpane, &allocation);
973
974 g_snprintf (widthbuf, sizeof (widthbuf), "%d",
975 allocation.width -
976 gtk_paned_get_position (GTK_PANED (private->right_hpane)));
977 aux = gimp_session_info_aux_new (GIMP_IMAGE_WINDOW_RIGHT_DOCKS_WIDTH,
978 widthbuf);
979 aux_info = g_list_append (aux_info, aux);
980
981 aux = gimp_session_info_aux_new (GIMP_IMAGE_WINDOW_MAXIMIZED,
982 gimp_image_window_is_maximized (GIMP_IMAGE_WINDOW (session_managed)) ?
983 "yes" : "no");
984 aux_info = g_list_append (aux_info, aux);
985 }
986
987 return aux_info;
988 }
989
990 static void
gimp_image_window_set_right_docks_width(GtkPaned * paned,GtkAllocation * allocation,void * data)991 gimp_image_window_set_right_docks_width (GtkPaned *paned,
992 GtkAllocation *allocation,
993 void *data)
994 {
995 gint width = GPOINTER_TO_INT (data);
996
997 g_return_if_fail (GTK_IS_PANED (paned));
998
999 if (width > 0)
1000 gtk_paned_set_position (paned, allocation->width - width);
1001 else
1002 gtk_paned_set_position (paned, - width);
1003
1004 g_signal_handlers_disconnect_by_func (paned,
1005 gimp_image_window_set_right_docks_width,
1006 data);
1007 }
1008
1009 static void
gimp_image_window_set_aux_info(GimpSessionManaged * session_managed,GList * aux_info)1010 gimp_image_window_set_aux_info (GimpSessionManaged *session_managed,
1011 GList *aux_info)
1012 {
1013 GimpImageWindowPrivate *private;
1014 GList *iter;
1015 gint left_docks_width = G_MININT;
1016 gint right_docks_width = G_MININT;
1017 gboolean wait_with_right_docks = FALSE;
1018 gboolean maximized = FALSE;
1019 #ifdef G_OS_WIN32
1020 STARTUPINFO StartupInfo;
1021
1022 GetStartupInfo (&StartupInfo);
1023 #endif
1024
1025 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (session_managed));
1026
1027 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (session_managed);
1028
1029 for (iter = aux_info; iter; iter = g_list_next (iter))
1030 {
1031 GimpSessionInfoAux *aux = iter->data;
1032 gint *width = NULL;
1033
1034 if (! strcmp (aux->name, GIMP_IMAGE_WINDOW_LEFT_DOCKS_WIDTH))
1035 width = &left_docks_width;
1036 else if (! strcmp (aux->name, GIMP_IMAGE_WINDOW_RIGHT_DOCKS_WIDTH))
1037 width = &right_docks_width;
1038 else if (! strcmp (aux->name, GIMP_IMAGE_WINDOW_RIGHT_DOCKS_POS))
1039 width = &right_docks_width;
1040 else if (! strcmp (aux->name, GIMP_IMAGE_WINDOW_MAXIMIZED))
1041 if (! g_ascii_strcasecmp (aux->value, "yes"))
1042 maximized = TRUE;
1043
1044 if (width)
1045 sscanf (aux->value, "%d", width);
1046
1047 /* compat handling for right docks */
1048 if (! strcmp (aux->name, GIMP_IMAGE_WINDOW_RIGHT_DOCKS_POS))
1049 {
1050 /* negate the value because negative docks pos means docks width,
1051 * also use the negativenes of a real docks pos as condition below.
1052 */
1053 *width = - *width;
1054 }
1055 }
1056
1057 if (left_docks_width != G_MININT &&
1058 gtk_paned_get_position (GTK_PANED (private->left_hpane)) !=
1059 left_docks_width)
1060 {
1061 gtk_paned_set_position (GTK_PANED (private->left_hpane), left_docks_width);
1062
1063 /* We can't set the position of the right docks, because it will
1064 * be undesirably adjusted when its get a new size
1065 * allocation. We must wait until after the size allocation.
1066 */
1067 wait_with_right_docks = TRUE;
1068 }
1069
1070 if (right_docks_width != G_MININT &&
1071 gtk_paned_get_position (GTK_PANED (private->right_hpane)) !=
1072 right_docks_width)
1073 {
1074 if (wait_with_right_docks || right_docks_width > 0)
1075 {
1076 /* We must wait for a size allocation before we can set the
1077 * position
1078 */
1079 g_signal_connect_data (private->right_hpane, "size-allocate",
1080 G_CALLBACK (gimp_image_window_set_right_docks_width),
1081 GINT_TO_POINTER (right_docks_width), NULL,
1082 G_CONNECT_AFTER);
1083 }
1084 else
1085 {
1086 /* We can set the position directly, because we didn't
1087 * change the left hpane position, and we got the old compat
1088 * dock pos property.
1089 */
1090 gtk_paned_set_position (GTK_PANED (private->right_hpane),
1091 - right_docks_width);
1092 }
1093 }
1094
1095 #ifdef G_OS_WIN32
1096 /* On Windows, user can provide startup hints to have a program
1097 * maximized/minimized on startup. This can be done through command
1098 * line: `start /max gimp-2.9.exe` or with the shortcut's "run"
1099 * property.
1100 * When such a hint is given, we should follow it and bypass the
1101 * session's information.
1102 */
1103 if (StartupInfo.wShowWindow == SW_SHOWMAXIMIZED)
1104 gtk_window_maximize (GTK_WINDOW (session_managed));
1105 else if (StartupInfo.wShowWindow == SW_SHOWMINIMIZED ||
1106 StartupInfo.wShowWindow == SW_SHOWMINNOACTIVE ||
1107 StartupInfo.wShowWindow == SW_MINIMIZE)
1108 /* XXX Iconification does not seem to work. I see the
1109 * window being iconified and immediately re-raised.
1110 * I leave this piece of code for later improvement. */
1111 gtk_window_iconify (GTK_WINDOW (session_managed));
1112 else
1113 /* Another show property not relevant to min/max.
1114 * Defaults is: SW_SHOWNORMAL
1115 */
1116 #endif
1117 if (maximized)
1118 gtk_window_maximize (GTK_WINDOW (session_managed));
1119 else
1120 gtk_window_unmaximize (GTK_WINDOW (session_managed));
1121 }
1122
1123
1124 /* public functions */
1125
1126 GimpImageWindow *
gimp_image_window_new(Gimp * gimp,GimpImage * image,GimpDialogFactory * dialog_factory,GdkScreen * screen,gint monitor)1127 gimp_image_window_new (Gimp *gimp,
1128 GimpImage *image,
1129 GimpDialogFactory *dialog_factory,
1130 GdkScreen *screen,
1131 gint monitor)
1132 {
1133 GimpImageWindow *window;
1134 GimpImageWindowPrivate *private;
1135
1136 g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
1137 g_return_val_if_fail (image == NULL || GIMP_IS_IMAGE (image), NULL);
1138 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (dialog_factory), NULL);
1139 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1140
1141 window = g_object_new (GIMP_TYPE_IMAGE_WINDOW,
1142 "gimp", gimp,
1143 "dialog-factory", dialog_factory,
1144 "initial-screen", screen,
1145 "initial-monitor", monitor,
1146 /* The window position will be overridden by the
1147 * dialog factory, it is only really used on first
1148 * startup.
1149 */
1150 image ? NULL : "window-position",
1151 GTK_WIN_POS_CENTER,
1152 NULL);
1153
1154 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1155
1156 gimp->image_windows = g_list_append (gimp->image_windows, window);
1157
1158 if (! GIMP_GUI_CONFIG (private->gimp->config)->single_window_mode)
1159 {
1160 GdkScreen *pointer_screen;
1161 gint pointer_monitor;
1162
1163 pointer_monitor = gimp_get_monitor_at_pointer (&pointer_screen);
1164
1165 /* If we are supposed to go to a monitor other than where the
1166 * pointer is, place the window on that monitor manually,
1167 * otherwise simply let the window manager place the window on
1168 * the poiner's monitor.
1169 */
1170 if (pointer_screen != screen ||
1171 pointer_monitor != monitor)
1172 {
1173 GdkRectangle rect;
1174 gchar geom[32];
1175
1176 gdk_screen_get_monitor_workarea (screen, monitor, &rect);
1177
1178 /* FIXME: image window placement
1179 *
1180 * This is ugly beyond description but better than showing
1181 * the window on the wrong monitor
1182 */
1183 g_snprintf (geom, sizeof (geom), "%+d%+d",
1184 rect.x + 300, rect.y + 30);
1185 gtk_window_parse_geometry (GTK_WINDOW (window), geom);
1186 }
1187 }
1188
1189 return window;
1190 }
1191
1192 void
gimp_image_window_destroy(GimpImageWindow * window)1193 gimp_image_window_destroy (GimpImageWindow *window)
1194 {
1195 GimpImageWindowPrivate *private;
1196
1197 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1198
1199 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1200
1201 private->gimp->image_windows = g_list_remove (private->gimp->image_windows,
1202 window);
1203
1204 gtk_widget_destroy (GTK_WIDGET (window));
1205 }
1206
1207 GimpUIManager *
gimp_image_window_get_ui_manager(GimpImageWindow * window)1208 gimp_image_window_get_ui_manager (GimpImageWindow *window)
1209 {
1210 GimpImageWindowPrivate *private;
1211
1212 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), FALSE);
1213
1214 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1215
1216 return private->menubar_manager;
1217 }
1218
1219 GimpDockColumns *
gimp_image_window_get_left_docks(GimpImageWindow * window)1220 gimp_image_window_get_left_docks (GimpImageWindow *window)
1221 {
1222 GimpImageWindowPrivate *private;
1223
1224 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), FALSE);
1225
1226 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1227
1228 return GIMP_DOCK_COLUMNS (private->left_docks);
1229 }
1230
1231 GimpDockColumns *
gimp_image_window_get_right_docks(GimpImageWindow * window)1232 gimp_image_window_get_right_docks (GimpImageWindow *window)
1233 {
1234 GimpImageWindowPrivate *private;
1235
1236 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), FALSE);
1237
1238 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1239
1240 return GIMP_DOCK_COLUMNS (private->right_docks);
1241 }
1242
1243 void
gimp_image_window_add_shell(GimpImageWindow * window,GimpDisplayShell * shell)1244 gimp_image_window_add_shell (GimpImageWindow *window,
1245 GimpDisplayShell *shell)
1246 {
1247 GimpImageWindowPrivate *private;
1248 GtkWidget *tab_label;
1249
1250 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1251 g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1252
1253 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1254
1255 g_return_if_fail (g_list_find (private->shells, shell) == NULL);
1256
1257 private->shells = g_list_append (private->shells, shell);
1258
1259 tab_label = gimp_image_window_create_tab_label (window, shell);
1260
1261 gtk_notebook_append_page (GTK_NOTEBOOK (private->notebook),
1262 GTK_WIDGET (shell), tab_label);
1263 gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (private->notebook),
1264 GTK_WIDGET (shell), TRUE);
1265
1266 gtk_widget_show (GTK_WIDGET (shell));
1267
1268 /* make it fetch the right monitor profile */
1269 gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (shell));
1270 }
1271
1272 GimpDisplayShell *
gimp_image_window_get_shell(GimpImageWindow * window,gint index)1273 gimp_image_window_get_shell (GimpImageWindow *window,
1274 gint index)
1275 {
1276 GimpImageWindowPrivate *private;
1277
1278 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), NULL);
1279
1280 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1281
1282 return g_list_nth_data (private->shells, index);
1283 }
1284
1285 void
gimp_image_window_remove_shell(GimpImageWindow * window,GimpDisplayShell * shell)1286 gimp_image_window_remove_shell (GimpImageWindow *window,
1287 GimpDisplayShell *shell)
1288 {
1289 GimpImageWindowPrivate *private;
1290
1291 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1292 g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1293
1294 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1295
1296 g_return_if_fail (g_list_find (private->shells, shell) != NULL);
1297
1298 private->shells = g_list_remove (private->shells, shell);
1299
1300 gtk_container_remove (GTK_CONTAINER (private->notebook),
1301 GTK_WIDGET (shell));
1302 }
1303
1304 gint
gimp_image_window_get_n_shells(GimpImageWindow * window)1305 gimp_image_window_get_n_shells (GimpImageWindow *window)
1306 {
1307 GimpImageWindowPrivate *private;
1308
1309 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), 0);
1310
1311 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1312
1313 return g_list_length (private->shells);
1314 }
1315
1316 void
gimp_image_window_set_active_shell(GimpImageWindow * window,GimpDisplayShell * shell)1317 gimp_image_window_set_active_shell (GimpImageWindow *window,
1318 GimpDisplayShell *shell)
1319 {
1320 GimpImageWindowPrivate *private;
1321 gint page_num;
1322
1323 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1324 g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1325
1326 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1327
1328 g_return_if_fail (g_list_find (private->shells, shell));
1329
1330 page_num = gtk_notebook_page_num (GTK_NOTEBOOK (private->notebook),
1331 GTK_WIDGET (shell));
1332
1333 gtk_notebook_set_current_page (GTK_NOTEBOOK (private->notebook), page_num);
1334 }
1335
1336 GimpDisplayShell *
gimp_image_window_get_active_shell(GimpImageWindow * window)1337 gimp_image_window_get_active_shell (GimpImageWindow *window)
1338 {
1339 GimpImageWindowPrivate *private;
1340
1341 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), NULL);
1342
1343 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1344
1345 return private->active_shell;
1346 }
1347
1348 void
gimp_image_window_set_fullscreen(GimpImageWindow * window,gboolean fullscreen)1349 gimp_image_window_set_fullscreen (GimpImageWindow *window,
1350 gboolean fullscreen)
1351 {
1352 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1353
1354 if (fullscreen != gimp_image_window_get_fullscreen (window))
1355 {
1356 if (fullscreen)
1357 gtk_window_fullscreen (GTK_WINDOW (window));
1358 else
1359 gtk_window_unfullscreen (GTK_WINDOW (window));
1360 }
1361 }
1362
1363 gboolean
gimp_image_window_get_fullscreen(GimpImageWindow * window)1364 gimp_image_window_get_fullscreen (GimpImageWindow *window)
1365 {
1366 GimpImageWindowPrivate *private;
1367
1368 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), FALSE);
1369
1370 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1371
1372 return (private->window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0;
1373 }
1374
1375 void
gimp_image_window_set_show_menubar(GimpImageWindow * window,gboolean show)1376 gimp_image_window_set_show_menubar (GimpImageWindow *window,
1377 gboolean show)
1378 {
1379 GimpImageWindowPrivate *private;
1380
1381 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1382
1383 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1384
1385 if (private->menubar)
1386 gtk_widget_set_visible (private->menubar, show);
1387 }
1388
1389 gboolean
gimp_image_window_get_show_menubar(GimpImageWindow * window)1390 gimp_image_window_get_show_menubar (GimpImageWindow *window)
1391 {
1392 GimpImageWindowPrivate *private;
1393
1394 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), FALSE);
1395
1396 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1397
1398 if (private->menubar)
1399 return gtk_widget_get_visible (private->menubar);
1400
1401 return FALSE;
1402 }
1403
1404 gboolean
gimp_image_window_is_iconified(GimpImageWindow * window)1405 gimp_image_window_is_iconified (GimpImageWindow *window)
1406 {
1407 GimpImageWindowPrivate *private;
1408
1409 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), FALSE);
1410
1411 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1412
1413 return (private->window_state & GDK_WINDOW_STATE_ICONIFIED) != 0;
1414 }
1415
1416 gboolean
gimp_image_window_is_maximized(GimpImageWindow * window)1417 gimp_image_window_is_maximized (GimpImageWindow *window)
1418 {
1419 GimpImageWindowPrivate *private;
1420
1421 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), FALSE);
1422
1423 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1424
1425 return (private->window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
1426 }
1427
1428 /**
1429 * gimp_image_window_has_toolbox:
1430 * @window:
1431 *
1432 * Returns: %TRUE if the image window contains a GimpToolbox.
1433 **/
1434 gboolean
gimp_image_window_has_toolbox(GimpImageWindow * window)1435 gimp_image_window_has_toolbox (GimpImageWindow *window)
1436 {
1437 GimpImageWindowPrivate *private;
1438 GList *iter = NULL;
1439
1440 g_return_val_if_fail (GIMP_IS_IMAGE_WINDOW (window), FALSE);
1441
1442 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1443
1444 for (iter = gimp_dock_columns_get_docks (GIMP_DOCK_COLUMNS (private->left_docks));
1445 iter;
1446 iter = g_list_next (iter))
1447 {
1448 if (GIMP_IS_TOOLBOX (iter->data))
1449 return TRUE;
1450 }
1451
1452 for (iter = gimp_dock_columns_get_docks (GIMP_DOCK_COLUMNS (private->right_docks));
1453 iter;
1454 iter = g_list_next (iter))
1455 {
1456 if (GIMP_IS_TOOLBOX (iter->data))
1457 return TRUE;
1458 }
1459
1460 return FALSE;
1461 }
1462
1463 void
gimp_image_window_shrink_wrap(GimpImageWindow * window,gboolean grow_only)1464 gimp_image_window_shrink_wrap (GimpImageWindow *window,
1465 gboolean grow_only)
1466 {
1467 GimpDisplayShell *active_shell;
1468 GtkWidget *widget;
1469 GtkAllocation allocation;
1470 GdkScreen *screen;
1471 GdkRectangle rect;
1472 gint monitor;
1473 gint disp_width, disp_height;
1474 gint width, height;
1475 gint max_auto_width, max_auto_height;
1476 gint border_width, border_height;
1477 gboolean resize = FALSE;
1478
1479 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1480
1481 if (! gtk_widget_get_realized (GTK_WIDGET (window)))
1482 return;
1483
1484 /* FIXME this so needs cleanup and shell/window separation */
1485
1486 active_shell = gimp_image_window_get_active_shell (window);
1487
1488 if (!active_shell)
1489 return;
1490
1491 widget = GTK_WIDGET (window);
1492 screen = gtk_widget_get_screen (widget);
1493
1494 gtk_widget_get_allocation (widget, &allocation);
1495
1496 monitor = gdk_screen_get_monitor_at_window (screen,
1497 gtk_widget_get_window (widget));
1498 gdk_screen_get_monitor_workarea (screen, monitor, &rect);
1499
1500 if (! gimp_display_shell_get_infinite_canvas (active_shell))
1501 {
1502 gimp_display_shell_scale_get_image_size (active_shell,
1503 &width, &height);
1504 }
1505 else
1506 {
1507 gimp_display_shell_scale_get_image_bounding_box (active_shell,
1508 NULL, NULL,
1509 &width, &height);
1510 }
1511
1512 disp_width = active_shell->disp_width;
1513 disp_height = active_shell->disp_height;
1514
1515
1516 /* As long as the disp_width/disp_height is larger than 1 we
1517 * can reliably depend on it to calculate the
1518 * border_width/border_height because that means there is enough
1519 * room in the top-level for the canvas as well as the rulers and
1520 * scrollbars. If it is 1 or smaller it is likely that the rulers
1521 * and scrollbars are overlapping each other and thus we cannot use
1522 * the normal approach to border size, so special case that.
1523 */
1524 if (disp_width > 1 || !active_shell->vsb)
1525 {
1526 border_width = allocation.width - disp_width;
1527 }
1528 else
1529 {
1530 GtkAllocation vsb_allocation;
1531
1532 gtk_widget_get_allocation (active_shell->vsb, &vsb_allocation);
1533
1534 border_width = allocation.width - disp_width + vsb_allocation.width;
1535 }
1536
1537 if (disp_height > 1 || !active_shell->hsb)
1538 {
1539 border_height = allocation.height - disp_height;
1540 }
1541 else
1542 {
1543 GtkAllocation hsb_allocation;
1544
1545 gtk_widget_get_allocation (active_shell->hsb, &hsb_allocation);
1546
1547 border_height = allocation.height - disp_height + hsb_allocation.height;
1548 }
1549
1550
1551 max_auto_width = (rect.width - border_width) * 0.75;
1552 max_auto_height = (rect.height - border_height) * 0.75;
1553
1554 /* If one of the display dimensions has changed and one of the
1555 * dimensions fits inside the screen
1556 */
1557 if (((width + border_width) < rect.width ||
1558 (height + border_height) < rect.height) &&
1559 (width != disp_width ||
1560 height != disp_height))
1561 {
1562 width = ((width + border_width) < rect.width) ? width : max_auto_width;
1563 height = ((height + border_height) < rect.height) ? height : max_auto_height;
1564
1565 resize = TRUE;
1566 }
1567
1568 /* If the projected dimension is greater than current, but less than
1569 * 3/4 of the screen size, expand automagically
1570 */
1571 else if ((width > disp_width ||
1572 height > disp_height) &&
1573 (disp_width < max_auto_width ||
1574 disp_height < max_auto_height))
1575 {
1576 width = MIN (max_auto_width, width);
1577 height = MIN (max_auto_height, height);
1578
1579 resize = TRUE;
1580 }
1581
1582 if (resize)
1583 {
1584 GimpStatusbar *statusbar = gimp_display_shell_get_statusbar (active_shell);
1585 gint statusbar_width;
1586
1587 gtk_widget_get_size_request (GTK_WIDGET (statusbar),
1588 &statusbar_width, NULL);
1589
1590 if (width < statusbar_width)
1591 width = statusbar_width;
1592
1593 width = width + border_width;
1594 height = height + border_height;
1595
1596 if (grow_only)
1597 {
1598 if (width < allocation.width)
1599 width = allocation.width;
1600
1601 if (height < allocation.height)
1602 height = allocation.height;
1603 }
1604
1605 gtk_window_resize (GTK_WINDOW (window), width, height);
1606 }
1607
1608 /* A wrap always means that we should center the image too. If the
1609 * window changes size another center will be done in
1610 * GimpDisplayShell::configure_event().
1611 */
1612 /* FIXME multiple shells */
1613 gimp_display_shell_scroll_center_content (active_shell, TRUE, TRUE);
1614 }
1615
1616 static GtkWidget *
gimp_image_window_get_first_dockbook(GimpDockColumns * columns)1617 gimp_image_window_get_first_dockbook (GimpDockColumns *columns)
1618 {
1619 GList *dock_iter;
1620
1621 for (dock_iter = gimp_dock_columns_get_docks (columns);
1622 dock_iter;
1623 dock_iter = g_list_next (dock_iter))
1624 {
1625 GimpDock *dock = GIMP_DOCK (dock_iter->data);
1626 GList *dockbooks = gimp_dock_get_dockbooks (dock);
1627
1628 if (dockbooks)
1629 return GTK_WIDGET (dockbooks->data);
1630 }
1631
1632 return NULL;
1633 }
1634
1635 /**
1636 * gimp_image_window_get_default_dockbook:
1637 * @window:
1638 *
1639 * Gets the default dockbook, which is the dockbook in which new
1640 * dockables should be put in single-window mode.
1641 *
1642 * Returns: The default dockbook for new dockables, or NULL if no
1643 * dockbook were available.
1644 **/
1645 GtkWidget *
gimp_image_window_get_default_dockbook(GimpImageWindow * window)1646 gimp_image_window_get_default_dockbook (GimpImageWindow *window)
1647 {
1648 GimpImageWindowPrivate *private;
1649 GimpDockColumns *dock_columns;
1650 GtkWidget *dockbook = NULL;
1651
1652 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1653
1654 /* First try the first dockbook in the right docks */
1655 dock_columns = GIMP_DOCK_COLUMNS (private->right_docks);
1656 dockbook = gimp_image_window_get_first_dockbook (dock_columns);
1657
1658 /* Then the left docks */
1659 if (! dockbook)
1660 {
1661 dock_columns = GIMP_DOCK_COLUMNS (private->left_docks);
1662 dockbook = gimp_image_window_get_first_dockbook (dock_columns);
1663 }
1664
1665 return dockbook;
1666 }
1667
1668 /**
1669 * gimp_image_window_keep_canvas_pos:
1670 * @window:
1671 *
1672 * Stores the coordinates of the current image canvas origin relatively
1673 * its GtkWindow; and on the first size-allocate sets the offsets in
1674 * the shell so that the image origin remains the same (even on another
1675 * GtkWindow).
1676 *
1677 * Example use case: The user hides docks attached to the side of image
1678 * windows. You want the image to remain fixed on the screen though,
1679 * so you use this function to keep the image fixed after the docks
1680 * have been hidden.
1681 **/
1682 void
gimp_image_window_keep_canvas_pos(GimpImageWindow * window)1683 gimp_image_window_keep_canvas_pos (GimpImageWindow *window)
1684 {
1685 GimpImageWindowPrivate *private;
1686 GimpDisplayShell *shell;
1687 gint canvas_x;
1688 gint canvas_y;
1689 gint window_x;
1690 gint window_y;
1691
1692 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1693
1694 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1695
1696 if (private->suspend_keep_pos > 0)
1697 return;
1698
1699 shell = gimp_image_window_get_active_shell (window);
1700
1701 gimp_display_shell_transform_xy (shell, 0.0, 0.0, &canvas_x, &canvas_y);
1702
1703 if (gtk_widget_translate_coordinates (GTK_WIDGET (shell->canvas),
1704 GTK_WIDGET (window),
1705 canvas_x, canvas_y,
1706 &window_x, &window_y))
1707 {
1708 PosCorrectionData *data = g_new0 (PosCorrectionData, 1);
1709
1710 data->canvas_x = canvas_x;
1711 data->canvas_y = canvas_y;
1712 data->window_x = window_x;
1713 data->window_y = window_y;
1714
1715 g_signal_connect_data (shell, "size-allocate",
1716 G_CALLBACK (gimp_image_window_shell_size_allocate),
1717 data, (GClosureNotify) g_free,
1718 G_CONNECT_AFTER);
1719 }
1720 }
1721
1722 void
gimp_image_window_suspend_keep_pos(GimpImageWindow * window)1723 gimp_image_window_suspend_keep_pos (GimpImageWindow *window)
1724 {
1725 GimpImageWindowPrivate *private;
1726
1727 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1728
1729 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1730
1731 private->suspend_keep_pos++;
1732 }
1733
1734 void
gimp_image_window_resume_keep_pos(GimpImageWindow * window)1735 gimp_image_window_resume_keep_pos (GimpImageWindow *window)
1736 {
1737 GimpImageWindowPrivate *private;
1738
1739 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1740
1741 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1742
1743 g_return_if_fail (private->suspend_keep_pos > 0);
1744
1745 private->suspend_keep_pos--;
1746 }
1747
1748 /**
1749 * gimp_image_window_update_tabs:
1750 * @window: the Image Window to update.
1751 *
1752 * Holds the logics of whether shell tabs are to be shown or not in the
1753 * Image Window @window. This function should be called after every
1754 * change to @window where one might expect tab visibility to change.
1755 *
1756 * No direct call to gtk_notebook_set_show_tabs() should ever be made.
1757 * If we change the logics of tab hiding, we should only change this
1758 * procedure instead.
1759 **/
1760 void
gimp_image_window_update_tabs(GimpImageWindow * window)1761 gimp_image_window_update_tabs (GimpImageWindow *window)
1762 {
1763 GimpImageWindowPrivate *private;
1764 GimpGuiConfig *config;
1765 GtkPositionType position;
1766
1767 g_return_if_fail (GIMP_IS_IMAGE_WINDOW (window));
1768
1769 private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1770 config = GIMP_GUI_CONFIG (private->gimp->config);
1771
1772 /* Tab visibility. */
1773 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (private->notebook),
1774 config->single_window_mode &&
1775 config->show_tabs &&
1776 ! config->hide_docks &&
1777 ((private->active_shell &&
1778 private->active_shell->display &&
1779 gimp_display_get_image (private->active_shell->display)) ||
1780 g_list_length (private->shells) > 1));
1781
1782 /* Tab position. */
1783 switch (config->tabs_position)
1784 {
1785 case GIMP_POSITION_TOP:
1786 position = GTK_POS_TOP;
1787 break;
1788 case GIMP_POSITION_BOTTOM:
1789 position = GTK_POS_BOTTOM;
1790 break;
1791 case GIMP_POSITION_LEFT:
1792 position = GTK_POS_LEFT;
1793 break;
1794 case GIMP_POSITION_RIGHT:
1795 position = GTK_POS_RIGHT;
1796 break;
1797 default:
1798 /* If we have any strange value, just reset to default. */
1799 position = GTK_POS_TOP;
1800 break;
1801 }
1802
1803 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (private->notebook), position);
1804 }
1805
1806
1807 /* private functions */
1808
1809 static void
gimp_image_window_show_tooltip(GimpUIManager * manager,const gchar * tooltip,GimpImageWindow * window)1810 gimp_image_window_show_tooltip (GimpUIManager *manager,
1811 const gchar *tooltip,
1812 GimpImageWindow *window)
1813 {
1814 GimpDisplayShell *shell = gimp_image_window_get_active_shell (window);
1815 GimpStatusbar *statusbar = NULL;
1816
1817 if (! shell)
1818 return;
1819
1820 statusbar = gimp_display_shell_get_statusbar (shell);
1821
1822 gimp_statusbar_push (statusbar, "menu-tooltip",
1823 NULL, "%s", tooltip);
1824 }
1825
1826 static void
gimp_image_window_config_notify(GimpImageWindow * window,GParamSpec * pspec,GimpGuiConfig * config)1827 gimp_image_window_config_notify (GimpImageWindow *window,
1828 GParamSpec *pspec,
1829 GimpGuiConfig *config)
1830 {
1831 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1832
1833 /* Dock column visibility */
1834 if (strcmp (pspec->name, "single-window-mode") == 0 ||
1835 strcmp (pspec->name, "hide-docks") == 0 ||
1836 strcmp (pspec->name, "show-tabs") == 0 ||
1837 strcmp (pspec->name, "tabs-position") == 0)
1838 {
1839 if (strcmp (pspec->name, "single-window-mode") == 0 ||
1840 strcmp (pspec->name, "hide-docks") == 0)
1841 {
1842 gboolean show_docks = (config->single_window_mode &&
1843 ! config->hide_docks);
1844
1845 gimp_image_window_keep_canvas_pos (window);
1846 gtk_widget_set_visible (private->left_docks, show_docks);
1847 gtk_widget_set_visible (private->right_docks, show_docks);
1848
1849 /* If docks are being shown, and we are in multi-window-mode,
1850 * and this is the window of the active display, try to set
1851 * the keyboard focus to this window because it might have
1852 * been stolen by a dock. See bug #567333.
1853 */
1854 if (strcmp (pspec->name, "hide-docks") == 0 &&
1855 ! config->single_window_mode &&
1856 ! config->hide_docks)
1857 {
1858 GimpDisplayShell *shell;
1859 GimpContext *user_context;
1860
1861 shell = gimp_image_window_get_active_shell (window);
1862 user_context = gimp_get_user_context (private->gimp);
1863
1864 if (gimp_context_get_display (user_context) == shell->display)
1865 {
1866 GdkWindow *w = gtk_widget_get_window (GTK_WIDGET (window));
1867
1868 if (w)
1869 gdk_window_focus (w, gtk_get_current_event_time ());
1870 }
1871 }
1872 }
1873
1874 gimp_image_window_update_tabs (window);
1875 }
1876
1877 /* Session management */
1878 if (strcmp (pspec->name, "single-window-mode") == 0)
1879 {
1880 gimp_image_window_session_update (window,
1881 NULL /*new_display*/,
1882 gimp_image_window_config_to_entry_id (config),
1883 gtk_widget_get_screen (GTK_WIDGET (window)),
1884 gimp_widget_get_monitor (GTK_WIDGET (window)));
1885 }
1886 }
1887
1888 static void
gimp_image_window_hide_tooltip(GimpUIManager * manager,GimpImageWindow * window)1889 gimp_image_window_hide_tooltip (GimpUIManager *manager,
1890 GimpImageWindow *window)
1891 {
1892 GimpDisplayShell *shell = gimp_image_window_get_active_shell (window);
1893 GimpStatusbar *statusbar = NULL;
1894
1895 if (! shell)
1896 return;
1897
1898 statusbar = gimp_display_shell_get_statusbar (shell);
1899
1900 gimp_statusbar_pop (statusbar, "menu-tooltip");
1901 }
1902
1903 static gboolean
gimp_image_window_update_ui_manager_idle(GimpImageWindow * window)1904 gimp_image_window_update_ui_manager_idle (GimpImageWindow *window)
1905 {
1906 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1907
1908 gimp_assert (private->active_shell != NULL);
1909
1910 gimp_ui_manager_update (private->menubar_manager,
1911 private->active_shell->display);
1912
1913 private->update_ui_manager_idle_id = 0;
1914
1915 return G_SOURCE_REMOVE;
1916 }
1917
1918 static void
gimp_image_window_update_ui_manager(GimpImageWindow * window)1919 gimp_image_window_update_ui_manager (GimpImageWindow *window)
1920 {
1921 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1922
1923 if (! private->update_ui_manager_idle_id)
1924 {
1925 private->update_ui_manager_idle_id =
1926 g_idle_add_full (GIMP_PRIORITY_IMAGE_WINDOW_UPDATE_UI_MANAGER_IDLE,
1927 (GSourceFunc) gimp_image_window_update_ui_manager_idle,
1928 window,
1929 NULL);
1930 }
1931 }
1932
1933 static void
gimp_image_window_shell_size_allocate(GimpDisplayShell * shell,GtkAllocation * allocation,PosCorrectionData * data)1934 gimp_image_window_shell_size_allocate (GimpDisplayShell *shell,
1935 GtkAllocation *allocation,
1936 PosCorrectionData *data)
1937 {
1938 GimpImageWindow *window = gimp_display_shell_get_window (shell);
1939 gint new_window_x;
1940 gint new_window_y;
1941
1942 if (gtk_widget_translate_coordinates (GTK_WIDGET (shell->canvas),
1943 GTK_WIDGET (window),
1944 data->canvas_x, data->canvas_y,
1945 &new_window_x, &new_window_y))
1946 {
1947 gint off_x = new_window_x - data->window_x;
1948 gint off_y = new_window_y - data->window_y;
1949
1950 if (off_x || off_y)
1951 gimp_display_shell_scroll (shell, off_x, off_y);
1952 }
1953
1954 g_signal_handlers_disconnect_by_func (shell,
1955 gimp_image_window_shell_size_allocate,
1956 data);
1957 }
1958
1959 static gboolean
gimp_image_window_shell_events(GtkWidget * widget,GdkEvent * event,GimpImageWindow * window)1960 gimp_image_window_shell_events (GtkWidget *widget,
1961 GdkEvent *event,
1962 GimpImageWindow *window)
1963 {
1964 GimpDisplayShell *shell = gimp_image_window_get_active_shell (window);
1965
1966 if (! shell)
1967 return FALSE;
1968
1969 return gimp_display_shell_events (widget, event, shell);
1970 }
1971
1972 static void
gimp_image_window_switch_page(GtkNotebook * notebook,gpointer page,gint page_num,GimpImageWindow * window)1973 gimp_image_window_switch_page (GtkNotebook *notebook,
1974 gpointer page,
1975 gint page_num,
1976 GimpImageWindow *window)
1977 {
1978 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
1979 GimpDisplayShell *shell;
1980 GimpDisplay *active_display;
1981
1982 shell = GIMP_DISPLAY_SHELL (gtk_notebook_get_nth_page (notebook, page_num));
1983
1984 if (shell == private->active_shell)
1985 return;
1986
1987 gimp_image_window_disconnect_from_active_shell (window);
1988
1989 GIMP_LOG (WM, "GimpImageWindow %p, private->active_shell = %p; \n",
1990 window, shell);
1991 private->active_shell = shell;
1992
1993 gimp_window_set_primary_focus_widget (GIMP_WINDOW (window),
1994 shell->canvas);
1995
1996 active_display = private->active_shell->display;
1997
1998 g_signal_connect (active_display, "notify::image",
1999 G_CALLBACK (gimp_image_window_image_notify),
2000 window);
2001
2002 g_signal_connect (private->active_shell, "scaled",
2003 G_CALLBACK (gimp_image_window_shell_scaled),
2004 window);
2005 g_signal_connect (private->active_shell, "rotated",
2006 G_CALLBACK (gimp_image_window_shell_rotated),
2007 window);
2008 g_signal_connect (private->active_shell, "notify::title",
2009 G_CALLBACK (gimp_image_window_shell_title_notify),
2010 window);
2011 g_signal_connect (private->active_shell, "notify::icon",
2012 G_CALLBACK (gimp_image_window_shell_icon_notify),
2013 window);
2014
2015 gtk_window_set_title (GTK_WINDOW (window), shell->title);
2016 gtk_window_set_icon (GTK_WINDOW (window), shell->icon);
2017
2018 gimp_display_shell_appearance_update (private->active_shell);
2019
2020 if (gtk_widget_get_window (GTK_WIDGET (window)))
2021 {
2022 /* we are fully initialized, use the window's current monitor
2023 */
2024 gimp_image_window_session_update (window,
2025 active_display,
2026 NULL /*new_entry_id*/,
2027 gtk_widget_get_screen (GTK_WIDGET (window)),
2028 gimp_widget_get_monitor (GTK_WIDGET (window)));
2029 }
2030 else
2031 {
2032 /* we are in construction, use the initial monitor; calling
2033 * gimp_widget_get_monitor() would get us the monitor where the
2034 * pointer is
2035 */
2036 gimp_image_window_session_update (window,
2037 active_display,
2038 NULL /*new_entry_id*/,
2039 private->initial_screen,
2040 private->initial_monitor);
2041 }
2042
2043 gimp_context_set_display (gimp_get_user_context (private->gimp),
2044 active_display);
2045
2046 gimp_image_window_update_ui_manager (window);
2047
2048 gimp_image_window_update_tab_labels (window);
2049 }
2050
2051 static void
gimp_image_window_page_removed(GtkNotebook * notebook,GtkWidget * widget,gint page_num,GimpImageWindow * window)2052 gimp_image_window_page_removed (GtkNotebook *notebook,
2053 GtkWidget *widget,
2054 gint page_num,
2055 GimpImageWindow *window)
2056 {
2057 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
2058
2059 if (GTK_WIDGET (private->active_shell) == widget)
2060 {
2061 GIMP_LOG (WM, "GimpImageWindow %p, private->active_shell = %p; \n",
2062 window, NULL);
2063 gimp_image_window_disconnect_from_active_shell (window);
2064 private->active_shell = NULL;
2065 }
2066 }
2067
2068 static void
gimp_image_window_page_reordered(GtkNotebook * notebook,GtkWidget * widget,gint page_num,GimpImageWindow * window)2069 gimp_image_window_page_reordered (GtkNotebook *notebook,
2070 GtkWidget *widget,
2071 gint page_num,
2072 GimpImageWindow *window)
2073 {
2074 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
2075 GimpContainer *displays = private->gimp->displays;
2076 gint index = g_list_index (private->shells, widget);
2077
2078 if (index != page_num)
2079 {
2080 private->shells = g_list_remove (private->shells, widget);
2081 private->shells = g_list_insert (private->shells, widget, page_num);
2082 }
2083
2084 /* We need to reorder the displays as well in order to update the
2085 * numbered accelerators (alt-1, alt-2, etc.).
2086 */
2087 gimp_container_reorder (displays,
2088 GIMP_OBJECT (GIMP_DISPLAY_SHELL (widget)->display),
2089 page_num);
2090
2091 gtk_notebook_reorder_child (notebook, widget, page_num);
2092 }
2093
2094 static void
gimp_image_window_disconnect_from_active_shell(GimpImageWindow * window)2095 gimp_image_window_disconnect_from_active_shell (GimpImageWindow *window)
2096 {
2097 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
2098 GimpDisplay *active_display = NULL;
2099
2100 if (! private->active_shell)
2101 return;
2102
2103 active_display = private->active_shell->display;
2104
2105 if (active_display)
2106 g_signal_handlers_disconnect_by_func (active_display,
2107 gimp_image_window_image_notify,
2108 window);
2109
2110 g_signal_handlers_disconnect_by_func (private->active_shell,
2111 gimp_image_window_shell_scaled,
2112 window);
2113 g_signal_handlers_disconnect_by_func (private->active_shell,
2114 gimp_image_window_shell_rotated,
2115 window);
2116 g_signal_handlers_disconnect_by_func (private->active_shell,
2117 gimp_image_window_shell_title_notify,
2118 window);
2119 g_signal_handlers_disconnect_by_func (private->active_shell,
2120 gimp_image_window_shell_icon_notify,
2121 window);
2122
2123 if (private->menubar_manager)
2124 gimp_image_window_hide_tooltip (private->menubar_manager, window);
2125
2126 if (private->update_ui_manager_idle_id)
2127 {
2128 g_source_remove (private->update_ui_manager_idle_id);
2129 private->update_ui_manager_idle_id = 0;
2130 }
2131 }
2132
2133 static void
gimp_image_window_image_notify(GimpDisplay * display,const GParamSpec * pspec,GimpImageWindow * window)2134 gimp_image_window_image_notify (GimpDisplay *display,
2135 const GParamSpec *pspec,
2136 GimpImageWindow *window)
2137 {
2138 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
2139 GtkWidget *tab_label;
2140 GList *children;
2141 GtkWidget *view;
2142
2143 gimp_image_window_session_update (window,
2144 display,
2145 NULL /*new_entry_id*/,
2146 gtk_widget_get_screen (GTK_WIDGET (window)),
2147 gimp_widget_get_monitor (GTK_WIDGET (window)));
2148
2149 tab_label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (private->notebook),
2150 GTK_WIDGET (gimp_display_get_shell (display)));
2151 children = gtk_container_get_children (GTK_CONTAINER (tab_label));
2152 view = GTK_WIDGET (children->data);
2153 g_list_free (children);
2154
2155 gimp_view_set_viewable (GIMP_VIEW (view),
2156 GIMP_VIEWABLE (gimp_display_get_image (display)));
2157
2158 gimp_image_window_update_ui_manager (window);
2159 }
2160
2161 static void
gimp_image_window_session_clear(GimpImageWindow * window)2162 gimp_image_window_session_clear (GimpImageWindow *window)
2163 {
2164 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
2165 GtkWidget *widget = GTK_WIDGET (window);
2166
2167 if (gimp_dialog_factory_from_widget (widget, NULL))
2168 gimp_dialog_factory_remove_dialog (private->dialog_factory,
2169 widget);
2170 }
2171
2172 static void
gimp_image_window_session_apply(GimpImageWindow * window,const gchar * entry_id,GdkScreen * screen,gint monitor)2173 gimp_image_window_session_apply (GimpImageWindow *window,
2174 const gchar *entry_id,
2175 GdkScreen *screen,
2176 gint monitor)
2177 {
2178 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
2179 GimpSessionInfo *session_info = NULL;
2180 gint width = -1;
2181 gint height = -1;
2182
2183 gtk_window_unfullscreen (GTK_WINDOW (window));
2184
2185 /* get the NIW size before adding the display to the dialog
2186 * factory so the window's current size doesn't affect the
2187 * stored session info entry.
2188 */
2189 session_info =
2190 gimp_dialog_factory_find_session_info (private->dialog_factory, entry_id);
2191
2192 if (session_info)
2193 {
2194 width = gimp_session_info_get_width (session_info);
2195 height = gimp_session_info_get_height (session_info);
2196 }
2197 else
2198 {
2199 GtkAllocation allocation;
2200
2201 gtk_widget_get_allocation (GTK_WIDGET (window), &allocation);
2202
2203 width = allocation.width;
2204 height = allocation.height;
2205 }
2206
2207 gimp_dialog_factory_add_foreign (private->dialog_factory,
2208 entry_id,
2209 GTK_WIDGET (window),
2210 screen,
2211 monitor);
2212
2213 gtk_window_unmaximize (GTK_WINDOW (window));
2214 gtk_window_resize (GTK_WINDOW (window), width, height);
2215 }
2216
2217 static void
gimp_image_window_session_update(GimpImageWindow * window,GimpDisplay * new_display,const gchar * new_entry_id,GdkScreen * screen,gint monitor)2218 gimp_image_window_session_update (GimpImageWindow *window,
2219 GimpDisplay *new_display,
2220 const gchar *new_entry_id,
2221 GdkScreen *screen,
2222 gint monitor)
2223 {
2224 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
2225
2226 /* Handle changes to the entry id */
2227 if (new_entry_id)
2228 {
2229 if (! private->entry_id)
2230 {
2231 /* We're initializing. If we're in single-window mode, this
2232 * will be the only window, so start to session manage
2233 * it. If we're in multi-window mode, we will find out if we
2234 * should session manage ourselves when we get a display
2235 */
2236 if (strcmp (new_entry_id, GIMP_SINGLE_IMAGE_WINDOW_ENTRY_ID) == 0)
2237 {
2238 gimp_image_window_session_apply (window, new_entry_id,
2239 screen, monitor);
2240 }
2241 }
2242 else if (strcmp (private->entry_id, new_entry_id) != 0)
2243 {
2244 /* The entry id changed, immediately and always stop session
2245 * managing the old entry
2246 */
2247 gimp_image_window_session_clear (window);
2248
2249 if (strcmp (new_entry_id, GIMP_EMPTY_IMAGE_WINDOW_ENTRY_ID) == 0)
2250 {
2251 /* If there is only one imageless display, we shall
2252 * become the empty image window
2253 */
2254 if (private->active_shell &&
2255 private->active_shell->display &&
2256 ! gimp_display_get_image (private->active_shell->display) &&
2257 g_list_length (private->shells) <= 1)
2258 {
2259 gimp_image_window_session_apply (window, new_entry_id,
2260 screen, monitor);
2261 }
2262 }
2263 else if (strcmp (new_entry_id, GIMP_SINGLE_IMAGE_WINDOW_ENTRY_ID) == 0)
2264 {
2265 /* As soon as we become the single image window, we
2266 * shall session manage ourself until single-window mode
2267 * is exited
2268 */
2269 gimp_image_window_session_apply (window, new_entry_id,
2270 screen, monitor);
2271 }
2272 }
2273
2274 private->entry_id = new_entry_id;
2275 }
2276
2277 /* Handle changes to the displays. When in single-window mode, we
2278 * just keep session managing the single image window. We only need
2279 * to care about the multi-window mode case here
2280 */
2281 if (new_display &&
2282 strcmp (private->entry_id, GIMP_EMPTY_IMAGE_WINDOW_ENTRY_ID) == 0)
2283 {
2284 if (gimp_display_get_image (new_display))
2285 {
2286 /* As soon as we have an image we should not affect the size of the
2287 * empty image window
2288 */
2289 gimp_image_window_session_clear (window);
2290 }
2291 else if (! gimp_display_get_image (new_display) &&
2292 g_list_length (private->shells) <= 1)
2293 {
2294 /* As soon as we have no image (and no other shells that may
2295 * contain images) we should become the empty image window
2296 */
2297 gimp_image_window_session_apply (window, private->entry_id,
2298 screen, monitor);
2299 }
2300 }
2301 }
2302
2303 static const gchar *
gimp_image_window_config_to_entry_id(GimpGuiConfig * config)2304 gimp_image_window_config_to_entry_id (GimpGuiConfig *config)
2305 {
2306 return (config->single_window_mode ?
2307 GIMP_SINGLE_IMAGE_WINDOW_ENTRY_ID :
2308 GIMP_EMPTY_IMAGE_WINDOW_ENTRY_ID);
2309 }
2310
2311 static void
gimp_image_window_shell_scaled(GimpDisplayShell * shell,GimpImageWindow * window)2312 gimp_image_window_shell_scaled (GimpDisplayShell *shell,
2313 GimpImageWindow *window)
2314 {
2315 /* update the <Image>/View/Zoom menu */
2316 gimp_image_window_update_ui_manager (window);
2317 }
2318
2319 static void
gimp_image_window_shell_rotated(GimpDisplayShell * shell,GimpImageWindow * window)2320 gimp_image_window_shell_rotated (GimpDisplayShell *shell,
2321 GimpImageWindow *window)
2322 {
2323 /* update the <Image>/View/Rotate menu */
2324 gimp_image_window_update_ui_manager (window);
2325 }
2326
2327 static void
gimp_image_window_shell_title_notify(GimpDisplayShell * shell,const GParamSpec * pspec,GimpImageWindow * window)2328 gimp_image_window_shell_title_notify (GimpDisplayShell *shell,
2329 const GParamSpec *pspec,
2330 GimpImageWindow *window)
2331 {
2332 gtk_window_set_title (GTK_WINDOW (window), shell->title);
2333 }
2334
2335 static void
gimp_image_window_shell_icon_notify(GimpDisplayShell * shell,const GParamSpec * pspec,GimpImageWindow * window)2336 gimp_image_window_shell_icon_notify (GimpDisplayShell *shell,
2337 const GParamSpec *pspec,
2338 GimpImageWindow *window)
2339 {
2340 gtk_window_set_icon (GTK_WINDOW (window), shell->icon);
2341 }
2342
2343 static void
gimp_image_window_shell_close_button_callback(GimpDisplayShell * shell)2344 gimp_image_window_shell_close_button_callback (GimpDisplayShell *shell)
2345 {
2346 if (shell)
2347 gimp_display_shell_close (shell, FALSE);
2348 }
2349
2350 static GtkWidget *
gimp_image_window_create_tab_label(GimpImageWindow * window,GimpDisplayShell * shell)2351 gimp_image_window_create_tab_label (GimpImageWindow *window,
2352 GimpDisplayShell *shell)
2353 {
2354 GtkWidget *hbox;
2355 GtkWidget *view;
2356 GimpImage *image;
2357 GtkWidget *button;
2358 GtkWidget *gtk_image;
2359
2360 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
2361 gtk_widget_show (hbox);
2362
2363 view = gimp_view_new_by_types (gimp_get_user_context (shell->display->gimp),
2364 GIMP_TYPE_VIEW, GIMP_TYPE_IMAGE,
2365 GIMP_VIEW_SIZE_LARGE, 0, FALSE);
2366 gtk_widget_set_size_request (view, GIMP_VIEW_SIZE_LARGE, -1);
2367 gimp_view_renderer_set_color_config (GIMP_VIEW (view)->renderer,
2368 gimp_display_shell_get_color_config (shell));
2369 gtk_box_pack_start (GTK_BOX (hbox), view, FALSE, FALSE, 0);
2370 gtk_widget_show (view);
2371
2372 image = gimp_display_get_image (shell->display);
2373 if (image)
2374 gimp_view_set_viewable (GIMP_VIEW (view), GIMP_VIEWABLE (image));
2375
2376 button = gtk_button_new ();
2377 gtk_widget_set_can_focus (button, FALSE);
2378 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2379 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
2380 gtk_widget_show (button);
2381
2382 gtk_image = gtk_image_new_from_icon_name (GIMP_ICON_CLOSE,
2383 GTK_ICON_SIZE_MENU);
2384 gtk_container_add (GTK_CONTAINER (button), gtk_image);
2385 gtk_widget_show (gtk_image);
2386
2387 g_signal_connect_swapped (button, "clicked",
2388 G_CALLBACK (gimp_image_window_shell_close_button_callback),
2389 shell);
2390
2391 g_object_set_data (G_OBJECT (hbox), "close-button", button);
2392
2393 return hbox;
2394 }
2395
2396 static void
gimp_image_window_update_tab_labels(GimpImageWindow * window)2397 gimp_image_window_update_tab_labels (GimpImageWindow *window)
2398 {
2399 GimpImageWindowPrivate *private = GIMP_IMAGE_WINDOW_GET_PRIVATE (window);
2400 GList *children;
2401 GList *list;
2402
2403 children = gtk_container_get_children (GTK_CONTAINER (private->notebook));
2404
2405 for (list = children; list; list = g_list_next (list))
2406 {
2407 GtkWidget *shell = list->data;
2408 GtkWidget *tab_widget;
2409 GtkWidget *close_button;
2410
2411 tab_widget = gtk_notebook_get_tab_label (GTK_NOTEBOOK (private->notebook),
2412 shell);
2413
2414 close_button = g_object_get_data (G_OBJECT (tab_widget), "close-button");
2415
2416 if (gimp_context_get_display (gimp_get_user_context (private->gimp)) ==
2417 GIMP_DISPLAY_SHELL (shell)->display)
2418 {
2419 gtk_widget_show (close_button);
2420 }
2421 else
2422 {
2423 gtk_widget_hide (close_button);
2424 }
2425 }
2426
2427 g_list_free (children);
2428 }
2429