]> Pileus Git - ~andy/gtk/blob - gtk/gtkxembed.c
API: Remove GDK_WINDOW_XWINDOW() macro
[~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 "config.h"
22 #include <string.h>
23 #include "gtkmain.h"
24 #include "gtkprivate.h"
25 #include "gtkxembed.h"
26 #include "gtkdebug.h"
27
28
29 typedef struct _GtkXEmbedMessage GtkXEmbedMessage;
30
31 struct _GtkXEmbedMessage
32 {
33   glong      message;
34   glong      detail;
35   glong      data1;
36   glong      data2;
37   guint32    time;
38 };
39
40 static GSList *current_messages;
41
42
43 /**
44  * _gtk_xembed_push_message:
45  * @xevent: a XEvent
46  * 
47  * Adds a client message to the stack of current XEMBED events.
48  **/
49 void
50 _gtk_xembed_push_message (XEvent *xevent)
51 {
52   GtkXEmbedMessage *message = g_slice_new (GtkXEmbedMessage);
53   
54   message->time = xevent->xclient.data.l[0];
55   message->message = xevent->xclient.data.l[1];
56   message->detail = xevent->xclient.data.l[2];
57   message->data1 = xevent->xclient.data.l[3];
58   message->data2 = xevent->xclient.data.l[4];
59
60   current_messages = g_slist_prepend (current_messages, message);
61 }
62
63 /**
64  * _gtk_xembed_pop_message:
65  * 
66  * Removes an event added with _gtk_xembed_push_message()
67  **/
68 void
69 _gtk_xembed_pop_message (void)
70 {
71   GtkXEmbedMessage *message = current_messages->data;
72   current_messages = g_slist_delete_link (current_messages, current_messages);
73   g_slice_free (GtkXEmbedMessage, message);
74 }
75
76 /**
77  * _gtk_xembed_set_focus_wrapped:
78  * 
79  * Sets a flag indicating that the current focus sequence wrapped
80  * around to the beginning of the ultimate toplevel.
81  **/
82 void
83 _gtk_xembed_set_focus_wrapped (void)
84 {
85   GtkXEmbedMessage *message;
86   
87   g_return_if_fail (current_messages != NULL);
88   message = current_messages->data;
89   g_return_if_fail (message->message == XEMBED_FOCUS_PREV || message->message == XEMBED_FOCUS_NEXT);
90   
91   message->data1 |= XEMBED_FOCUS_WRAPAROUND;
92 }
93
94 /**
95  * _gtk_xembed_get_focus_wrapped:
96  * 
97  * Gets whether the current focus sequence has wrapped around
98  * to the beginning of the ultimate toplevel.
99  * 
100  * Return value: %TRUE if the focus sequence has wrapped around.
101  **/
102 gboolean
103 _gtk_xembed_get_focus_wrapped (void)
104 {
105   GtkXEmbedMessage *message;
106   
107   g_return_val_if_fail (current_messages != NULL, FALSE);
108   message = current_messages->data;
109
110   return (message->data1 & XEMBED_FOCUS_WRAPAROUND) != 0;
111 }
112
113 static guint32
114 gtk_xembed_get_time (void)
115 {
116   if (current_messages)
117     {
118       GtkXEmbedMessage *message = current_messages->data;
119       return message->time;
120     }
121   else
122     return gtk_get_current_event_time ();
123 }
124
125 /**
126  * _gtk_xembed_send_message:
127  * @recipient: (allow-none): window to which to send the window, or %NULL
128  *             in which case nothing will be sent
129  * @message:   type of message
130  * @detail:    detail field of message
131  * @data1:     data1 field of message
132  * @data2:     data2 field of message
133  * 
134  * Sends a generic XEMBED message to a particular window.
135  **/
136 void
137 _gtk_xembed_send_message (GdkWindow        *recipient,
138                           XEmbedMessageType message,
139                           glong             detail,
140                           glong             data1,
141                           glong             data2)
142 {
143   GdkDisplay *display;
144   XClientMessageEvent xclient;
145
146   if (!recipient)
147     return;
148           
149   g_return_if_fail (GDK_IS_WINDOW (recipient));
150
151   display = gdk_window_get_display (recipient);
152   GTK_NOTE (PLUGSOCKET,
153             g_message ("Sending %s", _gtk_xembed_message_name (message)));
154
155   memset (&xclient, 0, sizeof (xclient));
156   xclient.window = GDK_WINDOW_XID (recipient);
157   xclient.type = ClientMessage;
158   xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED");
159   xclient.format = 32;
160   xclient.data.l[0] = gtk_xembed_get_time ();
161   xclient.data.l[1] = message;
162   xclient.data.l[2] = detail;
163   xclient.data.l[3] = data1;
164   xclient.data.l[4] = data2;
165
166   gdk_error_trap_push ();
167   XSendEvent (GDK_WINDOW_XDISPLAY(recipient),
168               GDK_WINDOW_XID (recipient),
169               False, NoEventMask, (XEvent *)&xclient);
170   gdk_error_trap_pop_ignored ();
171 }
172
173 /**
174  * _gtk_xembed_send_focus_message:
175  * @recipient: (allow-none): window to which to send the window, or %NULL
176  *             in which case nothing will be sent
177  * @message:   type of message
178  * @detail:    detail field of message
179  * 
180  * Sends a XEMBED message for moving the focus along the focus
181  * chain to a window. The flags field that these messages share
182  * will be correctly filled in.
183  **/
184 void
185 _gtk_xembed_send_focus_message (GdkWindow        *recipient,
186                                 XEmbedMessageType message,
187                                 glong             detail)
188 {
189   gulong flags = 0;
190
191   if (!recipient)
192     return;
193   
194   g_return_if_fail (GDK_IS_WINDOW (recipient));
195   g_return_if_fail (message == XEMBED_FOCUS_IN ||
196                     message == XEMBED_FOCUS_NEXT ||
197                     message == XEMBED_FOCUS_PREV);
198                     
199   if (current_messages)
200     {
201       GtkXEmbedMessage *message = current_messages->data;
202       switch (message->message)
203         {
204         case XEMBED_FOCUS_IN:
205         case XEMBED_FOCUS_NEXT:
206         case XEMBED_FOCUS_PREV:
207           flags = message->data1 & XEMBED_FOCUS_WRAPAROUND;
208           break;
209         default:
210           break;
211         }
212     }
213
214   _gtk_xembed_send_message (recipient, message, detail, flags, 0);
215 }
216
217 const char *
218 _gtk_xembed_message_name (XEmbedMessageType message)
219 {
220   static char unk[24];
221   
222   switch (message)
223     {
224 #define CASE(x) case XEMBED_##x: return "XEMBED_"#x
225       CASE (EMBEDDED_NOTIFY);
226       CASE (WINDOW_ACTIVATE);
227       CASE (WINDOW_DEACTIVATE);
228       CASE (REQUEST_FOCUS);
229       CASE (FOCUS_IN);
230       CASE (FOCUS_OUT);
231       CASE (FOCUS_NEXT);
232       CASE (FOCUS_PREV);
233       CASE (GRAB_KEY);
234       CASE (UNGRAB_KEY);
235       CASE (MODALITY_ON);
236       CASE (MODALITY_OFF);
237       CASE (GTK_GRAB_KEY);
238       CASE (GTK_UNGRAB_KEY);
239 #undef CASE
240     default:
241       snprintf (unk, 24, "UNKNOWN(%d)", message);
242       return unk;
243     }
244 }