]> Pileus Git - ~andy/gtk/blob - gtk/gtkxembed.c
Send the focus on to the parent when there was no focus widget before and
[~andy/gtk] / gtk / gtkxembed.c
1 /* GTK - The GIMP Toolkit
2  * gtkxembed.c: Utilities for the XEMBED protocol
3  * Copyright (C) 2001, 2003, Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "gtkmain.h"
22 #include "gtkprivate.h"
23 #include "gtkxembed.h"
24
25 typedef struct _GtkXEmbedMessage GtkXEmbedMessage;
26
27 struct _GtkXEmbedMessage
28 {
29   glong      message;
30   glong      detail;
31   glong      data1;
32   glong      data2;
33   guint32    time;
34 };
35
36 static GSList *current_messages;
37
38
39 /**
40  * _gtk_xembed_push_message:
41  * @xevent: a XEvent
42  * 
43  * Adds a client message to the stack of current XEMBED events.
44  **/
45 void
46 _gtk_xembed_push_message (XEvent *xevent)
47 {
48   GtkXEmbedMessage *message = g_new (GtkXEmbedMessage, 1);
49   
50   message->time = xevent->xclient.data.l[0];
51   message->message = xevent->xclient.data.l[1];
52   message->detail = xevent->xclient.data.l[2];
53   message->data1 = xevent->xclient.data.l[3];
54   message->data2 = xevent->xclient.data.l[4];
55
56   current_messages = g_slist_prepend (current_messages, message);
57 }
58
59 /**
60  * _gtk_xembed_pop_message:
61  * 
62  * Removes an event added with _gtk_xembed_push_message()
63  **/
64 void
65 _gtk_xembed_pop_message (void)
66 {
67   GtkXEmbedMessage *message = current_messages->data;
68   current_messages = g_slist_delete_link (current_messages, current_messages);
69
70   g_free (message);
71 }
72
73 /**
74  * _gtk_xembed_set_focus_wrapped:
75  * 
76  * Sets a flag indicating that the current focus sequence wrapped
77  * around to the beginning of the ultimate toplevel.
78  **/
79 void
80 _gtk_xembed_set_focus_wrapped (void)
81 {
82   GtkXEmbedMessage *message;
83   
84   g_return_if_fail (current_messages != NULL);
85   message = current_messages->data;
86   g_return_if_fail (message->message == XEMBED_FOCUS_PREV || message->message == XEMBED_FOCUS_NEXT);
87   
88   message->data1 |= XEMBED_FOCUS_WRAPAROUND;
89 }
90
91 /**
92  * _gtk_xembed_get_focus_wrapped:
93  * 
94  * Gets whether the current focus sequence has wrapped around
95  * to the beginning of the ultimate toplevel.
96  * 
97  * Return value: %TRUE if the focus sequence has wrapped around.
98  **/
99 gboolean
100 _gtk_xembed_get_focus_wrapped (void)
101 {
102   GtkXEmbedMessage *message;
103   
104   g_return_val_if_fail (current_messages != NULL, FALSE);
105   message = current_messages->data;
106
107   return (message->data1 & XEMBED_FOCUS_WRAPAROUND) != 0;
108 }
109
110 static guint32
111 gtk_xembed_get_time (void)
112 {
113   if (current_messages)
114     {
115       GtkXEmbedMessage *message = current_messages->data;
116       return message->time;
117     }
118   else
119     return gtk_get_current_event_time ();
120 }
121
122 /**
123  * _gtk_xembed_send_message:
124  * @recipient: window to which to send the window, or %NULL
125  *             in which case nothing wil be sent
126  * @message:   type of message
127  * @detail:    detail field of message
128  * @data1:     data1 field of message
129  * @data2:     data2 field of message
130  * 
131  * Sends a generic XEMBED message to a particular window.
132  **/
133 void
134 _gtk_xembed_send_message (GdkWindow        *recipient,
135                           XEmbedMessageType message,
136                           glong             detail,
137                           glong             data1,
138                           glong             data2)
139 {
140   GdkDisplay *display;
141   XEvent xevent;
142
143   if (!recipient)
144     return;
145           
146   g_return_if_fail (GDK_IS_WINDOW (recipient));
147
148   display = gdk_drawable_get_display (recipient);
149   GTK_NOTE (PLUGSOCKET,
150             g_message ("Sending XEMBED message of type %d", message));
151
152   xevent.xclient.window = GDK_WINDOW_XWINDOW (recipient);
153   xevent.xclient.type = ClientMessage;
154   xevent.xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED");
155   xevent.xclient.format = 32;
156   xevent.xclient.data.l[0] = gtk_xembed_get_time ();
157   xevent.xclient.data.l[1] = message;
158   xevent.xclient.data.l[2] = detail;
159   xevent.xclient.data.l[3] = data1;
160   xevent.xclient.data.l[4] = data2;
161
162   gdk_error_trap_push ();
163   XSendEvent (GDK_WINDOW_XDISPLAY(recipient),
164               GDK_WINDOW_XWINDOW (recipient),
165               False, NoEventMask, &xevent);
166   gdk_display_sync (display);
167   gdk_error_trap_pop ();
168 }
169
170 /**
171  * _gtk_xembed_send_focus_message:
172  * @recipient: window to which to send the window, or %NULL
173  *             in which case nothing wil be sent
174  * @message:   type of message
175  * @detail:    detail field of message
176  * 
177  * Sends a XEMBED message for moving the focus along the focus
178  * chain to a window. The flags field that these messages share
179  * will be correctly filled in.
180  **/
181 void
182 _gtk_xembed_send_focus_message (GdkWindow        *recipient,
183                                 XEmbedMessageType message,
184                                 glong             detail)
185 {
186   gulong flags = 0;
187   
188   g_return_if_fail (GDK_IS_WINDOW (recipient));
189   g_return_if_fail (message == XEMBED_FOCUS_IN ||
190                     message == XEMBED_FOCUS_NEXT ||
191                     message == XEMBED_FOCUS_PREV);
192                     
193   if (current_messages)
194     {
195       GtkXEmbedMessage *message = current_messages->data;
196       switch (message->message)
197         {
198         case XEMBED_FOCUS_IN:
199         case XEMBED_FOCUS_NEXT:
200         case XEMBED_FOCUS_PREV:
201           flags = message->data1 & XEMBED_FOCUS_WRAPAROUND;
202           break;
203         default:
204           break;
205         }
206     }
207
208   _gtk_xembed_send_message (recipient, message, detail, flags, 0);
209 }
210