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