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