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 <string.h>
21 #include <stdlib.h>
22 
23 #include <gegl.h>
24 #include <gtk/gtk.h>
25 
26 #include "libgimpbase/gimpbase.h"
27 #include "libgimpmath/gimpmath.h"
28 #include "libgimpcolor/gimpcolor.h"
29 #include "libgimpconfig/gimpconfig.h"
30 #include "libgimpwidgets/gimpwidgets.h"
31 
32 #include "display-types.h"
33 #include "tools/tools-types.h"
34 
35 #include "config/gimpcoreconfig.h"
36 #include "config/gimpdisplayconfig.h"
37 #include "config/gimpdisplayoptions.h"
38 
39 #include "core/gimp.h"
40 #include "core/gimp-utils.h"
41 #include "core/gimpchannel.h"
42 #include "core/gimpcontext.h"
43 #include "core/gimpimage.h"
44 #include "core/gimpimage-grid.h"
45 #include "core/gimpimage-guides.h"
46 #include "core/gimpimage-snap.h"
47 #include "core/gimppickable.h"
48 #include "core/gimpprojectable.h"
49 #include "core/gimpprojection.h"
50 #include "core/gimpmarshal.h"
51 #include "core/gimptemplate.h"
52 
53 #include "widgets/gimpdevices.h"
54 #include "widgets/gimphelp-ids.h"
55 #include "widgets/gimpuimanager.h"
56 #include "widgets/gimpwidgets-utils.h"
57 
58 #include "tools/tool_manager.h"
59 
60 #include "gimpcanvas.h"
61 #include "gimpcanvascanvasboundary.h"
62 #include "gimpcanvaslayerboundary.h"
63 #include "gimpdisplay.h"
64 #include "gimpdisplayshell.h"
65 #include "gimpdisplayshell-appearance.h"
66 #include "gimpdisplayshell-callbacks.h"
67 #include "gimpdisplayshell-cursor.h"
68 #include "gimpdisplayshell-dnd.h"
69 #include "gimpdisplayshell-expose.h"
70 #include "gimpdisplayshell-filter.h"
71 #include "gimpdisplayshell-handlers.h"
72 #include "gimpdisplayshell-items.h"
73 #include "gimpdisplayshell-profile.h"
74 #include "gimpdisplayshell-progress.h"
75 #include "gimpdisplayshell-render.h"
76 #include "gimpdisplayshell-rotate.h"
77 #include "gimpdisplayshell-rulers.h"
78 #include "gimpdisplayshell-scale.h"
79 #include "gimpdisplayshell-scroll.h"
80 #include "gimpdisplayshell-scrollbars.h"
81 #include "gimpdisplayshell-selection.h"
82 #include "gimpdisplayshell-title.h"
83 #include "gimpdisplayshell-tool-events.h"
84 #include "gimpdisplayshell-transform.h"
85 #include "gimpimagewindow.h"
86 #include "gimpmotionbuffer.h"
87 #include "gimpstatusbar.h"
88 
89 #include "about.h"
90 #include "gimp-log.h"
91 #include "gimp-priorities.h"
92 
93 #include "gimp-intl.h"
94 
95 
96 enum
97 {
98   PROP_0,
99   PROP_POPUP_MANAGER,
100   PROP_INITIAL_SCREEN,
101   PROP_INITIAL_MONITOR,
102   PROP_DISPLAY,
103   PROP_UNIT,
104   PROP_TITLE,
105   PROP_STATUS,
106   PROP_ICON,
107   PROP_SHOW_ALL,
108   PROP_INFINITE_CANVAS
109 };
110 
111 enum
112 {
113   SCALED,
114   SCROLLED,
115   ROTATED,
116   RECONNECT,
117   LAST_SIGNAL
118 };
119 
120 
121 typedef struct _GimpDisplayShellOverlay GimpDisplayShellOverlay;
122 
123 struct _GimpDisplayShellOverlay
124 {
125   gdouble          image_x;
126   gdouble          image_y;
127   GimpHandleAnchor anchor;
128   gint             spacing_x;
129   gint             spacing_y;
130 };
131 
132 
133 /*  local function prototypes  */
134 
135 static void      gimp_color_managed_iface_init     (GimpColorManagedInterface *iface);
136 
137 static void      gimp_display_shell_constructed    (GObject          *object);
138 static void      gimp_display_shell_dispose        (GObject          *object);
139 static void      gimp_display_shell_finalize       (GObject          *object);
140 static void      gimp_display_shell_set_property   (GObject          *object,
141                                                     guint             property_id,
142                                                     const GValue     *value,
143                                                     GParamSpec       *pspec);
144 static void      gimp_display_shell_get_property   (GObject          *object,
145                                                     guint             property_id,
146                                                     GValue           *value,
147                                                     GParamSpec       *pspec);
148 
149 static void      gimp_display_shell_unrealize      (GtkWidget        *widget);
150 static void      gimp_display_shell_unmap          (GtkWidget        *widget);
151 static void      gimp_display_shell_screen_changed (GtkWidget        *widget,
152                                                     GdkScreen        *previous);
153 static gboolean  gimp_display_shell_popup_menu     (GtkWidget        *widget);
154 
155 static void      gimp_display_shell_real_scaled    (GimpDisplayShell *shell);
156 static void      gimp_display_shell_real_scrolled  (GimpDisplayShell *shell);
157 static void      gimp_display_shell_real_rotated   (GimpDisplayShell *shell);
158 
159 static const guint8 *
160                  gimp_display_shell_get_icc_profile(GimpColorManaged *managed,
161                                                     gsize            *len);
162 static GimpColorProfile *
163                gimp_display_shell_get_color_profile(GimpColorManaged *managed);
164 static void      gimp_display_shell_profile_changed(GimpColorManaged *managed);
165 
166 static void      gimp_display_shell_menu_position  (GtkMenu          *menu,
167                                                     gint             *x,
168                                                     gint             *y,
169                                                     gpointer          data);
170 static void      gimp_display_shell_zoom_button_callback
171                                                    (GimpDisplayShell *shell,
172                                                     GtkWidget        *zoom_button);
173 static void      gimp_display_shell_sync_config    (GimpDisplayShell  *shell,
174                                                     GimpDisplayConfig *config);
175 
176 static void      gimp_display_shell_remove_overlay (GtkWidget        *canvas,
177                                                     GtkWidget        *child,
178                                                     GimpDisplayShell *shell);
179 static void   gimp_display_shell_transform_overlay (GimpDisplayShell *shell,
180                                                     GtkWidget        *child,
181                                                     gdouble          *x,
182                                                     gdouble          *y);
183 
184 
185 G_DEFINE_TYPE_WITH_CODE (GimpDisplayShell, gimp_display_shell,
186                          GTK_TYPE_EVENT_BOX,
187                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_PROGRESS,
188                                                 gimp_display_shell_progress_iface_init)
189                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_COLOR_MANAGED,
190                                                 gimp_color_managed_iface_init))
191 
192 
193 #define parent_class gimp_display_shell_parent_class
194 
195 static guint display_shell_signals[LAST_SIGNAL] = { 0 };
196 
197 
198 static const gchar display_rc_style[] =
199   "style \"check-button-style\"\n"
200   "{\n"
201   "  GtkToggleButton::child-displacement-x = 0\n"
202   "  GtkToggleButton::child-displacement-y = 0\n"
203   "}\n"
204   "widget \"*\" style \"check-button-style\"";
205 
206 static void
gimp_display_shell_class_init(GimpDisplayShellClass * klass)207 gimp_display_shell_class_init (GimpDisplayShellClass *klass)
208 {
209   GObjectClass   *object_class = G_OBJECT_CLASS (klass);
210   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
211 
212   display_shell_signals[SCALED] =
213     g_signal_new ("scaled",
214                   G_TYPE_FROM_CLASS (klass),
215                   G_SIGNAL_RUN_FIRST,
216                   G_STRUCT_OFFSET (GimpDisplayShellClass, scaled),
217                   NULL, NULL,
218                   gimp_marshal_VOID__VOID,
219                   G_TYPE_NONE, 0);
220 
221   display_shell_signals[SCROLLED] =
222     g_signal_new ("scrolled",
223                   G_TYPE_FROM_CLASS (klass),
224                   G_SIGNAL_RUN_FIRST,
225                   G_STRUCT_OFFSET (GimpDisplayShellClass, scrolled),
226                   NULL, NULL,
227                   gimp_marshal_VOID__VOID,
228                   G_TYPE_NONE, 0);
229 
230   display_shell_signals[ROTATED] =
231     g_signal_new ("rotated",
232                   G_TYPE_FROM_CLASS (klass),
233                   G_SIGNAL_RUN_FIRST,
234                   G_STRUCT_OFFSET (GimpDisplayShellClass, rotated),
235                   NULL, NULL,
236                   gimp_marshal_VOID__VOID,
237                   G_TYPE_NONE, 0);
238 
239   display_shell_signals[RECONNECT] =
240     g_signal_new ("reconnect",
241                   G_TYPE_FROM_CLASS (klass),
242                   G_SIGNAL_RUN_FIRST,
243                   G_STRUCT_OFFSET (GimpDisplayShellClass, reconnect),
244                   NULL, NULL,
245                   gimp_marshal_VOID__VOID,
246                   G_TYPE_NONE, 0);
247 
248   object_class->constructed        = gimp_display_shell_constructed;
249   object_class->dispose            = gimp_display_shell_dispose;
250   object_class->finalize           = gimp_display_shell_finalize;
251   object_class->set_property       = gimp_display_shell_set_property;
252   object_class->get_property       = gimp_display_shell_get_property;
253 
254   widget_class->unrealize          = gimp_display_shell_unrealize;
255   widget_class->unmap              = gimp_display_shell_unmap;
256   widget_class->screen_changed     = gimp_display_shell_screen_changed;
257   widget_class->popup_menu         = gimp_display_shell_popup_menu;
258 
259   klass->scaled                    = gimp_display_shell_real_scaled;
260   klass->scrolled                  = gimp_display_shell_real_scrolled;
261   klass->rotated                   = gimp_display_shell_real_rotated;
262   klass->reconnect                 = NULL;
263 
264   g_object_class_install_property (object_class, PROP_POPUP_MANAGER,
265                                    g_param_spec_object ("popup-manager",
266                                                         NULL, NULL,
267                                                         GIMP_TYPE_UI_MANAGER,
268                                                         GIMP_PARAM_READWRITE |
269                                                         G_PARAM_CONSTRUCT_ONLY));
270 
271   g_object_class_install_property (object_class, PROP_INITIAL_SCREEN,
272                                    g_param_spec_object ("initial-screen",
273                                                         NULL, NULL,
274                                                         GDK_TYPE_SCREEN,
275                                                         GIMP_PARAM_READWRITE |
276                                                         G_PARAM_CONSTRUCT_ONLY));
277 
278   g_object_class_install_property (object_class, PROP_INITIAL_MONITOR,
279                                    g_param_spec_int ("initial-monitor",
280                                                      NULL, NULL,
281                                                      0, 16, 0,
282                                                      GIMP_PARAM_READWRITE |
283                                                      G_PARAM_CONSTRUCT_ONLY));
284 
285   g_object_class_install_property (object_class, PROP_DISPLAY,
286                                    g_param_spec_object ("display", NULL, NULL,
287                                                         GIMP_TYPE_DISPLAY,
288                                                         GIMP_PARAM_READWRITE |
289                                                         G_PARAM_CONSTRUCT_ONLY));
290 
291   g_object_class_install_property (object_class, PROP_UNIT,
292                                    gimp_param_spec_unit ("unit", NULL, NULL,
293                                                          TRUE, FALSE,
294                                                          GIMP_UNIT_PIXEL,
295                                                          GIMP_PARAM_READWRITE));
296 
297   g_object_class_install_property (object_class, PROP_TITLE,
298                                    g_param_spec_string ("title", NULL, NULL,
299                                                         GIMP_NAME,
300                                                         GIMP_PARAM_READWRITE |
301                                                         G_PARAM_CONSTRUCT));
302 
303   g_object_class_install_property (object_class, PROP_STATUS,
304                                    g_param_spec_string ("status", NULL, NULL,
305                                                         NULL,
306                                                         GIMP_PARAM_READWRITE));
307 
308   g_object_class_install_property (object_class, PROP_ICON,
309                                    g_param_spec_object ("icon", NULL, NULL,
310                                                         GDK_TYPE_PIXBUF,
311                                                         GIMP_PARAM_READWRITE));
312 
313   g_object_class_install_property (object_class, PROP_SHOW_ALL,
314                                    g_param_spec_boolean ("show-all",
315                                                          NULL, NULL,
316                                                          FALSE,
317                                                          GIMP_PARAM_READWRITE));
318 
319   g_object_class_install_property (object_class, PROP_INFINITE_CANVAS,
320                                    g_param_spec_boolean ("infinite-canvas",
321                                                          NULL, NULL,
322                                                          FALSE,
323                                                          GIMP_PARAM_READABLE));
324 
325   gtk_rc_parse_string (display_rc_style);
326 }
327 
328 static void
gimp_color_managed_iface_init(GimpColorManagedInterface * iface)329 gimp_color_managed_iface_init (GimpColorManagedInterface *iface)
330 {
331   iface->get_icc_profile   = gimp_display_shell_get_icc_profile;
332   iface->get_color_profile = gimp_display_shell_get_color_profile;
333   iface->profile_changed   = gimp_display_shell_profile_changed;
334 }
335 
336 static void
gimp_display_shell_init(GimpDisplayShell * shell)337 gimp_display_shell_init (GimpDisplayShell *shell)
338 {
339   shell->options            = g_object_new (GIMP_TYPE_DISPLAY_OPTIONS, NULL);
340   shell->fullscreen_options = g_object_new (GIMP_TYPE_DISPLAY_OPTIONS_FULLSCREEN, NULL);
341   shell->no_image_options   = g_object_new (GIMP_TYPE_DISPLAY_OPTIONS_NO_IMAGE, NULL);
342 
343   shell->zoom        = gimp_zoom_model_new ();
344   shell->dot_for_dot = TRUE;
345   shell->scale_x     = 1.0;
346   shell->scale_y     = 1.0;
347 
348   shell->show_image  = TRUE;
349 
350   shell->show_all    = FALSE;
351 
352   gimp_display_shell_items_init (shell);
353 
354   shell->icon_size       = 128;
355   shell->icon_size_small = 96;
356 
357   shell->cursor_handedness = GIMP_HANDEDNESS_RIGHT;
358   shell->current_cursor    = (GimpCursorType) -1;
359   shell->tool_cursor       = GIMP_TOOL_CURSOR_NONE;
360   shell->cursor_modifier   = GIMP_CURSOR_MODIFIER_NONE;
361   shell->override_cursor   = (GimpCursorType) -1;
362 
363   shell->filter_format     = babl_format ("R'G'B'A float");
364 
365   shell->motion_buffer   = gimp_motion_buffer_new ();
366 
367   g_signal_connect (shell->motion_buffer, "stroke",
368                     G_CALLBACK (gimp_display_shell_buffer_stroke),
369                     shell);
370   g_signal_connect (shell->motion_buffer, "hover",
371                     G_CALLBACK (gimp_display_shell_buffer_hover),
372                     shell);
373 
374   shell->zoom_focus_pointer_queue = g_queue_new ();
375 
376   gtk_widget_set_events (GTK_WIDGET (shell), (GDK_POINTER_MOTION_MASK    |
377                                               GDK_BUTTON_PRESS_MASK      |
378                                               GDK_KEY_PRESS_MASK         |
379                                               GDK_KEY_RELEASE_MASK       |
380                                               GDK_FOCUS_CHANGE_MASK      |
381                                               GDK_VISIBILITY_NOTIFY_MASK |
382                                               GDK_SCROLL_MASK));
383 
384   /*  zoom model callback  */
385   g_signal_connect_swapped (shell->zoom, "zoomed",
386                             G_CALLBACK (gimp_display_shell_scale_update),
387                             shell);
388 
389   /*  active display callback  */
390   g_signal_connect (shell, "button-press-event",
391                     G_CALLBACK (gimp_display_shell_events),
392                     shell);
393   g_signal_connect (shell, "button-release-event",
394                     G_CALLBACK (gimp_display_shell_events),
395                     shell);
396   g_signal_connect (shell, "key-press-event",
397                     G_CALLBACK (gimp_display_shell_events),
398                     shell);
399 
400   gimp_help_connect (GTK_WIDGET (shell), gimp_standard_help_func,
401                      GIMP_HELP_IMAGE_WINDOW, NULL);
402 }
403 
404 static void
gimp_display_shell_constructed(GObject * object)405 gimp_display_shell_constructed (GObject *object)
406 {
407   GimpDisplayShell  *shell = GIMP_DISPLAY_SHELL (object);
408   GimpDisplayConfig *config;
409   GimpImage         *image;
410   GtkWidget         *main_vbox;
411   GtkWidget         *upper_hbox;
412   GtkWidget         *right_vbox;
413   GtkWidget         *lower_hbox;
414   GtkWidget         *inner_table;
415   GtkWidget         *gtk_image;
416   GimpAction        *action;
417   gint               image_width;
418   gint               image_height;
419   gint               shell_width;
420   gint               shell_height;
421 
422   G_OBJECT_CLASS (parent_class)->constructed (object);
423 
424   gimp_assert (GIMP_IS_UI_MANAGER (shell->popup_manager));
425   gimp_assert (GIMP_IS_DISPLAY (shell->display));
426 
427   config = shell->display->config;
428   image  = gimp_display_get_image (shell->display);
429 
430   gimp_display_shell_profile_init (shell);
431 
432   if (image)
433     {
434       image_width  = gimp_image_get_width  (image);
435       image_height = gimp_image_get_height (image);
436     }
437   else
438     {
439       /* These values are arbitrary. The width is determined by the
440        * menubar and the height is chosen to give a window aspect
441        * ratio of roughly 3:1 (as requested by the UI team).
442        */
443       image_width  = GIMP_DEFAULT_IMAGE_WIDTH;
444       image_height = GIMP_DEFAULT_IMAGE_HEIGHT / 3;
445     }
446 
447   shell->dot_for_dot = config->default_dot_for_dot;
448 
449   if (config->monitor_res_from_gdk)
450     {
451       gimp_get_monitor_resolution (shell->initial_screen,
452                                    shell->initial_monitor,
453                                    &shell->monitor_xres, &shell->monitor_yres);
454     }
455   else
456     {
457       shell->monitor_xres = config->monitor_xres;
458       shell->monitor_yres = config->monitor_yres;
459     }
460 
461   /* adjust the initial scale -- so that window fits on screen. */
462   if (image)
463     {
464       gimp_display_shell_set_initial_scale (shell, 1.0, //scale,
465                                             &shell_width, &shell_height);
466     }
467   else
468     {
469       shell_width  = -1;
470       shell_height = image_height;
471     }
472 
473   gimp_display_shell_sync_config (shell, config);
474 
475   /*  GtkTable widgets are not able to shrink a row/column correctly if
476    *  widgets are attached with GTK_EXPAND even if those widgets have
477    *  other rows/columns in their rowspan/colspan where they could
478    *  nicely expand without disturbing the row/column which is supposed
479    *  to shrink. --Mitch
480    *
481    *  Changed the packing to use hboxes and vboxes which behave nicer:
482    *
483    *  shell
484    *     |
485    *     +-- main_vbox
486    *            |
487    *            +-- upper_hbox
488    *            |      |
489    *            |      +-- inner_table
490    *            |      |      |
491    *            |      |      +-- origin
492    *            |      |      +-- hruler
493    *            |      |      +-- vruler
494    *            |      |      +-- canvas
495    *            |      |
496    *            |      +-- right_vbox
497    *            |             |
498    *            |             +-- zoom_on_resize_button
499    *            |             +-- vscrollbar
500    *            |
501    *            +-- lower_hbox
502    *            |      |
503    *            |      +-- quick_mask
504    *            |      +-- hscrollbar
505    *            |      +-- navbutton
506    *            |
507    *            +-- statusbar
508    *
509    *  Note that we separate "shell" and "main_vbox", so that we can make
510    *  "shell" a GtkEventBox, giving it its own window.  This isolates our
511    *  events from those of our ancestors, avoiding some potential slowdowns,
512    *  and making things generally smoother.  See bug #778966.
513    */
514 
515   /*  first, set up the container hierarchy  *********************************/
516 
517   /*  the root vbox  */
518 
519   main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
520   gtk_container_add (GTK_CONTAINER (shell), main_vbox);
521   gtk_widget_show (main_vbox);
522 
523   /*  a hbox for the inner_table and the vertical scrollbar  */
524   upper_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
525   gtk_box_pack_start (GTK_BOX (main_vbox), upper_hbox, TRUE, TRUE, 0);
526   gtk_widget_show (upper_hbox);
527 
528   /*  the table containing origin, rulers and the canvas  */
529   inner_table = gtk_table_new (2, 2, FALSE);
530   gtk_table_set_col_spacing (GTK_TABLE (inner_table), 0, 0);
531   gtk_table_set_row_spacing (GTK_TABLE (inner_table), 0, 0);
532   gtk_box_pack_start (GTK_BOX (upper_hbox), inner_table, TRUE, TRUE, 0);
533   gtk_widget_show (inner_table);
534 
535   /*  the vbox containing the color button and the vertical scrollbar  */
536   right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1);
537   gtk_box_pack_start (GTK_BOX (upper_hbox), right_vbox, FALSE, FALSE, 0);
538   gtk_widget_show (right_vbox);
539 
540   /*  the hbox containing the quickmask button, vertical scrollbar and
541    *  the navigation button
542    */
543   lower_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1);
544   gtk_box_pack_start (GTK_BOX (main_vbox), lower_hbox, FALSE, FALSE, 0);
545   gtk_widget_show (lower_hbox);
546 
547   /*  create the scrollbars  *************************************************/
548 
549   /*  the horizontal scrollbar  */
550   shell->hsbdata = GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, image_width,
551                                                        1, 1, image_width));
552   shell->hsb = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, shell->hsbdata);
553   gtk_widget_set_can_focus (shell->hsb, FALSE);
554 
555   /*  the vertical scrollbar  */
556   shell->vsbdata = GTK_ADJUSTMENT (gtk_adjustment_new (0, 0, image_height,
557                                                        1, 1, image_height));
558   shell->vsb = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, shell->vsbdata);
559   gtk_widget_set_can_focus (shell->vsb, FALSE);
560 
561   /*  create the contents of the inner_table  ********************************/
562 
563   /*  the menu popup button  */
564   shell->origin = gtk_event_box_new ();
565 
566   gtk_image = gtk_image_new_from_icon_name (GIMP_ICON_MENU_RIGHT,
567                                             GTK_ICON_SIZE_MENU);
568   gtk_container_add (GTK_CONTAINER (shell->origin), gtk_image);
569   gtk_widget_show (gtk_image);
570 
571   g_signal_connect (shell->origin, "button-press-event",
572                     G_CALLBACK (gimp_display_shell_origin_button_press),
573                     shell);
574 
575   gimp_help_set_help_data (shell->origin,
576                            _("Access the image menu"),
577                            GIMP_HELP_IMAGE_WINDOW_ORIGIN);
578 
579   shell->canvas = gimp_canvas_new (config);
580   gtk_widget_set_size_request (shell->canvas, shell_width, shell_height);
581   gtk_container_set_border_width (GTK_CONTAINER (shell->canvas), 10);
582 
583   g_signal_connect (shell->canvas, "remove",
584                     G_CALLBACK (gimp_display_shell_remove_overlay),
585                     shell);
586 
587   gimp_display_shell_dnd_init (shell);
588   gimp_display_shell_selection_init (shell);
589 
590   /*  the horizontal ruler  */
591   shell->hrule = gimp_ruler_new (GTK_ORIENTATION_HORIZONTAL);
592   gtk_widget_set_events (GTK_WIDGET (shell->hrule),
593                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
594 
595   gimp_ruler_add_track_widget (GIMP_RULER (shell->hrule), shell->canvas);
596   g_signal_connect (shell->hrule, "button-press-event",
597                     G_CALLBACK (gimp_display_shell_hruler_button_press),
598                     shell);
599 
600   gimp_help_set_help_data (shell->hrule, NULL, GIMP_HELP_IMAGE_WINDOW_RULER);
601 
602   /*  the vertical ruler  */
603   shell->vrule = gimp_ruler_new (GTK_ORIENTATION_VERTICAL);
604   gtk_widget_set_events (GTK_WIDGET (shell->vrule),
605                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
606 
607   gimp_ruler_add_track_widget (GIMP_RULER (shell->vrule), shell->canvas);
608   g_signal_connect (shell->vrule, "button-press-event",
609                     G_CALLBACK (gimp_display_shell_vruler_button_press),
610                     shell);
611 
612   gimp_help_set_help_data (shell->vrule, NULL, GIMP_HELP_IMAGE_WINDOW_RULER);
613 
614   /*  set the rulers as track widgets for each other, so we don't end up
615    *  with one ruler wrongly being stuck a few pixels off while we are
616    *  hovering the other
617    */
618   gimp_ruler_add_track_widget (GIMP_RULER (shell->hrule), shell->vrule);
619   gimp_ruler_add_track_widget (GIMP_RULER (shell->vrule), shell->hrule);
620 
621   gimp_devices_add_widget (shell->display->gimp, shell->hrule);
622   gimp_devices_add_widget (shell->display->gimp, shell->vrule);
623 
624   g_signal_connect (shell->canvas, "grab-notify",
625                     G_CALLBACK (gimp_display_shell_canvas_grab_notify),
626                     shell);
627 
628   g_signal_connect (shell->canvas, "realize",
629                     G_CALLBACK (gimp_display_shell_canvas_realize),
630                     shell);
631   g_signal_connect (shell->canvas, "realize",
632                     G_CALLBACK (gimp_display_shell_canvas_realize_after),
633                     shell);
634   g_signal_connect (shell->canvas, "size-allocate",
635                     G_CALLBACK (gimp_display_shell_canvas_size_allocate),
636                     shell);
637   g_signal_connect (shell->canvas, "expose-event",
638                     G_CALLBACK (gimp_display_shell_canvas_expose),
639                     shell);
640 
641   g_signal_connect (shell->canvas, "enter-notify-event",
642                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
643                     shell);
644   g_signal_connect (shell->canvas, "leave-notify-event",
645                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
646                     shell);
647   g_signal_connect (shell->canvas, "proximity-in-event",
648                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
649                     shell);
650   g_signal_connect (shell->canvas, "proximity-out-event",
651                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
652                     shell);
653   g_signal_connect (shell->canvas, "focus-in-event",
654                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
655                     shell);
656   g_signal_connect (shell->canvas, "focus-out-event",
657                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
658                     shell);
659   g_signal_connect (shell->canvas, "button-press-event",
660                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
661                     shell);
662   g_signal_connect (shell->canvas, "button-release-event",
663                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
664                     shell);
665   g_signal_connect (shell->canvas, "scroll-event",
666                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
667                     shell);
668   g_signal_connect (shell->canvas, "motion-notify-event",
669                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
670                     shell);
671   g_signal_connect (shell->canvas, "key-press-event",
672                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
673                     shell);
674   g_signal_connect (shell->canvas, "key-release-event",
675                     G_CALLBACK (gimp_display_shell_canvas_tool_events),
676                     shell);
677 
678   /*  create the contents of the right_vbox  *********************************/
679 
680   shell->zoom_button = g_object_new (GTK_TYPE_CHECK_BUTTON,
681                                      "draw-indicator", FALSE,
682                                      "relief",         GTK_RELIEF_NONE,
683                                      "width-request",  18,
684                                      "height-request", 18,
685                                      NULL);
686   gtk_widget_set_can_focus (shell->zoom_button, FALSE);
687 
688   gtk_image = gtk_image_new_from_icon_name (GIMP_ICON_ZOOM_FOLLOW_WINDOW,
689                                             GTK_ICON_SIZE_MENU);
690   gtk_container_add (GTK_CONTAINER (shell->zoom_button), gtk_image);
691   gtk_widget_show (gtk_image);
692 
693   gimp_help_set_help_data (shell->zoom_button,
694                            _("Zoom image when window size changes"),
695                            GIMP_HELP_IMAGE_WINDOW_ZOOM_FOLLOW_BUTTON);
696 
697   g_signal_connect_swapped (shell->zoom_button, "toggled",
698                             G_CALLBACK (gimp_display_shell_zoom_button_callback),
699                             shell);
700 
701   /*  create the contents of the lower_hbox  *********************************/
702 
703   /*  the quick mask button  */
704   shell->quick_mask_button = g_object_new (GTK_TYPE_CHECK_BUTTON,
705                                            "draw-indicator", FALSE,
706                                            "relief",         GTK_RELIEF_NONE,
707                                            "width-request",  18,
708                                            "height-request", 18,
709                                            NULL);
710   gtk_widget_set_can_focus (shell->quick_mask_button, FALSE);
711 
712   gtk_image = gtk_image_new_from_icon_name (GIMP_ICON_QUICK_MASK_OFF,
713                                             GTK_ICON_SIZE_MENU);
714   gtk_container_add (GTK_CONTAINER (shell->quick_mask_button), gtk_image);
715   gtk_widget_show (gtk_image);
716 
717   action = gimp_ui_manager_find_action (shell->popup_manager,
718                                         "quick-mask", "quick-mask-toggle");
719   if (action)
720     gimp_widget_set_accel_help (shell->quick_mask_button, action);
721   else
722     gimp_help_set_help_data (shell->quick_mask_button,
723                              _("Toggle Quick Mask"),
724                              GIMP_HELP_IMAGE_WINDOW_QUICK_MASK_BUTTON);
725 
726   g_signal_connect (shell->quick_mask_button, "toggled",
727                     G_CALLBACK (gimp_display_shell_quick_mask_toggled),
728                     shell);
729   g_signal_connect (shell->quick_mask_button, "button-press-event",
730                     G_CALLBACK (gimp_display_shell_quick_mask_button_press),
731                     shell);
732 
733   /*  the navigation window button  */
734   shell->nav_ebox = gtk_event_box_new ();
735 
736   gtk_image = gtk_image_new_from_icon_name (GIMP_ICON_DIALOG_NAVIGATION,
737                                             GTK_ICON_SIZE_MENU);
738   gtk_container_add (GTK_CONTAINER (shell->nav_ebox), gtk_image);
739   gtk_widget_show (gtk_image);
740 
741   g_signal_connect (shell->nav_ebox, "button-press-event",
742                     G_CALLBACK (gimp_display_shell_navigation_button_press),
743                     shell);
744 
745   gimp_help_set_help_data (shell->nav_ebox,
746                            _("Navigate the image display"),
747                            GIMP_HELP_IMAGE_WINDOW_NAV_BUTTON);
748 
749   /*  the statusbar  ********************************************************/
750 
751   shell->statusbar = gimp_statusbar_new ();
752   gimp_statusbar_set_shell (GIMP_STATUSBAR (shell->statusbar), shell);
753   gimp_help_set_help_data (shell->statusbar, NULL,
754                            GIMP_HELP_IMAGE_WINDOW_STATUS_BAR);
755   gtk_box_pack_end (GTK_BOX (main_vbox), shell->statusbar, FALSE, FALSE, 0);
756 
757   /*  pack all the widgets  **************************************************/
758 
759   /*  fill the inner_table  */
760   gtk_table_attach (GTK_TABLE (inner_table), shell->origin, 0, 1, 0, 1,
761                     GTK_FILL, GTK_FILL, 0, 0);
762   gtk_table_attach (GTK_TABLE (inner_table), shell->hrule, 1, 2, 0, 1,
763                     GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_FILL, 0, 0);
764   gtk_table_attach (GTK_TABLE (inner_table), shell->vrule, 0, 1, 1, 2,
765                     GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
766   gtk_table_attach (GTK_TABLE (inner_table), shell->canvas, 1, 2, 1, 2,
767                     GTK_EXPAND | GTK_SHRINK | GTK_FILL,
768                     GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
769 
770   /*  fill the right_vbox  */
771   gtk_box_pack_start (GTK_BOX (right_vbox),
772                       shell->zoom_button, FALSE, FALSE, 0);
773   gtk_box_pack_start (GTK_BOX (right_vbox),
774                       shell->vsb, TRUE, TRUE, 0);
775 
776   /*  fill the lower_hbox  */
777   gtk_box_pack_start (GTK_BOX (lower_hbox),
778                       shell->quick_mask_button, FALSE, FALSE, 0);
779   gtk_box_pack_start (GTK_BOX (lower_hbox),
780                       shell->hsb, TRUE, TRUE, 0);
781   gtk_box_pack_start (GTK_BOX (lower_hbox),
782                       shell->nav_ebox, FALSE, FALSE, 0);
783 
784   /*  show everything that is always shown ***********************************/
785 
786   gtk_widget_show (GTK_WIDGET (shell->canvas));
787 
788   if (image)
789     {
790       gimp_display_shell_connect (shell);
791 
792       /* After connecting to the image we want to center it. Since we
793        * not even finished creating the display shell, we can safely
794        * assume we will get a size-allocate later.
795        */
796       shell->size_allocate_center_image = TRUE;
797     }
798   else
799     {
800 #if 0
801       /* Disabled because it sets GDK_POINTER_MOTION_HINT on
802        * shell->canvas. For info see Bug 677375
803        */
804       gimp_help_set_help_data (shell->canvas,
805                                _("Drop image files here to open them"),
806                                NULL);
807 #endif
808 
809       gimp_statusbar_empty (GIMP_STATUSBAR (shell->statusbar));
810     }
811 
812   /* make sure the information is up-to-date */
813   gimp_display_shell_scale_update (shell);
814 
815   gimp_display_shell_set_show_all (shell, config->default_show_all);
816 }
817 
818 static void
gimp_display_shell_dispose(GObject * object)819 gimp_display_shell_dispose (GObject *object)
820 {
821   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (object);
822 
823   if (shell->display && gimp_display_get_shell (shell->display))
824     gimp_display_shell_disconnect (shell);
825 
826   shell->popup_manager = NULL;
827 
828   if (shell->selection)
829     gimp_display_shell_selection_free (shell);
830 
831   gimp_display_shell_filter_set (shell, NULL);
832 
833   if (shell->filter_idle_id)
834     {
835       g_source_remove (shell->filter_idle_id);
836       shell->filter_idle_id = 0;
837     }
838 
839   g_clear_pointer (&shell->mask_surface, cairo_surface_destroy);
840   g_clear_pointer (&shell->checkerboard, cairo_pattern_destroy);
841 
842   gimp_display_shell_profile_finalize (shell);
843 
844   g_clear_object (&shell->filter_buffer);
845   shell->filter_data   = NULL;
846   shell->filter_stride = 0;
847 
848   g_clear_object (&shell->mask);
849 
850   gimp_display_shell_items_free (shell);
851 
852   g_clear_object (&shell->motion_buffer);
853 
854   g_clear_pointer (&shell->zoom_focus_pointer_queue, g_queue_free);
855 
856   if (shell->title_idle_id)
857     {
858       g_source_remove (shell->title_idle_id);
859       shell->title_idle_id = 0;
860     }
861 
862   if (shell->fill_idle_id)
863     {
864       g_source_remove (shell->fill_idle_id);
865       shell->fill_idle_id = 0;
866     }
867 
868   g_clear_pointer (&shell->nav_popup, gtk_widget_destroy);
869 
870   if (shell->blink_timeout_id)
871     {
872       g_source_remove (shell->blink_timeout_id);
873       shell->blink_timeout_id = 0;
874     }
875 
876   shell->display = NULL;
877 
878   G_OBJECT_CLASS (parent_class)->dispose (object);
879 }
880 
881 static void
gimp_display_shell_finalize(GObject * object)882 gimp_display_shell_finalize (GObject *object)
883 {
884   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (object);
885 
886   g_clear_object (&shell->zoom);
887   g_clear_pointer (&shell->rotate_transform,   g_free);
888   g_clear_pointer (&shell->rotate_untransform, g_free);
889   g_clear_object (&shell->options);
890   g_clear_object (&shell->fullscreen_options);
891   g_clear_object (&shell->no_image_options);
892   g_clear_pointer (&shell->title,  g_free);
893   g_clear_pointer (&shell->status, g_free);
894   g_clear_object (&shell->icon);
895 
896   G_OBJECT_CLASS (parent_class)->finalize (object);
897 }
898 
899 static void
gimp_display_shell_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)900 gimp_display_shell_set_property (GObject      *object,
901                                  guint         property_id,
902                                  const GValue *value,
903                                  GParamSpec   *pspec)
904 {
905   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (object);
906 
907   switch (property_id)
908     {
909     case PROP_POPUP_MANAGER:
910       shell->popup_manager = g_value_get_object (value);
911       break;
912     case PROP_INITIAL_SCREEN:
913       shell->initial_screen = g_value_get_object (value);
914       break;
915     case PROP_INITIAL_MONITOR:
916       shell->initial_monitor = g_value_get_int (value);
917       break;
918     case PROP_DISPLAY:
919       shell->display = g_value_get_object (value);
920       break;
921     case PROP_UNIT:
922       gimp_display_shell_set_unit (shell, g_value_get_int (value));
923       break;
924     case PROP_TITLE:
925       g_free (shell->title);
926       shell->title = g_value_dup_string (value);
927       break;
928     case PROP_STATUS:
929       g_free (shell->status);
930       shell->status = g_value_dup_string (value);
931       break;
932     case PROP_ICON:
933       if (shell->icon)
934         g_object_unref (shell->icon);
935       shell->icon = g_value_dup_object (value);
936       break;
937     case PROP_SHOW_ALL:
938       gimp_display_shell_set_show_all (shell, g_value_get_boolean (value));
939       break;
940 
941     default:
942       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
943       break;
944     }
945 }
946 
947 static void
gimp_display_shell_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)948 gimp_display_shell_get_property (GObject    *object,
949                                  guint       property_id,
950                                  GValue     *value,
951                                  GParamSpec *pspec)
952 {
953   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (object);
954 
955   switch (property_id)
956     {
957     case PROP_POPUP_MANAGER:
958       g_value_set_object (value, shell->popup_manager);
959       break;
960     case PROP_INITIAL_SCREEN:
961       g_value_set_object (value, shell->initial_screen);
962       break;
963     case PROP_INITIAL_MONITOR:
964       g_value_set_int (value, shell->initial_monitor);
965       break;
966     case PROP_DISPLAY:
967       g_value_set_object (value, shell->display);
968       break;
969     case PROP_UNIT:
970       g_value_set_int (value, shell->unit);
971       break;
972     case PROP_TITLE:
973       g_value_set_string (value, shell->title);
974       break;
975     case PROP_STATUS:
976       g_value_set_string (value, shell->status);
977       break;
978     case PROP_ICON:
979       g_value_set_object (value, shell->icon);
980       break;
981     case PROP_SHOW_ALL:
982       g_value_set_boolean (value, shell->show_all);
983       break;
984     case PROP_INFINITE_CANVAS:
985       g_value_set_boolean (value,
986                            gimp_display_shell_get_infinite_canvas (shell));
987       break;
988 
989     default:
990       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
991       break;
992     }
993 }
994 
995 static void
gimp_display_shell_unrealize(GtkWidget * widget)996 gimp_display_shell_unrealize (GtkWidget *widget)
997 {
998   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (widget);
999 
1000   if (shell->nav_popup)
1001     gtk_widget_unrealize (shell->nav_popup);
1002 
1003   GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
1004 }
1005 
1006 static void
gimp_display_shell_unmap(GtkWidget * widget)1007 gimp_display_shell_unmap (GtkWidget *widget)
1008 {
1009   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (widget);
1010 
1011   gimp_display_shell_selection_undraw (shell);
1012 
1013   GTK_WIDGET_CLASS (parent_class)->unmap (widget);
1014 }
1015 
1016 static void
gimp_display_shell_screen_changed(GtkWidget * widget,GdkScreen * previous)1017 gimp_display_shell_screen_changed (GtkWidget *widget,
1018                                    GdkScreen *previous)
1019 {
1020   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (widget);
1021 
1022   if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
1023     GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, previous);
1024 
1025   if (shell->display->config->monitor_res_from_gdk)
1026     {
1027       gimp_get_monitor_resolution (gtk_widget_get_screen (widget),
1028                                    gimp_widget_get_monitor (widget),
1029                                    &shell->monitor_xres,
1030                                    &shell->monitor_yres);
1031     }
1032   else
1033     {
1034       shell->monitor_xres = shell->display->config->monitor_xres;
1035       shell->monitor_yres = shell->display->config->monitor_yres;
1036     }
1037 }
1038 
1039 static gboolean
gimp_display_shell_popup_menu(GtkWidget * widget)1040 gimp_display_shell_popup_menu (GtkWidget *widget)
1041 {
1042   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (widget);
1043 
1044   gimp_context_set_display (gimp_get_user_context (shell->display->gimp),
1045                             shell->display);
1046 
1047   gimp_ui_manager_ui_popup (shell->popup_manager, "/dummy-menubar/image-popup",
1048                             GTK_WIDGET (shell),
1049                             gimp_display_shell_menu_position,
1050                             shell->origin,
1051                             NULL, NULL);
1052 
1053   return TRUE;
1054 }
1055 
1056 static void
gimp_display_shell_real_scaled(GimpDisplayShell * shell)1057 gimp_display_shell_real_scaled (GimpDisplayShell *shell)
1058 {
1059   GimpContext *user_context;
1060 
1061   if (! shell->display)
1062     return;
1063 
1064   gimp_display_shell_title_update (shell);
1065 
1066   user_context = gimp_get_user_context (shell->display->gimp);
1067 
1068   if (shell->display == gimp_context_get_display (user_context))
1069     {
1070       gimp_display_shell_update_priority_rect (shell);
1071 
1072       gimp_ui_manager_update (shell->popup_manager, shell->display);
1073     }
1074 }
1075 
1076 static void
gimp_display_shell_real_scrolled(GimpDisplayShell * shell)1077 gimp_display_shell_real_scrolled (GimpDisplayShell *shell)
1078 {
1079   GimpContext *user_context;
1080 
1081   if (! shell->display)
1082     return;
1083 
1084   gimp_display_shell_title_update (shell);
1085 
1086   user_context = gimp_get_user_context (shell->display->gimp);
1087 
1088   if (shell->display == gimp_context_get_display (user_context))
1089     {
1090       gimp_display_shell_update_priority_rect (shell);
1091 
1092     }
1093 }
1094 
1095 static void
gimp_display_shell_real_rotated(GimpDisplayShell * shell)1096 gimp_display_shell_real_rotated (GimpDisplayShell *shell)
1097 {
1098   GimpContext *user_context;
1099 
1100   if (! shell->display)
1101     return;
1102 
1103   gimp_display_shell_title_update (shell);
1104 
1105   user_context = gimp_get_user_context (shell->display->gimp);
1106 
1107   if (shell->display == gimp_context_get_display (user_context))
1108     {
1109       gimp_display_shell_update_priority_rect (shell);
1110 
1111       gimp_ui_manager_update (shell->popup_manager, shell->display);
1112     }
1113 }
1114 
1115 static const guint8 *
gimp_display_shell_get_icc_profile(GimpColorManaged * managed,gsize * len)1116 gimp_display_shell_get_icc_profile (GimpColorManaged *managed,
1117                                     gsize            *len)
1118 {
1119   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (managed);
1120   GimpImage        *image = gimp_display_get_image (shell->display);
1121 
1122   if (image)
1123     return gimp_color_managed_get_icc_profile (GIMP_COLOR_MANAGED (image), len);
1124 
1125   return NULL;
1126 }
1127 
1128 static GimpColorProfile *
gimp_display_shell_get_color_profile(GimpColorManaged * managed)1129 gimp_display_shell_get_color_profile (GimpColorManaged *managed)
1130 {
1131   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (managed);
1132   GimpImage        *image = gimp_display_get_image (shell->display);
1133 
1134   if (image)
1135     return gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (image));
1136 
1137   return NULL;
1138 }
1139 
1140 static void
gimp_display_shell_profile_changed(GimpColorManaged * managed)1141 gimp_display_shell_profile_changed (GimpColorManaged *managed)
1142 {
1143   GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (managed);
1144 
1145   gimp_display_shell_profile_update (shell);
1146   gimp_display_shell_expose_full (shell);
1147 }
1148 
1149 static void
gimp_display_shell_menu_position(GtkMenu * menu,gint * x,gint * y,gpointer data)1150 gimp_display_shell_menu_position (GtkMenu  *menu,
1151                                   gint     *x,
1152                                   gint     *y,
1153                                   gpointer  data)
1154 {
1155   gimp_button_menu_position (GTK_WIDGET (data), menu, GTK_POS_RIGHT, x, y);
1156 }
1157 
1158 static void
gimp_display_shell_zoom_button_callback(GimpDisplayShell * shell,GtkWidget * zoom_button)1159 gimp_display_shell_zoom_button_callback (GimpDisplayShell *shell,
1160                                          GtkWidget        *zoom_button)
1161 {
1162   shell->zoom_on_resize =
1163     gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (zoom_button));
1164 
1165   if (shell->zoom_on_resize &&
1166       gimp_display_shell_scale_image_is_within_viewport (shell, NULL, NULL))
1167     {
1168       /* Implicitly make a View -> Fit Image in Window */
1169       gimp_display_shell_scale_fit_in (shell);
1170     }
1171 }
1172 
1173 static void
gimp_display_shell_sync_config(GimpDisplayShell * shell,GimpDisplayConfig * config)1174 gimp_display_shell_sync_config (GimpDisplayShell  *shell,
1175                                 GimpDisplayConfig *config)
1176 {
1177   gimp_config_sync (G_OBJECT (config->default_view),
1178                     G_OBJECT (shell->options), 0);
1179   gimp_config_sync (G_OBJECT (config->default_fullscreen_view),
1180                     G_OBJECT (shell->fullscreen_options), 0);
1181 }
1182 
1183 static void
gimp_display_shell_remove_overlay(GtkWidget * canvas,GtkWidget * child,GimpDisplayShell * shell)1184 gimp_display_shell_remove_overlay (GtkWidget        *canvas,
1185                                    GtkWidget        *child,
1186                                    GimpDisplayShell *shell)
1187 {
1188   shell->children = g_list_remove (shell->children, child);
1189 }
1190 
1191 static void
gimp_display_shell_transform_overlay(GimpDisplayShell * shell,GtkWidget * child,gdouble * x,gdouble * y)1192 gimp_display_shell_transform_overlay (GimpDisplayShell *shell,
1193                                       GtkWidget        *child,
1194                                       gdouble          *x,
1195                                       gdouble          *y)
1196 {
1197   GimpDisplayShellOverlay *overlay;
1198   GtkRequisition           requisition;
1199 
1200   overlay = g_object_get_data (G_OBJECT (child), "image-coords-overlay");
1201 
1202   gimp_display_shell_transform_xy_f (shell,
1203                                      overlay->image_x,
1204                                      overlay->image_y,
1205                                      x, y);
1206 
1207   gtk_widget_size_request (child, &requisition);
1208 
1209   switch (overlay->anchor)
1210     {
1211     case GIMP_HANDLE_ANCHOR_CENTER:
1212       *x -= requisition.width  / 2;
1213       *y -= requisition.height / 2;
1214       break;
1215 
1216     case GIMP_HANDLE_ANCHOR_NORTH:
1217       *x -= requisition.width / 2;
1218       *y += overlay->spacing_y;
1219       break;
1220 
1221     case GIMP_HANDLE_ANCHOR_NORTH_WEST:
1222       *x += overlay->spacing_x;
1223       *y += overlay->spacing_y;
1224       break;
1225 
1226     case GIMP_HANDLE_ANCHOR_NORTH_EAST:
1227       *x -= requisition.width + overlay->spacing_x;
1228       *y += overlay->spacing_y;
1229       break;
1230 
1231     case GIMP_HANDLE_ANCHOR_SOUTH:
1232       *x -= requisition.width / 2;
1233       *y -= requisition.height + overlay->spacing_y;
1234       break;
1235 
1236     case GIMP_HANDLE_ANCHOR_SOUTH_WEST:
1237       *x += overlay->spacing_x;
1238       *y -= requisition.height + overlay->spacing_y;
1239       break;
1240 
1241     case GIMP_HANDLE_ANCHOR_SOUTH_EAST:
1242       *x -= requisition.width + overlay->spacing_x;
1243       *y -= requisition.height + overlay->spacing_y;
1244       break;
1245 
1246     case GIMP_HANDLE_ANCHOR_WEST:
1247       *x += overlay->spacing_x;
1248       *y -= requisition.height / 2;
1249       break;
1250 
1251     case GIMP_HANDLE_ANCHOR_EAST:
1252       *x -= requisition.width + overlay->spacing_x;
1253       *y -= requisition.height / 2;
1254       break;
1255     }
1256 }
1257 
1258 
1259 /*  public functions  */
1260 
1261 GtkWidget *
gimp_display_shell_new(GimpDisplay * display,GimpUnit unit,gdouble scale,GimpUIManager * popup_manager,GdkScreen * screen,gint monitor)1262 gimp_display_shell_new (GimpDisplay   *display,
1263                         GimpUnit       unit,
1264                         gdouble        scale,
1265                         GimpUIManager *popup_manager,
1266                         GdkScreen     *screen,
1267                         gint           monitor)
1268 {
1269   g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
1270   g_return_val_if_fail (GIMP_IS_UI_MANAGER (popup_manager), NULL);
1271   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1272 
1273   return g_object_new (GIMP_TYPE_DISPLAY_SHELL,
1274                        "popup-manager",   popup_manager,
1275                        "initial-screen",  screen,
1276                        "initial-monitor", monitor,
1277                        "display",         display,
1278                        "unit",            unit,
1279                        NULL);
1280 }
1281 
1282 void
gimp_display_shell_add_overlay(GimpDisplayShell * shell,GtkWidget * child,gdouble image_x,gdouble image_y,GimpHandleAnchor anchor,gint spacing_x,gint spacing_y)1283 gimp_display_shell_add_overlay (GimpDisplayShell *shell,
1284                                 GtkWidget        *child,
1285                                 gdouble           image_x,
1286                                 gdouble           image_y,
1287                                 GimpHandleAnchor  anchor,
1288                                 gint              spacing_x,
1289                                 gint              spacing_y)
1290 {
1291   GimpDisplayShellOverlay *overlay;
1292   gdouble                  x, y;
1293 
1294   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1295   g_return_if_fail (GTK_IS_WIDGET (shell));
1296 
1297   overlay = g_new0 (GimpDisplayShellOverlay, 1);
1298 
1299   overlay->image_x   = image_x;
1300   overlay->image_y   = image_y;
1301   overlay->anchor    = anchor;
1302   overlay->spacing_x = spacing_x;
1303   overlay->spacing_y = spacing_y;
1304 
1305   g_object_set_data_full (G_OBJECT (child), "image-coords-overlay", overlay,
1306                           (GDestroyNotify) g_free);
1307 
1308   shell->children = g_list_prepend (shell->children, child);
1309 
1310   gimp_display_shell_transform_overlay (shell, child, &x, &y);
1311 
1312   gimp_overlay_box_add_child (GIMP_OVERLAY_BOX (shell->canvas), child, 0.0, 0.0);
1313   gimp_overlay_box_set_child_position (GIMP_OVERLAY_BOX (shell->canvas),
1314                                        child, x, y);
1315 }
1316 
1317 void
gimp_display_shell_move_overlay(GimpDisplayShell * shell,GtkWidget * child,gdouble image_x,gdouble image_y,GimpHandleAnchor anchor,gint spacing_x,gint spacing_y)1318 gimp_display_shell_move_overlay (GimpDisplayShell *shell,
1319                                  GtkWidget        *child,
1320                                  gdouble           image_x,
1321                                  gdouble           image_y,
1322                                  GimpHandleAnchor  anchor,
1323                                  gint              spacing_x,
1324                                  gint              spacing_y)
1325 {
1326   GimpDisplayShellOverlay *overlay;
1327   gdouble                  x, y;
1328 
1329   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1330   g_return_if_fail (GTK_IS_WIDGET (shell));
1331 
1332   overlay = g_object_get_data (G_OBJECT (child), "image-coords-overlay");
1333 
1334   g_return_if_fail (overlay != NULL);
1335 
1336   overlay->image_x   = image_x;
1337   overlay->image_y   = image_y;
1338   overlay->anchor    = anchor;
1339   overlay->spacing_x = spacing_x;
1340   overlay->spacing_y = spacing_y;
1341 
1342   gimp_display_shell_transform_overlay (shell, child, &x, &y);
1343 
1344   gimp_overlay_box_set_child_position (GIMP_OVERLAY_BOX (shell->canvas),
1345                                        child, x, y);
1346 }
1347 
1348 GimpImageWindow *
gimp_display_shell_get_window(GimpDisplayShell * shell)1349 gimp_display_shell_get_window (GimpDisplayShell *shell)
1350 {
1351   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
1352 
1353   return GIMP_IMAGE_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (shell),
1354                                                      GIMP_TYPE_IMAGE_WINDOW));
1355 }
1356 
1357 GimpStatusbar *
gimp_display_shell_get_statusbar(GimpDisplayShell * shell)1358 gimp_display_shell_get_statusbar (GimpDisplayShell *shell)
1359 {
1360   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
1361 
1362   return GIMP_STATUSBAR (shell->statusbar);
1363 }
1364 
1365 GimpColorConfig *
gimp_display_shell_get_color_config(GimpDisplayShell * shell)1366 gimp_display_shell_get_color_config (GimpDisplayShell *shell)
1367 {
1368   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
1369 
1370   return shell->color_config;
1371 }
1372 
1373 void
gimp_display_shell_present(GimpDisplayShell * shell)1374 gimp_display_shell_present (GimpDisplayShell *shell)
1375 {
1376   GimpImageWindow *window;
1377 
1378   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1379 
1380   window = gimp_display_shell_get_window (shell);
1381 
1382   if (window)
1383     {
1384       gimp_image_window_set_active_shell (window, shell);
1385 
1386       gtk_window_present (GTK_WINDOW (window));
1387     }
1388 }
1389 
1390 void
gimp_display_shell_reconnect(GimpDisplayShell * shell)1391 gimp_display_shell_reconnect (GimpDisplayShell *shell)
1392 {
1393   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1394   g_return_if_fail (GIMP_IS_DISPLAY (shell->display));
1395   g_return_if_fail (gimp_display_get_image (shell->display) != NULL);
1396 
1397   if (shell->fill_idle_id)
1398     {
1399       g_source_remove (shell->fill_idle_id);
1400       shell->fill_idle_id = 0;
1401     }
1402 
1403   g_signal_emit (shell, display_shell_signals[RECONNECT], 0);
1404 
1405   gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (shell));
1406 
1407   gimp_display_shell_scroll_clamp_and_update (shell);
1408 
1409   gimp_display_shell_scaled (shell);
1410 
1411   gimp_display_shell_expose_full (shell);
1412 }
1413 
1414 static gboolean
gimp_display_shell_blink(GimpDisplayShell * shell)1415 gimp_display_shell_blink (GimpDisplayShell *shell)
1416 {
1417   shell->blink_timeout_id = 0;
1418 
1419   if (shell->blink)
1420     {
1421       shell->blink = FALSE;
1422     }
1423   else
1424     {
1425       shell->blink = TRUE;
1426 
1427       shell->blink_timeout_id =
1428         g_timeout_add (100, (GSourceFunc) gimp_display_shell_blink, shell);
1429     }
1430 
1431   gimp_display_shell_expose_full (shell);
1432 
1433   return FALSE;
1434 }
1435 
1436 void
gimp_display_shell_empty(GimpDisplayShell * shell)1437 gimp_display_shell_empty (GimpDisplayShell *shell)
1438 {
1439   GimpContext     *user_context;
1440   GimpImageWindow *window;
1441 
1442   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1443   g_return_if_fail (GIMP_IS_DISPLAY (shell->display));
1444   g_return_if_fail (gimp_display_get_image (shell->display) == NULL);
1445 
1446   window = gimp_display_shell_get_window (shell);
1447 
1448   if (shell->fill_idle_id)
1449     {
1450       g_source_remove (shell->fill_idle_id);
1451       shell->fill_idle_id = 0;
1452     }
1453 
1454   gimp_display_shell_selection_undraw (shell);
1455 
1456   gimp_display_shell_unset_cursor (shell);
1457 
1458   gimp_display_shell_filter_set (shell, NULL);
1459 
1460   gimp_display_shell_sync_config (shell, shell->display->config);
1461 
1462   gimp_display_shell_appearance_update (shell);
1463   gimp_image_window_update_tabs (window);
1464 #if 0
1465   gimp_help_set_help_data (shell->canvas,
1466                            _("Drop image files here to open them"), NULL);
1467 #endif
1468 
1469   gimp_statusbar_empty (GIMP_STATUSBAR (shell->statusbar));
1470 
1471   shell->flip_horizontally = FALSE;
1472   shell->flip_vertically   = FALSE;
1473   shell->rotate_angle      = 0.0;
1474   gimp_display_shell_rotate_update_transform (shell);
1475 
1476   gimp_display_shell_expose_full (shell);
1477 
1478   user_context = gimp_get_user_context (shell->display->gimp);
1479 
1480   if (shell->display == gimp_context_get_display (user_context))
1481     gimp_ui_manager_update (shell->popup_manager, shell->display);
1482 
1483   shell->blink_timeout_id =
1484     g_timeout_add (1403230, (GSourceFunc) gimp_display_shell_blink, shell);
1485 }
1486 
1487 static gboolean
gimp_display_shell_fill_idle(GimpDisplayShell * shell)1488 gimp_display_shell_fill_idle (GimpDisplayShell *shell)
1489 {
1490   GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
1491 
1492   shell->fill_idle_id = 0;
1493 
1494   if (GTK_IS_WINDOW (toplevel))
1495     {
1496       gimp_display_shell_scale_shrink_wrap (shell, TRUE);
1497 
1498       gtk_window_present (GTK_WINDOW (toplevel));
1499     }
1500 
1501   return FALSE;
1502 }
1503 
1504 void
gimp_display_shell_fill(GimpDisplayShell * shell,GimpImage * image,GimpUnit unit,gdouble scale)1505 gimp_display_shell_fill (GimpDisplayShell *shell,
1506                          GimpImage        *image,
1507                          GimpUnit          unit,
1508                          gdouble           scale)
1509 {
1510   GimpDisplayConfig *config;
1511   GimpImageWindow   *window;
1512 
1513   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1514   g_return_if_fail (GIMP_IS_DISPLAY (shell->display));
1515   g_return_if_fail (GIMP_IS_IMAGE (image));
1516 
1517   config = shell->display->config;
1518   window = gimp_display_shell_get_window (shell);
1519 
1520   shell->show_image  = TRUE;
1521 
1522   shell->dot_for_dot = config->default_dot_for_dot;
1523 
1524   gimp_display_shell_set_unit (shell, unit);
1525   gimp_display_shell_set_initial_scale (shell, scale, NULL, NULL);
1526   gimp_display_shell_scale_update (shell);
1527 
1528   gimp_display_shell_sync_config (shell, config);
1529 
1530   gimp_image_window_suspend_keep_pos (window);
1531   gimp_display_shell_appearance_update (shell);
1532   gimp_image_window_resume_keep_pos (window);
1533 
1534   gimp_image_window_update_tabs (window);
1535 #if 0
1536   gimp_help_set_help_data (shell->canvas, NULL, NULL);
1537 #endif
1538 
1539   gimp_statusbar_fill (GIMP_STATUSBAR (shell->statusbar));
1540 
1541   /* make sure a size-allocate always occurs, even when the rulers and
1542    * scrollbars are hidden.  see issue #4968.
1543    */
1544   shell->size_allocate_center_image = TRUE;
1545   gtk_widget_queue_resize (GTK_WIDGET (shell->canvas));
1546 
1547   if (shell->blink_timeout_id)
1548     {
1549       g_source_remove (shell->blink_timeout_id);
1550       shell->blink_timeout_id = 0;
1551     }
1552 
1553   shell->fill_idle_id =
1554     g_idle_add_full (GIMP_PRIORITY_DISPLAY_SHELL_FILL_IDLE,
1555                      (GSourceFunc) gimp_display_shell_fill_idle, shell,
1556                      NULL);
1557 
1558   gimp_display_shell_set_show_all (shell, config->default_show_all);
1559 }
1560 
1561 void
gimp_display_shell_scaled(GimpDisplayShell * shell)1562 gimp_display_shell_scaled (GimpDisplayShell *shell)
1563 {
1564   GList *list;
1565 
1566   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1567 
1568   gimp_display_shell_rotate_update_transform (shell);
1569 
1570   for (list = shell->children; list; list = g_list_next (list))
1571     {
1572       GtkWidget *child = list->data;
1573       gdouble    x, y;
1574 
1575       gimp_display_shell_transform_overlay (shell, child, &x, &y);
1576 
1577       gimp_overlay_box_set_child_position (GIMP_OVERLAY_BOX (shell->canvas),
1578                                            child, x, y);
1579     }
1580 
1581   g_signal_emit (shell, display_shell_signals[SCALED], 0);
1582 }
1583 
1584 void
gimp_display_shell_scrolled(GimpDisplayShell * shell)1585 gimp_display_shell_scrolled (GimpDisplayShell *shell)
1586 {
1587   GList *list;
1588 
1589   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1590 
1591   gimp_display_shell_rotate_update_transform (shell);
1592 
1593   for (list = shell->children; list; list = g_list_next (list))
1594     {
1595       GtkWidget *child = list->data;
1596       gdouble    x, y;
1597 
1598       gimp_display_shell_transform_overlay (shell, child, &x, &y);
1599 
1600       gimp_overlay_box_set_child_position (GIMP_OVERLAY_BOX (shell->canvas),
1601                                            child, x, y);
1602     }
1603 
1604   g_signal_emit (shell, display_shell_signals[SCROLLED], 0);
1605 }
1606 
1607 void
gimp_display_shell_rotated(GimpDisplayShell * shell)1608 gimp_display_shell_rotated (GimpDisplayShell *shell)
1609 {
1610   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1611 
1612   gimp_display_shell_rotate_update_transform (shell);
1613 
1614   g_signal_emit (shell, display_shell_signals[ROTATED], 0);
1615 }
1616 
1617 void
gimp_display_shell_set_unit(GimpDisplayShell * shell,GimpUnit unit)1618 gimp_display_shell_set_unit (GimpDisplayShell *shell,
1619                              GimpUnit          unit)
1620 {
1621   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1622 
1623   if (shell->unit != unit)
1624     {
1625       shell->unit = unit;
1626 
1627       gimp_display_shell_rulers_update (shell);
1628 
1629       gimp_display_shell_scaled (shell);
1630 
1631       g_object_notify (G_OBJECT (shell), "unit");
1632     }
1633 }
1634 
1635 GimpUnit
gimp_display_shell_get_unit(GimpDisplayShell * shell)1636 gimp_display_shell_get_unit (GimpDisplayShell *shell)
1637 {
1638   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), GIMP_UNIT_PIXEL);
1639 
1640   return shell->unit;
1641 }
1642 
1643 gboolean
gimp_display_shell_snap_coords(GimpDisplayShell * shell,GimpCoords * coords,gint snap_offset_x,gint snap_offset_y,gint snap_width,gint snap_height)1644 gimp_display_shell_snap_coords (GimpDisplayShell *shell,
1645                                 GimpCoords       *coords,
1646                                 gint              snap_offset_x,
1647                                 gint              snap_offset_y,
1648                                 gint              snap_width,
1649                                 gint              snap_height)
1650 {
1651   GimpImage *image;
1652   gboolean   snap_to_guides  = FALSE;
1653   gboolean   snap_to_grid    = FALSE;
1654   gboolean   snap_to_canvas  = FALSE;
1655   gboolean   snap_to_vectors = FALSE;
1656   gboolean   snapped         = FALSE;
1657 
1658   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
1659   g_return_val_if_fail (coords != NULL, FALSE);
1660 
1661   image = gimp_display_get_image (shell->display);
1662 
1663   if (gimp_display_shell_get_snap_to_guides (shell) &&
1664       gimp_image_get_guides (image))
1665     {
1666       snap_to_guides = TRUE;
1667     }
1668 
1669   if (gimp_display_shell_get_snap_to_grid (shell) &&
1670       gimp_image_get_grid (image))
1671     {
1672       snap_to_grid = TRUE;
1673     }
1674 
1675   snap_to_canvas = gimp_display_shell_get_snap_to_canvas (shell);
1676 
1677   if (gimp_display_shell_get_snap_to_vectors (shell) &&
1678       gimp_image_get_active_vectors (image))
1679     {
1680       snap_to_vectors = TRUE;
1681     }
1682 
1683   if (snap_to_guides || snap_to_grid || snap_to_canvas || snap_to_vectors)
1684     {
1685       gint    snap_distance;
1686       gdouble tx, ty;
1687 
1688       snap_distance = shell->display->config->snap_distance;
1689 
1690       if (snap_width > 0 && snap_height > 0)
1691         {
1692           snapped = gimp_image_snap_rectangle (image,
1693                                                coords->x + snap_offset_x,
1694                                                coords->y + snap_offset_y,
1695                                                coords->x + snap_offset_x +
1696                                                snap_width,
1697                                                coords->y + snap_offset_y +
1698                                                snap_height,
1699                                                &tx,
1700                                                &ty,
1701                                                FUNSCALEX (shell, snap_distance),
1702                                                FUNSCALEY (shell, snap_distance),
1703                                                snap_to_guides,
1704                                                snap_to_grid,
1705                                                snap_to_canvas,
1706                                                snap_to_vectors);
1707         }
1708       else
1709         {
1710           snapped = gimp_image_snap_point (image,
1711                                            coords->x + snap_offset_x,
1712                                            coords->y + snap_offset_y,
1713                                            &tx,
1714                                            &ty,
1715                                            FUNSCALEX (shell, snap_distance),
1716                                            FUNSCALEY (shell, snap_distance),
1717                                            snap_to_guides,
1718                                            snap_to_grid,
1719                                            snap_to_canvas,
1720                                            snap_to_vectors,
1721                                            shell->show_all);
1722         }
1723 
1724       if (snapped)
1725         {
1726           coords->x = tx - snap_offset_x;
1727           coords->y = ty - snap_offset_y;
1728         }
1729     }
1730 
1731   return snapped;
1732 }
1733 
1734 gboolean
gimp_display_shell_mask_bounds(GimpDisplayShell * shell,gint * x,gint * y,gint * width,gint * height)1735 gimp_display_shell_mask_bounds (GimpDisplayShell *shell,
1736                                 gint             *x,
1737                                 gint             *y,
1738                                 gint             *width,
1739                                 gint             *height)
1740 {
1741   GimpImage *image;
1742   GimpLayer *layer;
1743   gint       x1, y1;
1744   gint       x2, y2;
1745   gdouble    x1_f, y1_f;
1746   gdouble    x2_f, y2_f;
1747 
1748   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
1749   g_return_val_if_fail (x != NULL, FALSE);
1750   g_return_val_if_fail (y != NULL, FALSE);
1751   g_return_val_if_fail (width != NULL, FALSE);
1752   g_return_val_if_fail (height != NULL, FALSE);
1753 
1754   image = gimp_display_get_image (shell->display);
1755 
1756   /*  If there is a floating selection, handle things differently  */
1757   if ((layer = gimp_image_get_floating_selection (image)))
1758     {
1759       gint fs_x;
1760       gint fs_y;
1761       gint fs_width;
1762       gint fs_height;
1763 
1764       gimp_item_get_offset (GIMP_ITEM (layer), &fs_x, &fs_y);
1765       fs_width  = gimp_item_get_width  (GIMP_ITEM (layer));
1766       fs_height = gimp_item_get_height (GIMP_ITEM (layer));
1767 
1768       if (! gimp_item_bounds (GIMP_ITEM (gimp_image_get_mask (image)),
1769                               x, y, width, height))
1770         {
1771           *x      = fs_x;
1772           *y      = fs_y;
1773           *width  = fs_width;
1774           *height = fs_height;
1775         }
1776       else
1777         {
1778           gimp_rectangle_union (*x, *y, *width, *height,
1779                                 fs_x, fs_y, fs_width, fs_height,
1780                                 x, y, width, height);
1781         }
1782     }
1783   else if (! gimp_item_bounds (GIMP_ITEM (gimp_image_get_mask (image)),
1784                                x, y, width, height))
1785     {
1786       return FALSE;
1787     }
1788 
1789   x1 = *x;
1790   y1 = *y;
1791   x2 = *x + *width;
1792   y2 = *y + *height;
1793 
1794   gimp_display_shell_transform_bounds (shell,
1795                                        x1, y1, x2, y2,
1796                                        &x1_f, &y1_f, &x2_f, &y2_f);
1797 
1798   /*  Make sure the extents are within bounds  */
1799   x1 = CLAMP (floor (x1_f), 0, shell->disp_width);
1800   y1 = CLAMP (floor (y1_f), 0, shell->disp_height);
1801   x2 = CLAMP (ceil (x2_f),  0, shell->disp_width);
1802   y2 = CLAMP (ceil (y2_f),  0, shell->disp_height);
1803 
1804   *x      = x1;
1805   *y      = y1;
1806   *width  = x2 - x1;
1807   *height = y2 - y1;
1808 
1809   return (*width > 0) && (*height > 0);
1810 }
1811 
1812 void
gimp_display_shell_set_show_image(GimpDisplayShell * shell,gboolean show_image)1813 gimp_display_shell_set_show_image (GimpDisplayShell *shell,
1814                                    gboolean          show_image)
1815 {
1816   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1817 
1818   if (show_image != shell->show_image)
1819     {
1820       shell->show_image = show_image;
1821 
1822       gimp_display_shell_expose_full (shell);
1823     }
1824 }
1825 
1826 void
gimp_display_shell_set_show_all(GimpDisplayShell * shell,gboolean show_all)1827 gimp_display_shell_set_show_all (GimpDisplayShell *shell,
1828                                  gboolean          show_all)
1829 {
1830   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1831 
1832   if (show_all != shell->show_all)
1833     {
1834       shell->show_all = show_all;
1835 
1836       if (shell->display && gimp_display_get_image (shell->display))
1837         {
1838           GimpImage   *image = gimp_display_get_image (shell->display);
1839           GimpContext *user_context;
1840 
1841           if (show_all)
1842             gimp_image_inc_show_all_count (image);
1843           else
1844             gimp_image_dec_show_all_count (image);
1845 
1846           gimp_image_flush (image);
1847 
1848           gimp_display_update_bounding_box (shell->display);
1849 
1850           gimp_display_shell_update_show_canvas (shell);
1851 
1852           gimp_display_shell_scroll_clamp_and_update (shell);
1853           gimp_display_shell_scrollbars_update (shell);
1854 
1855           gimp_display_shell_expose_full (shell);
1856 
1857           user_context = gimp_get_user_context (shell->display->gimp);
1858 
1859           if (shell->display == gimp_context_get_display (user_context))
1860             {
1861               gimp_display_shell_update_priority_rect (shell);
1862 
1863               gimp_ui_manager_update (shell->popup_manager, shell->display);
1864             }
1865         }
1866 
1867       g_object_notify (G_OBJECT (shell), "show-all");
1868       g_object_notify (G_OBJECT (shell), "infinite-canvas");
1869     }
1870 }
1871 
1872 
1873 GimpPickable *
gimp_display_shell_get_pickable(GimpDisplayShell * shell)1874 gimp_display_shell_get_pickable (GimpDisplayShell *shell)
1875 {
1876   GimpImage *image;
1877 
1878   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
1879 
1880   image = gimp_display_get_image (shell->display);
1881 
1882   if (image)
1883     {
1884       if (! shell->show_all)
1885         return GIMP_PICKABLE (image);
1886       else
1887         return GIMP_PICKABLE (gimp_image_get_projection (image));
1888     }
1889 
1890   return NULL;
1891 }
1892 
1893 GimpPickable *
gimp_display_shell_get_canvas_pickable(GimpDisplayShell * shell)1894 gimp_display_shell_get_canvas_pickable (GimpDisplayShell *shell)
1895 {
1896   GimpImage *image;
1897 
1898   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), NULL);
1899 
1900   image = gimp_display_get_image (shell->display);
1901 
1902   if (image)
1903     {
1904       if (! gimp_display_shell_get_infinite_canvas (shell))
1905         return GIMP_PICKABLE (image);
1906       else
1907         return GIMP_PICKABLE (gimp_image_get_projection (image));
1908     }
1909 
1910   return NULL;
1911 }
1912 
1913 GeglRectangle
gimp_display_shell_get_bounding_box(GimpDisplayShell * shell)1914 gimp_display_shell_get_bounding_box (GimpDisplayShell *shell)
1915 {
1916   GeglRectangle  bounding_box = {};
1917   GimpImage     *image;
1918 
1919   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), bounding_box);
1920 
1921   image = gimp_display_get_image (shell->display);
1922 
1923   if (image)
1924     {
1925       if (! shell->show_all)
1926         {
1927           bounding_box.width  = gimp_image_get_width  (image);
1928           bounding_box.height = gimp_image_get_height (image);
1929         }
1930       else
1931         {
1932           bounding_box = gimp_projectable_get_bounding_box (
1933             GIMP_PROJECTABLE (image));
1934         }
1935     }
1936 
1937   return bounding_box;
1938 }
1939 
1940 gboolean
gimp_display_shell_get_infinite_canvas(GimpDisplayShell * shell)1941 gimp_display_shell_get_infinite_canvas (GimpDisplayShell *shell)
1942 {
1943   g_return_val_if_fail (GIMP_IS_DISPLAY_SHELL (shell), FALSE);
1944 
1945   return shell->show_all &&
1946          ! gimp_display_shell_get_padding_in_show_all (shell);
1947 }
1948 
1949 void
gimp_display_shell_update_priority_rect(GimpDisplayShell * shell)1950 gimp_display_shell_update_priority_rect (GimpDisplayShell *shell)
1951 {
1952   GimpImage *image;
1953 
1954   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1955 
1956   image = gimp_display_get_image (shell->display);
1957 
1958   if (image)
1959     {
1960       GimpProjection *projection = gimp_image_get_projection (image);
1961       gint            x, y;
1962       gint            width, height;
1963 
1964       gimp_display_shell_untransform_viewport (shell, ! shell->show_all,
1965                                                &x, &y, &width, &height);
1966       gimp_projection_set_priority_rect (projection, x, y, width, height);
1967     }
1968 }
1969 
1970 void
gimp_display_shell_flush(GimpDisplayShell * shell,gboolean now)1971 gimp_display_shell_flush (GimpDisplayShell *shell,
1972                           gboolean          now)
1973 {
1974   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
1975 
1976   if (now)
1977     {
1978       gdk_window_process_updates (gtk_widget_get_window (shell->canvas),
1979                                   FALSE);
1980     }
1981   else
1982     {
1983       GimpImageWindow *window = gimp_display_shell_get_window (shell);
1984       GimpContext     *context;
1985 
1986       gimp_display_shell_title_update (shell);
1987 
1988       gimp_canvas_layer_boundary_set_layer (GIMP_CANVAS_LAYER_BOUNDARY (shell->layer_boundary),
1989                                             gimp_image_get_active_layer (gimp_display_get_image (shell->display)));
1990 
1991       gimp_canvas_canvas_boundary_set_image (GIMP_CANVAS_CANVAS_BOUNDARY (shell->canvas_boundary),
1992                                              gimp_display_get_image (shell->display));
1993 
1994       if (window && gimp_image_window_get_active_shell (window) == shell)
1995         {
1996           GimpUIManager *manager = gimp_image_window_get_ui_manager (window);
1997 
1998           gimp_ui_manager_update (manager, shell->display);
1999         }
2000 
2001       context = gimp_get_user_context (shell->display->gimp);
2002 
2003       if (shell->display == gimp_context_get_display (context))
2004         {
2005           gimp_ui_manager_update (shell->popup_manager, shell->display);
2006         }
2007     }
2008 }
2009 
2010 /**
2011  * gimp_display_shell_pause:
2012  * @shell: a display shell
2013  *
2014  * This function increments the pause count or the display shell.
2015  * If it was zero coming in, then the function pauses the active tool,
2016  * so that operations on the display can take place without corrupting
2017  * anything that the tool has drawn.  It "undraws" the current tool
2018  * drawing, and must be followed by gimp_display_shell_resume() after
2019  * the operation in question is completed.
2020  **/
2021 void
gimp_display_shell_pause(GimpDisplayShell * shell)2022 gimp_display_shell_pause (GimpDisplayShell *shell)
2023 {
2024   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
2025 
2026   shell->paused_count++;
2027 
2028   if (shell->paused_count == 1)
2029     {
2030       /*  pause the currently active tool  */
2031       tool_manager_control_active (shell->display->gimp,
2032                                    GIMP_TOOL_ACTION_PAUSE,
2033                                    shell->display);
2034     }
2035 }
2036 
2037 /**
2038  * gimp_display_shell_resume:
2039  * @shell: a display shell
2040  *
2041  * This function decrements the pause count for the display shell.
2042  * If this brings it to zero, then the current tool is resumed.
2043  * It is an error to call this function without having previously
2044  * called gimp_display_shell_pause().
2045  **/
2046 void
gimp_display_shell_resume(GimpDisplayShell * shell)2047 gimp_display_shell_resume (GimpDisplayShell *shell)
2048 {
2049   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
2050   g_return_if_fail (shell->paused_count > 0);
2051 
2052   shell->paused_count--;
2053 
2054   if (shell->paused_count == 0)
2055     {
2056       /* start the currently active tool */
2057       tool_manager_control_active (shell->display->gimp,
2058                                    GIMP_TOOL_ACTION_RESUME,
2059                                    shell->display);
2060     }
2061 }
2062 
2063 /**
2064  * gimp_display_shell_set_highlight:
2065  * @shell:     a #GimpDisplayShell
2066  * @highlight: a rectangle in image coordinates that should be brought out
2067  * @opacity:   how much to hide the unselected area
2068  *
2069  * This function sets an area of the image that should be
2070  * accentuated. The actual implementation is to dim all pixels outside
2071  * this rectangle. Passing %NULL for @highlight unsets the rectangle.
2072  **/
2073 void
gimp_display_shell_set_highlight(GimpDisplayShell * shell,const GdkRectangle * highlight,gdouble opacity)2074 gimp_display_shell_set_highlight (GimpDisplayShell   *shell,
2075                                   const GdkRectangle *highlight,
2076                                   gdouble             opacity)
2077 {
2078   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
2079 
2080   if (highlight)
2081     {
2082       gimp_canvas_item_begin_change (shell->passe_partout);
2083 
2084       gimp_canvas_rectangle_set (shell->passe_partout,
2085                                  highlight->x,
2086                                  highlight->y,
2087                                  highlight->width,
2088                                  highlight->height);
2089       g_object_set (shell->passe_partout, "opacity", opacity, NULL);
2090 
2091       gimp_canvas_item_set_visible (shell->passe_partout, TRUE);
2092 
2093       gimp_canvas_item_end_change (shell->passe_partout);
2094     }
2095   else
2096     {
2097       gimp_canvas_item_set_visible (shell->passe_partout, FALSE);
2098     }
2099 }
2100 
2101 /**
2102  * gimp_display_shell_set_mask:
2103  * @shell: a #GimpDisplayShell
2104  * @mask:  a #GimpDrawable (1 byte per pixel)
2105  * @color: the color to use for drawing the mask
2106  * @inverted: #TRUE if the mask should be drawn inverted
2107  *
2108  * Previews a mask originating at offset_x, offset_x. Depending on
2109  * @inverted, pixels that are selected or not selected are tinted with
2110  * the given color.
2111  **/
2112 void
gimp_display_shell_set_mask(GimpDisplayShell * shell,GeglBuffer * mask,gint offset_x,gint offset_y,const GimpRGB * color,gboolean inverted)2113 gimp_display_shell_set_mask (GimpDisplayShell *shell,
2114                              GeglBuffer       *mask,
2115                              gint              offset_x,
2116                              gint              offset_y,
2117                              const GimpRGB    *color,
2118                              gboolean          inverted)
2119 {
2120   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
2121   g_return_if_fail (mask == NULL || GEGL_IS_BUFFER (mask));
2122   g_return_if_fail (mask == NULL || color != NULL);
2123 
2124   if (mask)
2125     g_object_ref (mask);
2126 
2127   if (shell->mask)
2128     g_object_unref (shell->mask);
2129 
2130   shell->mask = mask;
2131 
2132   shell->mask_offset_x = offset_x;
2133   shell->mask_offset_y = offset_y;
2134 
2135   if (mask)
2136     shell->mask_color = *color;
2137 
2138   shell->mask_inverted = inverted;
2139 
2140   gimp_display_shell_expose_full (shell);
2141 }
2142