Blame gdk/x11/gdkgeometry-x11.c

Packit 98cdb6
/* GDK - The GIMP Drawing Kit
Packit 98cdb6
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
Packit 98cdb6
 *
Packit 98cdb6
 * This library is free software; you can redistribute it and/or
Packit 98cdb6
 * modify it under the terms of the GNU Lesser General Public
Packit 98cdb6
 * License as published by the Free Software Foundation; either
Packit 98cdb6
 * version 2 of the License, or (at your option) any later version.
Packit 98cdb6
 *
Packit 98cdb6
 * This library is distributed in the hope that it will be useful,
Packit 98cdb6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 98cdb6
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 98cdb6
 * Lesser General Public License for more details.
Packit 98cdb6
 *
Packit 98cdb6
 * You should have received a copy of the GNU Lesser General Public
Packit 98cdb6
 * License along with this library; if not, write to the
Packit 98cdb6
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Packit 98cdb6
 * Boston, MA 02111-1307, USA.
Packit 98cdb6
 */
Packit 98cdb6
Packit 98cdb6
#include "config.h"
Packit 98cdb6
#include "gdk.h"		/* For gdk_rectangle_intersect */
Packit 98cdb6
#include "gdkprivate-x11.h"
Packit 98cdb6
#include "gdkx.h"
Packit 98cdb6
#include "gdkregion.h"
Packit 98cdb6
#include "gdkinternals.h"
Packit 98cdb6
#include "gdkscreen-x11.h"
Packit 98cdb6
#include "gdkdisplay-x11.h"
Packit 98cdb6
#include "gdkwindow-x11.h"
Packit 98cdb6
#include "gdkalias.h"
Packit 98cdb6
Packit 98cdb6
typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
Packit 98cdb6
typedef struct _GdkWindowParentPos GdkWindowParentPos;
Packit 98cdb6
Packit 98cdb6
typedef enum {
Packit 98cdb6
  GDK_WINDOW_QUEUE_TRANSLATE,
Packit 98cdb6
  GDK_WINDOW_QUEUE_ANTIEXPOSE
Packit 98cdb6
} GdkWindowQueueType;
Packit 98cdb6
Packit 98cdb6
struct _GdkWindowQueueItem
Packit 98cdb6
{
Packit 98cdb6
  GdkWindow *window;
Packit 98cdb6
  gulong serial;
Packit 98cdb6
  GdkWindowQueueType type;
Packit 98cdb6
  union {
Packit 98cdb6
    struct {
Packit 98cdb6
      GdkRegion *area;
Packit 98cdb6
      gint dx;
Packit 98cdb6
      gint dy;
Packit 98cdb6
    } translate;
Packit 98cdb6
    struct {
Packit 98cdb6
      GdkRegion *area;
Packit 98cdb6
    } antiexpose;
Packit 98cdb6
  } u;
Packit 98cdb6
};
Packit 98cdb6
Packit 98cdb6
void
Packit 98cdb6
_gdk_window_move_resize_child (GdkWindow *window,
Packit 98cdb6
			       gint       x,
Packit 98cdb6
			       gint       y,
Packit 98cdb6
			       gint       width,
Packit 98cdb6
			       gint       height)
Packit 98cdb6
{
Packit 98cdb6
  GdkWindowObject *obj;
Packit 98cdb6
Packit 98cdb6
  g_return_if_fail (window != NULL);
Packit 98cdb6
  g_return_if_fail (GDK_IS_WINDOW (window));
Packit 98cdb6
Packit 98cdb6
  obj = GDK_WINDOW_OBJECT (window);
Packit 98cdb6
Packit 98cdb6
  if (width > 65535 ||
Packit 98cdb6
      height > 65535)
Packit 98cdb6
    {
Packit 98cdb6
      g_warning ("Native children wider or taller than 65535 pixels are not supported");
Packit 98cdb6
Packit 98cdb6
      if (width > 65535)
Packit 98cdb6
	width = 65535;
Packit 98cdb6
      if (height > 65535)
Packit 98cdb6
	height = 65535;
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  obj->x = x;
Packit 98cdb6
  obj->y = y;
Packit 98cdb6
  obj->width = width;
Packit 98cdb6
  obj->height = height;
Packit 98cdb6
Packit 98cdb6
  /* We don't really care about origin overflow, because on overflow
Packit 98cdb6
     the window won't be visible anyway and thus it will be shaped
Packit 98cdb6
     to nothing */
Packit 98cdb6
Packit 98cdb6
  _gdk_x11_window_tmp_unset_parent_bg (window);
Packit 98cdb6
  _gdk_x11_window_tmp_unset_bg (window, TRUE);
Packit 98cdb6
  XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
Packit 98cdb6
		     GDK_WINDOW_XID (window),
Packit 98cdb6
		     obj->x + obj->parent->abs_x,
Packit 98cdb6
		     obj->y + obj->parent->abs_y,
Packit 98cdb6
		     width, height);
Packit 98cdb6
  _gdk_x11_window_tmp_reset_parent_bg (window);
Packit 98cdb6
  _gdk_x11_window_tmp_reset_bg (window, TRUE);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static Bool
Packit 98cdb6
expose_serial_predicate (Display *xdisplay,
Packit 98cdb6
			 XEvent  *xev,
Packit 98cdb6
			 XPointer arg)
Packit 98cdb6
{
Packit 98cdb6
  gulong *serial = (gulong *)arg;
Packit 98cdb6
Packit 98cdb6
  if (xev->xany.type == Expose || xev->xany.type == GraphicsExpose)
Packit 98cdb6
    *serial = MIN (*serial, xev->xany.serial);
Packit 98cdb6
Packit 98cdb6
  return False;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
/* Find oldest possible serial for an outstanding expose event
Packit 98cdb6
 */
Packit 98cdb6
static gulong
Packit 98cdb6
find_current_serial (Display *xdisplay)
Packit 98cdb6
{
Packit 98cdb6
  XEvent xev;
Packit 98cdb6
  gulong serial = NextRequest (xdisplay);
Packit 98cdb6
  
Packit 98cdb6
  XSync (xdisplay, False);
Packit 98cdb6
Packit 98cdb6
  XCheckIfEvent (xdisplay, &xev, expose_serial_predicate, (XPointer)&serial);
Packit 98cdb6
Packit 98cdb6
  return serial;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
queue_delete_link (GQueue *queue,
Packit 98cdb6
		   GList  *link)
Packit 98cdb6
{
Packit 98cdb6
  if (queue->tail == link)
Packit 98cdb6
    queue->tail = link->prev;
Packit 98cdb6
  
Packit 98cdb6
  queue->head = g_list_remove_link (queue->head, link);
Packit 98cdb6
  g_list_free_1 (link);
Packit 98cdb6
  queue->length--;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
queue_item_free (GdkWindowQueueItem *item)
Packit 98cdb6
{
Packit 98cdb6
  if (item->window)
Packit 98cdb6
    {
Packit 98cdb6
      g_object_remove_weak_pointer (G_OBJECT (item->window),
Packit 98cdb6
				    (gpointer *)&(item->window));
Packit 98cdb6
    }
Packit 98cdb6
  
Packit 98cdb6
  if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
Packit 98cdb6
    gdk_region_destroy (item->u.antiexpose.area);
Packit 98cdb6
  else
Packit 98cdb6
    {
Packit 98cdb6
      if (item->u.translate.area)
Packit 98cdb6
	gdk_region_destroy (item->u.translate.area);
Packit 98cdb6
    }
Packit 98cdb6
  
Packit 98cdb6
  g_free (item);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
static void
Packit 98cdb6
gdk_window_queue (GdkWindow          *window,
Packit 98cdb6
		  GdkWindowQueueItem *item)
Packit 98cdb6
{
Packit 98cdb6
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
Packit 98cdb6
  
Packit 98cdb6
  if (!display_x11->translate_queue)
Packit 98cdb6
    display_x11->translate_queue = g_queue_new ();
Packit 98cdb6
Packit 98cdb6
  /* Keep length of queue finite by, if it grows too long,
Packit 98cdb6
   * figuring out the latest relevant serial and discarding
Packit 98cdb6
   * irrelevant queue items.
Packit 98cdb6
   */
Packit 98cdb6
  if (display_x11->translate_queue->length >= 64)
Packit 98cdb6
    {
Packit 98cdb6
      gulong serial = find_current_serial (GDK_WINDOW_XDISPLAY (window));
Packit 98cdb6
      GList *tmp_list = display_x11->translate_queue->head;
Packit 98cdb6
      
Packit 98cdb6
      while (tmp_list)
Packit 98cdb6
	{
Packit 98cdb6
	  GdkWindowQueueItem *item = tmp_list->data;
Packit 98cdb6
	  GList *next = tmp_list->next;
Packit 98cdb6
	  
Packit 98cdb6
	  /* an overflow-safe (item->serial < serial) */
Packit 98cdb6
	  if (item->serial - serial > (gulong) G_MAXLONG)
Packit 98cdb6
	    {
Packit 98cdb6
	      queue_delete_link (display_x11->translate_queue, tmp_list);
Packit 98cdb6
	      queue_item_free (item);
Packit 98cdb6
	    }
Packit 98cdb6
Packit 98cdb6
	  tmp_list = next;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  /* Catch the case where someone isn't processing events and there
Packit 98cdb6
   * is an event stuck in the event queue with an old serial:
Packit 98cdb6
   * If we can't reduce the queue length by the above method,
Packit 98cdb6
   * discard anti-expose items. (We can't discard translate
Packit 98cdb6
   * items 
Packit 98cdb6
   */
Packit 98cdb6
  if (display_x11->translate_queue->length >= 64)
Packit 98cdb6
    {
Packit 98cdb6
      GList *tmp_list = display_x11->translate_queue->head;
Packit 98cdb6
      
Packit 98cdb6
      while (tmp_list)
Packit 98cdb6
	{
Packit 98cdb6
	  GdkWindowQueueItem *item = tmp_list->data;
Packit 98cdb6
	  GList *next = tmp_list->next;
Packit 98cdb6
	  
Packit 98cdb6
	  if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
Packit 98cdb6
	    {
Packit 98cdb6
	      queue_delete_link (display_x11->translate_queue, tmp_list);
Packit 98cdb6
	      queue_item_free (item);
Packit 98cdb6
	    }
Packit 98cdb6
Packit 98cdb6
	  tmp_list = next;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  item->window = window;
Packit 98cdb6
  item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
Packit 98cdb6
  
Packit 98cdb6
  g_object_add_weak_pointer (G_OBJECT (window),
Packit 98cdb6
			     (gpointer *)&(item->window));
Packit 98cdb6
Packit 98cdb6
  g_queue_push_tail (display_x11->translate_queue, item);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
void
Packit 98cdb6
_gdk_x11_window_queue_translation (GdkWindow *window,
Packit 98cdb6
				   GdkGC     *gc,
Packit 98cdb6
				   GdkRegion *area,
Packit 98cdb6
				   gint       dx,
Packit 98cdb6
				   gint       dy)
Packit 98cdb6
{
Packit 98cdb6
  GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
Packit 98cdb6
  item->type = GDK_WINDOW_QUEUE_TRANSLATE;
Packit 98cdb6
  item->u.translate.area = area ? gdk_region_copy (area) : NULL;
Packit 98cdb6
  item->u.translate.dx = dx;
Packit 98cdb6
  item->u.translate.dy = dy;
Packit 98cdb6
Packit 98cdb6
  /* Ensure that the gc is flushed so that we get the right
Packit 98cdb6
     serial from NextRequest in gdk_window_queue, i.e. the
Packit 98cdb6
     the serial for the XCopyArea, not the ones from flushing
Packit 98cdb6
     the gc. */
Packit 98cdb6
  _gdk_x11_gc_flush (gc);
Packit 98cdb6
  gdk_window_queue (window, item);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
gboolean
Packit 98cdb6
_gdk_x11_window_queue_antiexpose (GdkWindow *window,
Packit 98cdb6
				  GdkRegion *area)
Packit 98cdb6
{
Packit 98cdb6
  GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
Packit 98cdb6
  item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
Packit 98cdb6
  item->u.antiexpose.area = area;
Packit 98cdb6
Packit 98cdb6
  gdk_window_queue (window, item);
Packit 98cdb6
Packit 98cdb6
  return TRUE;
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
void
Packit 98cdb6
_gdk_window_process_expose (GdkWindow    *window,
Packit 98cdb6
			    gulong        serial,
Packit 98cdb6
			    GdkRectangle *area)
Packit 98cdb6
{
Packit 98cdb6
  GdkRegion *invalidate_region = gdk_region_rectangle (area);
Packit 98cdb6
  GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
Packit 98cdb6
Packit 98cdb6
  if (display_x11->translate_queue)
Packit 98cdb6
    {
Packit 98cdb6
      GList *tmp_list = display_x11->translate_queue->head;
Packit 98cdb6
Packit 98cdb6
      while (tmp_list)
Packit 98cdb6
	{
Packit 98cdb6
	  GdkWindowQueueItem *item = tmp_list->data;
Packit 98cdb6
          GList *next = tmp_list->next;
Packit 98cdb6
Packit 98cdb6
	  /* an overflow-safe (serial < item->serial) */
Packit 98cdb6
	  if (serial - item->serial > (gulong) G_MAXLONG)
Packit 98cdb6
	    {
Packit 98cdb6
	      if (item->window == window)
Packit 98cdb6
		{
Packit 98cdb6
		  if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
Packit 98cdb6
		    {
Packit 98cdb6
		      if (item->u.translate.area)
Packit 98cdb6
			{
Packit 98cdb6
			  GdkRegion *intersection;
Packit 98cdb6
Packit 98cdb6
			  intersection = gdk_region_copy (invalidate_region);
Packit 98cdb6
			  gdk_region_intersect (intersection, item->u.translate.area);
Packit 98cdb6
			  gdk_region_subtract (invalidate_region, intersection);
Packit 98cdb6
			  gdk_region_offset (intersection, item->u.translate.dx, item->u.translate.dy);
Packit 98cdb6
			  gdk_region_union (invalidate_region, intersection);
Packit 98cdb6
			  gdk_region_destroy (intersection);
Packit 98cdb6
			}
Packit 98cdb6
		      else
Packit 98cdb6
			gdk_region_offset (invalidate_region, item->u.translate.dx, item->u.translate.dy);
Packit 98cdb6
		    }
Packit 98cdb6
		  else		/* anti-expose */
Packit 98cdb6
		    {
Packit 98cdb6
		      gdk_region_subtract (invalidate_region, item->u.antiexpose.area);
Packit 98cdb6
		    }
Packit 98cdb6
		}
Packit 98cdb6
	    }
Packit 98cdb6
	  else
Packit 98cdb6
	    {
Packit 98cdb6
	      queue_delete_link (display_x11->translate_queue, tmp_list);
Packit 98cdb6
	      queue_item_free (item);
Packit 98cdb6
	    }
Packit 98cdb6
	  tmp_list = next;
Packit 98cdb6
	}
Packit 98cdb6
    }
Packit 98cdb6
Packit 98cdb6
  if (!gdk_region_empty (invalidate_region))
Packit 98cdb6
    _gdk_window_invalidate_for_expose (window, invalidate_region);
Packit 98cdb6
Packit 98cdb6
  gdk_region_destroy (invalidate_region);
Packit 98cdb6
}
Packit 98cdb6
Packit 98cdb6
#define __GDK_GEOMETRY_X11_C__
Packit 98cdb6
#include "gdkaliasdef.c"