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 Library 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 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library 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.
20 /* gdkgeometry-x11.c: emulation of 32 bit coordinates within the
23 * By Owen Taylor <otaylor@redhat.com>
24 * Copyright Red Hat, Inc. 2000
27 #include "gdk.h" /* For gdk_rectangle_intersect */
28 #include "gdkprivate-x11.h"
30 #include "gdkregion.h"
32 typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
33 typedef struct _GdkWindowParentPos GdkWindowParentPos;
36 GDK_WINDOW_QUEUE_TRANSLATE,
37 GDK_WINDOW_QUEUE_ANTIEXPOSE
40 struct _GdkWindowQueueItem
44 GdkWindowQueueType type;
56 struct _GdkWindowParentPos
62 GdkRectangle clip_rect;
65 static void gdk_window_compute_position (GdkWindow *window,
66 GdkWindowParentPos *parent_pos,
67 GdkXPositionInfo *info);
68 static void gdk_window_compute_parent_pos (GdkWindow *window,
69 GdkWindowParentPos *parent_pos);
70 static void gdk_window_premove (GdkWindow *window,
71 GdkWindowParentPos *parent_pos);
72 static void gdk_window_postmove (GdkWindow *window,
73 GdkWindowParentPos *parent_pos);
74 static void gdk_window_queue_translation (GdkWindow *window,
77 static void gdk_window_tmp_unset_bg (GdkWindow *window);
78 static void gdk_window_tmp_reset_bg (GdkWindow *window);
79 static void gdk_window_clip_changed (GdkWindow *window,
80 GdkRectangle *old_clip,
81 GdkRectangle *new_clip);
83 static GSList *translate_queue = NULL;
86 _gdk_windowing_window_get_offsets (GdkWindow *window,
90 GdkWindowPrivate *private = (GdkWindowPrivate *)window;
91 GdkWindowXData *data = (GdkWindowXData *)private->drawable.klass_data;
93 *x_offset = data->position_info.x_offset;
94 *y_offset = data->position_info.y_offset;
98 _gdk_window_init_position (GdkWindow *window)
100 GdkWindowPrivate *private = (GdkWindowPrivate *)window;
101 GdkWindowXData *data;
102 GdkWindowParentPos parent_pos;
104 g_return_if_fail (window != NULL);
105 g_return_if_fail (GDK_IS_WINDOW (window));
107 data = (GdkWindowXData *)private->drawable.klass_data;
109 gdk_window_compute_parent_pos (window, &parent_pos);
110 gdk_window_compute_position (window, &parent_pos, &data->position_info);
114 _gdk_window_move_resize_child (GdkWindow *window,
120 GdkWindowPrivate *private = (GdkWindowPrivate *)window;
121 GdkXPositionInfo new_info;
122 GdkWindowParentPos parent_pos;
123 GdkWindowXData *data;
126 gint d_xoffset, d_yoffset;
131 g_return_if_fail (window != NULL);
132 g_return_if_fail (GDK_IS_WINDOW (window));
134 data = (GdkWindowXData *)private->drawable.klass_data;
139 is_move = dx != 0 || dy != 0;
140 is_resize = private->drawable.width != width || private->drawable.height != height;
142 if (!is_move && !is_resize)
147 private->drawable.width = width;
148 private->drawable.height = height;
150 gdk_window_compute_parent_pos (window, &parent_pos);
151 gdk_window_compute_position (window, &parent_pos, &new_info);
153 gdk_window_clip_changed (window, &data->position_info.clip_rect, &new_info.clip_rect);
155 parent_pos.x += private->x;
156 parent_pos.y += private->y;
157 parent_pos.x11_x += new_info.x;
158 parent_pos.x11_y += new_info.y;
159 parent_pos.clip_rect = new_info.clip_rect;
161 d_xoffset = new_info.x_offset - data->position_info.x_offset;
162 d_yoffset = new_info.y_offset - data->position_info.y_offset;
164 if (d_xoffset != 0 || d_yoffset != 0)
166 gint new_x0, new_y0, new_x1, new_y1;
168 gdk_window_set_static_gravities (window, TRUE);
170 if (d_xoffset < 0 || d_yoffset < 0)
171 gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
175 new_x0 = data->position_info.x + d_xoffset;
176 new_x1 = data->position_info.x + data->position_info.width;
180 new_x0 = data->position_info.x;
181 new_x1 = data->position_info.x + new_info.width + d_xoffset;
186 new_y0 = data->position_info.y + d_yoffset;
187 new_y1 = data->position_info.y + data->position_info.height;
191 new_y0 = data->position_info.y;
192 new_y1 = data->position_info.y + new_info.height + d_yoffset;
195 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
196 GDK_DRAWABLE_XID (window),
197 new_x0, new_y0, new_x1 - new_x0, new_y1 - new_y0);
199 tmp_list = private->children;
202 gdk_window_premove (tmp_list->data, &parent_pos);
203 tmp_list = tmp_list->next;
206 XMoveWindow (GDK_DRAWABLE_XDISPLAY (window),
207 GDK_DRAWABLE_XID (window),
208 new_x0 + dx, new_y0 + dy);
210 if (d_xoffset > 0 || d_yoffset > 0)
211 gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
213 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
214 GDK_DRAWABLE_XID (window),
215 new_info.x, new_info.y, new_info.width, new_info.height);
217 if (data->position_info.no_bg)
218 gdk_window_tmp_reset_bg (window);
220 if (!data->position_info.mapped && new_info.mapped && private->mapped)
221 XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
223 data->position_info = new_info;
225 tmp_list = private->children;
228 gdk_window_postmove (tmp_list->data, &parent_pos);
229 tmp_list = tmp_list->next;
234 if (is_move && is_resize)
235 gdk_window_set_static_gravities (window, FALSE);
237 if (data->position_info.mapped && !new_info.mapped)
238 XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
240 tmp_list = private->children;
243 gdk_window_premove (tmp_list->data, &parent_pos);
244 tmp_list = tmp_list->next;
248 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
249 GDK_DRAWABLE_XID (window),
250 new_info.x, new_info.y, new_info.width, new_info.height);
252 XMoveWindow (GDK_DRAWABLE_XDISPLAY (window),
253 GDK_DRAWABLE_XID (window),
254 new_info.x, new_info.y);
256 tmp_list = private->children;
259 gdk_window_postmove (tmp_list->data, &parent_pos);
260 tmp_list = tmp_list->next;
263 if (data->position_info.no_bg)
264 gdk_window_tmp_reset_bg (window);
266 if (!data->position_info.mapped && new_info.mapped && private->mapped)
267 XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
269 data->position_info = new_info;
274 gdk_window_compute_position (GdkWindow *window,
275 GdkWindowParentPos *parent_pos,
276 GdkXPositionInfo *info)
278 GdkWindowPrivate *private = (GdkWindowPrivate *)window;
284 if (private->drawable.width <= 32768)
286 info->width = private->drawable.width;
287 info->x = parent_pos->x + private->x - parent_pos->x11_x;
293 if (parent_pos->x + private->x < -16384)
295 if (parent_pos->x + private->x + private->drawable.width < 16384)
296 info->x = parent_pos->x + private->x + private->drawable.width - 32768 - parent_pos->x11_x;
298 info->x = -16384 - parent_pos->x11_y;
301 info->x = parent_pos->x + private->x - parent_pos->x11_x;
304 if (private->drawable.height <= 32768)
306 info->height = private->drawable.height;
307 info->y = parent_pos->y + private->y - parent_pos->x11_y;
312 info->height = 32768;
313 if (parent_pos->y + private->y < -16384)
315 if (parent_pos->y + private->y + private->drawable.height < 16384)
316 info->y = parent_pos->y + private->y + private->drawable.height - 32768 - parent_pos->x11_y;
318 info->y = -16384 - parent_pos->x11_y;
321 info->y = parent_pos->y + private->y - parent_pos->x11_y;
324 parent_x_offset = parent_pos->x11_x - parent_pos->x;
325 parent_y_offset = parent_pos->x11_y - parent_pos->y;
327 info->x_offset = parent_x_offset + info->x - private->x;
328 info->y_offset = parent_y_offset + info->y - private->y;
330 /* We don't considering the clipping of toplevel windows and their immediate children
331 * by their parents, and simply always map those windows.
333 if (parent_pos->clip_rect.width == G_MAXINT)
335 /* Check if the window would wrap around into the visible space in either direction */
336 else if (info->x + parent_x_offset < parent_pos->clip_rect.x + parent_pos->clip_rect.width - 65536 ||
337 info->x + info->width + parent_x_offset > parent_pos->clip_rect.x + 65536 ||
338 info->y + parent_y_offset < parent_pos->clip_rect.y + parent_pos->clip_rect.height - 65536 ||
339 info->y + info->width + parent_y_offset > parent_pos->clip_rect.y + 65536)
340 info->mapped = FALSE;
346 if (GDK_DRAWABLE_TYPE (private) == GDK_WINDOW_CHILD)
348 info->clip_rect.x = private->x;
349 info->clip_rect.y = private->y;
350 info->clip_rect.width = private->drawable.width;
351 info->clip_rect.height = private->drawable.height;
353 gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect);
355 info->clip_rect.x -= private->x;
356 info->clip_rect.y -= private->y;
360 info->clip_rect.x = 0;
361 info->clip_rect.y = 0;
362 info->clip_rect.width = G_MAXINT;
363 info->clip_rect.height = G_MAXINT;
368 gdk_window_compute_parent_pos (GdkWindow *window,
369 GdkWindowParentPos *parent_pos)
371 GdkWindowPrivate *private = (GdkWindowPrivate *)window;
372 GdkWindowXData *data;
373 GdkRectangle tmp_clip;
375 int clip_xoffset = 0;
376 int clip_yoffset = 0;
380 parent_pos->x11_x = 0;
381 parent_pos->x11_y = 0;
383 /* We take a simple approach here and simply consider toplevel
384 * windows not to clip their children on the right/bottom, since the
385 * size of toplevel windows is not directly under our
386 * control. Clipping only really matters when scrolling and
387 * generally we aren't going to be moving the immediate child of a
388 * toplevel beyond the bounds of that toplevel.
390 * We could go ahead and recompute the clips of toplevel windows and
391 * their descendents when we receive size notification, but it would
392 * probably not be an improvement in most cases.
394 parent_pos->clip_rect.x = 0;
395 parent_pos->clip_rect.y = 0;
396 parent_pos->clip_rect.width = G_MAXINT;
397 parent_pos->clip_rect.height = G_MAXINT;
399 private = (GdkWindowPrivate *)private->parent;
400 while (private && private->drawable.window_type == GDK_WINDOW_CHILD)
402 data = (GdkWindowXData *)private->drawable.klass_data;
404 tmp_clip.x = - clip_xoffset;
405 tmp_clip.y = - clip_yoffset;
406 tmp_clip.width = private->drawable.width;
407 tmp_clip.height = private->drawable.height;
409 gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect);
411 parent_pos->x += private->x;
412 parent_pos->y += private->y;
413 parent_pos->x11_x += data->position_info.x;
414 parent_pos->x11_y += data->position_info.y;
416 clip_xoffset += private->x;
417 clip_yoffset += private->y;
419 private = (GdkWindowPrivate *)private->parent;
424 gdk_window_premove (GdkWindow *window,
425 GdkWindowParentPos *parent_pos)
427 GdkWindowPrivate *private = (GdkWindowPrivate *)window;
428 GdkWindowXData *data = GDK_WINDOW_XDATA (window);
429 GdkXPositionInfo new_info;
431 gint d_xoffset, d_yoffset;
432 GdkWindowParentPos this_pos;
434 gdk_window_compute_position (window, parent_pos, &new_info);
436 gdk_window_clip_changed (window, &data->position_info.clip_rect, &new_info.clip_rect);
438 this_pos.x = parent_pos->x + private->x;
439 this_pos.y = parent_pos->y + private->y;
440 this_pos.x11_x = parent_pos->x11_x + new_info.x;
441 this_pos.x11_y = parent_pos->x11_y + new_info.y;
442 this_pos.clip_rect = new_info.clip_rect;
444 if (data->position_info.mapped && !new_info.mapped)
445 XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
447 d_xoffset = new_info.x_offset - data->position_info.x_offset;
448 d_yoffset = new_info.y_offset - data->position_info.y_offset;
450 if (d_xoffset != 0 || d_yoffset != 0)
452 gint new_x0, new_y0, new_x1, new_y1;
454 if (d_xoffset < 0 || d_yoffset < 0)
455 gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
459 new_x0 = data->position_info.x + d_xoffset;
460 new_x1 = data->position_info.x + data->position_info.width;
464 new_x0 = data->position_info.x;
465 new_x1 = data->position_info.x + new_info.width + d_xoffset;
470 new_y0 = data->position_info.y + d_yoffset;
471 new_y1 = data->position_info.y + data->position_info.height;
475 new_y0 = data->position_info.y;
476 new_y1 = data->position_info.y + new_info.height + d_yoffset;
479 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
480 GDK_DRAWABLE_XID (window),
481 new_x0, new_y0, new_x1 - new_x0, new_y1 - new_y0);
484 tmp_list = private->children;
487 gdk_window_premove (tmp_list->data, &this_pos);
488 tmp_list = tmp_list->next;
493 gdk_window_postmove (GdkWindow *window,
494 GdkWindowParentPos *parent_pos)
496 GdkWindowPrivate *private = (GdkWindowPrivate *)window;
497 GdkWindowXData *data = (GdkWindowXData *)private->drawable.klass_data;
498 GdkXPositionInfo new_info;
500 gint d_xoffset, d_yoffset;
501 GdkWindowParentPos this_pos;
503 gdk_window_compute_position (window, parent_pos, &new_info);
505 this_pos.x = parent_pos->x + private->x;
506 this_pos.y = parent_pos->y + private->y;
507 this_pos.x11_x = parent_pos->x11_x + new_info.x;
508 this_pos.x11_y = parent_pos->x11_y + new_info.y;
509 this_pos.clip_rect = new_info.clip_rect;
511 d_xoffset = new_info.x_offset - data->position_info.x_offset;
512 d_yoffset = new_info.y_offset - data->position_info.y_offset;
514 if (d_xoffset != 0 || d_yoffset != 0)
516 if (d_xoffset > 0 || d_yoffset > 0)
517 gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
519 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
520 GDK_DRAWABLE_XID (window),
521 new_info.x, new_info.y, new_info.width, new_info.height);
524 if (!data->position_info.mapped && new_info.mapped && private->mapped)
525 XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
527 if (data->position_info.no_bg)
528 gdk_window_tmp_reset_bg (window);
530 data->position_info = new_info;
532 tmp_list = private->children;
535 gdk_window_postmove (tmp_list->data, &this_pos);
536 tmp_list = tmp_list->next;
541 gdk_window_queue_translation (GdkWindow *window,
545 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
546 item->window = window;
547 item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
548 item->type = GDK_WINDOW_QUEUE_TRANSLATE;
549 item->u.translate.dx = dx;
550 item->u.translate.dy = dy;
552 gdk_drawable_ref (window);
553 translate_queue = g_slist_append (translate_queue, item);
557 _gdk_windowing_window_queue_antiexpose (GdkWindow *window,
560 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
561 item->window = window;
562 item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
563 item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
564 item->u.antiexpose.area = area;
566 gdk_drawable_ref (window);
567 translate_queue = g_slist_append (translate_queue, item);
573 _gdk_window_process_expose (GdkWindow *window,
577 GdkWindowXData *data = GDK_WINDOW_XDATA (window);
578 GdkRegion *invalidate_region = gdk_region_rectangle (area);
579 GdkRegion *clip_region;
581 GSList *tmp_list = translate_queue;
585 GdkWindowQueueItem *item = tmp_list->data;
586 tmp_list = tmp_list->next;
588 if (serial < item->serial)
590 if (item->window == window)
592 if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
593 gdk_region_offset (invalidate_region, - item->u.translate.dx, - item->u.translate.dy);
594 else /* anti-expose */
595 gdk_region_subtract (invalidate_region, item->u.antiexpose.area);
600 GSList *tmp_link = translate_queue;
602 translate_queue = g_slist_remove_link (translate_queue, translate_queue);
603 gdk_drawable_unref (item->window);
605 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
606 gdk_region_destroy (item->u.antiexpose.area);
609 g_slist_free_1 (tmp_link);
613 clip_region = gdk_region_rectangle (&data->position_info.clip_rect);
614 gdk_region_intersect (invalidate_region, clip_region);
616 if (!gdk_region_empty (invalidate_region))
617 gdk_window_invalidate_region (window, invalidate_region, FALSE);
619 gdk_region_destroy (invalidate_region);
620 gdk_region_destroy (clip_region);
624 gdk_window_tmp_unset_bg (GdkWindow *window)
626 GdkWindowPrivate *private = (GdkWindowPrivate *)window;
627 GdkWindowXData *data = GDK_WINDOW_XDATA (window);
629 data->position_info.no_bg = TRUE;
631 if (private->bg_pixmap != GDK_NO_BG)
632 XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window),
633 GDK_DRAWABLE_XID (window), None);
637 gdk_window_tmp_reset_bg (GdkWindow *window)
639 GdkWindowPrivate *private = (GdkWindowPrivate *)window;
640 GdkWindowXData *data = GDK_WINDOW_XDATA (window);
642 data->position_info.no_bg = FALSE;
644 if (private->bg_pixmap == GDK_NO_BG)
647 if (private->bg_pixmap)
651 if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG)
652 xpixmap = ParentRelative;
654 xpixmap = GDK_DRAWABLE_XID (private->bg_pixmap);
656 XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window),
657 GDK_DRAWABLE_XID (window), xpixmap);
661 XSetWindowBackground (GDK_DRAWABLE_XDISPLAY (window),
662 GDK_DRAWABLE_XID (window),
663 private->bg_color.pixel);
668 gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, GdkRectangle *new_clip)
670 GdkWindowPrivate *private = (GdkWindowPrivate *)window;
672 GdkRegion *old_clip_region;
673 GdkRegion *new_clip_region;
675 if (private->input_only)
678 old_clip_region = gdk_region_rectangle (old_clip);
679 new_clip_region = gdk_region_rectangle (new_clip);
681 /* Trim invalid region of window to new clip rectangle
683 if (private->update_area)
684 gdk_region_intersect (private->update_area, new_clip_region);
686 /* Invalidate newly exposed portion of window
688 gdk_region_subtract (new_clip_region, old_clip_region);
689 if (!gdk_region_empty (new_clip_region))
691 gdk_window_tmp_unset_bg (window);
692 gdk_window_invalidate_region (window, new_clip_region, FALSE);
695 gdk_region_destroy (new_clip_region);
696 gdk_region_destroy (old_clip_region);