]> Pileus Git - ~andy/gtk/blob - gtk/gtkplug.c
set RECEIVES_DEFAULT on init, and a button press on the widget doesn't
[~andy/gtk] / gtk / gtkplug.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /* By Owen Taylor <otaylor@gtk.org>              98/4/4 */
20
21 #include "gdk/gdkx.h"
22 #include "gdk/gdkkeysyms.h"
23 #include "gtkplug.h"
24
25 static void gtk_plug_class_init (GtkPlugClass *klass);
26 static void gtk_plug_init       (GtkPlug      *plug);
27
28 static void gtk_plug_realize    (GtkWidget *widget);
29 static gint gtk_plug_key_press_event (GtkWidget   *widget,
30                                       GdkEventKey *event);
31 static void gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event);
32 static gint gtk_plug_focus_in_event (GtkWidget     *widget, GdkEventFocus *event);
33 static gint gtk_plug_focus_out_event (GtkWidget     *widget, GdkEventFocus *event);
34 static void gtk_plug_set_focus       (GtkWindow         *window,
35                                       GtkWidget         *focus);
36
37 /* From Tk */
38 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
39
40 guint
41 gtk_plug_get_type ()
42 {
43   static guint plug_type = 0;
44
45   if (!plug_type)
46     {
47       static const GtkTypeInfo plug_info =
48       {
49         "GtkPlug",
50         sizeof (GtkPlug),
51         sizeof (GtkPlugClass),
52         (GtkClassInitFunc) gtk_plug_class_init,
53         (GtkObjectInitFunc) gtk_plug_init,
54         (GtkArgSetFunc) NULL,
55         (GtkArgGetFunc) NULL
56       };
57
58       plug_type = gtk_type_unique (gtk_window_get_type (), &plug_info);
59     }
60
61   return plug_type;
62 }
63
64 static void
65 gtk_plug_class_init (GtkPlugClass *class)
66 {
67   GtkWidgetClass *widget_class;
68   GtkWindowClass *window_class;
69
70   widget_class = (GtkWidgetClass *)class;
71   window_class = (GtkWindowClass *)class;
72
73   widget_class->realize = gtk_plug_realize;
74   widget_class->key_press_event = gtk_plug_key_press_event;
75   widget_class->focus_in_event = gtk_plug_focus_in_event;
76   widget_class->focus_out_event = gtk_plug_focus_out_event;
77
78   window_class->set_focus = gtk_plug_set_focus;
79 }
80
81 static void
82 gtk_plug_init (GtkPlug *plug)
83 {
84   GtkWindow *window;
85
86   window = GTK_WINDOW (plug);
87
88   window->type = GTK_WINDOW_TOPLEVEL;
89   window->auto_shrink = TRUE;
90 }
91
92 void
93 gtk_plug_construct (GtkPlug *plug, guint32 socket_id)
94 {
95   plug->socket_window = gdk_window_lookup (socket_id);
96   plug->same_app = TRUE;
97
98   if (plug->socket_window == NULL)
99     {
100       plug->socket_window = gdk_window_foreign_new (socket_id);
101       plug->same_app = FALSE;
102     }
103 }
104
105 GtkWidget*
106 gtk_plug_new (guint32 socket_id)
107 {
108   GtkPlug *plug;
109
110   plug = GTK_PLUG (gtk_type_new (gtk_plug_get_type ()));
111   gtk_plug_construct (plug, socket_id);
112   return GTK_WIDGET (plug);
113 }
114
115 static void
116 gtk_plug_realize (GtkWidget *widget)
117 {
118   GtkWindow *window;
119   GtkPlug *plug;
120   GdkWindowAttr attributes;
121   gint attributes_mask;
122
123   g_return_if_fail (widget != NULL);
124   g_return_if_fail (GTK_IS_PLUG (widget));
125
126   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
127   window = GTK_WINDOW (widget);
128   plug = GTK_PLUG (widget);
129
130   attributes.window_type = GDK_WINDOW_CHILD;    /* XXX GDK_WINDOW_PLUG ? */
131   attributes.title = window->title;
132   attributes.wmclass_name = window->wmclass_name;
133   attributes.wmclass_class = window->wmclass_class;
134   attributes.width = widget->allocation.width;
135   attributes.height = widget->allocation.height;
136   attributes.wclass = GDK_INPUT_OUTPUT;
137
138   /* this isn't right - we should match our parent's visual/colormap.
139    * though that will require handling "foreign" colormaps */
140   attributes.visual = gtk_widget_get_visual (widget);
141   attributes.colormap = gtk_widget_get_colormap (widget);
142   attributes.event_mask = gtk_widget_get_events (widget);
143   attributes.event_mask |= (GDK_EXPOSURE_MASK |
144                             GDK_KEY_PRESS_MASK |
145                             GDK_ENTER_NOTIFY_MASK |
146                             GDK_LEAVE_NOTIFY_MASK |
147                             GDK_FOCUS_CHANGE_MASK |
148                             GDK_STRUCTURE_MASK);
149
150   attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
151   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
152   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
153
154   widget->window = gdk_window_new (plug->socket_window, 
155                                    &attributes, attributes_mask);
156   ((GdkWindowPrivate *)widget->window)->window_type = GDK_WINDOW_TOPLEVEL;
157   gdk_window_set_user_data (widget->window, window);
158
159   widget->style = gtk_style_attach (widget->style, widget->window);
160   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
161 }
162
163 static gint
164 gtk_plug_key_press_event (GtkWidget   *widget,
165                           GdkEventKey *event)
166 {
167   GtkWindow *window;
168   GtkPlug *plug;
169   GtkDirectionType direction = 0;
170   gint return_val;
171
172   g_return_val_if_fail (widget != NULL, FALSE);
173   g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
174   g_return_val_if_fail (event != NULL, FALSE);
175
176   window = GTK_WINDOW (widget);
177   plug = GTK_PLUG (widget);
178
179   if (!GTK_WIDGET_HAS_FOCUS(widget))
180     {
181       gtk_plug_forward_key_press (plug, event);
182       return TRUE;
183     }
184
185   return_val = FALSE;
186   if (window->focus_widget)
187     return_val = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
188
189 #if 0
190   if (!return_val && gtk_window_check_accelerator (window, event->keyval, event->state))
191     return_val = TRUE;
192 #endif
193   
194   if (!return_val)
195     {
196       switch (event->keyval)
197         {
198         case GDK_space:
199           if (window->focus_widget)
200             {
201               gtk_widget_activate (window->focus_widget);
202               return_val = TRUE;
203             }
204           break;
205         case GDK_Return:
206         case GDK_KP_Enter:
207           if (window->default_widget &&
208               (!window->focus_widget || 
209                !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget)))
210             {
211               gtk_widget_activate (window->default_widget);
212               return_val = TRUE;
213             }
214           else if (window->focus_widget)
215             {
216               gtk_widget_activate (window->focus_widget);
217               return_val = TRUE;
218             }
219           break;
220         case GDK_Up:
221         case GDK_Down:
222         case GDK_Left:
223         case GDK_Right:
224         case GDK_Tab:
225           switch (event->keyval)
226             {
227             case GDK_Up:
228               direction = GTK_DIR_UP;
229               break;
230             case GDK_Down:
231               direction = GTK_DIR_DOWN;
232               break;
233             case GDK_Left:
234               direction = GTK_DIR_LEFT;
235               break;
236             case GDK_Right:
237               direction = GTK_DIR_RIGHT;
238               break;
239             case GDK_Tab:
240               if (event->state & GDK_SHIFT_MASK)
241                 direction = GTK_DIR_TAB_BACKWARD;
242               else
243                 direction = GTK_DIR_TAB_FORWARD;
244               break;
245             default :
246               direction = GTK_DIR_UP; /* never reached, but makes compiler happy */
247             }
248
249           gtk_container_focus (GTK_CONTAINER (widget), direction);
250
251           if (!GTK_CONTAINER (window)->focus_child)
252             {
253               gtk_window_set_focus (GTK_WINDOW (widget), NULL);
254               
255               XSetInputFocus (GDK_DISPLAY (),
256                               GDK_WINDOW_XWINDOW (plug->socket_window),
257                               RevertToParent, event->time);
258
259               gtk_plug_forward_key_press (plug, event);
260             }
261
262           return_val = TRUE;
263
264           break;
265         }
266     }
267
268   return return_val;
269 }
270
271 static void
272 gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event)
273 {
274   XEvent xevent;
275   
276   xevent.xkey.type = KeyPress;
277   xevent.xkey.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window);
278   xevent.xkey.window = GDK_WINDOW_XWINDOW (plug->socket_window);
279   xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */
280   xevent.xkey.time = event->time;
281   /* FIXME, the following might cause big problems for
282    * non-GTK apps */
283   xevent.xkey.x = 0;
284   xevent.xkey.y = 0;
285   xevent.xkey.x_root = 0;
286   xevent.xkey.y_root = 0;
287   xevent.xkey.state = event->state;
288   xevent.xkey.keycode =  XKeysymToKeycode(GDK_DISPLAY(), 
289                                           event->keyval);
290   xevent.xkey.same_screen = TRUE; /* FIXME ? */
291   
292   XSendEvent (gdk_display,
293               GDK_WINDOW_XWINDOW (plug->socket_window),
294               False, NoEventMask, &xevent);
295 }
296
297 /* Copied from Window, Ughh */
298
299 static gint
300 gtk_plug_focus_in_event (GtkWidget     *widget,
301                          GdkEventFocus *event)
302 {
303   GtkWindow *window;
304   GdkEventFocus fevent;
305
306   g_return_val_if_fail (widget != NULL, FALSE);
307   g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
308   g_return_val_if_fail (event != NULL, FALSE);
309
310   /* It appears spurious focus in events can occur when
311    *  the window is hidden. So we'll just check to see if
312    *  the window is visible before actually handling the
313    *  event
314    */
315   if (GTK_WIDGET_VISIBLE (widget))
316     {
317       GTK_OBJECT_SET_FLAGS (widget, GTK_HAS_FOCUS);
318       window = GTK_WINDOW (widget);
319       if (window->focus_widget && !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
320         {
321           fevent.type = GDK_FOCUS_CHANGE;
322           fevent.window = window->focus_widget->window;
323           fevent.in = TRUE;
324
325           gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
326         }
327     }
328
329   return FALSE;
330 }
331
332 static gint
333 gtk_plug_focus_out_event (GtkWidget     *widget,
334                           GdkEventFocus *event)
335 {
336   GtkWindow *window;
337   GdkEventFocus fevent;
338
339   g_return_val_if_fail (widget != NULL, FALSE);
340   g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
341   g_return_val_if_fail (event != NULL, FALSE);
342
343   GTK_OBJECT_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
344
345   window = GTK_WINDOW (widget);
346
347   if (window->focus_widget && GTK_WIDGET_HAS_FOCUS (window->focus_widget))
348     {
349       fevent.type = GDK_FOCUS_CHANGE;
350       fevent.window = window->focus_widget->window;
351       fevent.in = FALSE;
352
353       gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
354     }
355
356   return FALSE;
357 }
358
359 static void
360 gtk_plug_set_focus (GtkWindow *window,
361                     GtkWidget *focus)
362 {
363   GtkPlug *plug;
364   GdkEventFocus event;
365
366   g_return_if_fail (window != NULL);
367   g_return_if_fail (GTK_IS_PLUG (window));
368
369   plug = GTK_PLUG (window);
370
371   if (focus && !GTK_WIDGET_CAN_FOCUS (focus))
372     return;
373
374   if (window->focus_widget != focus)
375     {
376       if (window->focus_widget)
377         {
378           event.type = GDK_FOCUS_CHANGE;
379           event.window = window->focus_widget->window;
380           event.in = FALSE;
381
382           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
383         }
384
385       window->focus_widget = focus;
386
387       if (window->focus_widget)
388         {
389           event.type = GDK_FOCUS_CHANGE;
390           event.window = window->focus_widget->window;
391           event.in = TRUE;
392
393           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
394         }
395     }
396
397   /* Ask for focus from parent */
398
399   if (focus && !GTK_WIDGET_HAS_FOCUS(window))
400     {
401       XEvent xevent;
402
403       xevent.xfocus.type = FocusIn;
404       xevent.xfocus.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window);
405       xevent.xfocus.window = GDK_WINDOW_XWINDOW (plug->socket_window);
406       xevent.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
407       xevent.xfocus.detail = FALSE; /* Don't force */
408
409       XSendEvent (gdk_display,
410                   GDK_WINDOW_XWINDOW (plug->socket_window),
411                   False, NoEventMask, &xevent);
412     }
413 }