1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
22 #include "gdkinternals.h"
23 #include "gdkrectangle.h"
24 #include "gdkprivate-x11.h"
25 #include "gdkscreen-x11.h"
26 #include "gdkdisplay-x11.h"
27 #include "gdkwindow-x11.h"
30 typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
31 typedef struct _GdkWindowParentPos GdkWindowParentPos;
34 GDK_WINDOW_QUEUE_TRANSLATE,
35 GDK_WINDOW_QUEUE_ANTIEXPOSE
38 struct _GdkWindowQueueItem
42 GdkWindowQueueType type;
56 _gdk_x11_window_move_resize_child (GdkWindow *window,
62 g_return_if_fail (window != NULL);
63 g_return_if_fail (GDK_IS_WINDOW (window));
68 g_warning ("Native children wider or taller than 65535 pixels are not supported");
78 window->width = width;
79 window->height = height;
81 /* We don't really care about origin overflow, because on overflow
82 * the window won't be visible anyway and thus it will be shaped
85 _gdk_x11_window_tmp_unset_parent_bg (window);
86 _gdk_x11_window_tmp_unset_bg (window, TRUE);
87 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
88 GDK_WINDOW_XID (window),
89 window->x + window->parent->abs_x,
90 window->y + window->parent->abs_y,
92 _gdk_x11_window_tmp_reset_parent_bg (window);
93 _gdk_x11_window_tmp_reset_bg (window, TRUE);
97 expose_serial_predicate (Display *xdisplay,
101 gulong *serial = (gulong *)arg;
103 if (xev->xany.type == Expose || xev->xany.type == GraphicsExpose)
104 *serial = MIN (*serial, xev->xany.serial);
109 /* Find oldest possible serial for an outstanding expose event
112 find_current_serial (Display *xdisplay)
115 gulong serial = NextRequest (xdisplay);
117 XSync (xdisplay, False);
119 XCheckIfEvent (xdisplay, &xev, expose_serial_predicate, (XPointer)&serial);
125 queue_delete_link (GQueue *queue,
128 if (queue->tail == link)
129 queue->tail = link->prev;
131 queue->head = g_list_remove_link (queue->head, link);
132 g_list_free_1 (link);
137 queue_item_free (GdkWindowQueueItem *item)
141 g_object_remove_weak_pointer (G_OBJECT (item->window),
142 (gpointer *)&(item->window));
145 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
146 cairo_region_destroy (item->u.antiexpose.area);
149 if (item->u.translate.area)
150 cairo_region_destroy (item->u.translate.area);
157 _gdk_x11_display_free_translate_queue (GdkDisplay *display)
159 GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
161 if (display_x11->translate_queue)
163 g_queue_foreach (display_x11->translate_queue, (GFunc)queue_item_free, NULL);
164 g_queue_free (display_x11->translate_queue);
165 display_x11->translate_queue = NULL;
170 gdk_window_queue (GdkWindow *window,
171 GdkWindowQueueItem *item)
173 GdkX11Display *display_x11 = GDK_X11_DISPLAY (GDK_WINDOW_DISPLAY (window));
175 if (!display_x11->translate_queue)
176 display_x11->translate_queue = g_queue_new ();
178 /* Keep length of queue finite by, if it grows too long,
179 * figuring out the latest relevant serial and discarding
180 * irrelevant queue items.
182 if (display_x11->translate_queue->length >= 64)
184 gulong serial = find_current_serial (GDK_WINDOW_XDISPLAY (window));
185 GList *tmp_list = display_x11->translate_queue->head;
189 GdkWindowQueueItem *item = tmp_list->data;
190 GList *next = tmp_list->next;
192 /* an overflow-safe (item->serial < serial) */
193 if (item->serial - serial > (gulong) G_MAXLONG)
195 queue_delete_link (display_x11->translate_queue, tmp_list);
196 queue_item_free (item);
203 /* Catch the case where someone isn't processing events and there
204 * is an event stuck in the event queue with an old serial:
205 * If we can't reduce the queue length by the above method,
206 * discard anti-expose items. (We can't discard translate
209 if (display_x11->translate_queue->length >= 64)
211 GList *tmp_list = display_x11->translate_queue->head;
215 GdkWindowQueueItem *item = tmp_list->data;
216 GList *next = tmp_list->next;
218 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
220 queue_delete_link (display_x11->translate_queue, tmp_list);
221 queue_item_free (item);
228 item->window = window;
229 item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
231 g_object_add_weak_pointer (G_OBJECT (window),
232 (gpointer *)&(item->window));
234 g_queue_push_tail (display_x11->translate_queue, item);
238 _get_scratch_gc (GdkWindow *window, cairo_region_t *clip_region)
240 GdkX11Screen *screen;
241 XRectangle *rectangles;
245 screen = GDK_X11_SCREEN (gdk_window_get_screen (window));
246 depth = gdk_visual_get_depth (gdk_window_get_visual (window)) - 1;
248 if (!screen->subwindow_gcs[depth])
252 values.graphics_exposures = True;
253 values.subwindow_mode = IncludeInferiors;
255 screen->subwindow_gcs[depth] = XCreateGC (screen->xdisplay,
256 GDK_WINDOW_XID (window),
257 GCSubwindowMode | GCGraphicsExposures,
261 _gdk_x11_region_get_xrectangles (clip_region,
266 XSetClipRectangles (screen->xdisplay,
267 screen->subwindow_gcs[depth],
273 return screen->subwindow_gcs[depth];
279 _gdk_x11_window_translate (GdkWindow *window,
280 cairo_region_t *area,
284 GdkWindowQueueItem *item;
286 GdkRectangle extents;
288 cairo_region_get_extents (area, &extents);
290 xgc = _get_scratch_gc (window, area);
292 cairo_region_translate (area, -dx, -dy); /* Move to source region */
294 item = g_new (GdkWindowQueueItem, 1);
295 item->type = GDK_WINDOW_QUEUE_TRANSLATE;
296 item->u.translate.area = cairo_region_copy (area);
297 item->u.translate.dx = dx;
298 item->u.translate.dy = dy;
299 gdk_window_queue (window, item);
301 XCopyArea (GDK_WINDOW_XDISPLAY (window),
302 GDK_WINDOW_XID (window),
303 GDK_WINDOW_XID (window),
305 extents.x - dx, extents.y - dy,
306 extents.width, extents.height,
307 extents.x, extents.y);
311 _gdk_x11_window_queue_antiexpose (GdkWindow *window,
312 cairo_region_t *area)
314 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
315 item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
316 item->u.antiexpose.area = area;
318 gdk_window_queue (window, item);
324 _gdk_x11_window_process_expose (GdkWindow *window,
328 cairo_region_t *invalidate_region = cairo_region_create_rectangle (area);
329 GdkX11Display *display_x11 = GDK_X11_DISPLAY (GDK_WINDOW_DISPLAY (window));
331 if (display_x11->translate_queue)
333 GList *tmp_list = display_x11->translate_queue->head;
337 GdkWindowQueueItem *item = tmp_list->data;
338 GList *next = tmp_list->next;
340 /* an overflow-safe (serial < item->serial) */
341 if (serial - item->serial > (gulong) G_MAXLONG)
343 if (item->window == window)
345 if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
347 if (item->u.translate.area)
349 cairo_region_t *intersection;
351 intersection = cairo_region_copy (invalidate_region);
352 cairo_region_intersect (intersection, item->u.translate.area);
353 cairo_region_subtract (invalidate_region, intersection);
354 cairo_region_translate (intersection, item->u.translate.dx, item->u.translate.dy);
355 cairo_region_union (invalidate_region, intersection);
356 cairo_region_destroy (intersection);
359 cairo_region_translate (invalidate_region, item->u.translate.dx, item->u.translate.dy);
361 else /* anti-expose */
363 cairo_region_subtract (invalidate_region, item->u.antiexpose.area);
369 queue_delete_link (display_x11->translate_queue, tmp_list);
370 queue_item_free (item);
376 if (!cairo_region_is_empty (invalidate_region))
377 _gdk_window_invalidate_for_expose (window, invalidate_region);
379 cairo_region_destroy (invalidate_region);