/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */ /* Copyright (C) 1998 Redhat Software Inc. * Code available under the Gnu GPL. * Authors: Owen Taylor */ #include #include #include #include "wm-properties.h" typedef struct _RestartInfo RestartInfo; struct _RestartInfo { GnomeDesktopItem *dentry; gint retries; WMResultFunc callback; gpointer data; }; gboolean wm_is_running (void) { gboolean result; XWindowAttributes attrs; gdk_error_trap_push (); XGetWindowAttributes (GDK_DISPLAY(), GDK_ROOT_WINDOW(), &attrs); XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), SubstructureRedirectMask); XSync (GDK_DISPLAY(), False); if (gdk_error_trap_pop () == 0) { result = FALSE; XSelectInput (GDK_DISPLAY(), GDK_ROOT_WINDOW(), attrs.your_event_mask); } else result = TRUE; return result; } /* Cut and paste from gnome-libs/gnome_win_hints_wm_exists, except that we * return the xid instead of a window */ static Window find_gnome_wm_window(void) { Atom r_type; int r_format; unsigned long count; unsigned long bytes_remain; unsigned char *prop, *prop2; GdkAtom cardinal_atom = gdk_atom_intern ("CARDINAL", FALSE); gdk_error_trap_push (); if (XGetWindowProperty(GDK_DISPLAY(), GDK_ROOT_WINDOW(), gdk_x11_atom_to_xatom (gdk_atom_intern ("_WIN_SUPPORTING_WM_CHECK", FALSE)), 0, 1, False, gdk_x11_atom_to_xatom (cardinal_atom), &r_type, &r_format, &count, &bytes_remain, &prop) == Success && prop) { if (r_type == gdk_x11_atom_to_xatom (cardinal_atom) && r_format == 32 && count == 1) { Window n = *(long *)prop; if (XGetWindowProperty(GDK_DISPLAY(), n, gdk_x11_atom_to_xatom (gdk_atom_intern ("_WIN_SUPPORTING_WM_CHECK", FALSE)), 0, 1, False, gdk_x11_atom_to_xatom (cardinal_atom), &r_type, &r_format, &count, &bytes_remain, &prop2) == Success && prop) { if (r_type == gdk_x11_atom_to_xatom (cardinal_atom) && r_format == 32 && count == 1) { XFree(prop); XFree(prop2); gdk_error_trap_pop (); return n; } XFree(prop2); } } XFree(prop); } gdk_error_trap_pop (); return None; } static Window find_wm_window_from_client (GdkWindow *client) { Window window, frame, parent, root; Window *children; unsigned int nchildren; gboolean needs_pop = TRUE; if (!client) return None; frame = None; window = GDK_WINDOW_XWINDOW (client); gdk_error_trap_push (); while (XQueryTree (GDK_DISPLAY(), window, &root, &parent, &children, &nchildren)) { if (gdk_error_trap_pop != 0) { needs_pop = FALSE; break; } gdk_error_trap_push (); if (children) XFree(children); if (window == root) break; if (root == parent) { frame = window; break; } window = parent; } if (needs_pop) gdk_error_trap_pop (); return frame; } static gboolean window_has_wm_state (Window window) { Atom r_type; int r_format; unsigned long count; unsigned long bytes_remain; unsigned char *prop; if (XGetWindowProperty(GDK_DISPLAY(), window, gdk_x11_atom_to_xatom (gdk_atom_intern ("WM_STATE", FALSE)), 0, 0, False, AnyPropertyType, &r_type, &r_format, &count, &bytes_remain, &prop) == Success) { if (r_type != None) { XFree(prop); return TRUE; } } return FALSE; } static gboolean descendent_has_wm_state (Window window) { gboolean result = FALSE; Window parent, root; Window *children; unsigned int nchildren; gint i; if (!XQueryTree (GDK_DISPLAY(), window, &root, &parent, &children, &nchildren)) return FALSE; for (i=0; icallback(WM_SUCCESS, info->data); gnome_desktop_item_unref (info->dentry); g_free (info); return FALSE; } else { info->retries--; if (info->retries > 0) return TRUE; else { info->callback(WM_CANT_START, info->data); gnome_desktop_item_unref (info->dentry); g_free (info); return FALSE; } } } static void start_do (RestartInfo *info) { gnome_desktop_item_launch (info->dentry, 0, 0, NULL); info->retries = 10; gtk_timeout_add (1000, start_timeout, info); } static gboolean kill_timeout (gpointer data) { RestartInfo *info = data; if (!wm_is_running ()) { start_do (info); return FALSE; } else { info->retries--; if (info->retries > 0) return TRUE; else { info->callback(WM_ALREADY_RUNNING, info->data); gnome_desktop_item_unref (info->dentry); g_free (info); return FALSE; } } } void wm_restart (WindowManager *new, GdkWindow *client, WMResultFunc callback, gpointer data) { Window wm_window; RestartInfo *info; g_return_if_fail (new->is_present); info = g_new (RestartInfo, 1); info->dentry = gnome_desktop_item_copy (new->dentry); info->callback = callback; info->data = data; info->retries = 10; if (wm_is_running ()) { wm_window = find_wm_window (client); if (!wm_window) { (*callback) (WM_ALREADY_RUNNING, data); gnome_desktop_item_unref (info->dentry); g_free (info); } else { XKillClient (GDK_DISPLAY(), wm_window); gtk_timeout_add (1000, kill_timeout, info); } } else { start_do (info); } } WindowManager * wm_guess_current (void) { return NULL; }