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