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