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 "config/gimpguiconfig.h"
26 
27 #include "core/gimpimage.h"
28 
29 #include "widgets/gimpcursor.h"
30 #include "widgets/gimpdialogfactory.h"
31 #include "widgets/gimpdockcontainer.h"
32 #include "widgets/gimpsessioninfo.h"
33 
34 #include "gimpcanvascursor.h"
35 #include "gimpdisplay.h"
36 #include "gimpcursorview.h"
37 #include "gimpdisplayshell.h"
38 #include "gimpdisplayshell-cursor.h"
39 #include "gimpdisplayshell-transform.h"
40 #include "gimpstatusbar.h"
41 
42 
43 static void  gimp_display_shell_real_set_cursor (GimpDisplayShell   *shell,
44                                                  GimpCursorType      cursor_type,
45                                                  GimpToolCursorType  tool_cursor,
46                                                  GimpCursorModifier  modifier,
47                                                  gboolean            always_install);
48 
49 
50 /*  public functions  */
51 
52 void
gimp_display_shell_set_cursor(GimpDisplayShell * shell,GimpCursorType cursor_type,GimpToolCursorType tool_cursor,GimpCursorModifier modifier)53 gimp_display_shell_set_cursor (GimpDisplayShell   *shell,
54                                GimpCursorType      cursor_type,
55                                GimpToolCursorType  tool_cursor,
56                                GimpCursorModifier  modifier)
57 {
58   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
59 
60   if (! shell->using_override_cursor)
61     {
62       gimp_display_shell_real_set_cursor (shell,
63                                           cursor_type,
64                                           tool_cursor,
65                                           modifier,
66                                           FALSE);
67     }
68 }
69 
70 void
gimp_display_shell_unset_cursor(GimpDisplayShell * shell)71 gimp_display_shell_unset_cursor (GimpDisplayShell *shell)
72 {
73   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
74 
75   if (! shell->using_override_cursor)
76     {
77       gimp_display_shell_real_set_cursor (shell,
78                                           (GimpCursorType) -1, 0, 0, FALSE);
79     }
80 }
81 
82 void
gimp_display_shell_set_override_cursor(GimpDisplayShell * shell,GimpCursorType cursor_type)83 gimp_display_shell_set_override_cursor (GimpDisplayShell *shell,
84                                         GimpCursorType    cursor_type)
85 {
86   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
87 
88   if (! shell->using_override_cursor ||
89       (shell->using_override_cursor &&
90        shell->override_cursor != cursor_type))
91     {
92       shell->override_cursor       = cursor_type;
93       shell->using_override_cursor = TRUE;
94 
95       gimp_cursor_set (shell->canvas,
96                        shell->cursor_handedness,
97                        cursor_type,
98                        GIMP_TOOL_CURSOR_NONE,
99                        GIMP_CURSOR_MODIFIER_NONE);
100     }
101 }
102 
103 void
gimp_display_shell_unset_override_cursor(GimpDisplayShell * shell)104 gimp_display_shell_unset_override_cursor (GimpDisplayShell *shell)
105 {
106   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
107 
108   if (shell->using_override_cursor)
109     {
110       shell->using_override_cursor = FALSE;
111 
112       gimp_display_shell_real_set_cursor (shell,
113                                           shell->current_cursor,
114                                           shell->tool_cursor,
115                                           shell->cursor_modifier,
116                                           TRUE);
117     }
118 }
119 
120 void
gimp_display_shell_update_software_cursor(GimpDisplayShell * shell,GimpCursorPrecision precision,gint display_x,gint display_y,gdouble image_x,gdouble image_y)121 gimp_display_shell_update_software_cursor (GimpDisplayShell    *shell,
122                                            GimpCursorPrecision  precision,
123                                            gint                 display_x,
124                                            gint                 display_y,
125                                            gdouble              image_x,
126                                            gdouble              image_y)
127 {
128   GimpImageWindow   *image_window;
129   GimpDialogFactory *factory;
130   GimpStatusbar     *statusbar;
131   GtkWidget         *widget;
132   GimpImage         *image;
133 
134   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
135 
136   image = gimp_display_get_image (shell->display);
137 
138   if (shell->draw_cursor &&
139       shell->proximity   &&
140       display_x >= 0     &&
141       display_y >= 0)
142     {
143       gimp_canvas_item_begin_change (shell->cursor);
144 
145       gimp_canvas_cursor_set (shell->cursor,
146                               display_x,
147                               display_y);
148       gimp_canvas_item_set_visible (shell->cursor, TRUE);
149 
150       gimp_canvas_item_end_change (shell->cursor);
151     }
152   else
153     {
154       gimp_canvas_item_set_visible (shell->cursor, FALSE);
155     }
156 
157   /*  use the passed image_coords for the statusbar because they are
158    *  possibly snapped...
159    */
160   statusbar = gimp_display_shell_get_statusbar (shell);
161 
162   gimp_statusbar_update_cursor (statusbar, precision, image_x, image_y);
163 
164   image_window = gimp_display_shell_get_window (shell);
165   factory = gimp_dock_container_get_dialog_factory (GIMP_DOCK_CONTAINER (image_window));
166 
167   widget = gimp_dialog_factory_find_widget (factory, "gimp-cursor-view");
168 
169   if (widget)
170     {
171       GtkWidget *cursor_view = gtk_bin_get_child (GTK_BIN (widget));
172 
173       if (cursor_view)
174         {
175           gint t_x = -1;
176           gint t_y = -1;
177 
178           /*  ...but use the unsnapped display_coords for the info window  */
179           if (display_x >= 0 && display_y >= 0)
180             gimp_display_shell_untransform_xy (shell, display_x, display_y,
181                                                &t_x, &t_y, FALSE);
182 
183           gimp_cursor_view_update_cursor (GIMP_CURSOR_VIEW (cursor_view),
184                                           image, shell->unit,
185                                           t_x, t_y);
186         }
187     }
188 }
189 
190 void
gimp_display_shell_clear_software_cursor(GimpDisplayShell * shell)191 gimp_display_shell_clear_software_cursor (GimpDisplayShell *shell)
192 {
193   GimpImageWindow   *image_window;
194   GimpDialogFactory *factory;
195   GimpStatusbar     *statusbar;
196   GtkWidget         *widget;
197 
198   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
199 
200   gimp_canvas_item_set_visible (shell->cursor, FALSE);
201 
202   statusbar = gimp_display_shell_get_statusbar (shell);
203 
204   gimp_statusbar_clear_cursor (statusbar);
205 
206   image_window = gimp_display_shell_get_window (shell);
207   factory = gimp_dock_container_get_dialog_factory (GIMP_DOCK_CONTAINER (image_window));
208 
209   widget = gimp_dialog_factory_find_widget (factory, "gimp-cursor-view");
210 
211   if (widget)
212     {
213       GtkWidget *cursor_view = gtk_bin_get_child (GTK_BIN (widget));
214 
215       if (cursor_view)
216         gimp_cursor_view_clear_cursor (GIMP_CURSOR_VIEW (cursor_view));
217     }
218 }
219 
220 
221 /*  private functions  */
222 
223 static void
gimp_display_shell_real_set_cursor(GimpDisplayShell * shell,GimpCursorType cursor_type,GimpToolCursorType tool_cursor,GimpCursorModifier modifier,gboolean always_install)224 gimp_display_shell_real_set_cursor (GimpDisplayShell   *shell,
225                                     GimpCursorType      cursor_type,
226                                     GimpToolCursorType  tool_cursor,
227                                     GimpCursorModifier  modifier,
228                                     gboolean            always_install)
229 {
230   GimpHandedness cursor_handedness;
231 
232   g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
233 
234   if (cursor_type == (GimpCursorType) -1)
235     {
236       shell->current_cursor = cursor_type;
237 
238       if (gtk_widget_is_drawable (shell->canvas))
239         gdk_window_set_cursor (gtk_widget_get_window (shell->canvas), NULL);
240 
241       return;
242     }
243 
244   if (cursor_type != GIMP_CURSOR_NONE &&
245       cursor_type != GIMP_CURSOR_BAD)
246     {
247       switch (shell->display->config->cursor_mode)
248         {
249         case GIMP_CURSOR_MODE_TOOL_ICON:
250           break;
251 
252         case GIMP_CURSOR_MODE_TOOL_CROSSHAIR:
253           if (cursor_type < GIMP_CURSOR_CORNER_TOP ||
254               cursor_type > GIMP_CURSOR_SIDE_TOP_LEFT)
255             {
256               /* the corner and side cursors count as crosshair, so leave
257                * them and override everything else
258                */
259               cursor_type = GIMP_CURSOR_CROSSHAIR_SMALL;
260             }
261           break;
262 
263         case GIMP_CURSOR_MODE_CROSSHAIR:
264           cursor_type = GIMP_CURSOR_CROSSHAIR;
265           tool_cursor = GIMP_TOOL_CURSOR_NONE;
266 
267           if (modifier != GIMP_CURSOR_MODIFIER_BAD)
268             {
269               /* the bad modifier is always shown */
270               modifier = GIMP_CURSOR_MODIFIER_NONE;
271             }
272           break;
273         }
274     }
275 
276   cursor_type = gimp_cursor_rotate (cursor_type, shell->rotate_angle);
277 
278   cursor_handedness = GIMP_GUI_CONFIG (shell->display->config)->cursor_handedness;
279 
280   if (shell->cursor_handedness != cursor_handedness ||
281       shell->current_cursor    != cursor_type       ||
282       shell->tool_cursor       != tool_cursor       ||
283       shell->cursor_modifier   != modifier          ||
284       always_install)
285     {
286       shell->cursor_handedness = cursor_handedness;
287       shell->current_cursor    = cursor_type;
288       shell->tool_cursor       = tool_cursor;
289       shell->cursor_modifier   = modifier;
290 
291       gimp_cursor_set (shell->canvas,
292                        cursor_handedness,
293                        cursor_type, tool_cursor, modifier);
294     }
295 }
296