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 <gegl.h>
21 #include <gtk/gtk.h>
22 
23 #include "libgimpmath/gimpmath.h"
24 
25 #include "display-types.h"
26 #include "tools/tools-types.h"
27 
28 #include "config/gimpguiconfig.h"
29 
30 #include "core/gimp.h"
31 #include "core/gimpcontainer.h"
32 #include "core/gimpcontext.h"
33 #include "core/gimpimage.h"
34 #include "core/gimpprogress.h"
35 
36 #include "widgets/gimpdialogfactory.h"
37 
38 #include "tools/gimptool.h"
39 #include "tools/tool_manager.h"
40 
41 #include "gimpdisplay.h"
42 #include "gimpdisplay-handlers.h"
43 #include "gimpdisplayshell.h"
44 #include "gimpdisplayshell-expose.h"
45 #include "gimpdisplayshell-handlers.h"
46 #include "gimpdisplayshell-icon.h"
47 #include "gimpdisplayshell-scroll.h"
48 #include "gimpdisplayshell-scrollbars.h"
49 #include "gimpdisplayshell-title.h"
50 #include "gimpdisplayshell-transform.h"
51 #include "gimpimagewindow.h"
52 
53 #include "gimp-intl.h"
54 
55 
56 #define FLUSH_NOW_INTERVAL      (G_TIME_SPAN_SECOND / 60)
57 
58 #define PAINT_AREA_CHUNK_WIDTH  32
59 #define PAINT_AREA_CHUNK_HEIGHT 32
60 
61 
62 enum
63 {
64   PROP_0,
65   PROP_ID,
66   PROP_GIMP,
67   PROP_IMAGE,
68   PROP_SHELL
69 };
70 
71 
72 typedef struct _GimpDisplayPrivate GimpDisplayPrivate;
73 
74 struct _GimpDisplayPrivate
75 {
76   gint            ID;           /*  unique identifier for this display  */
77 
78   GimpImage      *image;        /*  pointer to the associated image     */
79   gint            instance;     /*  the instance # of this display as
80                                  *  taken from the image at creation    */
81 
82   GeglRectangle   bounding_box;
83 
84   GtkWidget      *shell;
85   cairo_region_t *update_region;
86 
87   guint64         last_flush_now;
88 };
89 
90 #define GIMP_DISPLAY_GET_PRIVATE(display) \
91         ((GimpDisplayPrivate *) gimp_display_get_instance_private ((GimpDisplay *) (display)))
92 
93 
94 /*  local function prototypes  */
95 
96 static void     gimp_display_progress_iface_init  (GimpProgressInterface *iface);
97 
98 static void     gimp_display_set_property           (GObject             *object,
99                                                      guint                property_id,
100                                                      const GValue        *value,
101                                                      GParamSpec          *pspec);
102 static void     gimp_display_get_property           (GObject             *object,
103                                                      guint                property_id,
104                                                      GValue              *value,
105                                                      GParamSpec          *pspec);
106 
107 static GimpProgress * gimp_display_progress_start   (GimpProgress        *progress,
108                                                      gboolean             cancellable,
109                                                      const gchar         *message);
110 static void     gimp_display_progress_end           (GimpProgress        *progress);
111 static gboolean gimp_display_progress_is_active     (GimpProgress        *progress);
112 static void     gimp_display_progress_set_text      (GimpProgress        *progress,
113                                                      const gchar         *message);
114 static void     gimp_display_progress_set_value     (GimpProgress        *progress,
115                                                      gdouble              percentage);
116 static gdouble  gimp_display_progress_get_value     (GimpProgress        *progress);
117 static void     gimp_display_progress_pulse         (GimpProgress        *progress);
118 static guint32  gimp_display_progress_get_window_id (GimpProgress        *progress);
119 static gboolean gimp_display_progress_message       (GimpProgress        *progress,
120                                                      Gimp                *gimp,
121                                                      GimpMessageSeverity  severity,
122                                                      const gchar         *domain,
123                                                      const gchar         *message);
124 static void     gimp_display_progress_canceled      (GimpProgress        *progress,
125                                                      GimpDisplay         *display);
126 
127 static void     gimp_display_flush_whenever         (GimpDisplay         *display,
128                                                      gboolean             now);
129 static void     gimp_display_paint_area             (GimpDisplay         *display,
130                                                      gint                 x,
131                                                      gint                 y,
132                                                      gint                 w,
133                                                      gint                 h);
134 
135 
G_DEFINE_TYPE_WITH_CODE(GimpDisplay,gimp_display,GIMP_TYPE_OBJECT,G_ADD_PRIVATE (GimpDisplay)G_IMPLEMENT_INTERFACE (GIMP_TYPE_PROGRESS,gimp_display_progress_iface_init))136 G_DEFINE_TYPE_WITH_CODE (GimpDisplay, gimp_display, GIMP_TYPE_OBJECT,
137                          G_ADD_PRIVATE (GimpDisplay)
138                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_PROGRESS,
139                                                 gimp_display_progress_iface_init))
140 
141 #define parent_class gimp_display_parent_class
142 
143 
144 static void
145 gimp_display_class_init (GimpDisplayClass *klass)
146 {
147   GObjectClass *object_class = G_OBJECT_CLASS (klass);
148 
149   object_class->set_property = gimp_display_set_property;
150   object_class->get_property = gimp_display_get_property;
151 
152   g_object_class_install_property (object_class, PROP_ID,
153                                    g_param_spec_int ("id",
154                                                      NULL, NULL,
155                                                      0, G_MAXINT, 0,
156                                                      GIMP_PARAM_READABLE));
157 
158   g_object_class_install_property (object_class, PROP_GIMP,
159                                    g_param_spec_object ("gimp",
160                                                         NULL, NULL,
161                                                         GIMP_TYPE_GIMP,
162                                                         GIMP_PARAM_READWRITE |
163                                                         G_PARAM_CONSTRUCT_ONLY));
164 
165   g_object_class_install_property (object_class, PROP_IMAGE,
166                                    g_param_spec_object ("image",
167                                                         NULL, NULL,
168                                                         GIMP_TYPE_IMAGE,
169                                                         GIMP_PARAM_READABLE));
170 
171   g_object_class_install_property (object_class, PROP_SHELL,
172                                    g_param_spec_object ("shell",
173                                                         NULL, NULL,
174                                                         GIMP_TYPE_DISPLAY_SHELL,
175                                                         GIMP_PARAM_READABLE));
176 }
177 
178 static void
gimp_display_init(GimpDisplay * display)179 gimp_display_init (GimpDisplay *display)
180 {
181 }
182 
183 static void
gimp_display_progress_iface_init(GimpProgressInterface * iface)184 gimp_display_progress_iface_init (GimpProgressInterface *iface)
185 {
186   iface->start         = gimp_display_progress_start;
187   iface->end           = gimp_display_progress_end;
188   iface->is_active     = gimp_display_progress_is_active;
189   iface->set_text      = gimp_display_progress_set_text;
190   iface->set_value     = gimp_display_progress_set_value;
191   iface->get_value     = gimp_display_progress_get_value;
192   iface->pulse         = gimp_display_progress_pulse;
193   iface->get_window_id = gimp_display_progress_get_window_id;
194   iface->message       = gimp_display_progress_message;
195 }
196 
197 static void
gimp_display_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)198 gimp_display_set_property (GObject      *object,
199                            guint         property_id,
200                            const GValue *value,
201                            GParamSpec   *pspec)
202 {
203   GimpDisplay        *display = GIMP_DISPLAY (object);
204   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
205 
206   switch (property_id)
207     {
208     case PROP_GIMP:
209       {
210         gint ID;
211 
212         display->gimp = g_value_get_object (value); /* don't ref the gimp */
213         display->config = GIMP_DISPLAY_CONFIG (display->gimp->config);
214 
215         do
216           {
217             ID = display->gimp->next_display_ID++;
218 
219             if (display->gimp->next_display_ID == G_MAXINT)
220               display->gimp->next_display_ID = 1;
221           }
222         while (gimp_display_get_by_ID (display->gimp, ID));
223 
224         private->ID = ID;
225       }
226       break;
227 
228     default:
229       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
230       break;
231     }
232 }
233 
234 static void
gimp_display_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)235 gimp_display_get_property (GObject    *object,
236                            guint       property_id,
237                            GValue     *value,
238                            GParamSpec *pspec)
239 {
240   GimpDisplay        *display = GIMP_DISPLAY (object);
241   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
242 
243   switch (property_id)
244     {
245     case PROP_ID:
246       g_value_set_int (value, private->ID);
247       break;
248 
249     case PROP_GIMP:
250       g_value_set_object (value, display->gimp);
251       break;
252 
253     case PROP_IMAGE:
254       g_value_set_object (value, private->image);
255       break;
256 
257     case PROP_SHELL:
258       g_value_set_object (value, private->shell);
259       break;
260 
261     default:
262       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
263       break;
264     }
265 }
266 
267 static GimpProgress *
gimp_display_progress_start(GimpProgress * progress,gboolean cancellable,const gchar * message)268 gimp_display_progress_start (GimpProgress *progress,
269                              gboolean      cancellable,
270                              const gchar  *message)
271 {
272   GimpDisplay        *display = GIMP_DISPLAY (progress);
273   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
274 
275   if (private->shell)
276     return gimp_progress_start (GIMP_PROGRESS (private->shell), cancellable,
277                                 "%s", message);
278 
279   return NULL;
280 }
281 
282 static void
gimp_display_progress_end(GimpProgress * progress)283 gimp_display_progress_end (GimpProgress *progress)
284 {
285   GimpDisplay        *display = GIMP_DISPLAY (progress);
286   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
287 
288   if (private->shell)
289     gimp_progress_end (GIMP_PROGRESS (private->shell));
290 }
291 
292 static gboolean
gimp_display_progress_is_active(GimpProgress * progress)293 gimp_display_progress_is_active (GimpProgress *progress)
294 {
295   GimpDisplay        *display = GIMP_DISPLAY (progress);
296   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
297 
298   if (private->shell)
299     return gimp_progress_is_active (GIMP_PROGRESS (private->shell));
300 
301   return FALSE;
302 }
303 
304 static void
gimp_display_progress_set_text(GimpProgress * progress,const gchar * message)305 gimp_display_progress_set_text (GimpProgress *progress,
306                                 const gchar  *message)
307 {
308   GimpDisplay        *display = GIMP_DISPLAY (progress);
309   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
310 
311   if (private->shell)
312     gimp_progress_set_text_literal (GIMP_PROGRESS (private->shell), message);
313 }
314 
315 static void
gimp_display_progress_set_value(GimpProgress * progress,gdouble percentage)316 gimp_display_progress_set_value (GimpProgress *progress,
317                                  gdouble       percentage)
318 {
319   GimpDisplay        *display = GIMP_DISPLAY (progress);
320   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
321 
322   if (private->shell)
323     gimp_progress_set_value (GIMP_PROGRESS (private->shell), percentage);
324 }
325 
326 static gdouble
gimp_display_progress_get_value(GimpProgress * progress)327 gimp_display_progress_get_value (GimpProgress *progress)
328 {
329   GimpDisplay        *display = GIMP_DISPLAY (progress);
330   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
331 
332   if (private->shell)
333     return gimp_progress_get_value (GIMP_PROGRESS (private->shell));
334 
335   return 0.0;
336 }
337 
338 static void
gimp_display_progress_pulse(GimpProgress * progress)339 gimp_display_progress_pulse (GimpProgress *progress)
340 {
341   GimpDisplay        *display = GIMP_DISPLAY (progress);
342   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
343 
344   if (private->shell)
345     gimp_progress_pulse (GIMP_PROGRESS (private->shell));
346 }
347 
348 static guint32
gimp_display_progress_get_window_id(GimpProgress * progress)349 gimp_display_progress_get_window_id (GimpProgress *progress)
350 {
351   GimpDisplay        *display = GIMP_DISPLAY (progress);
352   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
353 
354   if (private->shell)
355     return gimp_progress_get_window_id (GIMP_PROGRESS (private->shell));
356 
357   return 0;
358 }
359 
360 static gboolean
gimp_display_progress_message(GimpProgress * progress,Gimp * gimp,GimpMessageSeverity severity,const gchar * domain,const gchar * message)361 gimp_display_progress_message (GimpProgress        *progress,
362                                Gimp                *gimp,
363                                GimpMessageSeverity  severity,
364                                const gchar         *domain,
365                                const gchar         *message)
366 {
367   GimpDisplay        *display = GIMP_DISPLAY (progress);
368   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
369 
370   if (private->shell)
371     return gimp_progress_message (GIMP_PROGRESS (private->shell), gimp,
372                                   severity, domain, message);
373 
374   return FALSE;
375 }
376 
377 static void
gimp_display_progress_canceled(GimpProgress * progress,GimpDisplay * display)378 gimp_display_progress_canceled (GimpProgress *progress,
379                                 GimpDisplay  *display)
380 {
381   gimp_progress_cancel (GIMP_PROGRESS (display));
382 }
383 
384 
385 /*  public functions  */
386 
387 GimpDisplay *
gimp_display_new(Gimp * gimp,GimpImage * image,GimpUnit unit,gdouble scale,GimpUIManager * popup_manager,GimpDialogFactory * dialog_factory,GdkScreen * screen,gint monitor)388 gimp_display_new (Gimp              *gimp,
389                   GimpImage         *image,
390                   GimpUnit           unit,
391                   gdouble            scale,
392                   GimpUIManager     *popup_manager,
393                   GimpDialogFactory *dialog_factory,
394                   GdkScreen         *screen,
395                   gint               monitor)
396 {
397   GimpDisplay        *display;
398   GimpDisplayPrivate *private;
399   GimpImageWindow    *window = NULL;
400   GimpDisplayShell   *shell;
401 
402   g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
403   g_return_val_if_fail (image == NULL || GIMP_IS_IMAGE (image), NULL);
404   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
405 
406   /*  If there isn't an interface, never create a display  */
407   if (gimp->no_interface)
408     return NULL;
409 
410   display = g_object_new (GIMP_TYPE_DISPLAY,
411                           "gimp", gimp,
412                           NULL);
413 
414   private = GIMP_DISPLAY_GET_PRIVATE (display);
415 
416   /*  refs the image  */
417   if (image)
418     gimp_display_set_image (display, image);
419 
420   /*  get an image window  */
421   if (GIMP_GUI_CONFIG (display->config)->single_window_mode)
422     {
423       GimpDisplay *active_display;
424 
425       active_display = gimp_context_get_display (gimp_get_user_context (gimp));
426 
427       if (! active_display)
428         {
429           active_display =
430             GIMP_DISPLAY (gimp_container_get_first_child (gimp->displays));
431         }
432 
433       if (active_display)
434         {
435           GimpDisplayShell *shell = gimp_display_get_shell (active_display);
436 
437           window = gimp_display_shell_get_window (shell);
438         }
439     }
440 
441   if (! window)
442     {
443       window = gimp_image_window_new (gimp,
444                                       private->image,
445                                       dialog_factory,
446                                       screen,
447                                       monitor);
448     }
449 
450   /*  create the shell for the image  */
451   private->shell = gimp_display_shell_new (display, unit, scale,
452                                            popup_manager,
453                                            screen,
454                                            monitor);
455 
456   shell = gimp_display_get_shell (display);
457 
458   gimp_display_update_bounding_box (display);
459 
460   gimp_image_window_add_shell (window, shell);
461   gimp_display_shell_present (shell);
462 
463   /* make sure the docks are visible, in case all other image windows
464    * are iconified, see bug #686544.
465    */
466   gimp_dialog_factory_show_with_display (dialog_factory);
467 
468   g_signal_connect (gimp_display_shell_get_statusbar (shell), "cancel",
469                     G_CALLBACK (gimp_display_progress_canceled),
470                     display);
471 
472   /* add the display to the list */
473   gimp_container_add (gimp->displays, GIMP_OBJECT (display));
474 
475   return display;
476 }
477 
478 /**
479  * gimp_display_delete:
480  * @display:
481  *
482  * Closes the display and removes it from the display list. You should
483  * not call this function directly, use gimp_display_close() instead.
484  */
485 void
gimp_display_delete(GimpDisplay * display)486 gimp_display_delete (GimpDisplay *display)
487 {
488   GimpDisplayPrivate *private;
489   GimpTool           *active_tool;
490 
491   g_return_if_fail (GIMP_IS_DISPLAY (display));
492 
493   private = GIMP_DISPLAY_GET_PRIVATE (display);
494 
495   /* remove the display from the list */
496   gimp_container_remove (display->gimp->displays, GIMP_OBJECT (display));
497 
498   /*  unrefs the image  */
499   gimp_display_set_image (display, NULL);
500 
501   active_tool = tool_manager_get_active (display->gimp);
502 
503   if (active_tool && active_tool->focus_display == display)
504     tool_manager_focus_display_active (display->gimp, NULL);
505 
506   if (private->shell)
507     {
508       GimpDisplayShell *shell  = gimp_display_get_shell (display);
509       GimpImageWindow  *window = gimp_display_shell_get_window (shell);
510 
511       /*  set private->shell to NULL *before* destroying the shell.
512        *  all callbacks in gimpdisplayshell-callbacks.c will check
513        *  this pointer and do nothing if the shell is in destruction.
514        */
515       private->shell = NULL;
516 
517       if (window)
518         {
519           if (gimp_image_window_get_n_shells (window) > 1)
520             {
521               g_object_ref (shell);
522 
523               gimp_image_window_remove_shell (window, shell);
524               gtk_widget_destroy (GTK_WIDGET (shell));
525 
526               g_object_unref (shell);
527             }
528           else
529             {
530               gimp_image_window_destroy (window);
531             }
532         }
533       else
534         {
535           g_object_unref (shell);
536         }
537     }
538 
539   g_object_unref (display);
540 }
541 
542 /**
543  * gimp_display_close:
544  * @display:
545  *
546  * Closes the display. If this is the last display, it will remain
547  * open, but without an image.
548  */
549 void
gimp_display_close(GimpDisplay * display)550 gimp_display_close (GimpDisplay *display)
551 {
552   g_return_if_fail (GIMP_IS_DISPLAY (display));
553 
554   if (gimp_container_get_n_children (display->gimp->displays) > 1)
555     {
556       gimp_display_delete (display);
557     }
558   else
559     {
560       gimp_display_empty (display);
561     }
562 }
563 
564 gint
gimp_display_get_ID(GimpDisplay * display)565 gimp_display_get_ID (GimpDisplay *display)
566 {
567   GimpDisplayPrivate *private;
568 
569   g_return_val_if_fail (GIMP_IS_DISPLAY (display), -1);
570 
571   private = GIMP_DISPLAY_GET_PRIVATE (display);
572 
573   return private->ID;
574 }
575 
576 GimpDisplay *
gimp_display_get_by_ID(Gimp * gimp,gint ID)577 gimp_display_get_by_ID (Gimp *gimp,
578                         gint  ID)
579 {
580   GList *list;
581 
582   g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
583 
584   for (list = gimp_get_display_iter (gimp);
585        list;
586        list = g_list_next (list))
587     {
588       GimpDisplay *display = list->data;
589 
590       if (gimp_display_get_ID (display) == ID)
591         return display;
592     }
593 
594   return NULL;
595 }
596 
597 /**
598  * gimp_display_get_action_name:
599  * @display:
600  *
601  * Returns: The action name for the given display. The action name
602  * depends on the display ID. The result must be freed with g_free().
603  **/
604 gchar *
gimp_display_get_action_name(GimpDisplay * display)605 gimp_display_get_action_name (GimpDisplay *display)
606 {
607   g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
608 
609   return g_strdup_printf ("windows-display-%04d",
610                           gimp_display_get_ID (display));
611 }
612 
613 Gimp *
gimp_display_get_gimp(GimpDisplay * display)614 gimp_display_get_gimp (GimpDisplay *display)
615 {
616   g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
617 
618   return display->gimp;
619 }
620 
621 GimpImage *
gimp_display_get_image(GimpDisplay * display)622 gimp_display_get_image (GimpDisplay *display)
623 {
624   g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
625 
626   return GIMP_DISPLAY_GET_PRIVATE (display)->image;
627 }
628 
629 void
gimp_display_set_image(GimpDisplay * display,GimpImage * image)630 gimp_display_set_image (GimpDisplay *display,
631                         GimpImage   *image)
632 {
633   GimpDisplayPrivate *private;
634   GimpImage          *old_image = NULL;
635   GimpDisplayShell   *shell;
636 
637   g_return_if_fail (GIMP_IS_DISPLAY (display));
638   g_return_if_fail (image == NULL || GIMP_IS_IMAGE (image));
639 
640   private = GIMP_DISPLAY_GET_PRIVATE (display);
641 
642   shell = gimp_display_get_shell (display);
643 
644   if (private->image)
645     {
646       /*  stop any active tool  */
647       tool_manager_control_active (display->gimp, GIMP_TOOL_ACTION_HALT,
648                                    display);
649 
650       gimp_display_shell_disconnect (shell);
651 
652       gimp_display_disconnect (display);
653 
654       g_clear_pointer (&private->update_region, cairo_region_destroy);
655 
656       gimp_image_dec_display_count (private->image);
657 
658       /*  set private->image before unrefing because there may be code
659        *  that listens for image removals and then iterates the
660        *  display list to find a valid display.
661        */
662       old_image = private->image;
663 
664 #if 0
665       g_print ("%s: image->ref_count before unrefing: %d\n",
666                G_STRFUNC, G_OBJECT (old_image)->ref_count);
667 #endif
668     }
669 
670   private->image = image;
671 
672   if (image)
673     {
674 #if 0
675       g_print ("%s: image->ref_count before refing: %d\n",
676                G_STRFUNC, G_OBJECT (image)->ref_count);
677 #endif
678 
679       g_object_ref (image);
680 
681       private->instance = gimp_image_get_instance_count (image);
682       gimp_image_inc_instance_count (image);
683 
684       gimp_image_inc_display_count (image);
685 
686       gimp_display_connect (display);
687 
688       if (shell)
689         gimp_display_shell_connect (shell);
690     }
691 
692   if (old_image)
693     g_object_unref (old_image);
694 
695   gimp_display_update_bounding_box (display);
696 
697   if (shell)
698     {
699       if (image)
700         {
701           gimp_display_shell_reconnect (shell);
702         }
703       else
704         {
705           gimp_display_shell_title_update (shell);
706           gimp_display_shell_icon_update (shell);
707         }
708     }
709 
710   if (old_image != image)
711     g_object_notify (G_OBJECT (display), "image");
712 }
713 
714 gint
gimp_display_get_instance(GimpDisplay * display)715 gimp_display_get_instance (GimpDisplay *display)
716 {
717   GimpDisplayPrivate *private;
718 
719   g_return_val_if_fail (GIMP_IS_DISPLAY (display), 0);
720 
721   private = GIMP_DISPLAY_GET_PRIVATE (display);
722 
723   return private->instance;
724 }
725 
726 GimpDisplayShell *
gimp_display_get_shell(GimpDisplay * display)727 gimp_display_get_shell (GimpDisplay *display)
728 {
729   GimpDisplayPrivate *private;
730 
731   g_return_val_if_fail (GIMP_IS_DISPLAY (display), NULL);
732 
733   private = GIMP_DISPLAY_GET_PRIVATE (display);
734 
735   return GIMP_DISPLAY_SHELL (private->shell);
736 }
737 
738 void
gimp_display_empty(GimpDisplay * display)739 gimp_display_empty (GimpDisplay *display)
740 {
741   GimpDisplayPrivate *private;
742   GList              *iter;
743 
744   g_return_if_fail (GIMP_IS_DISPLAY (display));
745 
746   private = GIMP_DISPLAY_GET_PRIVATE (display);
747 
748   g_return_if_fail (GIMP_IS_IMAGE (private->image));
749 
750   for (iter = display->gimp->context_list; iter; iter = g_list_next (iter))
751     {
752       GimpContext *context = iter->data;
753 
754       if (gimp_context_get_display (context) == display)
755         gimp_context_set_image (context, NULL);
756     }
757 
758   gimp_display_set_image (display, NULL);
759 
760   gimp_display_shell_empty (gimp_display_get_shell (display));
761 }
762 
763 void
gimp_display_fill(GimpDisplay * display,GimpImage * image,GimpUnit unit,gdouble scale)764 gimp_display_fill (GimpDisplay *display,
765                    GimpImage   *image,
766                    GimpUnit     unit,
767                    gdouble      scale)
768 {
769   GimpDisplayPrivate *private;
770 
771   g_return_if_fail (GIMP_IS_DISPLAY (display));
772   g_return_if_fail (GIMP_IS_IMAGE (image));
773 
774   private = GIMP_DISPLAY_GET_PRIVATE (display);
775 
776   g_return_if_fail (private->image == NULL);
777 
778   gimp_display_set_image (display, image);
779 
780   gimp_display_shell_fill (gimp_display_get_shell (display),
781                            image, unit, scale);
782 }
783 
784 void
gimp_display_update_bounding_box(GimpDisplay * display)785 gimp_display_update_bounding_box (GimpDisplay *display)
786 {
787   GimpDisplayPrivate *private;
788   GimpDisplayShell   *shell;
789   GeglRectangle       bounding_box = {};
790 
791   g_return_if_fail (GIMP_IS_DISPLAY (display));
792 
793   private = GIMP_DISPLAY_GET_PRIVATE (display);
794   shell   = gimp_display_get_shell (display);
795 
796   if (shell)
797     {
798       bounding_box = gimp_display_shell_get_bounding_box (shell);
799 
800       if (! gegl_rectangle_equal (&bounding_box, &private->bounding_box))
801         {
802           GeglRectangle diff_rects[4];
803           gint          n_diff_rects;
804           gint          i;
805 
806           n_diff_rects = gegl_rectangle_subtract (diff_rects,
807                                                   &private->bounding_box,
808                                                   &bounding_box);
809 
810           for (i = 0; i < n_diff_rects; i++)
811             {
812               gimp_display_paint_area (display,
813                                        diff_rects[i].x,     diff_rects[i].y,
814                                        diff_rects[i].width, diff_rects[i].height);
815             }
816 
817           private->bounding_box = bounding_box;
818 
819           gimp_display_shell_scroll_clamp_and_update (shell);
820           gimp_display_shell_scrollbars_update (shell);
821         }
822     }
823   else
824     {
825       private->bounding_box = bounding_box;
826     }
827 }
828 
829 void
gimp_display_update_area(GimpDisplay * display,gboolean now,gint x,gint y,gint w,gint h)830 gimp_display_update_area (GimpDisplay *display,
831                           gboolean     now,
832                           gint         x,
833                           gint         y,
834                           gint         w,
835                           gint         h)
836 {
837   GimpDisplayPrivate *private;
838 
839   g_return_if_fail (GIMP_IS_DISPLAY (display));
840 
841   private = GIMP_DISPLAY_GET_PRIVATE (display);
842 
843   if (now)
844     {
845       gimp_display_paint_area (display, x, y, w, h);
846     }
847   else
848     {
849       cairo_rectangle_int_t rect;
850       gint                  image_width;
851       gint                  image_height;
852 
853       image_width  = gimp_image_get_width  (private->image);
854       image_height = gimp_image_get_height (private->image);
855 
856       rect.x      = CLAMP (x,     0, image_width);
857       rect.y      = CLAMP (y,     0, image_height);
858       rect.width  = CLAMP (x + w, 0, image_width)  - rect.x;
859       rect.height = CLAMP (y + h, 0, image_height) - rect.y;
860 
861       if (private->update_region)
862         cairo_region_union_rectangle (private->update_region, &rect);
863       else
864         private->update_region = cairo_region_create_rectangle (&rect);
865     }
866 }
867 
868 void
gimp_display_flush(GimpDisplay * display)869 gimp_display_flush (GimpDisplay *display)
870 {
871   g_return_if_fail (GIMP_IS_DISPLAY (display));
872 
873   /* FIXME: we can end up being called during shell construction if "show all"
874    * is enabled by default, in which case the shell's display pointer is still
875    * NULL
876    */
877   if (gimp_display_get_shell (display))
878     gimp_display_flush_whenever (display, FALSE);
879 }
880 
881 void
gimp_display_flush_now(GimpDisplay * display)882 gimp_display_flush_now (GimpDisplay *display)
883 {
884   g_return_if_fail (GIMP_IS_DISPLAY (display));
885 
886   gimp_display_flush_whenever (display, TRUE);
887 }
888 
889 
890 /*  private functions  */
891 
892 static void
gimp_display_flush_whenever(GimpDisplay * display,gboolean now)893 gimp_display_flush_whenever (GimpDisplay *display,
894                              gboolean     now)
895 {
896   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
897 
898   if (private->update_region)
899     {
900       gint n_rects = cairo_region_num_rectangles (private->update_region);
901       gint i;
902 
903       for (i = 0; i < n_rects; i++)
904         {
905           cairo_rectangle_int_t rect;
906 
907           cairo_region_get_rectangle (private->update_region,
908                                       i, &rect);
909 
910           gimp_display_paint_area (display,
911                                    rect.x,
912                                    rect.y,
913                                    rect.width,
914                                    rect.height);
915         }
916 
917       g_clear_pointer (&private->update_region, cairo_region_destroy);
918     }
919 
920   if (now)
921     {
922       guint64 now = g_get_monotonic_time ();
923 
924       if ((now - private->last_flush_now) > FLUSH_NOW_INTERVAL)
925         {
926           gimp_display_shell_flush (gimp_display_get_shell (display), TRUE);
927 
928           private->last_flush_now = now;
929         }
930     }
931   else
932     {
933       gimp_display_shell_flush (gimp_display_get_shell (display), now);
934     }
935 }
936 
937 static void
gimp_display_paint_area(GimpDisplay * display,gint x,gint y,gint w,gint h)938 gimp_display_paint_area (GimpDisplay *display,
939                          gint         x,
940                          gint         y,
941                          gint         w,
942                          gint         h)
943 {
944   GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display);
945   GimpDisplayShell   *shell   = gimp_display_get_shell (display);
946   GeglRectangle       rect;
947   gint                x1, y1, x2, y2;
948   gdouble             x1_f, y1_f, x2_f, y2_f;
949 
950   if (! gegl_rectangle_intersect (&rect,
951                                   &private->bounding_box,
952                                   GEGL_RECTANGLE (x, y, w, h)))
953     {
954       return;
955     }
956 
957   /*  display the area  */
958   gimp_display_shell_transform_bounds (shell,
959                                        rect.x,
960                                        rect.y,
961                                        rect.x + rect.width,
962                                        rect.y + rect.height,
963                                        &x1_f, &y1_f, &x2_f, &y2_f);
964 
965   /*  make sure to expose a superset of the transformed sub-pixel expose
966    *  area, not a subset. bug #126942. --mitch
967    *
968    *  also accommodate for spill introduced by potential box filtering.
969    *  (bug #474509). --simon
970    */
971   x1 = floor (x1_f - 0.5);
972   y1 = floor (y1_f - 0.5);
973   x2 = ceil (x2_f + 0.5);
974   y2 = ceil (y2_f + 0.5);
975 
976   /*  align transformed area to a coarse grid, to simplify the
977    *  invalidated area
978    */
979   x1 = floor ((gdouble) x1 / PAINT_AREA_CHUNK_WIDTH)  * PAINT_AREA_CHUNK_WIDTH;
980   y1 = floor ((gdouble) y1 / PAINT_AREA_CHUNK_HEIGHT) * PAINT_AREA_CHUNK_HEIGHT;
981   x2 = ceil  ((gdouble) x2 / PAINT_AREA_CHUNK_WIDTH)  * PAINT_AREA_CHUNK_WIDTH;
982   y2 = ceil  ((gdouble) y2 / PAINT_AREA_CHUNK_HEIGHT) * PAINT_AREA_CHUNK_HEIGHT;
983 
984   gimp_display_shell_expose_area (shell, x1, y1, x2 - x1, y2 - y1);
985 }
986