[sawfish] Acquire the manager selection.



commit 5390d95a6e010b154944d05d55652b26a0844d0d
Author: Timo Korvola <tkorvola iki fi>
Date:   Wed Sep 9 23:13:54 2009 +0300

    Acquire the manager selection.
    
    No selection request handling yet.

 src/display.c       |  107 ++++++++++++++++++++++++++++++++++++++++++++-------
 src/events.c        |    4 +-
 src/sawfish.h       |    3 +
 src/sawfish_subrs.h |    3 +-
 4 files changed, 100 insertions(+), 17 deletions(-)
---
diff --git a/src/display.c b/src/display.c
index b9c47fc..ebc2bd8 100644
--- a/src/display.c
+++ b/src/display.c
@@ -55,8 +55,8 @@ int preferred_depth;
 
 /* some atoms that may be useful.. */
 Atom xa_wm_state, xa_wm_change_state, xa_wm_protocols, xa_wm_delete_window,
-  xa_wm_colormap_windows, xa_wm_take_focus, xa_compound_text,
-  xa_wm_net_name, xa_wm_net_icon_name, xa_utf8_string;
+    xa_wm_colormap_windows, xa_wm_take_focus, xa_compound_text,
+    xa_wm_net_name, xa_wm_net_icon_name, xa_utf8_string, xa_manager, xa_wm_sn;
 
 DEFSYM(display_name, "display-name");
 DEFSYM(canonical_display_name, "canonical-display-name");
@@ -113,6 +113,14 @@ error_other_wm (Display *dpy, XErrorEvent *ev)
 }
 
 
+static void
+replace_race_error
+{
+    fputs ("It is getting kind of crowded here.\n", strerr);
+    exit (1);
+}
+
+
 static char *
 canonical_host (char *host)
 {
@@ -279,6 +287,57 @@ choose_visual (void)
     }
 }
 
+
+/* Acquire the manager selection, replacing its previous owner if any. */
+static void
+acquire_manager_selection(Window sel_owner)
+{
+    Time time = get_server_timestamp();
+    XClientMessageEvent cm;
+    if (sel_owner != None)
+    {
+        Window sel2;
+        XSelectInput (dpy, sel_owner, StructureNotifyMask);
+        sel2 = XGetSelectionOwner (dpy, xa_wm_sn);
+        if (sel2 == None)
+        {
+            /* Gone already! */
+            XSelectInput (dpy, sel_owner, 0);
+            sel_owner = None;
+        }
+        else if (sel2 != sel_owner)
+            /* Somebody else has taken over, so we quit. */
+            replace_race_error ();
+    }
+    XSetSelectionOwner (dpy, xa_wm_sn, no_focus_window, time);
+    if (XGetSelectionOwner (dpy, xa_wm_sn) != no_focus_window)
+    {
+        fputs ("Could not acquire manager selection.\n", strerr);
+        exit (1);
+    }
+    if (sel_owner != None)
+    {
+        fputs ("Waiting for the previous manager to go away.\n", strerr);
+        for (;;)
+        {
+            XEvent ev;
+            XWindowEvent (dpy,  sel_owner, StructureNotifyMask,
+                          &ev);
+            if (ev.type == DestroyNotify
+                && ev.xdestroywindow.window == sel_owner)
+                break;
+            fputs ("Wrong event!  Still waiting.\n", strerr);
+        }
+    }
+    cm.message_type = xa_manager;
+    cm.format = 32;
+    cm.data.l[0] = time;
+    cm.data.l[1] = xa_wm_sn;
+    cm.data.l[2] = no_focus_window;
+    XSendEvent (dpy, root_window, False, StructureNotifyMask, &cm);
+}
+
+
 /* Called from main(). */
 bool
 sys_init(char *program_name)
@@ -315,6 +374,7 @@ sys_init(char *program_name)
 	dpy = XOpenDisplay(display_name);
 	if(dpy != 0)
 	{
+            Window sel_owner;
 	    Fset (Qdisplay_name, rep_string_dup (display_name));
 	    Fset (Qcanonical_display_name,
 		  rep_string_dup (canonical_display (display_name)));
@@ -325,37 +385,49 @@ sys_init(char *program_name)
 	    screen_height = DisplayHeight(dpy, screen_num);
 	    choose_visual ();
 
+            {
+                char buf[50];
+                snprintf (buf, sizeof buf, "WM_S%d", screen_num);
+                xa_wm_sn = XInternAtom (dpy, buf, False);
+            }
 	    xa_wm_state = XInternAtom (dpy, "WM_STATE", False);
 	    xa_wm_change_state = XInternAtom (dpy, "WM_CHANGE_STATE", False);
 	    xa_wm_protocols = XInternAtom (dpy, "WM_PROTOCOLS", False);
 	    xa_wm_delete_window = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
-	    xa_wm_colormap_windows = XInternAtom (dpy, "WM_COLORMAP_WINDOWS", False);
+	    xa_wm_colormap_windows = XInternAtom (dpy, "WM_COLORMAP_WINDOWS",
+                                                  False);
 	    xa_wm_take_focus = XInternAtom (dpy, "WM_TAKE_FOCUS", False);
 	    xa_compound_text = XInternAtom (dpy, "COMPOUND_TEXT", False);
 	    xa_wm_net_name = XInternAtom (dpy, "_NET_WM_NAME", False);
-	    xa_wm_net_icon_name = XInternAtom (dpy, "_NET_WM_ICON_NAME", False);
+	    xa_wm_net_icon_name = XInternAtom (dpy, "_NET_WM_ICON_NAME",
+                                               False);
 	    xa_utf8_string = XInternAtom (dpy, "UTF8_STRING", False);
+            xa_manager = XInternAtom (dpy, "MANAGER", False);
+
+            sel_owner = XGetSelectionOwner (dpy, xa_wm_sn);
+            if (sel_owner != None && !rep_get_option ("--replace", 0))
+            {
+                fputs ("A window manager is already running but "
+                       "--replace was not given.\n", stderr);
+                exit (1);
+            }
 
 	    if (!XShapeQueryExtension (dpy, &shape_event_base,
 				       &shape_error_base))
 	    {
-		fprintf (stderr, "sawfish: your X server doesn't suppot the SHAPE extension; aborting\n");
+		fprintf (stderr, "sawfish: your X server doesn't support "
+                         "the SHAPE extension; aborting\n");
 		return FALSE;
 	    }
 
 	    /* Error handler is used to prevent from two Sawfish running.
 	     * (Not sure for other WMs.) */
-	    XSetErrorHandler (error_other_wm);
-	    XSelectInput (dpy, root_window, ROOT_EVENTS);
-	    XSync (dpy, False);
-	    XSetErrorHandler (error_handler);
-
 	    {
-		/* Create the mapped-but-invisible window that is given
-		   the focus when no other window has it. */
+                /* Create the mapped-but-invisible window that is given
+		   the focus when no other window has it.  The window
+                   is also used for selection manipulation. */
 		XSetWindowAttributes attr;
-		/* this value is assumed in events.c:get_server_timestamp */
-		attr.event_mask = KeyPressMask;
+		attr.event_mask = NO_FOCUS_EVENTS;
 		attr.override_redirect = True;
 		no_focus_window = XCreateWindow (dpy, root_window,
 						 -10, -10, 10, 10, 0, 0,
@@ -366,6 +438,13 @@ sys_init(char *program_name)
 		XMapWindow (dpy, no_focus_window);
 	    }
 
+            acquire_manager_selection (sel_owner);
+
+	    XSetErrorHandler (error_other_wm);
+	    XSelectInput (dpy, root_window, ROOT_EVENTS);
+	    XSync (dpy, False);
+	    XSetErrorHandler (error_handler);
+
 	    /* This should _never_ be used in Real Life; only for
 	       debugging. Sawfish tries to work out when the error
 	       handle might be called (i.e. after any XGet, XQuery, XFetch
diff --git a/src/events.c b/src/events.c
index 9b6a1db..a1943df 100644
--- a/src/events.c
+++ b/src/events.c
@@ -1368,10 +1368,10 @@ get_server_timestamp (void)
 
     /* XXX There must be an easier method.. */
     while (XCheckWindowEvent (dpy, w, PropertyChangeMask, &ev)) ;
-    XSelectInput (dpy, w, PropertyChangeMask | KeyPressMask);
+    XSelectInput (dpy, w, PropertyChangeMask | NO_FOCUS_EVENTS);
     XChangeProperty (dpy, w, xa_sawfish_timestamp,
 		     XA_STRING, 8, PropModeReplace, (unsigned char *)"foo", 3);
-    XSelectInput (dpy, w, KeyPressMask);
+    XSelectInput (dpy, w, NO_FOCUS_EVENTS);
     XWindowEvent (dpy, w, PropertyChangeMask, &ev);
 
     return ev.xproperty.time;
diff --git a/src/sawfish.h b/src/sawfish.h
index 6ce231e..b11228c 100644
--- a/src/sawfish.h
+++ b/src/sawfish.h
@@ -92,6 +92,9 @@ typedef int bool;
 #define POINTER_GRAB_EVENTS (ButtonPressMask | ButtonReleaseMask \
 			     | PointerMotionMask | PointerMotionHintMask)
 
+/* Events selected on the invisible no_focus_window */
+#define NO_FOCUS_EVENTS (KeyPressMask | StructureNotifyMask)
+
 /* Type defs */
 
 /* A managed window */
diff --git a/src/sawfish_subrs.h b/src/sawfish_subrs.h
index 33c5c32..c09a9cc 100644
--- a/src/sawfish_subrs.h
+++ b/src/sawfish_subrs.h
@@ -57,7 +57,8 @@ extern Visual *preferred_visual;
 extern Window root_window, no_focus_window;
 extern Atom xa_wm_state, xa_wm_change_state, xa_wm_protocols,
     xa_wm_delete_window, xa_wm_colormap_windows, xa_wm_take_focus,
-  xa_compound_text, xa_wm_net_name, xa_wm_net_icon_name, xa_utf8_string;
+    xa_compound_text, xa_wm_net_name, xa_wm_net_icon_name, xa_utf8_string,
+    xa_manager, xa_wm_sn;
 extern int shape_event_base, shape_error_base;
 extern repv Qdisplay_name, Qcanonical_display_name;
 extern bool sys_init (char *program_name);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]