Browse all patches

Author Edit

Timo Korvola

Synopsis Edit

Fixes things to work better with the Composite extension.

Adds new functions window-obscured and stacking-visibility, which compute window visibility from the stacking order and do not rely on VisibilityNotify events. Modifies raise-lower and grow-pack to use these functions instead of window-visibility. VisibilityEvents appear unreliable when Composite is in use: every window is reported unobscured by window-visibility.

This patch is also available via Git from branch stacking-visibility at and you should pull it from there because Wiki may have messed with the formatting here.

Patch testing Edit

  1. Copy/paste the patch listed below into some file, eg. TEST.diff.
  2. If you don't have sawfish sources yet, have one, as described get it from GIT repo.
  3. Go into the directory where sawfish sources reside, eg. cd sawfish
  4. Test if the patch applies cleanly with this command:
    patch -p1 --ignore-whitespace --dry-run < TEST.diff
    in case of problems try also: -p0 or -p2
  5. If it applies cleanly, then remove the --dry-run from above command and run it again, otherwise ask on the mailing list.
  6. Compile sawfish: ./ && make
  7. Install it for testing, but it depends on your linux distribution.
    1. It is always better to install sawfish as your distribution package, but it is different for each distribution.
    2. So you may try make install, which will install sawifish in /usr/local/share/sawfish/ (if you have write access). But then make sure that you run the correct version and delete it from that directory afterwards, to avoid any conflicts.
  8. Se also

PS: edit this template if you feel that those instructions can be improved.

Patch Edit

diff --git a/lisp/sawfish/wm/commands/grow-pack.jl b/lisp/sawfish/wm/commands/gr
index 7501bda..0749c7c 100644
--- a/lisp/sawfish/wm/commands/grow-pack.jl
+++ b/lisp/sawfish/wm/commands/grow-pack.jl
@@ -54,6 +54,7 @@
+         sawfish.wm.stacking
   (define-structure-alias grow-pack sawfish.wm.commands.grow-pack)
@@ -214,7 +215,7 @@ See `pack-window-up'."
                            (window-avoided-p x)
                          (eq grow-pack-bump-other-depth 'always))))
                  (or grow-pack-bump-obscured
-                     (not (eq (window-visibility x) 'fully-obscured)))
+                     (not (eq (stacking-visibility x) 'fully-obscured)))
                  (or grow-pack-bump-ignored
                      (not (window-ignored-p x)))
                  (setq xa (window-position x)
diff --git a/lisp/sawfish/wm/stacking.jl b/lisp/sawfish/wm/stacking.jl
index 42d08fd..403eebb 100644
--- a/lisp/sawfish/wm/stacking.jl
+++ b/lisp/sawfish/wm/stacking.jl
@@ -23,6 +23,8 @@
     (export save-stacking-order
+            window-obscured
+            stacking-visibility
@@ -46,7 +48,8 @@
-         sawfish.wm.state.transient)
+         sawfish.wm.state.transient
+          sawfish.wm.util.rects)
   ;; Each window will have a `depth' property--an integer, zero
   ;; represents the level of normal windows, negative for windows below
@@ -208,6 +211,53 @@ the empty list."
   (define (mapped-stacking-order)
     (delete-if-not window-mapped-p (stacking-order)))
+  (define (window-obscured window)
+    "Check whether WINDOW is obscured.  Return `t' if WINDOW is fully obscured
+by some other window, otherwise a list of windows partially obscuring WINDOW.
+In particular return `nil' if WINDOW is unobscured.  Note that if a list of
+partially obscuring windows is returned, taken together they may or may not
+fully obscure WINDOW."
+    (define w window)
+    (define ws (nearest-workspace-with-window w current-workspace))
+    (let loop ((stack (stacking-order))
+               (obs nil))
+         (if (null stack)               ; Should not happen
+             obs
+           (let ((w2 (car stack)))
+             (cond ((eq w2 w) obs)
+                   ((and (window-visible-p w2)
+                         (window-appears-in-workspace-p w2 ws))
+                    (case (apply rect-obscured
+                                 (rectangles-from-windows (list w w2)))
+                      ((unobscured) (loop (cdr stack) obs))
+                      ((fully-obscured) t)
+                      (t (loop (cdr stack) (cons w2 obs))))) ; Partially
+                   (t (loop (cdr stack) obs)))))))
+  (define (stacking-visibility window)
+    "Compute the visibility of WINDOW from the stacking order.  This should
+work even with the Composite extension, which appears to disable
+VisibilityNotify events.  Note that deciding between fully and partially
+obscured may require quite a bit of computation.  If you do not need that
+distinction, window-obscured should be faster."
+    (define (rect-list-minus rs s tail)
+      (if (null rs)
+          tail
+        (rect-list-minus (cdr rs) s
+                         (rect-minus (car rs) s tail))))
+    (let ((obs (window-obscured window)))
+      (case obs
+        ((t) 'fully-obscured)
+        ((()) 'unobscured)
+        (t
+         (do ((unobs (rectangles-from-windows (list window))
+                     (rect-list-minus unobs (car robs) nil))
+              (robs (rectangles-from-windows obs) (cdr robs)))
+             ((or (null unobs) (null robs))
+              (if (null unobs)
+                  'fully-obscured
+                'partially-obscured)))))))
 ;;; stacking functions
@@ -340,7 +390,7 @@ order they are stacked within the layer (top to bottom)."
   (define (raise-lower-window w)
     "If the window is at its highest possible position, then lower it to its
 lowest possible position. Otherwise raise it as far as allowed."
-    (if (or (eq (window-visibility w) 'unobscured)
+    (if (or (not (window-obscured w))
            (window-on-top-p w))
        (lower-window w)
       (raise-window w)))
@@ -424,7 +474,7 @@ lowest possible position. Otherwise raise it as far as allow
          (loop (delq lowest rest) (cons lowest out))))))
   (define (raise-lower-windows w order)
-    (if (or (eq (window-visibility w) 'unobscured)
+    (if (or (not (window-obscured w))
            (and (window-on-top-p (car order))
                 ;; look for the group as a block.. this is a heuristic
                 (let loop ((rest (memq (car order) (stacking-order))))
diff --git a/lisp/sawfish/wm/util/rects.jl b/lisp/sawfish/wm/util/rects.jl
index eebb326..d4b0ba1 100644
--- a/lisp/sawfish/wm/util/rects.jl
+++ b/lisp/sawfish/wm/util/rects.jl
@@ -21,7 +21,9 @@
 (define-structure sawfish.wm.util.rects
-    (export rectangles-from-grid
+    (export rect-left rect-top rect-right rect-bottom
+            rect-obscured rect-minus
+            rectangles-from-grid
@@ -47,10 +49,75 @@
   ;; Commentary:
   ;; A rectangle is (LEFT TOP RIGHT BOTTOM [WEIGHT])
+  ;; The left and top edges are considered part of the rectangle,
+  ;; the right and bottom edges are not.
 ;;; rectangles
+  (define rect-left car)
+  (define rect-top cadr)
+  (define rect-right caddr)
+  (define rect-bottom cadddr)
+  (define (rect-obscured r by)
+    "Check whether rectangle R is wholly or partially contained in
+rectangle BY.  Return `unobscured', `partially-obscured' or `fully-obscured'."
+    (cond ((or (<= (rect-right by) (rect-left r))
+               (<= (rect-right r) (rect-left by))
+               (<= (rect-bottom by) (rect-top r))
+               (<= (rect-bottom r) (rect-top by)))
+           'unobscured)
+          ((and (<= (rect-left by) (rect-left r))
+                (<= (rect-right r) (rect-right by))
+                (<= (rect-top by) (rect-top r))
+                (<= (rect-bottom r) (rect-bottom by)))
+           'fully-obscured)
+          (t 'partially-obscured)))
+  (define (rect-minus r s #!optional tail)
+    "Return a list of disjoint rectangles whose union is the part of
+rectangle R not contained in rectangle S.  If TAIL is given, the
+result is prepended to it."
+    (let rminus ((r r) (result tail))
+         (cond
+          ;; Check for complete disjointness.
+          ((or (<= (rect-right s) (rect-left r))
+               (<= (rect-right r) (rect-left s))
+               (<= (rect-bottom s) (rect-top r))
+               (<= (rect-bottom r) (rect-top s)))
+           (cons r result))
+          ;; Extract a free slice from the bottom of r.
+          ((< (rect-bottom s) (rect-bottom r))
+           (rminus (list (rect-left r) (rect-top r)
+                         (rect-right r) (rect-bottom s))
+                   (cons (list (rect-left r) (rect-bottom s)
+                               (rect-right r) (rect-bottom r))
+                         result)))
+          ;; Extract a free slice from the right side of r.
+          ((< (rect-right s) (rect-right r))
+           (rminus (list (rect-left r) (rect-top r)
+                         (rect-right s) (rect-bottom r))
+                   (cons (list (rect-right s) (rect-top r)
+                               (rect-right r) (rect-bottom r))
+                         result)))
+          ;; Extract a free slice from the top of r.
+          ((> (rect-top s) (rect-top r))
+           (rminus (list (rect-left r) (rect-top s)
+                         (rect-right r) (rect-bottom r))
+                   (cons (list (rect-left r) (rect-top r)
+                               (rect-right r) (rect-top s))
+                         result)))
+          ;; Extract a free slice from the left side of r.
+          ((> (rect-left s) (rect-left r))
+           (rminus (list (rect-left s) (rect-top r)
+                         (rect-right r) (rect-bottom r))
+                   (cons (list (rect-left r) (rect-top r)
+                               (rect-left s) (rect-bottom r))
+                         result)))
+          ;; Completely covered.
+          (t result))))
   (define (rectangles-from-grid x-points y-points #!optional pred)
     "The two lists of integers X-POINTS and Y-POINTS define a rectangular
 grid. Return the complete list of rectangles formed by the

Community's reasons for inclusion or rejection Edit

Patch submitters, please vote also! Yes, obviosuly your vote will be positive, but it's the place to give your explanation why this patch is good for all Sawfish users, and why it is correct - good reasons for inclusion.

When voting anonymously please write your name, so that it can be associated with your posts on the mailing list. If you are logged in you can sign yourself by typing four tilda characters: ~~~~.

  • Yes vote: yes. - This turned out to be more difficult than I thought. The unobscured case is fine and suffices for raise-lower, but grow-pack needs to distinguish between partially and fully obscured windows. That is tricky: a window may be fully obscured by a set of windows without being fully obscured by any single window. stacking-visibility now checks for that. window-obscured is faster if you only need to check whether a window is at all obscured. Tkorvola 07:21, 29 August 2008 (UTC)
  • Yes vote: yes. This patch works really great now. I tested also with grop-pack and shrink-yank. Applied. Janek Kozicki 11:57, 29 August 2008 (UTC)

Ad blocker interference detected!

Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.