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 "display-types.h"
24 
25 #include "core/gimp.h"
26 #include "core/gimpcontainer.h"
27 #include "core/gimpcontext.h"
28 #include "core/gimpimage.h"
29 #include "core/gimplist.h"
30 
31 #include "gimpdisplay.h"
32 #include "gimpdisplay-foreach.h"
33 #include "gimpdisplayshell.h"
34 #include "gimpdisplayshell-cursor.h"
35 
36 
37 gboolean
gimp_displays_dirty(Gimp * gimp)38 gimp_displays_dirty (Gimp *gimp)
39 {
40   GList *list;
41 
42   g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
43 
44   for (list = gimp_get_display_iter (gimp);
45        list;
46        list = g_list_next (list))
47     {
48       GimpDisplay *display = list->data;
49       GimpImage   *image   = gimp_display_get_image (display);
50 
51       if (image && gimp_image_is_dirty (image))
52         return TRUE;
53     }
54 
55   return FALSE;
56 }
57 
58 static void
gimp_displays_image_dirty_callback(GimpImage * image,GimpDirtyMask dirty_mask,GimpContainer * container)59 gimp_displays_image_dirty_callback (GimpImage     *image,
60                                     GimpDirtyMask  dirty_mask,
61                                     GimpContainer *container)
62 {
63   if (gimp_image_is_dirty (image)              &&
64       gimp_image_get_display_count (image) > 0 &&
65       ! gimp_container_have (container, GIMP_OBJECT (image)))
66     gimp_container_add (container, GIMP_OBJECT (image));
67 }
68 
69 static void
gimp_displays_dirty_images_disconnect(GimpContainer * dirty_container,GimpContainer * global_container)70 gimp_displays_dirty_images_disconnect (GimpContainer *dirty_container,
71                                        GimpContainer *global_container)
72 {
73   GQuark handler;
74 
75   handler = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dirty_container),
76                                                 "clean-handler"));
77   gimp_container_remove_handler (global_container, handler);
78 
79   handler = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dirty_container),
80                                                 "dirty-handler"));
81   gimp_container_remove_handler (global_container, handler);
82 }
83 
84 static void
gimp_displays_image_clean_callback(GimpImage * image,GimpDirtyMask dirty_mask,GimpContainer * container)85 gimp_displays_image_clean_callback (GimpImage     *image,
86                                     GimpDirtyMask  dirty_mask,
87                                     GimpContainer *container)
88 {
89   if (! gimp_image_is_dirty (image))
90     gimp_container_remove (container, GIMP_OBJECT (image));
91 }
92 
93 GimpContainer *
gimp_displays_get_dirty_images(Gimp * gimp)94 gimp_displays_get_dirty_images (Gimp *gimp)
95 {
96   g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
97 
98   if (gimp_displays_dirty (gimp))
99     {
100       GimpContainer *container = gimp_list_new_weak (GIMP_TYPE_IMAGE, FALSE);
101       GList         *list;
102       GQuark         handler;
103 
104       handler =
105         gimp_container_add_handler (gimp->images, "clean",
106                                     G_CALLBACK (gimp_displays_image_dirty_callback),
107                                     container);
108       g_object_set_data (G_OBJECT (container), "clean-handler",
109                          GINT_TO_POINTER (handler));
110 
111       handler =
112         gimp_container_add_handler (gimp->images, "dirty",
113                                     G_CALLBACK (gimp_displays_image_dirty_callback),
114                                     container);
115       g_object_set_data (G_OBJECT (container), "dirty-handler",
116                          GINT_TO_POINTER (handler));
117 
118       g_signal_connect_object (container, "disconnect",
119                                G_CALLBACK (gimp_displays_dirty_images_disconnect),
120                                G_OBJECT (gimp->images), 0);
121 
122       gimp_container_add_handler (container, "clean",
123                                   G_CALLBACK (gimp_displays_image_clean_callback),
124                                   container);
125       gimp_container_add_handler (container, "dirty",
126                                   G_CALLBACK (gimp_displays_image_clean_callback),
127                                   container);
128 
129       for (list = gimp_get_image_iter (gimp);
130            list;
131            list = g_list_next (list))
132         {
133           GimpImage *image = list->data;
134 
135           if (gimp_image_is_dirty (image) &&
136               gimp_image_get_display_count (image) > 0)
137             gimp_container_add (container, GIMP_OBJECT (image));
138         }
139 
140       return container;
141     }
142 
143   return NULL;
144 }
145 
146 /**
147  * gimp_displays_delete:
148  * @gimp:
149  *
150  * Calls gimp_display_delete() an all displays in the display list.
151  * This closes all displays, including the first one which is usually
152  * kept open.
153  */
154 void
gimp_displays_delete(Gimp * gimp)155 gimp_displays_delete (Gimp *gimp)
156 {
157   /*  this removes the GimpDisplay from the list, so do a while loop
158    *  "around" the first element to get them all
159    */
160   while (! gimp_container_is_empty (gimp->displays))
161     {
162       GimpDisplay *display = gimp_get_display_iter (gimp)->data;
163 
164       gimp_display_delete (display);
165     }
166 }
167 
168 /**
169  * gimp_displays_close:
170  * @gimp:
171  *
172  * Calls gimp_display_close() an all displays in the display list. The
173  * first display will remain open without an image.
174  */
175 void
gimp_displays_close(Gimp * gimp)176 gimp_displays_close (Gimp *gimp)
177 {
178   GList *list;
179   GList *iter;
180 
181   g_return_if_fail (GIMP_IS_GIMP (gimp));
182 
183   list = g_list_copy (gimp_get_display_iter (gimp));
184 
185   for (iter = list; iter; iter = g_list_next (iter))
186     {
187       GimpDisplay *display = iter->data;
188 
189       gimp_display_close (display);
190     }
191 
192   g_list_free (list);
193 }
194 
195 void
gimp_displays_reconnect(Gimp * gimp,GimpImage * old,GimpImage * new)196 gimp_displays_reconnect (Gimp      *gimp,
197                          GimpImage *old,
198                          GimpImage *new)
199 {
200   GList *contexts = NULL;
201   GList *list;
202 
203   g_return_if_fail (GIMP_IS_GIMP (gimp));
204   g_return_if_fail (GIMP_IS_IMAGE (old));
205   g_return_if_fail (GIMP_IS_IMAGE (new));
206 
207   /*  check which contexts refer to old_image  */
208   for (list = gimp->context_list; list; list = g_list_next (list))
209     {
210       GimpContext *context = list->data;
211 
212       if (gimp_context_get_image (context) == old)
213         contexts = g_list_prepend (contexts, list->data);
214     }
215 
216   /*  set the new_image on the remembered contexts (in reverse order,
217    *  since older contexts are usually the parents of newer
218    *  ones). Also, update the contexts before the displays, or we
219    *  might run into menu update functions that would see an
220    *  inconsistent state (display = new, context = old), and thus
221    *  inadvertently call actions as if the user had selected a menu
222    *  item.
223    */
224   g_list_foreach (contexts, (GFunc) gimp_context_set_image, new);
225   g_list_free (contexts);
226 
227   for (list = gimp_get_display_iter (gimp);
228        list;
229        list = g_list_next (list))
230     {
231       GimpDisplay *display = list->data;
232 
233       if (gimp_display_get_image (display) == old)
234         gimp_display_set_image (display, new);
235     }
236 }
237 
238 gint
gimp_displays_get_num_visible(Gimp * gimp)239 gimp_displays_get_num_visible (Gimp *gimp)
240 {
241   GList *list;
242   gint   visible = 0;
243 
244   g_return_val_if_fail (GIMP_IS_GIMP (gimp), 0);
245 
246   for (list = gimp_get_display_iter (gimp);
247        list;
248        list = g_list_next (list))
249     {
250       GimpDisplay      *display = list->data;
251       GimpDisplayShell *shell   = gimp_display_get_shell (display);
252 
253       if (gtk_widget_is_drawable (GTK_WIDGET (shell)))
254         {
255           GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
256 
257           if (GTK_IS_WINDOW (toplevel))
258             {
259               GdkWindow      *window = gtk_widget_get_window (toplevel);
260               GdkWindowState  state  = gdk_window_get_state (window);
261 
262               if ((state & (GDK_WINDOW_STATE_WITHDRAWN |
263                             GDK_WINDOW_STATE_ICONIFIED)) == 0)
264                 {
265                   visible++;
266                 }
267             }
268         }
269     }
270 
271   return visible;
272 }
273 
274 void
gimp_displays_set_busy(Gimp * gimp)275 gimp_displays_set_busy (Gimp *gimp)
276 {
277   GList *list;
278 
279   g_return_if_fail (GIMP_IS_GIMP (gimp));
280 
281   for (list = gimp_get_display_iter (gimp);
282        list;
283        list = g_list_next (list))
284     {
285       GimpDisplayShell *shell =
286         gimp_display_get_shell (GIMP_DISPLAY (list->data));
287 
288       gimp_display_shell_set_override_cursor (shell, (GimpCursorType) GDK_WATCH);
289     }
290 }
291 
292 void
gimp_displays_unset_busy(Gimp * gimp)293 gimp_displays_unset_busy (Gimp *gimp)
294 {
295   GList *list;
296 
297   g_return_if_fail (GIMP_IS_GIMP (gimp));
298 
299   for (list = gimp_get_display_iter (gimp);
300        list;
301        list = g_list_next (list))
302     {
303       GimpDisplayShell *shell =
304         gimp_display_get_shell (GIMP_DISPLAY (list->data));
305 
306       gimp_display_shell_unset_override_cursor (shell);
307     }
308 }
309