]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkgeometry-x11.c
gdk/: fully remove gdkalias hacks
[~andy/gtk] / gdk / x11 / gdkgeometry-x11.c
1 /* GDK - The GIMP Drawing Kit
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
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21 #include "gdk.h"                /* For gdk_rectangle_intersect */
22 #include "gdkprivate-x11.h"
23 #include "gdkx.h"
24 #include "gdkinternals.h"
25 #include "gdkscreen-x11.h"
26 #include "gdkdisplay-x11.h"
27 #include "gdkwindow-x11.h"
28
29
30 typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
31 typedef struct _GdkWindowParentPos GdkWindowParentPos;
32
33 typedef enum {
34   GDK_WINDOW_QUEUE_TRANSLATE,
35   GDK_WINDOW_QUEUE_ANTIEXPOSE
36 } GdkWindowQueueType;
37
38 struct _GdkWindowQueueItem
39 {
40   GdkWindow *window;
41   gulong serial;
42   GdkWindowQueueType type;
43   union {
44     struct {
45       cairo_region_t *area;
46       gint dx;
47       gint dy;
48     } translate;
49     struct {
50       cairo_region_t *area;
51     } antiexpose;
52   } u;
53 };
54
55 void
56 _gdk_window_move_resize_child (GdkWindow *window,
57                                gint       x,
58                                gint       y,
59                                gint       width,
60                                gint       height)
61 {
62   GdkWindowObject *obj;
63
64   g_return_if_fail (window != NULL);
65   g_return_if_fail (GDK_IS_WINDOW (window));
66
67   obj = GDK_WINDOW_OBJECT (window);
68
69   if (width > 65535 ||
70       height > 65535)
71     {
72       g_warning ("Native children wider or taller than 65535 pixels are not supported");
73
74       if (width > 65535)
75         width = 65535;
76       if (height > 65535)
77         height = 65535;
78     }
79
80   obj->x = x;
81   obj->y = y;
82   obj->width = width;
83   obj->height = height;
84
85   /* We don't really care about origin overflow, because on overflow
86      the window won't be visible anyway and thus it will be shaped
87      to nothing */
88
89   _gdk_x11_window_tmp_unset_parent_bg (window);
90   _gdk_x11_window_tmp_unset_bg (window, TRUE);
91   XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
92                      GDK_WINDOW_XID (window),
93                      obj->x + obj->parent->abs_x,
94                      obj->y + obj->parent->abs_y,
95                      width, height);
96   _gdk_x11_window_tmp_reset_parent_bg (window);
97   _gdk_x11_window_tmp_reset_bg (window, TRUE);
98 }
99
100 static Bool
101 expose_serial_predicate (Display *xdisplay,
102                          XEvent  *xev,
103                          XPointer arg)
104 {
105   gulong *serial = (gulong *)arg;
106
107   if (xev->xany.type == Expose || xev->xany.type == GraphicsExpose)
108     *serial = MIN (*serial, xev->xany.serial);
109
110   return False;
111 }
112
113 /* Find oldest possible serial for an outstanding expose event
114  */
115 static gulong
116 find_current_serial (Display *xdisplay)
117 {
118   XEvent xev;
119   gulong serial = NextRequest (xdisplay);
120   
121   XSync (xdisplay, False);
122
123   XCheckIfEvent (xdisplay, &xev, expose_serial_predicate, (XPointer)&serial);
124
125   return serial;
126 }
127
128 static void
129 queue_delete_link (GQueue *queue,
130                    GList  *link)
131 {
132   if (queue->tail == link)
133     queue->tail = link->prev;
134   
135   queue->head = g_list_remove_link (queue->head, link);
136   g_list_free_1 (link);
137   queue->length--;
138 }
139
140 static void
141 queue_item_free (GdkWindowQueueItem *item)
142 {
143   if (item->window)
144     {
145       g_object_remove_weak_pointer (G_OBJECT (item->window),
146                                     (gpointer *)&(item->window));
147     }
148   
149   if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
150     cairo_region_destroy (item->u.antiexpose.area);
151   else
152     {
153       if (item->u.translate.area)
154         cairo_region_destroy (item->u.translate.area);
155     }
156   
157   g_free (item);
158 }
159
160 static void
161 gdk_window_queue (GdkWindow          *window,
162                   GdkWindowQueueItem *item)
163 {
164   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
165   
166   if (!display_x11->translate_queue)
167     display_x11->translate_queue = g_queue_new ();
168
169   /* Keep length of queue finite by, if it grows too long,
170    * figuring out the latest relevant serial and discarding
171    * irrelevant queue items.
172    */
173   if (display_x11->translate_queue->length >= 64)
174     {
175       gulong serial = find_current_serial (GDK_WINDOW_XDISPLAY (window));
176       GList *tmp_list = display_x11->translate_queue->head;
177       
178       while (tmp_list)
179         {
180           GdkWindowQueueItem *item = tmp_list->data;
181           GList *next = tmp_list->next;
182           
183           /* an overflow-safe (item->serial < serial) */
184           if (item->serial - serial > (gulong) G_MAXLONG)
185             {
186               queue_delete_link (display_x11->translate_queue, tmp_list);
187               queue_item_free (item);
188             }
189
190           tmp_list = next;
191         }
192     }
193
194   /* Catch the case where someone isn't processing events and there
195    * is an event stuck in the event queue with an old serial:
196    * If we can't reduce the queue length by the above method,
197    * discard anti-expose items. (We can't discard translate
198    * items 
199    */
200   if (display_x11->translate_queue->length >= 64)
201     {
202       GList *tmp_list = display_x11->translate_queue->head;
203       
204       while (tmp_list)
205         {
206           GdkWindowQueueItem *item = tmp_list->data;
207           GList *next = tmp_list->next;
208           
209           if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
210             {
211               queue_delete_link (display_x11->translate_queue, tmp_list);
212               queue_item_free (item);
213             }
214
215           tmp_list = next;
216         }
217     }
218
219   item->window = window;
220   item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
221   
222   g_object_add_weak_pointer (G_OBJECT (window),
223                              (gpointer *)&(item->window));
224
225   g_queue_push_tail (display_x11->translate_queue, item);
226 }
227
228 void
229 _gdk_x11_window_queue_translation (GdkWindow *window,
230                                    GdkGC     *gc,
231                                    cairo_region_t *area,
232                                    gint       dx,
233                                    gint       dy)
234 {
235   GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
236   item->type = GDK_WINDOW_QUEUE_TRANSLATE;
237   item->u.translate.area = area ? cairo_region_copy (area) : NULL;
238   item->u.translate.dx = dx;
239   item->u.translate.dy = dy;
240
241   /* Ensure that the gc is flushed so that we get the right
242      serial from NextRequest in gdk_window_queue, i.e. the
243      the serial for the XCopyArea, not the ones from flushing
244      the gc. */
245   _gdk_x11_gc_flush (gc);
246   gdk_window_queue (window, item);
247 }
248
249 gboolean
250 _gdk_x11_window_queue_antiexpose (GdkWindow *window,
251                                   cairo_region_t *area)
252 {
253   GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
254   item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
255   item->u.antiexpose.area = area;
256
257   gdk_window_queue (window, item);
258
259   return TRUE;
260 }
261
262 void
263 _gdk_window_process_expose (GdkWindow    *window,
264                             gulong        serial,
265                             GdkRectangle *area)
266 {
267   cairo_region_t *invalidate_region = cairo_region_create_rectangle (area);
268   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
269
270   if (display_x11->translate_queue)
271     {
272       GList *tmp_list = display_x11->translate_queue->head;
273
274       while (tmp_list)
275         {
276           GdkWindowQueueItem *item = tmp_list->data;
277           GList *next = tmp_list->next;
278
279           /* an overflow-safe (serial < item->serial) */
280           if (serial - item->serial > (gulong) G_MAXLONG)
281             {
282               if (item->window == window)
283                 {
284                   if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
285                     {
286                       if (item->u.translate.area)
287                         {
288                           cairo_region_t *intersection;
289
290                           intersection = cairo_region_copy (invalidate_region);
291                           cairo_region_intersect (intersection, item->u.translate.area);
292                           cairo_region_subtract (invalidate_region, intersection);
293                           cairo_region_translate (intersection, item->u.translate.dx, item->u.translate.dy);
294                           cairo_region_union (invalidate_region, intersection);
295                           cairo_region_destroy (intersection);
296                         }
297                       else
298                         cairo_region_translate (invalidate_region, item->u.translate.dx, item->u.translate.dy);
299                     }
300                   else          /* anti-expose */
301                     {
302                       cairo_region_subtract (invalidate_region, item->u.antiexpose.area);
303                     }
304                 }
305             }
306           else
307             {
308               queue_delete_link (display_x11->translate_queue, tmp_list);
309               queue_item_free (item);
310             }
311           tmp_list = next;
312         }
313     }
314
315   if (!cairo_region_is_empty (invalidate_region))
316     _gdk_window_invalidate_for_expose (window, invalidate_region);
317
318   cairo_region_destroy (invalidate_region);
319 }