Пример #1
0
static gboolean
myScreenSetWMAtom (ScreenInfo *screen_info, gboolean replace_wm)
{
    const char *wm_name;
    gchar selection[32];
    gchar *display_name;
    gulong wait, timeout;
    DisplayInfo *display_info;
    XSetWindowAttributes attrs;
    Window current_wm;
    XEvent event;
    Atom wm_sn_atom;


    g_return_val_if_fail (screen_info, FALSE);
    g_return_val_if_fail (screen_info->display_info, FALSE);

    TRACE ("entering myScreenReplaceWM");

    display_info = screen_info->display_info;
    g_snprintf (selection, sizeof (selection), "WM_S%d", screen_info->screen);
    wm_sn_atom = XInternAtom (display_info->dpy, selection, FALSE);
    display_name = gdk_screen_make_display_name (screen_info->gscr);
    wm_name = gdk_x11_screen_get_window_manager_name (screen_info->gscr);

    XSync (display_info->dpy, FALSE);
    current_wm = XGetSelectionOwner (display_info->dpy, wm_sn_atom);
    if (current_wm)
    {
        if (!replace_wm)
        {
            g_message ("Another Window Manager (%s) is already running on screen %s", wm_name, display_name);
            g_message ("To replace the current window manager, try \"--replace\"");
            g_free (display_name);

            return FALSE;
        }
        gdk_error_trap_push ();
        attrs.event_mask = StructureNotifyMask;
        XChangeWindowAttributes (display_info->dpy, current_wm, CWEventMask, &attrs);
        if (gdk_error_trap_pop ())
        {
            current_wm = None;
        }
    }

    if (!setXAtomManagerOwner (display_info, wm_sn_atom, screen_info->xroot, screen_info->xfwm4_win))
    {
        g_warning ("Cannot acquire window manager selection on screen %s", display_name);
        g_free (display_name);

        return FALSE;
    }

    /* Waiting for previous window manager to exit */
    if (current_wm)
    {
        g_print ("Waiting for current window manager (%s) on screen %s to exit:", wm_name, display_name);
        wait = 0;
        timeout = WM_EXITING_TIMEOUT * G_USEC_PER_SEC;
        while (wait < timeout)
        {
            if (XCheckWindowEvent (display_info->dpy, current_wm, StructureNotifyMask, &event) && (event.type == DestroyNotify))
            {
                break;
            }
            g_usleep(G_USEC_PER_SEC / 10);
            wait += G_USEC_PER_SEC / 10;
            if (wait % G_USEC_PER_SEC == 0)
            {
              g_print (".");
            }
        }

        if (wait >= timeout)
        {
            g_print(" Failed\n");
            g_warning("Previous window manager (%s) on screen %s is not exiting", wm_name, display_name);
            g_free (display_name);

            return FALSE;
        }
        g_print(" Done\n");
    }
    g_free (display_name);

    return TRUE;
}
Пример #2
0
static VALUE
rg_s_error_trap_pop(VALUE self)
{
    gdk_error_trap_pop();
    return self;
}
Пример #3
0
static void
sn_error_trap_pop(SnDisplay *display, Display *xdisplay)
{
	gdk_error_trap_pop();
}
Пример #4
0
GtkWidget *
na_tray_child_new (GdkScreen *screen,
                   Window     icon_window)
{
  XWindowAttributes window_attributes;
  Display *xdisplay;
  NaTrayChild *child;
  GdkVisual *visual;
  gboolean visual_has_alpha;
  GdkColormap *colormap;
  gboolean new_colormap;
  int result;

  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
  g_return_val_if_fail (icon_window != None, NULL);

  xdisplay = GDK_SCREEN_XDISPLAY (screen);

  /* We need to determine the visual of the window we are embedding and create
   * the socket in the same visual.
   */

  gdk_error_trap_push ();
  result = XGetWindowAttributes (xdisplay, icon_window,
                                 &window_attributes);
  gdk_error_trap_pop ();

  if (!result) /* Window already gone */
    return NULL;

  visual = gdk_x11_screen_lookup_visual (screen,
                                         window_attributes.visual->visualid);
  if (!visual) /* Icon window is on another screen? */
    return NULL;

  new_colormap = FALSE;

  if (visual == gdk_screen_get_rgb_visual (screen))
    colormap = gdk_screen_get_rgb_colormap (screen);
  else if (visual == gdk_screen_get_rgba_visual (screen))
    colormap = gdk_screen_get_rgba_colormap (screen);
  else if (visual == gdk_screen_get_system_visual (screen))
    colormap = gdk_screen_get_system_colormap (screen);
  else
    {
      colormap = gdk_colormap_new (visual, FALSE);
      new_colormap = TRUE;
    }

  child = g_object_new (NA_TYPE_TRAY_CHILD, NULL);
  child->icon_window = icon_window;

  gtk_widget_set_colormap (GTK_WIDGET (child), colormap);

  /* We have alpha if the visual has something other than red, green,
   * and blue */
  visual_has_alpha = visual->red_prec + visual->blue_prec + visual->green_prec < visual->depth;
  child->has_alpha = (visual_has_alpha &&
		      gdk_display_supports_composite (gdk_screen_get_display (screen)));

  child->composited = child->has_alpha;

  if (new_colormap)
    g_object_unref (colormap);

  return GTK_WIDGET (child);
}
Пример #5
0
Файл: errors.c Проект: dnk/marco
int
meta_error_trap_pop_with_return  (MetaDisplay *display,
                                  gboolean     last_request_was_roundtrip)
{
  return gdk_error_trap_pop ();
}
Пример #6
0
gboolean
update_window_decoration_size (WnckWindow *win)
{
    decor_t           *d;
    GdkPixmap         *pixmap, *buffer_pixmap = NULL;
    Picture           picture;
    Display           *xdisplay;
    XRenderPictFormat *format;

    if (win == NULL)
	return FALSE;

    d = g_object_get_data (G_OBJECT (win), "decor");

    if (!d->decorated)
	return FALSE;

    xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());

    gdk_error_trap_push ();

    /* Get the correct depth for the frame window in reparenting mode, otherwise
     * enforce 32 */
    if (d->frame_window)
	pixmap = create_native_pixmap_and_wrap (d->width, d->height, d->frame->style_window_rgb);
    else
	pixmap = create_native_pixmap_and_wrap (d->width, d->height, d->frame->style_window_rgba);

    gdk_flush ();

    /* Handle failure */
    if (!pixmap || gdk_error_trap_pop ())
    {
	memset (pixmap, 0, sizeof (*pixmap));
	return FALSE;
    }

    gdk_error_trap_push ();

    if (d->frame_window)
	buffer_pixmap = create_pixmap (d->width, d->height, d->frame->style_window_rgb);
    else
	buffer_pixmap = create_pixmap (d->width, d->height, d->frame->style_window_rgba);

    gdk_flush ();

    /* Handle failure */
    if (!buffer_pixmap || gdk_error_trap_pop ())
    {
	memset (buffer_pixmap, 0, sizeof (*buffer_pixmap));
	g_object_unref (G_OBJECT (pixmap));
	return FALSE;
    }

    /* Create XRender context */
    format = get_format_for_drawable (d, GDK_DRAWABLE (buffer_pixmap));
    picture = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (buffer_pixmap),
				    format, 0, NULL);

    /* Destroy the old pixmaps and pictures */
    if (d->pixmap)
	g_object_unref (d->pixmap);

    if (d->x11Pixmap)
	decor_post_delete_pixmap (xdisplay,
				  wnck_window_get_xid (d->win),
				  d->x11Pixmap);

    if (d->buffer_pixmap)
	g_object_unref (G_OBJECT (d->buffer_pixmap));

    if (d->picture)
	XRenderFreePicture (xdisplay, d->picture);

    if (d->cr)
	cairo_destroy (d->cr);

    /* Assign new pixmaps and pictures */
    d->pixmap	     = pixmap;
    d->x11Pixmap     = GDK_PIXMAP_XID (d->pixmap);
    d->buffer_pixmap = buffer_pixmap;
    d->cr	     = gdk_cairo_create (pixmap);

    d->picture = picture;

    d->prop_xid = wnck_window_get_xid (win);

    update_window_decoration_name (win);

    /* Redraw decoration on idle */
    queue_decor_draw (d);

    return TRUE;
}
Пример #7
0
int
my_wnck_error_trap_pop (void)
{
    XSync (gdk_x11_get_default_xdisplay (), False);
    return gdk_error_trap_pop ();
}
Пример #8
0
/*
 * update_event_windows
 *
 * Returns: void
 * Description: creates small "event windows" for the buttons specified to be
 * on the titlebar by wnck. Note here that for the pixmap mode we create actual
 * X windows but in the reparenting mode this is not possible so we create event
 * capture boxes on the window instead. The geometry of the decoration is retrieved
 * with window_get_client_window_geometry and adjusted for shade. Also we
 * need to query the theme for what window positions are appropriate here.
 *
 * This function works on the buttons and also the small event regions that we need
 * in order to toggle certain actions on the window decoration (eg resize, move)
 *
 * So your window decoration might look something like this (not to scale):
 *
 * -----------------------------------------------------------
 * | rtl |                   rt                        | rtr |
 * | --- |---------------------------------------------| --- |
 * |     | [i][s][m]         mv              [_][M][X] |     |
 * |     |---------------------------------------------|     |
 * |     |                                             |     |
 * | rl  |             window contents                 | rr  |
 * |     |                                             |     |
 * |     |                                             |     |
 * | --- |---------------------------------------------| --- |
 * | rbl |                  rb                         | rbr |
 * -----------------------------------------------------------
 *
 * Where:
 * - rtl = resize top left
 * - rtr = resize top right
 * - rbl = resize bottom left
 * - rbr = resize bottom right
 * - rt = resize top
 * - rb = resize bottom
 * - rl = resize left
 * - rr = resize right
 * - mv = "grab move" area (eg titlebar)
 * - i = icon
 * - s = shade
 * - m = menu
 * - _ = minimize
 * - M = maximize
 * - X = close
 *
 * For the reparenting mode we use button_windows[i].pos and for the pixmap mode
 * we use buttons_windows[i].window
 *
 */
void
update_event_windows (WnckWindow *win)
{
    Display *xdisplay;
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
    gint    x0, y0, width, height, x, y, w, h;
    gint    i, j, k, l;
    gint    actions = d->actions;

    xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());

    /* Get the geometry of the client */
    wnck_window_get_client_window_geometry (win, &x0, &y0, &width, &height);

    /* Shaded windows have no height - also skip some event windows */
    if (d->state & WNCK_WINDOW_STATE_SHADED)
    {
	height = 0;
	k = l = 1;
    }
    else
    {
	k = 0;
	l = 2;
    }

    gdk_error_trap_push ();

    /* [rtl, ru, rtr], [rl, mv, rr], [rbl, rb, rbr] */
    for (i = 0; i < 3; ++i)
    {
	static guint event_window_actions[3][3] = {
	    {
		WNCK_WINDOW_ACTION_RESIZE,
		WNCK_WINDOW_ACTION_RESIZE,
		WNCK_WINDOW_ACTION_RESIZE
	    }, {
		WNCK_WINDOW_ACTION_RESIZE,
		WNCK_WINDOW_ACTION_MOVE,
		WNCK_WINDOW_ACTION_RESIZE
	    }, {
		WNCK_WINDOW_ACTION_RESIZE,
		WNCK_WINDOW_ACTION_RESIZE,
		WNCK_WINDOW_ACTION_RESIZE
	    }
	};

	for (j = 0; j < 3; ++j)
	{
	    w = 0;
	    h = 0;

	    if (actions & event_window_actions[i][j] && i >= k && i <= l)
		(*theme_get_event_window_position) (d, i, j, width, height,
						    &x, &y, &w, &h);

	    /* Reparenting mode - create boxes which we monitor motionnotify on */
	    if (d->frame_window)
	    {
		BoxPtr box = &d->event_windows[i][j].pos;
		box->x1  = x;
		box->x2 = x + w;
		box->y1 = y;
		box->y2 = y + h;
	    }
	    /* Pixmap mode with window geometry - create small event windows */
	    else if (!d->frame_window && w != 0 && h != 0)
	    {
		XMapWindow (xdisplay, d->event_windows[i][j].window);
		XMoveResizeWindow (xdisplay, d->event_windows[i][j].window,
				   x, y, w, h);
	    }
	    /* No parent and no geometry - unmap all event windows */
	    else if (!d->frame_window)
	    {
		XUnmapWindow (xdisplay, d->event_windows[i][j].window);
	    }
	}
    }

    /* no button event windows if width is less than minimum width */
    if (width < ICON_SPACE + d->button_width)
	actions = 0;

    /* Above, stick, unshade and unstick are only available in wnck => 2.18.1 */
    for (i = 0; i < BUTTON_NUM; ++i)
    {
	static guint button_actions[BUTTON_NUM] = {
	    WNCK_WINDOW_ACTION_CLOSE,
	    WNCK_WINDOW_ACTION_MAXIMIZE,
	    WNCK_WINDOW_ACTION_MINIMIZE,
	    0,
	    WNCK_WINDOW_ACTION_SHADE,

#ifdef HAVE_LIBWNCK_2_18_1
	    WNCK_WINDOW_ACTION_ABOVE,
	    WNCK_WINDOW_ACTION_STICK,
	    WNCK_WINDOW_ACTION_UNSHADE,
	    WNCK_WINDOW_ACTION_ABOVE,
	    WNCK_WINDOW_ACTION_UNSTICK
#else
	    0,
	    0,
	    0,
	    0,
	    0
#endif

	};

	/* Reparenting mode - if a box was set and we no longer need it reset its geometry */
	if (d->frame_window &&
	    button_actions[i] && !(actions & button_actions[i]))
	{
	    memset (&d->button_windows[i].pos, 0, sizeof (Box));
	}
	/* Pixmap mode - if a box was set and we no longer need it unmap its window */
	else if (!d->frame_window &&
		 button_actions[i] && !(actions & button_actions[i]))
	{
	    XUnmapWindow (xdisplay, d->button_windows[i].window);
	    continue;
	}

	/* Reparenting mode - if there is a button position for this
	 * button then set the geometry */
	if (d->frame_window &&
	    (*theme_get_button_position) (d, i, width, height, &x, &y, &w, &h))
	{
	    BoxPtr box = &d->button_windows[i].pos;
	    box->x1 = x;
	    box->y1 = y;
	    box->x2 = x + w;
	    box->y2 = y + h;
	}
	/* Pixmap mode - if there is a button position for this button then map the window
	 * and resize it to this position */
	else if (!d->frame_window &&
		 (*theme_get_button_position) (d, i, width, height,
					       &x, &y, &w, &h))
	{
	    Window win = d->button_windows[i].window;
	    XMapWindow (xdisplay, win);
	    XMoveResizeWindow (xdisplay, win, x, y, w, h);
	}
	else if (!d->frame_window)
	{
	    XUnmapWindow (xdisplay, d->button_windows[i].window);
	}
    }

    gdk_display_sync (gdk_display_get_default ());
    gdk_error_trap_pop ();
}
Пример #9
0
void
nsScreenGtk :: Init (GdkWindow *aRootWindow)
{
  gint scale = nsScreenGtk::GetGtkMonitorScaleFactor();
  gint width = gdk_screen_width()*scale;
  gint height = gdk_screen_height()*scale;

  // We listen for configure events on the root window to pick up
  // changes to this rect.  We could listen for "size_changed" signals
  // on the default screen to do this, except that doesn't work with
  // versions of GDK predating the GdkScreen object.  See bug 256646.
  mAvailRect = mRect = nsIntRect(0, 0, width, height);

#ifdef MOZ_X11
  // We need to account for the taskbar, etc in the available rect.
  // See http://freedesktop.org/Standards/wm-spec/index.html#id2767771

  // XXX do we care about _NET_WM_STRUT_PARTIAL?  That will
  // add much more complexity to the code here (our screen
  // could have a non-rectangular shape), but should
  // lead to greater accuracy.

  long *workareas;
  GdkAtom type_returned;
  int format_returned;
  int length_returned;

  GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL);

  gdk_error_trap_push();

  // gdk_property_get uses (length + 3) / 4, hence G_MAXLONG - 3 here.
  if (!gdk_property_get(aRootWindow,
                        gdk_atom_intern ("_NET_WORKAREA", FALSE),
                        cardinal_atom,
                        0, G_MAXLONG - 3, FALSE,
                        &type_returned,
                        &format_returned,
                        &length_returned,
                        (guchar **) &workareas)) {
    // This window manager doesn't support the freedesktop standard.
    // Nothing we can do about it, so assume full screen size.
    return;
  }

  // Flush the X queue to catch errors now.
  gdk_flush();

  if (!gdk_error_trap_pop() &&
      type_returned == cardinal_atom &&
      length_returned && (length_returned % 4) == 0 &&
      format_returned == 32) {
    int num_items = length_returned / sizeof(long);

    for (int i = 0; i < num_items; i += 4) {
      nsIntRect workarea(workareas[i],     workareas[i + 1],
                         workareas[i + 2], workareas[i + 3]);
      if (!mRect.Contains(workarea)) {
        // Note that we hit this when processing screen size changes,
        // since we'll get the configure event before the toolbars have
        // been moved.  We'll end up cleaning this up when we get the
        // change notification to the _NET_WORKAREA property.  However,
        // we still want to listen to both, so we'll handle changes
        // properly for desktop environments that don't set the
        // _NET_WORKAREA property.
        NS_WARNING("Invalid bounds");
        continue;
      }

      mAvailRect.IntersectRect(mAvailRect, workarea);
    }
  }
  g_free (workareas);
#endif
}
Пример #10
0
guint
egg_tray_icon_send_message (EggTrayIcon *icon,
			    gint         timeout,
			    const gchar *message,
			    gint         len)
{
  guint stamp;

  g_return_val_if_fail (EGG_IS_TRAY_ICON (icon), 0);
  g_return_val_if_fail (timeout >= 0, 0);
  g_return_val_if_fail (message != NULL, 0);

#ifdef GDK_WINDOWING_X11
  if (icon->manager_window == None)
    return 0;
#endif

  if (len < 0)
    len = strlen (message);

  stamp = icon->stamp++;

#ifdef GDK_WINDOWING_X11
  /* Get ready to send the message */
  egg_tray_icon_send_manager_message (icon, SYSTEM_TRAY_BEGIN_MESSAGE,
				      icon->manager_window,
				      timeout, len, stamp);

  /* Now to send the actual message */
  gdk_error_trap_push ();
  while (len > 0)
    {
      XClientMessageEvent ev;
      Display *xdisplay;

      xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (GTK_WIDGET (icon)));

      ev.type = ClientMessage;
      ev.window = icon->manager_window;
      ev.format = 8;
      ev.message_type = XInternAtom (xdisplay,
				     "_NET_SYSTEM_TRAY_MESSAGE_DATA", False);
      if (len > 20)
	{
	  memcpy (&ev.data, message, 20);
	  len -= 20;
	  message += 20;
	}
      else
	{
	  memcpy (&ev.data, message, len);
	  len = 0;
	}

      XSendEvent (xdisplay,
		  icon->manager_window, False, StructureNotifyMask, (XEvent *)&ev);
      XSync (xdisplay, False);
    }
  gdk_error_trap_pop ();
#endif

  return stamp;
}
Пример #11
0
static void
activate_window(Display *display, Window window)
{
    Window toplevel = window;
    Atom window_state_atom = gdk_x11_get_xatom_by_name("WM_STATE");
    Atom active_window_atom = gdk_x11_get_xatom_by_name("_NET_ACTIVE_WINDOW");
    Window root;
    XEvent xev;
    
    /* The window_id we have is the window ID of a child window. So, we first
     * need to walk up the window hierarachy until we find the WM_STATE window,
     * then activate that window. Lots of X roundtrips here, but we only do
     * this on a user click as an alternative to launching a new firefox 
     * process, so it doesn't really matter.
     */
    gdk_error_trap_push();

    while (TRUE) {
        Window parent;
        Window *children;
        guint n_children;
        
        Atom type;
        int format;
        gulong n_items;
        gulong bytes_after;
        guchar *data;

        if (!XQueryTree(display, toplevel, &root, &parent, &children, &n_children)) {
            g_debug("XQueryTree failed\n");
            goto out;
        }

        XFree(children);

        if (root == parent) /* No window manager or non-reparenting window manager */
            break;
        
        if (XGetWindowProperty(display, toplevel, window_state_atom,
                               0, G_MAXLONG, False, AnyPropertyType,
                               &type, &format, &n_items, &bytes_after, &data) != Success) {
            g_debug("XGetWindowProperty failed\n");
            goto out;
        }
        
        if (type != None) { /* Found the real client toplevel */
            XFree(data);
            break;
        }

        toplevel = parent;
    }

    xev.xclient.type = ClientMessage;
    xev.xclient.window = toplevel;
    xev.xclient.message_type = active_window_atom;
    xev.xclient.format = 32;
    xev.xclient.data.l[0] = 2; /* We're sort of like a pager ... we're activating a window
                                * from a different app as a response to direct user action
                                */
    xev.xclient.data.l[1] = gtk_get_current_event_time();
    xev.xclient.data.l[2] = None; /* We don't really have an active toplevel */
    xev.xclient.data.l[3] = 0;
    xev.xclient.data.l[4] = 0;

    XSendEvent(display, root, False, SubstructureNotifyMask | SubstructureRedirectMask, &xev);

 out:
    gdk_error_trap_pop();
}
Пример #12
0
/* Doesn't handle HIPPO_WINDOW_STATE_ACTIVE - see comment below */
static HippoWindowState
get_window_state(Display *display, Window window)
{
    HippoWindowState result =  HIPPO_WINDOW_STATE_HIDDEN;
    XWindowAttributes window_attributes;
    GdkRectangle rect;
    GdkRegion *visible_region = NULL;
    Window child = None;
    
    Window root;
    Window parent;
    Window *children = NULL;
    guint n_children;

    gdk_error_trap_push();
    
    /* First check if the window and all ancestors are mapped
     */

    if (!XGetWindowAttributes(display, window, &window_attributes)) {
        g_debug("XGetWindowAttributes failed\n");
        goto out;
    }

    if (window_attributes.map_state != IsViewable)
        goto out;

    /* Get the area of the window in parent coordinates
     */
    rect.x = window_attributes.x;
    rect.y = window_attributes.y;
    rect.width = window_attributes.width;
    rect.height = window_attributes.height;

    visible_region = gdk_region_rectangle(&rect);

    if (!XQueryTree(display, window, &root, &parent, &children, &n_children)) {
        g_debug("XQueryTree failed\n");
        goto out;
    }

    XFree(children);
    children = NULL;

    child = window;
    window = parent;

    /* Walk up the hierarchy, clipping to parents, and subtracting
     * overlayed siblings (yuck!)
     */
    while (TRUE) {
        GdkRegion *parent_region;
        gboolean seen_child = FALSE;
        int x, y;
        unsigned int width, height, border, depth;
        unsigned int i;

        gdk_region_get_clipbox(visible_region, &rect);
        
        /* Clip to parent */
        if (!XGetGeometry(display, window, &root, &x, &y, &width, &height, &border, &depth)) {
            g_debug("XGetGeometry failed\n");
            goto out;
        }

        rect.x = 0;
        rect.y = 0;
        rect.width = width;
        rect.height= height;

        parent_region = gdk_region_rectangle(&rect);
        gdk_region_intersect(visible_region, parent_region);
        gdk_region_destroy(parent_region);

        if (gdk_region_empty(visible_region))
            goto out;
                
        if (!XQueryTree(display, window, &root, &parent, &children, &n_children)) {
            g_debug("XQueryTree failed\n");
            goto out;
        }

        for (i = 0; i < n_children; i++) {
            if (seen_child) {
                /* A sibling above */
                GdkRegion *child_region;
                XWindowAttributes child_attributes;
                
                if (!XGetWindowAttributes(display, children[i], &child_attributes)) {
                    g_debug("XGetWindowAttributes failed for child\n");
                    goto out;
                }

                if (child_attributes.map_state == IsViewable) {
                    rect.x = child_attributes.x - child_attributes.border_width;
                    rect.y = child_attributes.y - child_attributes.border_width;
                    rect.width = child_attributes.width + 2 * child_attributes.border_width;
                    rect.height = child_attributes.height + 2 * child_attributes.border_width;

                    child_region = gdk_region_rectangle(&rect);
                    gdk_region_subtract(visible_region, child_region);
                    gdk_region_destroy(child_region);
                    
                    if (gdk_region_empty(visible_region))
                        goto out;
                }
                
            } else if (children[i] == child) {
                seen_child = TRUE;
            }
        }
    
        XFree(children);
        children = NULL;

        if (window == root)
            break;
        
        child = window;
        window = parent;

        /* Translate to parent coordinates */
        gdk_region_offset(visible_region, x, y);
    }

    if (!gdk_region_empty(visible_region))
        result = HIPPO_WINDOW_STATE_ONSCREEN;

 out:
    gdk_error_trap_pop();

    if (children)
        XFree(children);

    if (visible_region)
        gdk_region_destroy(visible_region);

    return result;
}