]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkgeometry-x11.c
Inclusion cleanups in sources
[~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
22 #include "gdkrectangle.h"
23 #include "gdkprivate-x11.h"
24 #include "gdkx.h"
25 #include "gdkinternals.h"
26 #include "gdkscreen-x11.h"
27 #include "gdkdisplay-x11.h"
28 #include "gdkwindow-x11.h"
29
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       cairo_region_t *area;
47       gint dx;
48       gint dy;
49     } translate;
50     struct {
51       cairo_region_t *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     cairo_region_destroy (item->u.antiexpose.area);
152   else
153     {
154       if (item->u.translate.area)
155         cairo_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 static GC
230 _get_scratch_gc (GdkWindowObject *window, cairo_region_t *clip_region)
231 {
232   GdkScreenX11 *screen;
233   XRectangle *rectangles;
234   gint n_rects;
235   gint depth;
236
237   screen = GDK_SCREEN_X11 (gdk_window_get_screen (GDK_WINDOW (window)));
238   depth = gdk_visual_get_depth (gdk_window_get_visual (GDK_WINDOW (window))) - 1;
239
240   if (!screen->subwindow_gcs[depth])
241     {
242       XGCValues values;
243       
244       values.graphics_exposures = True;
245       values.subwindow_mode = IncludeInferiors;
246       
247       screen->subwindow_gcs[depth] = XCreateGC (screen->xdisplay,
248                                                 GDK_WINDOW_XID (window),
249                                                 GCSubwindowMode | GCGraphicsExposures,
250                                                 &values);
251     }
252   
253   _gdk_region_get_xrectangles (clip_region,
254                                0, 0,
255                                &rectangles,
256                                &n_rects);
257   
258   XSetClipRectangles (screen->xdisplay,
259                       screen->subwindow_gcs[depth],
260                       0, 0,
261                       rectangles, n_rects,
262                       YXBanded);
263   
264   g_free (rectangles);
265   return screen->subwindow_gcs[depth];
266 }
267
268
269
270 void
271 _gdk_x11_window_translate (GdkWindow      *window,
272                            cairo_region_t *area,
273                            gint            dx,
274                            gint            dy)
275 {
276   GdkWindowQueueItem *item;
277   GC xgc;
278   GdkRectangle extents;
279   GdkWindowObject *private, *impl;
280   int px, py;
281
282   /* We need to get data from subwindows here, because we might have
283    * shaped a native window over the moving region (with bg none,
284    * so the pixels are still there). In fact we might need to get data
285    * from overlapping native window that are not children of this window,
286    * so we copy from the toplevel with INCLUDE_INFERIORS.
287    */
288   private = impl = (GdkWindowObject *) window;
289   px = py = 0;
290   while (private->parent != NULL &&
291          private->parent->window_type != GDK_WINDOW_ROOT)
292     {
293       dx -= private->parent->abs_x + private->x;
294       dy -= private->parent->abs_y + private->y;
295       private = (GdkWindowObject *) _gdk_window_get_impl_window ((GdkWindow *) private->parent);
296     }
297
298   cairo_region_get_extents (area, &extents);
299
300   xgc = _get_scratch_gc (impl, area);
301
302   cairo_region_translate (area, -dx, -dy); /* Move to source region */
303
304   item = g_new (GdkWindowQueueItem, 1);
305   item->type = GDK_WINDOW_QUEUE_TRANSLATE;
306   item->u.translate.area = cairo_region_copy (area);
307   item->u.translate.dx = dx;
308   item->u.translate.dy = dy;
309   gdk_window_queue (window, item);
310
311   XCopyArea (GDK_WINDOW_XDISPLAY (impl),
312              GDK_DRAWABLE_IMPL_X11 (private->impl)->xid,
313              GDK_DRAWABLE_IMPL_X11 (impl->impl)->xid,
314              xgc,
315              extents.x - dx, extents.y - dy,
316              extents.width, extents.height,
317              extents.x, extents.y);
318 }
319
320 gboolean
321 _gdk_x11_window_queue_antiexpose (GdkWindow *window,
322                                   cairo_region_t *area)
323 {
324   GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
325   item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
326   item->u.antiexpose.area = area;
327
328   gdk_window_queue (window, item);
329
330   return TRUE;
331 }
332
333 void
334 _gdk_window_process_expose (GdkWindow    *window,
335                             gulong        serial,
336                             GdkRectangle *area)
337 {
338   cairo_region_t *invalidate_region = cairo_region_create_rectangle (area);
339   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
340
341   if (display_x11->translate_queue)
342     {
343       GList *tmp_list = display_x11->translate_queue->head;
344
345       while (tmp_list)
346         {
347           GdkWindowQueueItem *item = tmp_list->data;
348           GList *next = tmp_list->next;
349
350           /* an overflow-safe (serial < item->serial) */
351           if (serial - item->serial > (gulong) G_MAXLONG)
352             {
353               if (item->window == window)
354                 {
355                   if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
356                     {
357                       if (item->u.translate.area)
358                         {
359                           cairo_region_t *intersection;
360
361                           intersection = cairo_region_copy (invalidate_region);
362                           cairo_region_intersect (intersection, item->u.translate.area);
363                           cairo_region_subtract (invalidate_region, intersection);
364                           cairo_region_translate (intersection, item->u.translate.dx, item->u.translate.dy);
365                           cairo_region_union (invalidate_region, intersection);
366                           cairo_region_destroy (intersection);
367                         }
368                       else
369                         cairo_region_translate (invalidate_region, item->u.translate.dx, item->u.translate.dy);
370                     }
371                   else          /* anti-expose */
372                     {
373                       cairo_region_subtract (invalidate_region, item->u.antiexpose.area);
374                     }
375                 }
376             }
377           else
378             {
379               queue_delete_link (display_x11->translate_queue, tmp_list);
380               queue_item_free (item);
381             }
382           tmp_list = next;
383         }
384     }
385
386   if (!cairo_region_is_empty (invalidate_region))
387     _gdk_window_invalidate_for_expose (window, invalidate_region);
388
389   cairo_region_destroy (invalidate_region);
390 }