]> Pileus Git - ~andy/gtk/blob - gtk/gtkplug.c
applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[~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 Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include "gdkconfig.h"
29 #include "gdkprivate.h"
30
31 #if defined (GDK_WINDOWING_X11)
32 #include "x11/gdkx.h"
33 #elif defined (GDK_WINDOWING_WIN32)
34 #include "win32/gdkwin32.h"
35 #elif defined (GDK_WINDOWING_NANOX)
36 #include "nanox/gdkprivate-nanox.h"
37 #elif defined (GDK_WINDOWING_FB)
38 #include "linux-fb/gdkfb.h"
39 #endif
40
41 #include "gdk/gdkkeysyms.h"
42 #include "gtkplug.h"
43
44 static void gtk_plug_class_init (GtkPlugClass *klass);
45 static void gtk_plug_init       (GtkPlug      *plug);
46
47 static void gtk_plug_realize    (GtkWidget *widget);
48 static void gtk_plug_unrealize  (GtkWidget *widget);
49 static gint gtk_plug_key_press_event (GtkWidget   *widget,
50                                       GdkEventKey *event);
51 static void gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event);
52 static gint gtk_plug_focus_in_event (GtkWidget     *widget, GdkEventFocus *event);
53 static gint gtk_plug_focus_out_event (GtkWidget     *widget, GdkEventFocus *event);
54 static void gtk_plug_set_focus       (GtkWindow         *window,
55                                       GtkWidget         *focus);
56
57 /* From Tk */
58 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
59   
60 static GtkWindowClass *parent_class = NULL;
61
62 GtkType
63 gtk_plug_get_type ()
64 {
65   static GtkType plug_type = 0;
66
67   if (!plug_type)
68     {
69       static const GTypeInfo plug_info =
70       {
71         sizeof (GtkPlugClass),
72         NULL,           /* base_init */
73         NULL,           /* base_finalize */
74         (GClassInitFunc) gtk_plug_class_init,
75         NULL,           /* class_finalize */
76         NULL,           /* class_data */
77         sizeof (GtkPlug),
78         16,             /* n_preallocs */
79         (GInstanceInitFunc) gtk_plug_init,
80       };
81
82       plug_type = g_type_register_static (GTK_TYPE_WINDOW, "GtkPlug", &plug_info);
83     }
84
85   return plug_type;
86 }
87
88 static void
89 gtk_plug_class_init (GtkPlugClass *class)
90 {
91   GtkWidgetClass *widget_class;
92   GtkWindowClass *window_class;
93
94   widget_class = (GtkWidgetClass *)class;
95   window_class = (GtkWindowClass *)class;
96
97   parent_class = gtk_type_class (GTK_TYPE_WINDOW);
98
99   widget_class->realize = gtk_plug_realize;
100   widget_class->unrealize = gtk_plug_unrealize;
101   widget_class->key_press_event = gtk_plug_key_press_event;
102   widget_class->focus_in_event = gtk_plug_focus_in_event;
103   widget_class->focus_out_event = gtk_plug_focus_out_event;
104
105   window_class->set_focus = gtk_plug_set_focus;
106 }
107
108 static void
109 gtk_plug_init (GtkPlug *plug)
110 {
111   GtkWindow *window;
112
113   window = GTK_WINDOW (plug);
114
115   window->type = GTK_WINDOW_TOPLEVEL;
116   window->auto_shrink = TRUE;
117 }
118
119 void
120 gtk_plug_construct (GtkPlug *plug, GdkNativeWindow socket_id)
121 {
122   plug->socket_window = gdk_window_lookup (socket_id);
123   plug->same_app = TRUE;
124
125   if (plug->socket_window == NULL)
126     {
127       plug->socket_window = gdk_window_foreign_new (socket_id);
128       plug->same_app = FALSE;
129     }
130 }
131
132 GtkWidget*
133 gtk_plug_new (GdkNativeWindow socket_id)
134 {
135   GtkPlug *plug;
136
137   plug = GTK_PLUG (gtk_type_new (GTK_TYPE_PLUG));
138   gtk_plug_construct (plug, socket_id);
139   return GTK_WIDGET (plug);
140 }
141
142 static void
143 gtk_plug_unrealize (GtkWidget *widget)
144 {
145   GtkPlug *plug;
146
147   g_return_if_fail (widget != NULL);
148   g_return_if_fail (GTK_IS_PLUG (widget));
149
150   plug = GTK_PLUG (widget);
151
152   if (plug->socket_window != NULL)
153     {
154       gdk_window_set_user_data (plug->socket_window, NULL);
155       gdk_window_unref (plug->socket_window);
156       plug->socket_window = NULL;
157     }
158
159   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
160     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
161 }
162
163 static void
164 gtk_plug_realize (GtkWidget *widget)
165 {
166   GtkWindow *window;
167   GtkPlug *plug;
168   GdkWindowAttr attributes;
169   gint attributes_mask;
170
171   g_return_if_fail (widget != NULL);
172   g_return_if_fail (GTK_IS_PLUG (widget));
173
174   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
175   window = GTK_WINDOW (widget);
176   plug = GTK_PLUG (widget);
177
178   attributes.window_type = GDK_WINDOW_CHILD;    /* XXX GDK_WINDOW_PLUG ? */
179   attributes.title = window->title;
180   attributes.wmclass_name = window->wmclass_name;
181   attributes.wmclass_class = window->wmclass_class;
182   attributes.width = widget->allocation.width;
183   attributes.height = widget->allocation.height;
184   attributes.wclass = GDK_INPUT_OUTPUT;
185
186   /* this isn't right - we should match our parent's visual/colormap.
187    * though that will require handling "foreign" colormaps */
188   attributes.visual = gtk_widget_get_visual (widget);
189   attributes.colormap = gtk_widget_get_colormap (widget);
190   attributes.event_mask = gtk_widget_get_events (widget);
191   attributes.event_mask |= (GDK_EXPOSURE_MASK |
192                             GDK_KEY_PRESS_MASK |
193                             GDK_ENTER_NOTIFY_MASK |
194                             GDK_LEAVE_NOTIFY_MASK |
195                             GDK_FOCUS_CHANGE_MASK |
196                             GDK_STRUCTURE_MASK);
197
198   attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
199   attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
200   attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
201
202   gdk_error_trap_push ();
203   widget->window = gdk_window_new (plug->socket_window, 
204                                    &attributes, attributes_mask);
205   gdk_flush ();
206   if (gdk_error_trap_pop ()) /* Uh-oh */
207     {
208       gdk_error_trap_push ();
209       gdk_window_destroy (widget->window);
210       gdk_flush ();
211       gdk_error_trap_pop ();
212       widget->window = gdk_window_new (NULL, &attributes, attributes_mask);
213     }
214   
215   GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
216   gdk_window_set_user_data (widget->window, window);
217
218   widget->style = gtk_style_attach (widget->style, widget->window);
219   gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
220 }
221
222 static gint
223 gtk_plug_key_press_event (GtkWidget   *widget,
224                           GdkEventKey *event)
225 {
226   GtkWindow *window;
227   GtkPlug *plug;
228   GtkDirectionType direction = 0;
229   gint return_val;
230
231   g_return_val_if_fail (widget != NULL, FALSE);
232   g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
233   g_return_val_if_fail (event != NULL, FALSE);
234
235   window = GTK_WINDOW (widget);
236   plug = GTK_PLUG (widget);
237
238   if (!GTK_WIDGET_HAS_FOCUS(widget))
239     {
240       gtk_plug_forward_key_press (plug, event);
241       return TRUE;
242     }
243
244   return_val = FALSE;
245   if (window->focus_widget)
246     return_val = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
247
248 #if 0
249   if (!return_val && gtk_window_check_accelerator (window, event->keyval, event->state))
250     return_val = TRUE;
251 #endif
252   
253   if (!return_val)
254     {
255       switch (event->keyval)
256         {
257         case GDK_space:
258           if (window->focus_widget)
259             {
260               gtk_widget_activate (window->focus_widget);
261               return_val = TRUE;
262             }
263           break;
264         case GDK_Return:
265         case GDK_KP_Enter:
266           if (window->default_widget &&
267               (!window->focus_widget || 
268                !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget)))
269             {
270               gtk_widget_activate (window->default_widget);
271               return_val = TRUE;
272             }
273           else if (window->focus_widget)
274             {
275               gtk_widget_activate (window->focus_widget);
276               return_val = TRUE;
277             }
278           break;
279         case GDK_Up:
280         case GDK_Down:
281         case GDK_Left:
282         case GDK_Right:
283         case GDK_Tab:
284           switch (event->keyval)
285             {
286             case GDK_Up:
287               direction = GTK_DIR_UP;
288               break;
289             case GDK_Down:
290               direction = GTK_DIR_DOWN;
291               break;
292             case GDK_Left:
293               direction = GTK_DIR_LEFT;
294               break;
295             case GDK_Right:
296               direction = GTK_DIR_RIGHT;
297               break;
298             case GDK_Tab:
299               if (event->state & GDK_SHIFT_MASK)
300                 direction = GTK_DIR_TAB_BACKWARD;
301               else
302                 direction = GTK_DIR_TAB_FORWARD;
303               break;
304             default :
305               direction = GTK_DIR_UP; /* never reached, but makes compiler happy */
306             }
307
308           gtk_container_focus (GTK_CONTAINER (widget), direction);
309
310           if (!GTK_CONTAINER (window)->focus_child)
311             {
312               gtk_window_set_focus (GTK_WINDOW (widget), NULL);
313
314               gdk_error_trap_push ();
315 #ifdef GDK_WINDOWING_X11
316               XSetInputFocus (GDK_DISPLAY (),
317                               GDK_WINDOW_XWINDOW (plug->socket_window),
318                               RevertToParent, event->time);
319 #elif defined (GDK_WINDOWING_WIN32)
320               SetFocus (GDK_WINDOW_HWND (plug->socket_window));
321 #endif
322               gdk_flush ();
323               gdk_error_trap_pop ();
324
325               gtk_plug_forward_key_press (plug, event);
326             }
327
328           return_val = TRUE;
329
330           break;
331         }
332     }
333
334   return return_val;
335 }
336
337 static void
338 gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event)
339 {
340 #ifdef GDK_WINDOWING_X11
341   XEvent xevent;
342   
343   xevent.xkey.type = KeyPress;
344   xevent.xkey.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window);
345   xevent.xkey.window = GDK_WINDOW_XWINDOW (plug->socket_window);
346   xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */
347   xevent.xkey.time = event->time;
348   /* FIXME, the following might cause big problems for
349    * non-GTK apps */
350   xevent.xkey.x = 0;
351   xevent.xkey.y = 0;
352   xevent.xkey.x_root = 0;
353   xevent.xkey.y_root = 0;
354   xevent.xkey.state = event->state;
355   xevent.xkey.keycode =  XKeysymToKeycode(GDK_DISPLAY(), 
356                                           event->keyval);
357   xevent.xkey.same_screen = TRUE; /* FIXME ? */
358
359   gdk_error_trap_push ();
360   XSendEvent (gdk_display,
361               GDK_WINDOW_XWINDOW (plug->socket_window),
362               False, NoEventMask, &xevent);
363   gdk_flush ();
364   gdk_error_trap_pop ();
365 #elif defined (GDK_WINDOWING_WIN32)
366   /* This is pretty bogus, and not tested at all. */
367   WPARAM wParam;
368   LPARAM lParam;
369   gboolean no_WM_CHAR = TRUE;
370
371   lParam = 0;
372   switch (event->keyval)
373     {
374     case GDK_Cancel:
375       wParam = VK_CANCEL; break;
376     case GDK_BackSpace:
377       wParam = VK_BACK; break;
378     case GDK_Tab:
379       wParam = VK_TAB; break;
380     case GDK_Clear:
381       wParam = VK_CLEAR; break;
382     case GDK_Return:
383       wParam = VK_RETURN; break;
384     case GDK_Shift_L:
385       wParam = VK_SHIFT; break;
386     case GDK_Control_L:
387       wParam = VK_CONTROL; break;
388     case GDK_Control_R:
389       wParam = VK_CONTROL; lParam |= 0x01000000; break;
390     case GDK_Alt_L:
391       wParam = VK_MENU; break;
392     case GDK_Alt_R:
393       wParam = VK_MENU; lParam |= 0x01000000; break;
394     case GDK_Pause:
395       wParam = VK_PAUSE; break;
396     case GDK_Caps_Lock:
397       wParam = VK_CAPITAL; break;
398     case GDK_Escape:
399       wParam = VK_ESCAPE; break;
400     case GDK_Prior:
401       wParam = VK_PRIOR; break;
402     case GDK_Next:
403       wParam = VK_NEXT; break;
404     case GDK_End:
405       wParam = VK_END; break;
406     case GDK_Home:
407       wParam = VK_HOME; break;
408     case GDK_Left:
409       wParam = VK_LEFT; break;
410     case GDK_Up:
411       wParam = VK_UP; break;
412     case GDK_Right:
413       wParam = VK_RIGHT; break;
414     case GDK_Down:
415       wParam = VK_DOWN; break;
416     case GDK_Select:
417       wParam = VK_SELECT; break;
418     case GDK_Print:
419       wParam = VK_PRINT; break;
420     case GDK_Execute:
421       wParam = VK_EXECUTE; break;
422     case GDK_Insert:
423       wParam = VK_INSERT; break;
424     case GDK_Delete:
425       wParam = VK_DELETE; break;
426     case GDK_Help:
427       wParam = VK_HELP; break;
428     case GDK_KP_0:
429       wParam = VK_NUMPAD0; break;
430     case GDK_KP_1:
431       wParam = VK_NUMPAD1; break;
432     case GDK_KP_2:
433       wParam = VK_NUMPAD2; break;
434     case GDK_KP_3:
435       wParam = VK_NUMPAD3; break;
436     case GDK_KP_4:
437       wParam = VK_NUMPAD4; break;
438     case GDK_KP_5:
439       wParam = VK_NUMPAD5; break;
440     case GDK_KP_6:
441       wParam = VK_NUMPAD6; break;
442     case GDK_KP_7:
443       wParam = VK_NUMPAD7; break;
444     case GDK_KP_8:
445       wParam = VK_NUMPAD8; break;
446     case GDK_KP_9:
447       wParam = VK_NUMPAD9; break;
448     case GDK_KP_Multiply:
449       wParam = VK_MULTIPLY; break;
450     case GDK_KP_Add:
451       wParam = VK_ADD; break;
452     case GDK_KP_Separator:
453       wParam = VK_SEPARATOR; break;
454     case GDK_KP_Subtract:
455       wParam = VK_SUBTRACT; break;
456     case GDK_KP_Decimal:
457       wParam = VK_DECIMAL; break;
458     case GDK_KP_Divide:
459       wParam = VK_DIVIDE; break;
460     case GDK_F1:
461       wParam = VK_F1; break;
462     case GDK_F2:
463       wParam = VK_F2; break;
464     case GDK_F3:
465       wParam = VK_F3; break;
466     case GDK_F4:
467       wParam = VK_F4; break;
468     case GDK_F5:
469       wParam = VK_F5; break;
470     case GDK_F6:
471       wParam = VK_F6; break;
472     case GDK_F7:
473       wParam = VK_F7; break;
474     case GDK_F8:
475       wParam = VK_F8; break;
476     case GDK_F9:
477       wParam = VK_F9; break;
478     case GDK_F10:
479       wParam = VK_F10; break;
480     case GDK_F11:
481       wParam = VK_F11; break;
482     case GDK_F12:
483       wParam = VK_F12; break;
484     case GDK_F13:
485       wParam = VK_F13; break;
486     case GDK_F14:
487       wParam = VK_F14; break;
488     case GDK_F15:
489       wParam = VK_F15; break;
490     case GDK_F16:
491       wParam = VK_F16; break;
492     default:
493       wParam = event->keyval;
494       no_WM_CHAR = FALSE;
495       break;
496     }
497   
498   PostMessage (GDK_WINDOW_HWND (plug->socket_window),
499                WM_KEYDOWN, wParam, lParam);
500   if (!no_WM_CHAR)
501     PostMessage (GDK_WINDOW_HWND (plug->socket_window),
502                  WM_CHAR, wParam, lParam);
503   PostMessage (GDK_WINDOW_HWND (plug->socket_window),
504                WM_KEYUP, wParam, lParam);
505 #endif
506 }
507
508 /* Copied from Window, Ughh */
509
510 static gint
511 gtk_plug_focus_in_event (GtkWidget     *widget,
512                          GdkEventFocus *event)
513 {
514   GtkWindow *window;
515   GdkEventFocus fevent;
516
517   g_return_val_if_fail (widget != NULL, FALSE);
518   g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
519   g_return_val_if_fail (event != NULL, FALSE);
520
521   /* It appears spurious focus in events can occur when
522    *  the window is hidden. So we'll just check to see if
523    *  the window is visible before actually handling the
524    *  event
525    */
526   if (GTK_WIDGET_VISIBLE (widget))
527     {
528       GTK_OBJECT_SET_FLAGS (widget, GTK_HAS_FOCUS);
529       window = GTK_WINDOW (widget);
530       if (window->focus_widget && !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
531         {
532           fevent.type = GDK_FOCUS_CHANGE;
533           fevent.window = window->focus_widget->window;
534           fevent.in = TRUE;
535
536           gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
537         }
538     }
539
540   return FALSE;
541 }
542
543 static gint
544 gtk_plug_focus_out_event (GtkWidget     *widget,
545                           GdkEventFocus *event)
546 {
547   GtkWindow *window;
548   GdkEventFocus fevent;
549
550   g_return_val_if_fail (widget != NULL, FALSE);
551   g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
552   g_return_val_if_fail (event != NULL, FALSE);
553
554   GTK_OBJECT_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
555
556   window = GTK_WINDOW (widget);
557
558   if (window->focus_widget && GTK_WIDGET_HAS_FOCUS (window->focus_widget))
559     {
560       fevent.type = GDK_FOCUS_CHANGE;
561       fevent.window = window->focus_widget->window;
562       fevent.in = FALSE;
563
564       gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
565     }
566
567   return FALSE;
568 }
569
570 static void
571 gtk_plug_set_focus (GtkWindow *window,
572                     GtkWidget *focus)
573 {
574   GtkPlug *plug;
575   GdkEventFocus event;
576
577   g_return_if_fail (window != NULL);
578   g_return_if_fail (GTK_IS_PLUG (window));
579
580   plug = GTK_PLUG (window);
581
582   if (focus && !GTK_WIDGET_CAN_FOCUS (focus))
583     return;
584
585   if (window->focus_widget != focus)
586     {
587       if (window->focus_widget)
588         {
589           event.type = GDK_FOCUS_CHANGE;
590           event.window = window->focus_widget->window;
591           event.in = FALSE;
592
593           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
594         }
595
596       window->focus_widget = focus;
597
598       if (window->focus_widget)
599         {
600           event.type = GDK_FOCUS_CHANGE;
601           event.window = window->focus_widget->window;
602           event.in = TRUE;
603
604           gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
605         }
606     }
607
608   /* Ask for focus from parent */
609
610   if (focus && !GTK_WIDGET_HAS_FOCUS(window))
611     {
612 #ifdef GDK_WINDOWING_X11
613       XEvent xevent;
614
615       xevent.xfocus.type = FocusIn;
616       xevent.xfocus.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window);
617       xevent.xfocus.window = GDK_WINDOW_XWINDOW (plug->socket_window);
618       xevent.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
619       xevent.xfocus.detail = FALSE; /* Don't force */
620
621       gdk_error_trap_push ();
622       XSendEvent (gdk_display,
623                   GDK_WINDOW_XWINDOW (plug->socket_window),
624                   False, NoEventMask, &xevent);
625       gdk_flush ();
626       gdk_error_trap_pop ();
627 #elif defined (GDK_WINDOWING_WIN32)
628       /* XXX Not implemented */
629 #endif
630     }
631 }