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