1 ;;; --------------------------------------------------------------------------
2 ;;; CLFSWM - FullScreen Window Manager
4 ;;; --------------------------------------------------------------------------
5 ;;; Documentation: Utility
6 ;;; --------------------------------------------------------------------------
8 ;;; (C) 2012 Philippe Brochard <pbrochard@common-lisp.net>
10 ;;; This program is free software; you can redistribute it and/or modify
11 ;;; it under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 3 of the License, or
13 ;;; (at your option) any later version.
15 ;;; This program is distributed in the hope that it will be useful,
16 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with this program; if not, write to the Free Software
22 ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 ;;; --------------------------------------------------------------------------
29 ;;; Configuration file
30 (defun xdg-config-home ()
31 (aif (getenv "XDG_CONFIG_HOME")
32 (pathname-directory (concatenate 'string it
"/"))
33 (append (pathname-directory (user-homedir-pathname)) '(".config"))))
36 (let ((saved-conf-name nil
))
37 (defun conf-file-name (&optional alternate-name
)
38 (unless (and saved-conf-name
(not alternate-name
))
39 (let* ((user-conf (probe-file (merge-pathnames (user-homedir-pathname) #p
".clfswmrc")))
40 (etc-conf (probe-file #p
"/etc/clfswmrc"))
41 (config-user-conf (probe-file (make-pathname :directory
(append (xdg-config-home) '("clfswm"))
43 (alternate-conf (and alternate-name
(probe-file alternate-name
))))
44 (setf saved-conf-name
(or alternate-conf config-user-conf user-conf etc-conf
))))
45 (print saved-conf-name
)
51 (defun load-contrib (file)
52 "Load a file in the contrib directory"
53 (let ((truename (merge-pathnames file
*contrib-dir
*)))
54 (format t
"Loading contribution file: ~A~%" truename
)
55 (when (probe-file truename
)
56 (load truename
:verbose nil
))))
59 (defun reload-clfswm ()
61 (format t
"~&-*- Reloading CLFSWM -*-~%")
62 (asdf:oos
'asdf
:load-op
:clfswm
)
67 (defun query-yes-or-no (formatter &rest args
)
68 (let ((rep (query-string (apply #'format nil formatter args
) "" '("Yes" "No"))))
70 (char= (char rep
0) #\y
)
71 (char= (char rep
0) #\Y
))))
75 (defun banish-pointer ()
76 "Move the pointer to the lower right corner of the screen"
77 (with-placement (*banish-pointer-placement
* x y
)
78 (xlib:warp-pointer
*root
* x y
)))
83 ;;; Root functions utility
84 (defun show-current-root ()
85 (when *have-to-show-current-root
*
86 (let ((*notify-window-placement
* *show-current-root-placement
*))
87 (notify-message *show-current-root-delay
* *show-current-root-message
*))))
89 (defun select-generic-root (fun restart-menu
)
91 (let* ((current-root (find-root (current-child)))
92 (parent (find-parent-frame (root-original current-root
))))
94 (setf (frame-child parent
) (funcall fun
(frame-child parent
)))
95 (let ((new-root (find-root (frame-selected-child parent
))))
96 (setf (current-child) (aif (root-current-child new-root
)
98 (frame-selected-child parent
))))))
102 (open-menu (find-menu 'root-menu
))
103 (leave-second-mode)))
105 (defun select-next-root ()
106 "Select the next root"
107 (select-generic-root #'rotate-list nil
))
109 (defun select-previous-root ()
110 "Select the previous root"
111 (select-generic-root #'anti-rotate-list nil
))
114 (defun select-next-root-restart-menu ()
115 "Select the next root"
116 (select-generic-root #'rotate-list t
))
118 (defun select-previous-root-restart-menu ()
119 "Select the previous root"
120 (select-generic-root #'anti-rotate-list t
))
123 (defun rotate-root-geometry-generic (fun restart-menu
)
126 (show-all-children t
)
129 (open-menu (find-menu 'root-menu
))
130 (leave-second-mode)))
133 (defun rotate-root-geometry-next ()
134 "Rotate root geometry to next root"
135 (rotate-root-geometry-generic #'rotate-root-geometry nil
))
137 (defun rotate-root-geometry-previous ()
138 "Rotate root geometry to previous root"
139 (rotate-root-geometry-generic #'anti-rotate-root-geometry nil
))
141 (defun rotate-root-geometry-next-restart-menu ()
142 "Rotate root geometry to next root"
143 (rotate-root-geometry-generic #'rotate-root-geometry t
))
145 (defun rotate-root-geometry-previous-restart-menu ()
146 "Rotate root geometry to previous root"
147 (rotate-root-geometry-generic #'anti-rotate-root-geometry t
))
151 (defun exchange-root-geometry-with-mouse ()
152 "Exchange two root geometry pointed with the mouse"
153 (open-notify-window '("Select the first root to exchange"))
154 (wait-no-key-or-button-press)
155 (wait-mouse-button-release)
156 (close-notify-window)
157 (multiple-value-bind (x1 y1
) (xlib:query-pointer
*root
*)
158 (open-notify-window '("Select the second root to exchange"))
159 (wait-no-key-or-button-press)
160 (wait-mouse-button-release)
161 (close-notify-window)
162 (multiple-value-bind (x2 y2
) (xlib:query-pointer
*root
*)
163 (exchange-root-geometry (find-root-by-coordinates x1 y1
)
164 (find-root-by-coordinates x2 y2
))))
169 (defun change-current-root-geometry ()
170 "Change the current root geometry"
171 (let* ((root (find-root (current-child)))
172 (x (query-number "New root X position" (root-x root
)))
173 (y (query-number "New root Y position" (root-y root
)))
174 (w (query-number "New root width" (root-w root
)))
175 (h (query-number "New root height" (root-h root
))))
176 (setf (root-x root
) x
(root-y root
) y
177 (root-w root
) w
(root-h root
) h
)
180 (leave-second-mode)))
184 (defun display-all-frame-info ()
185 (with-all-frames (*root-frame
* frame
)
186 (display-frame-info frame
)))
188 (defun display-all-root-frame-info ()
189 (with-all-root-child (root)
190 (display-frame-info root
)))
194 (defun place-window-from-hints (window)
195 "Place a window from its hints"
196 (let* ((hints (xlib:wm-normal-hints window
))
197 (min-width (or (and hints
(xlib:wm-size-hints-min-width hints
)) 0))
198 (min-height (or (and hints
(xlib:wm-size-hints-min-height hints
)) 0))
199 (max-width (or (and hints
(xlib:wm-size-hints-max-width hints
)) (x-drawable-width *root
*)))
200 (max-height (or (and hints
(xlib:wm-size-hints-max-height hints
)) (x-drawable-height *root
*)))
201 (rwidth (or (and hints
(or (xlib:wm-size-hints-width hints
) (xlib:wm-size-hints-base-width hints
)))
202 (x-drawable-width window
)))
203 (rheight (or (and hints
(or (xlib:wm-size-hints-height hints
) (xlib:wm-size-hints-base-height hints
)))
204 (x-drawable-height window
))))
205 (setf (x-drawable-width window
) (min (max min-width rwidth
*default-window-width
*) max-width
)
206 (x-drawable-height window
) (min (max min-height rheight
*default-window-height
*) max-height
))
207 (with-placement (*unmanaged-window-placement
* x y
(x-drawable-width window
) (x-drawable-height window
))
208 (setf (x-drawable-x window
) x
209 (x-drawable-y window
) y
))
210 (xlib:display-finish-output
*display
*)))
213 (defun rename-current-child ()
214 "Rename the current child"
215 (let ((name (query-string (format nil
"New child name: (last: ~A)" (child-name (current-child)))
216 (child-name (current-child)))))
217 (rename-child (current-child) name
)
218 (leave-second-mode)))
221 (defun ask-child-transparency (msg child
)
222 (let ((trans (query-number (format nil
"New ~A transparency: (last: ~A)"
224 (* 100 (child-transparency child
)))
225 (* 100 (child-transparency child
)))))
226 (when (numberp trans
)
227 (setf (child-transparency child
) (float (/ trans
100))))))
229 (defun set-current-child-transparency ()
230 "Set the current child transparency"
231 (ask-child-transparency "child" (current-child))
235 (defun ask-child-border-size (msg child
)
236 (let ((size (query-number (format nil
"New ~A border size: (last: ~A)"
238 (child-border-size child
))
239 (child-border-size child
))))
241 (setf (child-border-size child
) size
))))
244 (defun set-current-child-border-size ()
245 "Set the current child border size"
246 (ask-child-border-size "child" (current-child))
250 (defun renumber-current-frame ()
251 "Renumber the current frame"
252 (when (frame-p (current-child))
253 (let ((number (query-number (format nil
"New child number: (last: ~A)" (frame-number (current-child)))
254 (frame-number (current-child)))))
255 (setf (frame-number (current-child)) number
)
256 (leave-second-mode))))
261 (defun add-default-frame ()
262 "Add a default frame in the current frame"
263 (when (frame-p (current-child))
264 (let ((name (query-string "Frame name")))
265 (push (create-frame :name name
) (frame-child (current-child)))))
268 (defun add-frame-in-parent-frame ()
269 "Add a frame in the parent frame (and reorganize parent frame)"
270 (let ((parent (find-parent-frame (current-child))))
271 (when (and parent
(not (child-original-root-p (current-child))))
272 (let ((new-frame (create-frame)))
273 (pushnew new-frame
(frame-child parent
))
274 (awhen (child-root-p (current-child))
275 (change-root it parent
))
276 (setf (current-child) parent
)
277 (set-layout-once #'tile-space-layout
)
278 (setf (current-child) new-frame
)
279 (leave-second-mode)))))
284 (defun add-placed-frame ()
285 "Add a placed frame in the current frame"
286 (when (frame-p (current-child))
287 (let ((name (query-string "Frame name"))
288 (x (/ (query-number "Frame x in percent (%)") 100))
289 (y (/ (query-number "Frame y in percent (%)") 100))
290 (w (/ (query-number "Frame width in percent (%)" 100) 100))
291 (h (/ (query-number "Frame height in percent (%)" 100) 100)))
292 (push (create-frame :name name
:x x
:y y
:w w
:h h
)
293 (frame-child (current-child)))))
298 (defun delete-focus-window-generic (close-fun)
299 (with-focus-window (window)
300 (when (child-equal-p window
(current-child))
301 (setf (current-child) (find-current-root)))
302 (delete-child-and-children-in-all-frames window close-fun
)))
305 (defun delete-focus-window ()
306 "Close focus window: Delete the focus window in all frames and workspaces"
307 (delete-focus-window-generic 'delete-window
))
309 (defun destroy-focus-window ()
310 "Kill focus window: Destroy the focus window in all frames and workspaces"
311 (delete-focus-window-generic 'destroy-window
))
313 (defun remove-focus-window ()
314 "Remove the focus window from the current frame"
315 (with-focus-window (window)
316 (setf (current-child) (find-current-root))
318 (remove-child-in-frame window
(find-parent-frame window
))
319 (show-all-children)))
322 (defun unhide-all-windows-in-current-child ()
323 "Unhide all hidden windows into the current child"
324 (dolist (window (get-hidden-windows))
325 (unhide-window window
)
326 (process-new-window window
)
333 (defun find-window-under-mouse (x y
)
334 "Return the child window under the mouse"
336 (with-all-root-child (root)
337 (with-all-windows-frames-and-parent (root child parent
)
338 (when (and (or (managed-window-p child parent
) (child-equal-p parent
(current-child)))
339 (not (window-hidden-p child
))
340 (in-window child x y
))
342 (when (in-frame child x y
)
343 (setf win
(frame-window child
)))))
349 (defun find-child-under-mouse-in-never-managed-windows (x y
)
350 "Return the child under mouse from never managed windows"
352 (dolist (win (xlib:query-tree
*root
*))
353 (unless (window-hidden-p win
)
354 (multiple-value-bind (never-managed raise
)
355 (never-managed-window-p win
)
356 (when (and never-managed raise
(in-window win x y
))
361 (defun find-child-under-mouse-in-child-tree (x y
&optional first-foundp
)
362 "Return the child under the mouse"
364 (with-all-root-child (root)
365 (with-all-windows-frames (root child
)
366 (when (and (not (window-hidden-p child
))
367 (in-window child x y
))
369 (return-from find-child-under-mouse-in-child-tree child
)
371 (when (in-frame child x y
)
373 (return-from find-child-under-mouse-in-child-tree child
)
379 (defun find-child-under-mouse (x y
&optional first-foundp also-never-managed
)
380 "Return the child under the mouse"
381 (or (and also-never-managed
382 (find-child-under-mouse-in-never-managed-windows x y
))
383 (find-child-under-mouse-in-child-tree x y first-foundp
)))
389 ;;; Selection functions
390 (defun clear-selection ()
391 "Clear the current selection"
392 (setf *child-selection
* nil
)
393 (display-all-root-frame-info))
395 (defun copy-current-child ()
396 "Copy the current child to the selection"
397 (pushnew (current-child) *child-selection
*)
398 (display-all-root-frame-info))
401 (defun cut-current-child (&optional
(show-now t
))
402 "Cut the current child to the selection"
403 (unless (child-root-p (current-child))
404 (let ((parent (find-parent-frame (current-child))))
405 (hide-all (current-child))
407 (remove-child-in-frame (current-child) (find-parent-frame (current-child) (find-current-root)))
409 (setf (current-child) parent
))
411 (show-all-children t
))
414 (defun remove-current-child ()
415 "Remove the current child from its parent frame"
416 (unless (child-root-p (current-child))
417 (let ((parent (find-parent-frame (current-child))))
418 (hide-all (current-child))
419 (remove-child-in-frame (current-child) (find-parent-frame (current-child) (find-current-root)))
421 (setf (current-child) parent
))
422 (show-all-children t
)
423 (leave-second-mode))))
425 (defun delete-current-child ()
426 "Delete the current child and its children in all frames"
427 (unless (child-root-p (current-child))
428 (hide-all (current-child))
429 (delete-child-and-children-in-all-frames (current-child))
430 (show-all-children t
)
431 (leave-second-mode)))
434 (defun paste-selection-no-clear ()
435 "Paste the selection in the current frame - Do not clear the selection after paste"
436 (when (frame-p (current-child))
437 (dolist (child *child-selection
*)
438 (unless (find-child-in-parent child
(current-child))
439 (pushnew child
(frame-child (current-child)) :test
#'child-equal-p
)))
440 (show-all-children)))
442 (defun paste-selection ()
443 "Paste the selection in the current frame"
444 (when (frame-p (current-child))
445 (paste-selection-no-clear)
446 (setf *child-selection
* nil
)
447 (display-all-root-frame-info)))
450 (defun copy-focus-window ()
451 "Copy the focus window to the selection"
452 (with-focus-window (window)
453 (with-current-child (window)
454 (copy-current-child))))
457 (defun cut-focus-window ()
458 "Cut the focus window to the selection"
459 (with-focus-window (window)
460 (setf (current-child) (with-current-child (window)
461 (cut-current-child nil
)))
462 (show-all-children t
)))
469 ;;; Maximize function
470 (defun frame-toggle-maximize ()
471 "Maximize/Unmaximize the current frame in its parent frame"
472 (when (frame-p (current-child))
473 (let ((unmaximized-coords (frame-data-slot (current-child) :unmaximized-coords
)))
474 (if unmaximized-coords
475 (with-slots (x y w h
) (current-child)
476 (destructuring-bind (nx ny nw nh
) unmaximized-coords
477 (setf (frame-data-slot (current-child) :unmaximized-coords
) nil
478 x nx y ny w nw h nh
)))
479 (with-slots (x y w h
) (current-child)
480 (setf (frame-data-slot (current-child) :unmaximized-coords
)
484 (leave-second-mode)))
494 ;;; CONFIG - Identify mode
495 (defun identify-key ()
498 (font (xlib:open-font
*display
* *identify-font-string
*))
499 (window (xlib:create-window
:parent
*root
*
501 :width
(- (xlib:screen-width
*screen
*) (* *border-size
* 2))
502 :height
(* 5 (+ (xlib:max-char-ascent font
) (xlib:max-char-descent font
)))
503 :background
(get-color *identify-background
*)
504 :border-width
*border-size
*
505 :border
(get-color *identify-border
*)
506 :colormap
(xlib:screen-default-colormap
*screen
*)
507 :event-mask
'(:exposure
)))
508 (gc (xlib:create-gcontext
:drawable window
509 :foreground
(get-color *identify-foreground
*)
510 :background
(get-color *identify-background
*)
512 :line-style
:solid
)))
513 (setf (window-transparency window
) *identify-transparency
*)
514 (labels ((print-doc (msg hash-table-key pos code state
)
515 (let ((function (find-key-from-code hash-table-key code state
)))
516 (when (and function
(fboundp (first function
)))
517 (xlib:draw-glyphs
*pixmap-buffer
* gc
10 (+ (* pos
(+ (xlib:max-char-ascent font
) (xlib:max-char-descent font
))) 5)
518 (format nil
"~A ~A" msg
(documentation (first function
) 'function
))))))
519 (print-key (code state keysym key modifiers
)
520 (clear-pixmap-buffer window gc
)
521 (setf (xlib:gcontext-foreground gc
) (get-color *identify-foreground
*))
522 (xlib:draw-glyphs
*pixmap-buffer
* gc
5 (+ (xlib:max-char-ascent font
) 5)
523 (format nil
"Press a key to identify. Press 'q' to stop the identify loop."))
525 (xlib:draw-glyphs
*pixmap-buffer
* gc
10 (+ (* 2 (+ (xlib:max-char-ascent font
) (xlib:max-char-descent font
))) 5)
526 (format nil
"Code=~A KeySym=~S Key=~S Modifiers=~A"
527 code keysym key modifiers
))
528 (print-doc "Main mode : " *main-keys
* 3 code state
)
529 (print-doc "Second mode: " *second-keys
* 4 code state
))
530 (copy-pixmap-buffer window gc
))
531 (handle-identify-key (&rest event-slots
&key root code state
&allow-other-keys
)
532 (declare (ignore event-slots root
))
533 (let* ((modifiers (state->modifiers state
))
534 (key (keycode->char code state
))
535 (keysym (keysym->keysym-name
(keycode->keysym code modifiers
))))
536 (setf done
(and (equal key
#\q
) (equal modifiers
*default-modifiers
*)))
537 (dbg code keysym key modifiers
)
538 (print-key code state keysym key modifiers
)
540 (handle-identify (&rest event-slots
&key display event-key
&allow-other-keys
)
541 (declare (ignore display
))
543 (:key-press
(apply #'handle-identify-key event-slots
) t
)
544 (:exposure
(print-key nil nil nil nil nil
)))
546 (xgrab-pointer *root
* 92 93)
548 (format t
"~&Press 'q' to stop the identify loop~%")
549 (print-key nil nil nil nil nil
)
553 (with-xlib-protect (:Identify-Loop nil
)
554 (when (xlib:event-listen
*display
* *loop-timeout
*)
555 (xlib:process-event
*display
* :handler
#'handle-identify
))
556 (xlib:display-finish-output
*display
*)))
558 (xlib:destroy-window window
)
559 (xlib:close-font font
)
560 (xgrab-pointer *root
* 66 67))))))
567 (let ((all-symbols (collect-all-symbols)))
568 (defun eval-from-query-string ()
569 "Eval a lisp form from the query input"
570 (let ((form (query-string (format nil
"Eval Lisp <~A> " (package-name *package
*))
573 (when (and form
(not (equal form
"")))
574 (let ((printed-result
575 (with-output-to-string (*standard-output
*)
576 (setf result
(handler-case
577 (loop for i in
(multiple-value-list
578 (eval (read-from-string form
)))
579 collect
(format nil
"~S" i
))
581 (format nil
"~A" condition
)))))))
582 (let ((ret (info-mode (expand-newline (append (ensure-list (format nil
"> ~A" form
))
583 (ensure-list printed-result
)
584 (ensure-list result
)))
585 :width
(- (xlib:screen-width
*screen
*) 2))))
586 (when (or (search "defparameter" form
:test
#'string-equal
)
587 (search "defvar" form
:test
#'string-equal
))
588 (let ((elem (split-string form
)))
589 (pushnew (string-downcase (if (string= (first elem
) "(") (third elem
) (second elem
)))
590 all-symbols
:test
#'string
=)))
591 (when (search "in-package" form
:test
#'string-equal
)
592 (let ((*notify-window-placement
* 'middle-middle-root-placement
))
593 (open-notify-window '("Collecting all symbols for Lisp REPL completion."))
594 (setf all-symbols
(collect-all-symbols))
595 (close-notify-window)))
597 (eval-from-query-string))))))))
603 (let ((commands (command-in-path)))
604 (defun run-program-from-query-string ()
605 "Run a program from the query input"
606 (multiple-value-bind (program return
)
607 (query-string "Run:" "" commands
)
608 (when (and (equal return
:return
) program
(not (equal program
"")))
609 (setf *second-mode-leave-function
* (let ((cmd (concatenate 'string
"cd $HOME && " program
)))
612 (leave-second-mode)))))
617 ;;; Frame name actions
618 (defun ask-frame-name (msg)
620 (let ((all-frame-name nil
))
621 (with-all-frames (*root-frame
* frame
)
622 (awhen (frame-name frame
) (push it all-frame-name
)))
623 (query-string msg
"" all-frame-name
)))
626 ;;; Focus by functions
627 (defun focus-frame-by (frame)
628 (when (frame-p frame
)
629 (focus-all-children frame
(or (find-parent-frame frame
(find-current-root))
630 (find-parent-frame frame
)
632 (show-all-children t
)))
635 (defun focus-frame-by-name ()
636 "Focus a frame by name"
637 (focus-frame-by (find-frame-by-name (ask-frame-name "Focus frame:")))
640 (defun focus-frame-by-number ()
641 "Focus a frame by number"
642 (focus-frame-by (find-frame-by-number (query-number "Focus frame by number:")))
646 ;;; Open by functions
647 (defun open-frame-by (frame)
648 (when (frame-p frame
)
649 (push (create-frame :name
(query-string "Frame name")) (frame-child frame
))
650 (show-all-children)))
654 (defun open-frame-by-name ()
655 "Open a new frame in a named frame"
656 (open-frame-by (find-frame-by-name (ask-frame-name "Open a new frame in: ")))
659 (defun open-frame-by-number ()
660 "Open a new frame in a numbered frame"
661 (open-frame-by (find-frame-by-number (query-number "Open a new frame in the group numbered:")))
665 ;;; Delete by functions
666 (defun delete-frame-by (frame)
667 (unless (or (child-equal-p frame
*root-frame
*)
668 (child-root-p frame
))
669 (when (child-equal-p frame
(current-child))
670 (setf (current-child) (find-current-root)))
671 (remove-child-in-frame frame
(find-parent-frame frame
)))
672 (show-all-children t
))
675 (defun delete-frame-by-name ()
676 "Delete a frame by name"
677 (delete-frame-by (find-frame-by-name (ask-frame-name "Delete frame: ")))
680 (defun delete-frame-by-number ()
681 "Delete a frame by number"
682 (delete-frame-by (find-frame-by-number (query-number "Delete frame by number:")))
687 (defun move-child-to (child frame-dest
)
688 (when (and child
(frame-p frame-dest
))
689 (remove-child-in-frame child
(find-parent-frame child
))
690 (pushnew child
(frame-child frame-dest
))
691 (focus-all-children child frame-dest
)
692 (show-all-children t
)))
694 (defun move-current-child-by-name ()
695 "Move current child in a named frame"
696 (move-child-to (current-child)
698 (ask-frame-name (format nil
"Move '~A' to frame: " (child-name (current-child))))))
701 (defun move-current-child-by-number ()
702 "Move current child in a numbered frame"
703 (move-child-to (current-child)
704 (find-frame-by-number
705 (query-number (format nil
"Move '~A' to frame numbered:" (child-name (current-child))))))
710 (defun copy-child-to (child frame-dest
)
711 (when (and child
(frame-p frame-dest
))
712 (pushnew child
(frame-child frame-dest
))
713 (focus-all-children child frame-dest
)
714 (show-all-children t
)))
716 (defun copy-current-child-by-name ()
717 "Copy current child in a named frame"
718 (copy-child-to (current-child)
720 (ask-frame-name (format nil
"Copy '~A' to frame: " (child-name (current-child))))))
723 (defun copy-current-child-by-number ()
724 "Copy current child in a numbered frame"
725 (copy-child-to (current-child)
726 (find-frame-by-number
727 (query-number (format nil
"Copy '~A' to frame numbered:" (child-name (current-child))))))
734 (defun show-all-frames-info ()
735 "Show all frames info windows"
736 (let ((*show-root-frame-p
* t
))
738 (with-all-root-child (root)
739 (with-all-frames (root frame
)
740 (raise-window (frame-window frame
))
741 (display-frame-info frame
)))))
743 (defun hide-all-frames-info ()
744 "Hide all frames info windows"
747 (defun show-all-frames-info-key ()
748 "Show all frames info windows until a key is release"
749 (show-all-frames-info)
750 (wait-no-key-or-button-press)
751 (hide-all-frames-info))
754 (defun move-frame (frame parent orig-x orig-y
)
755 (when (and frame parent
(not (child-root-p frame
)))
756 (hide-all-children frame
)
757 (with-slots (window) frame
758 (move-window window orig-x orig-y
#'display-frame-info
(list frame
))
759 (setf (frame-x frame
) (x-px->fl
(x-drawable-x window
) parent
)
760 (frame-y frame
) (y-px->fl
(x-drawable-y window
) parent
)))
761 (show-all-children)))
763 (defun resize-frame (frame parent orig-x orig-y
)
764 (when (and frame parent
(not (child-root-p frame
)))
765 (hide-all-children frame
)
766 (with-slots (window) frame
767 (resize-window window orig-x orig-y
#'display-frame-info
(list frame
))
768 (setf (frame-w frame
) (w-px->fl
(anti-adj-border-wh (x-drawable-width window
) frame
) parent
)
769 (frame-h frame
) (h-px->fl
(anti-adj-border-wh (x-drawable-height window
) frame
) parent
)))
770 (show-all-children)))
774 (defun mouse-click-to-focus-generic (root-x root-y mouse-fn
)
775 "Focus the current frame or focus the current window parent
776 mouse-fun is #'move-frame or #'resize-frame"
778 (child (find-child-under-mouse root-x root-y
))
779 (parent (find-parent-frame child
))
780 (root-p (child-root-p child
)))
781 (labels ((add-new-frame ()
782 (when (frame-p child
)
785 mouse-fn
#'resize-frame
786 (current-child) child
)
787 (place-frame child parent root-x root-y
10 10)
788 (map-window (frame-window child
))
789 (pushnew child
(frame-child parent
)))))
790 (when (and root-p
*create-frame-on-root
*)
792 (when (and (frame-p child
) (not (child-root-p child
)))
793 (funcall mouse-fn child parent root-x root-y
))
794 (when (and child parent
795 (focus-all-children child parent
(not (child-root-p child
))))
796 (when (show-all-children)
797 (setf to-replay nil
)))
799 (replay-button-event)
800 (stop-button-event)))))
803 (defun mouse-click-to-focus-and-move (window root-x root-y
)
804 "Move and focus the current frame or focus the current window parent.
805 Or do actions on corners"
806 (declare (ignore window
))
807 (or (do-corner-action root-x root-y
*corner-main-mode-left-button
*)
808 (mouse-click-to-focus-generic root-x root-y
#'move-frame
)))
810 (defun mouse-click-to-focus-and-resize (window root-x root-y
)
811 "Resize and focus the current frame or focus the current window parent.
812 Or do actions on corners"
813 (declare (ignore window
))
814 (or (do-corner-action root-x root-y
*corner-main-mode-right-button
*)
815 (mouse-click-to-focus-generic root-x root-y
#'resize-frame
)))
817 (defun mouse-middle-click (window root-x root-y
)
818 "Do actions on corners"
819 (declare (ignore window
))
820 (or (do-corner-action root-x root-y
*corner-main-mode-middle-button
*)
821 (replay-button-event)))
826 (defun mouse-focus-move/resize-generic
(root-x root-y mouse-fn window-parent
)
827 "Focus the current frame or focus the current window parent
828 mouse-fun is #'move-frame or #'resize-frame.
829 Focus child and its parents -
830 For window: set current child to window or its parent according to window-parent"
831 (labels ((move/resize-managed
(child)
832 (let ((parent (find-parent-frame child
)))
835 (child-root-p child
))
838 mouse-fn
#'resize-frame
)
839 (place-frame child parent root-x root-y
10 10)
840 (map-window (frame-window child
))
841 (push child
(frame-child parent
)))
842 (focus-all-children child parent window-parent
)
846 (if (managed-window-p child parent
)
847 (funcall mouse-fn parent
(find-parent-frame parent
) root-x root-y
)
848 (funcall (cond ((or (eql mouse-fn
#'move-frame
)
849 (eql mouse-fn
#'move-frame-constrained
))
851 ((or (eql mouse-fn
#'resize-frame
)
852 (eql mouse-fn
#'resize-frame-constrained
))
854 child root-x root-y
)))
855 (frame (funcall mouse-fn child parent root-x root-y
)))
856 (show-all-children)))
857 (move/resize-never-managed
(child raise-fun
)
858 (funcall raise-fun child
)
859 (funcall (cond ((eql mouse-fn
#'move-frame
) #'move-window
)
860 ((eql mouse-fn
#'resize-frame
) #'resize-window
))
861 child root-x root-y
)))
862 (let ((child (find-child-under-mouse root-x root-y nil t
)))
863 (multiple-value-bind (never-managed raise-fun
)
864 (never-managed-window-p child
)
865 (if (and (xlib:window-p child
) never-managed raise-fun
)
866 (move/resize-never-managed child raise-fun
)
867 (move/resize-managed child
))))))
870 (defun test-mouse-binding (window root-x root-y
)
871 (dbg window root-x root-y
)
872 (replay-button-event))
876 (defun mouse-select-next-level (window root-x root-y
)
877 "Select the next level in frame"
878 (declare (ignore root-x root-y
))
879 (let ((frame (find-frame-window window
)))
880 (when (or frame
(xlib:window-equal window
*root
*))
882 (replay-button-event)))
886 (defun mouse-select-previous-level (window root-x root-y
)
887 "Select the previous level in frame"
888 (declare (ignore root-x root-y
))
889 (let ((frame (find-frame-window window
)))
890 (when (or frame
(xlib:window-equal window
*root
*))
891 (select-previous-level))
892 (replay-button-event)))
896 (defun mouse-enter-frame (window root-x root-y
)
897 "Enter in the selected frame - ie make it the root frame"
898 (declare (ignore root-x root-y
))
899 (let ((frame (find-frame-window window
)))
900 (when (or frame
(xlib:window-equal window
*root
*))
902 (replay-button-event)))
906 (defun mouse-leave-frame (window root-x root-y
)
907 "Leave the selected frame - ie make its parent the root frame"
908 (declare (ignore root-x root-y
))
909 (let ((frame (find-frame-window window
)))
910 (when (or frame
(xlib:window-equal window
*root
*))
912 (replay-button-event)))
917 ;;;;;| Various definitions
920 (defun show-help (&optional
(browser "dillo") (tempfile "/tmp/clfswm.html"))
921 "Show current keys and buttons bindings"
923 (produce-doc-html-in-file tempfile
))
925 (do-shell (format nil
"~A ~A" browser tempfile
)))
929 ;;; Bind or jump functions
930 (let ((key-slots (make-array 10 :initial-element nil
))
932 (defun reset-bind-or-jump-slots ()
934 (setf (aref key-slots i
) nil
)))
936 (defun bind-on-slot (&optional
(slot current-slot
))
937 "Bind current child to slot"
938 (setf (aref key-slots slot
) (current-child)))
940 (defun remove-binding-on-slot ()
941 "Remove binding on slot"
942 (setf (aref key-slots current-slot
) nil
))
944 (defun jump-to-slot ()
946 (let ((jump-child (aref key-slots current-slot
)))
947 (when (and jump-child
(find-child jump-child
*root-frame
*))
948 (unless (find-child-in-all-root jump-child
)
949 (change-root (find-root jump-child
) jump-child
))
950 (setf (current-child) jump-child
)
951 (focus-all-children jump-child jump-child
)
952 (show-all-children t
))))
954 (defun bind-or-jump (n)
955 "Bind or jump to a slot (a frame or a window)"
956 (setf current-slot
(- n
1))
957 (let ((default-bind `("b" bind-on-slot
958 ,(format nil
"Bind slot ~A on child: ~A" n
(child-fullname (current-child))))))
959 (info-mode-menu (aif (aref key-slots current-slot
)
961 ("BackSpace" remove-binding-on-slot
962 ,(format nil
"Remove slot ~A binding on child: ~A" n
(child-fullname (current-child))))
965 ,(format nil
"Jump to child: ~A" (aif (aref key-slots current-slot
)
967 "Not set - Please, bind it with 'b'")))
968 ("Return" jump-to-slot
"Same thing")
969 ("space" jump-to-slot
"Same thing"))
970 (list default-bind
))))))
974 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
975 ;;; Useful function for the second mode ;;;
976 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
977 (defmacro with-movement
(&body body
)
978 `(when (frame-p (current-child))
983 (display-all-frame-info)
984 (draw-second-mode-window)
985 (open-menu (find-menu 'frame-movement-menu
)))))
989 (defun current-frame-pack-up ()
990 "Pack the current frame up"
991 (with-movement (pack-frame-up (current-child) (find-parent-frame (current-child) (find-current-root)))))
993 (defun current-frame-pack-down ()
994 "Pack the current frame down"
995 (with-movement (pack-frame-down (current-child) (find-parent-frame (current-child) (find-current-root)))))
997 (defun current-frame-pack-left ()
998 "Pack the current frame left"
999 (with-movement (pack-frame-left (current-child) (find-parent-frame (current-child) (find-current-root)))))
1001 (defun current-frame-pack-right ()
1002 "Pack the current frame right"
1003 (with-movement (pack-frame-right (current-child) (find-parent-frame (current-child) (find-current-root)))))
1006 (defun center-current-frame ()
1007 "Center the current frame"
1008 (with-movement (center-frame (current-child))))
1011 (defun current-frame-fill-up ()
1012 "Fill the current frame up"
1013 (with-movement (fill-frame-up (current-child) (find-parent-frame (current-child) (find-current-root)))))
1015 (defun current-frame-fill-down ()
1016 "Fill the current frame down"
1017 (with-movement (fill-frame-down (current-child) (find-parent-frame (current-child) (find-current-root)))))
1019 (defun current-frame-fill-left ()
1020 "Fill the current frame left"
1021 (with-movement (fill-frame-left (current-child) (find-parent-frame (current-child) (find-current-root)))))
1023 (defun current-frame-fill-right ()
1024 "Fill the current frame right"
1025 (with-movement (fill-frame-right (current-child) (find-parent-frame (current-child) (find-current-root)))))
1027 (defun current-frame-fill-all-dir ()
1028 "Fill the current frame in all directions"
1030 (let ((parent (find-parent-frame (current-child) (find-current-root))))
1031 (fill-frame-up (current-child) parent
)
1032 (fill-frame-down (current-child) parent
)
1033 (fill-frame-left (current-child) parent
)
1034 (fill-frame-right (current-child) parent
))))
1036 (defun current-frame-fill-vertical ()
1037 "Fill the current frame vertically"
1039 (let ((parent (find-parent-frame (current-child) (find-current-root))))
1040 (fill-frame-up (current-child) parent
)
1041 (fill-frame-down (current-child) parent
))))
1043 (defun current-frame-fill-horizontal ()
1044 "Fill the current frame horizontally"
1046 (let ((parent (find-parent-frame (current-child) (find-current-root))))
1047 (fill-frame-left (current-child) parent
)
1048 (fill-frame-right (current-child) parent
))))
1052 (defun current-frame-resize-up ()
1053 "Resize the current frame up to its half height"
1054 (with-movement (resize-half-height-up (current-child))))
1056 (defun current-frame-resize-down ()
1057 "Resize the current frame down to its half height"
1058 (with-movement (resize-half-height-down (current-child))))
1060 (defun current-frame-resize-left ()
1061 "Resize the current frame left to its half width"
1062 (with-movement (resize-half-width-left (current-child))))
1064 (defun current-frame-resize-right ()
1065 "Resize the current frame right to its half width"
1066 (with-movement (resize-half-width-right (current-child))))
1068 (defun current-frame-resize-all-dir ()
1069 "Resize down the current frame"
1070 (with-movement (resize-frame-down (current-child))))
1072 (defun current-frame-resize-all-dir-minimal ()
1073 "Resize down the current frame to its minimal size"
1074 (with-movement (resize-minimal-frame (current-child))))
1077 ;;; Children navigation
1078 (defun with-movement-select-next-brother ()
1079 "Select the next brother frame"
1080 (with-movement (select-next-brother-simple)))
1082 (defun with-movement-select-previous-brother ()
1083 "Select the previous brother frame"
1084 (with-movement (select-previous-brother-simple)))
1086 (defun with-movement-select-next-level ()
1087 "Select the next level"
1088 (with-movement (select-next-level)))
1090 (defun with-movement-select-previous-level ()
1091 "Select the previous levelframe"
1092 (with-movement (select-previous-level)))
1094 (defun with-movement-select-next-child ()
1095 "Select the next child"
1096 (with-movement (select-next-child-simple)))
1100 ;;; Adapt frame functions
1101 (defun adapt-current-frame-to-window-hints-generic (width-p height-p
)
1102 "Adapt the current frame to the current window minimal size hints"
1103 (when (frame-p (current-child))
1104 (let ((window (first (frame-child (current-child)))))
1105 (when (xlib:window-p window
)
1106 (let* ((hints (xlib:wm-normal-hints window
))
1107 (min-width (and hints
(xlib:wm-size-hints-min-width hints
)))
1108 (min-height (and hints
(xlib:wm-size-hints-min-height hints
))))
1109 (when (and width-p min-width
)
1110 (setf (frame-rw (current-child)) min-width
))
1111 (when (and height-p min-height
)
1112 (setf (frame-rh (current-child)) min-height
))
1113 (fixe-real-size (current-child) (find-parent-frame (current-child)))
1114 (leave-second-mode))))))
1116 (defun adapt-current-frame-to-window-hints ()
1117 "Adapt the current frame to the current window minimal size hints"
1118 (adapt-current-frame-to-window-hints-generic t t
))
1120 (defun adapt-current-frame-to-window-width-hint ()
1121 "Adapt the current frame to the current window minimal width hint"
1122 (adapt-current-frame-to-window-hints-generic t nil
))
1124 (defun adapt-current-frame-to-window-height-hint ()
1125 "Adapt the current frame to the current window minimal height hint"
1126 (adapt-current-frame-to-window-hints-generic nil t
))
1131 ;;; Managed window type functions
1132 (defun current-frame-manage-window-type-generic (type-list)
1133 (when (frame-p (current-child))
1134 (setf (frame-managed-type (current-child)) type-list
1135 (frame-forced-managed-window (current-child)) nil
1136 (frame-forced-unmanaged-window (current-child)) nil
))
1137 (leave-second-mode))
1140 (defun current-frame-manage-window-type ()
1141 "Change window types to be managed by a frame"
1142 (when (frame-p (current-child))
1143 (let* ((type-str (query-string "Managed window type: (all, normal, transient, maxsize, desktop, dock, toolbar, menu, utility, splash, dialog)"
1144 (format nil
"~{~:(~A~) ~}" (frame-managed-type (current-child)))))
1145 (type-list (loop :for type
:in
(split-string type-str
)
1146 :collect
(intern (string-upcase type
) :keyword
))))
1147 (current-frame-manage-window-type-generic type-list
))))
1150 (defun current-frame-manage-all-window-type ()
1151 "Manage all window type"
1152 (current-frame-manage-window-type-generic '(:all
)))
1154 (defun current-frame-manage-only-normal-window-type ()
1155 "Manage only normal window type"
1156 (current-frame-manage-window-type-generic '(:normal
)))
1158 (defun current-frame-manage-no-window-type ()
1159 "Do not manage any window type"
1160 (current-frame-manage-window-type-generic nil
))
1169 ;;; Force window functions
1170 (defun force-window-in-frame ()
1171 "Force the current window to move in the frame (Useful only for unmanaged windows)"
1172 (with-current-window
1173 (let ((parent (find-parent-frame window
)))
1174 (setf (x-drawable-x window
) (frame-rx parent
)
1175 (x-drawable-y window
) (frame-ry parent
))
1176 (xlib:display-finish-output
*display
*)))
1177 (leave-second-mode))
1180 (defun force-window-center-in-frame ()
1181 "Force the current window to move in the center of the frame (Useful only for unmanaged windows)"
1182 (with-current-window
1183 (let ((parent (find-parent-frame window
)))
1184 (setf (x-drawable-x window
) (truncate (+ (frame-rx parent
)
1185 (/ (- (frame-rw parent
)
1186 (x-drawable-width window
)) 2)))
1187 (x-drawable-y window
) (truncate (+ (frame-ry parent
)
1188 (/ (- (frame-rh parent
)
1189 (x-drawable-height window
)) 2))))
1190 (xlib:display-finish-output
*display
*)))
1191 (leave-second-mode))
1195 (defun display-current-window-info ()
1196 "Display information on the current window"
1197 (with-current-window
1198 (info-mode (list (format nil
"Window: ~A" window
)
1199 (format nil
"Window name: ~A" (xlib:wm-name window
))
1200 (format nil
"Window class: ~A" (xlib:get-wm-class window
))
1201 (format nil
"Window type: ~:(~A~)" (window-type window
))
1202 (format nil
"Window id: 0x~X" (xlib:window-id window
))
1203 (format nil
"Window transparency: ~A" (* 100 (window-transparency window
))))))
1204 (leave-second-mode))
1206 (defun set-current-window-transparency ()
1207 "Set the current window transparency"
1208 (with-current-window
1209 (ask-child-transparency "window" window
))
1210 (leave-second-mode))
1213 (defun manage-current-window ()
1214 "Force to manage the current window by its parent frame"
1215 (with-current-window
1216 (let ((parent (find-parent-frame window
)))
1217 (with-slots ((managed forced-managed-window
)
1218 (unmanaged forced-unmanaged-window
)) parent
1219 (setf unmanaged
(child-remove window unmanaged
)
1220 unmanaged
(remove (xlib:wm-name window
) unmanaged
:test
#'string-equal-p
))
1221 (pushnew window managed
))))
1222 (leave-second-mode))
1224 (defun unmanage-current-window ()
1225 "Force to not manage the current window by its parent frame"
1226 (with-current-window
1227 (let ((parent (find-parent-frame window
)))
1228 (with-slots ((managed forced-managed-window
)
1229 (unmanaged forced-unmanaged-window
)) parent
1230 (setf managed
(child-remove window managed
)
1231 managed
(remove (xlib:wm-name window
) managed
:test
#'string-equal-p
))
1232 (pushnew window unmanaged
))))
1233 (leave-second-mode))
1237 ;;; Moving child with the mouse button
1238 (defun mouse-move-child-over-frame (window root-x root-y
)
1239 "Move the child under the mouse cursor to another frame"
1240 (declare (ignore window
))
1241 (let ((child (find-child-under-mouse root-x root-y
)))
1242 (unless (child-root-p child
)
1244 (remove-child-in-frame child
(find-parent-frame child
))
1245 (wait-mouse-button-release 50 51)
1246 (multiple-value-bind (x y
)
1247 (xlib:query-pointer
*root
*)
1248 (let ((dest (find-child-under-mouse x y
)))
1249 (when (xlib:window-p dest
)
1250 (setf dest
(find-parent-frame dest
)))
1251 (unless (child-equal-p child dest
)
1252 (move-child-to child dest
)
1253 (show-all-children))))))
1254 (stop-button-event))
1259 ;;; Hide/Show frame window functions
1260 (defun hide/show-frame-window
(frame value
)
1261 "Hide/show the frame window"
1262 (when (frame-p frame
)
1263 (setf (frame-show-window-p (current-child)) value
)
1264 (show-all-children))
1265 (leave-second-mode))
1268 (defun hide-current-frame-window ()
1269 "Hide the current frame window"
1270 (hide/show-frame-window
(current-child) nil
))
1272 (defun show-current-frame-window ()
1273 "Show the current frame window"
1274 (hide/show-frame-window
(current-child) t
))
1278 ;;; Hide/Unhide current child
1279 (defun hide-current-child ()
1280 "Hide the current child"
1281 (unless (child-root-p (current-child))
1282 (let ((parent (find-parent-frame (current-child))))
1283 (when (frame-p parent
)
1284 (with-slots (child hidden-children
) parent
1285 (hide-all (current-child))
1286 (setf child
(child-remove (current-child) child
))
1287 (pushnew (current-child) hidden-children
)
1288 (setf (current-child) parent
))
1289 (show-all-children)))
1290 (leave-second-mode)))
1293 (defun frame-unhide-child (hidden frame-src frame-dest
)
1294 "Unhide a hidden child from frame-src in frame-dest"
1295 (with-slots (hidden-children) frame-src
1296 (setf hidden-children
(child-remove hidden hidden-children
)))
1297 (with-slots (child) frame-dest
1298 (pushnew hidden child
)))
1302 (defun unhide-a-child ()
1303 "Unhide a child in the current frame"
1304 (when (frame-p (current-child))
1305 (with-slots (child hidden-children
) (current-child)
1306 (info-mode-menu (loop :for i
:from
0
1307 :for hidden
:in hidden-children
1308 :collect
(list (code-char (+ (char-code #\a) i
))
1311 (frame-unhide-child lhd
(current-child) (current-child))))
1312 (format nil
"Unhide ~A" (child-fullname hidden
))))))
1313 (show-all-children))
1314 (leave-second-mode))
1317 (defun unhide-all-children ()
1318 "Unhide all current frame hidden children"
1319 (when (frame-p (current-child))
1320 (with-slots (child hidden-children
) (current-child)
1321 (dolist (c hidden-children
)
1323 (setf hidden-children nil
))
1324 (show-all-children))
1325 (leave-second-mode))
1328 (defun unhide-a-child-from-all-frames ()
1329 "Unhide a child from all frames in the current frame"
1330 (when (frame-p (current-child))
1333 (with-all-frames (*root-frame
* frame
)
1334 (when (frame-hidden-children frame
)
1335 (push (format nil
"~A" (child-fullname frame
)) acc
)
1336 (dolist (hidden (frame-hidden-children frame
))
1337 (push (list (code-char (+ (char-code #\a) (incf keynum
)))
1340 (frame-unhide-child lhd frame
(current-child))))
1341 (format nil
"Unhide ~A" (child-fullname hidden
)))
1343 (info-mode-menu (nreverse acc
)))
1344 (show-all-children))
1345 (leave-second-mode))
1351 (let ((last-child nil
))
1352 (defun init-last-child ()
1353 (setf last-child nil
))
1354 (defun switch-to-last-child ()
1355 "Store the current child and switch to the previous one"
1356 (let ((current-child (current-child)))
1358 (change-root (find-root last-child
) last-child
)
1359 (setf (current-child) last-child
)
1360 (focus-all-children (current-child) (current-child))
1361 (show-all-children t
))
1362 (setf last-child current-child
))
1363 (leave-second-mode)))
1371 ;;; Focus policy functions
1372 (defun set-focus-policy-generic (focus-policy)
1373 (when (frame-p (current-child))
1374 (setf (frame-focus-policy (current-child)) focus-policy
))
1375 (leave-second-mode))
1378 (defun current-frame-set-click-focus-policy ()
1379 "Set a click focus policy for the current frame."
1380 (set-focus-policy-generic :click
))
1382 (defun current-frame-set-sloppy-focus-policy ()
1383 "Set a sloppy focus policy for the current frame."
1384 (set-focus-policy-generic :sloppy
))
1386 (defun current-frame-set-sloppy-strict-focus-policy ()
1387 "Set a (strict) sloppy focus policy only for windows in the current frame."
1388 (set-focus-policy-generic :sloppy-strict
))
1390 (defun current-frame-set-sloppy-select-policy ()
1391 "Set a sloppy select policy for the current frame."
1392 (set-focus-policy-generic :sloppy-select
))
1396 (defun set-focus-policy-generic-for-all (focus-policy)
1397 (with-all-frames (*root-frame
* frame
)
1398 (setf (frame-focus-policy frame
) focus-policy
))
1399 (leave-second-mode))
1402 (defun all-frames-set-click-focus-policy ()
1403 "Set a click focus policy for all frames."
1404 (set-focus-policy-generic-for-all :click
))
1406 (defun all-frames-set-sloppy-focus-policy ()
1407 "Set a sloppy focus policy for all frames."
1408 (set-focus-policy-generic-for-all :sloppy
))
1410 (defun all-frames-set-sloppy-strict-focus-policy ()
1411 "Set a (strict) sloppy focus policy for all frames."
1412 (set-focus-policy-generic-for-all :sloppy-strict
))
1414 (defun all-frames-set-sloppy-select-policy ()
1415 "Set a sloppy select policy for all frames."
1416 (set-focus-policy-generic-for-all :sloppy-select
))
1420 ;;; Ensure unique name/number functions
1421 (defun extract-number-from-name (name)
1422 (when (stringp name
)
1423 (let* ((pos (1+ (or (position #\. name
:from-end t
) -
1)))
1424 (number (parse-integer name
:junk-allowed t
:start pos
)))
1426 (if number
(subseq name
0 (1- pos
)) name
)))))
1431 (defun ensure-unique-name ()
1432 "Ensure that all children names are unique"
1433 (with-all-children (*root-frame
* child
)
1434 (multiple-value-bind (num1 name1
)
1435 (extract-number-from-name (child-name child
))
1436 (declare (ignore num1
))
1439 (with-all-children (*root-frame
* c
)
1440 (unless (child-equal-p child c
))
1441 (multiple-value-bind (num2 name2
)
1442 (extract-number-from-name (child-name c
))
1443 (when (string-equal name1 name2
)
1446 (when (> (length acc
) 1)
1447 (setf (child-name child
)
1448 (format nil
"~A.~A" name1
1449 (1+ (find-free-number (loop for i in acc when i collect
(1- i
)))))))))))
1450 (leave-second-mode))
1452 (defun ensure-unique-number ()
1453 "Ensure that all children numbers are unique"
1455 (with-all-frames (*root-frame
* frame
)
1456 (setf (frame-number frame
) (incf num
))))
1457 (leave-second-mode))
1461 ;;; Standard menu functions - Based on the XDG specifications
1462 (defun um-create-xdg-section-list (menu)
1463 (dolist (section *xdg-section-list
*)
1464 (add-sub-menu menu
:next section
(format nil
"~A" section
) menu
))
1465 (unless (find-toplevel-menu 'Utility menu
)
1466 (add-sub-menu menu
:next
'Utility
(format nil
"~A" 'Utility
) menu
)))
1468 (defun um-find-submenu (menu section-list
)
1470 (dolist (section section-list
)
1471 (awhen (find-toplevel-menu (intern (string-upcase section
) :clfswm
) menu
)
1475 (list (find-toplevel-menu 'Utility menu
)))))
1478 (defun um-extract-value (line)
1479 (second (split-string line
#\
=)))
1482 (defun um-add-desktop (desktop menu
)
1483 (let (name exec categories comment
)
1484 (when (probe-file desktop
)
1485 (with-open-file (stream desktop
:direction
:input
)
1486 (loop for line
= (read-line stream nil nil
)
1489 (cond ((first-position "Name=" line
) (setf name
(um-extract-value line
)))
1490 ((first-position "Exec=" line
) (setf exec
(um-extract-value line
)))
1491 ((first-position "Categories=" line
) (setf categories
(um-extract-value line
)))
1492 ((first-position "Comment=" line
) (setf comment
(um-extract-value line
))))
1493 (when (and name exec categories
)
1494 (let* ((sub-menu (um-find-submenu menu
(split-string categories
#\
;)))
1495 (fun-name (intern name
:clfswm
)))
1496 (setf (symbol-function fun-name
) (let ((do-exec exec
))
1499 (leave-second-mode)))
1500 (documentation fun-name
'function
) (format nil
"~A~A" name
(if comment
1501 (format nil
" - ~A" comment
)
1503 (dolist (m sub-menu
)
1504 (add-menu-key (menu-name m
) :next fun-name m
)))
1505 (setf name nil exec nil categories nil comment nil
)))))))
1508 (defun update-menus (&optional
(menu (make-menu :name
'main
:doc
"Main menu")))
1509 (um-create-xdg-section-list menu
)
1511 (found (make-hash-table :test
#'equal
)))
1512 (dolist (dir (remove-duplicates
1513 (split-string (or (getenv "XDG_DATA_DIRS") "/usr/local/share/:/usr/share/")
1514 #\
:) :test
#'string-equal
))
1515 (dolist (desktop (directory (concatenate 'string dir
"/applications/**/*.desktop")))
1516 (unless (gethash (file-namestring desktop
) found
)
1517 (setf (gethash (file-namestring desktop
) found
) t
)
1518 (um-add-desktop desktop menu
)
1524 ;;; Close/Kill focused window
1526 (defun ask-close/kill-current-window
()
1527 "Close or kill the current window (ask before doing anything)"
1528 (let ((window (xlib:input-focus
*display
*))
1529 (*info-mode-placement
* *ask-close
/kill-placement
*))
1531 (if (and window
(not (xlib:window-equal window
*no-focus-window
*)))
1532 `(,(format nil
"Focus window: ~A" (xlib:wm-name window
))
1533 (#\s delete-focus-window
"Close the focus window")
1534 (#\k destroy-focus-window
"Kill the focus window")
1535 (#\x cut-focus-window
)
1536 (#\c copy-focus-window
)
1537 (#\v paste-selection
))
1538 `(,(format nil
"Focus window: None")
1539 (#\v paste-selection
))))
1544 ;;; Other window manager functions
1545 (defun get-proc-list ()
1546 (let ((proc (do-shell "ps x -o pid=" nil t
))
1548 (loop for line
= (read-line proc nil nil
)
1550 do
(push line proc-list
))
1554 (defun run-other-window-manager ()
1555 (let ((proc-start (get-proc-list)))
1556 (do-shell *other-window-manager
* nil t
:terminal
)
1557 (let* ((proc-end (get-proc-list))
1558 (proc-diff (set-difference proc-end proc-start
:test
#'equal
)))
1559 (dbg 'killing-sigterm proc-diff
)
1560 (do-shell (format nil
"kill ~{ ~A ~} 2> /dev/null" proc-diff
) nil t
:terminal
)
1561 (dbg 'killing-sigkill proc-diff
)
1562 (do-shell (format nil
"kill -9 ~{ ~A ~} 2> /dev/null" proc-diff
) nil t
:terminal
)
1564 (setf *other-window-manager
* nil
)))
1567 (defun do-run-other-window-manager (window-manager)
1568 (setf *other-window-manager
* window-manager
)
1569 (throw 'exit-main-loop nil
))
1571 (defmacro def-run-other-window-manager
(name &optional definition
)
1572 (let ((definition (or definition name
)))
1573 `(defun ,(create-symbol "run-" name
) ()
1574 ,(format nil
"Run ~A" definition
)
1575 (do-run-other-window-manager ,(format nil
"~A" name
)))))
1577 (def-run-other-window-manager "xterm")
1578 (def-run-other-window-manager "icewm")
1579 (def-run-other-window-manager "twm")
1580 (def-run-other-window-manager "gnome-session" "Gnome")
1581 (def-run-other-window-manager "startkde" "KDE")
1582 (def-run-other-window-manager "xfce4-session" "XFCE")
1586 (do-run-other-window-manager "( lxsession & ); xterm -e \"echo ' /----------------------------------\\' ; echo ' | CLFSWM Note: |' ; echo ' | Close this window when done. |' ; echo ' \\----------------------------------/'; echo; echo; $SHELL\""))
1590 (do-run-other-window-manager "( xfce4-session &) ; xterm -e \"echo ' /----------------------------------\\' ; echo ' | CLFSWM Note: |' ; echo ' | Close this window when done. |' ; echo ' \\----------------------------------/'; echo; echo; $SHELL\""))
1593 (defun run-prompt-wm ()
1594 "Prompt for an other window manager"
1595 (let ((wm (query-string "Run an other window manager:" "icewm")))
1596 (do-run-other-window-manager wm
)))
1599 ;;; Hide or show unmanaged windows utility.
1600 (defun set-hide-unmanaged-window ()
1601 "Hide unmanaged windows when frame is not selected"
1602 (when (frame-p (current-child))
1603 (setf (frame-data-slot (current-child) :unmanaged-window-action
) :hide
)
1604 (leave-second-mode)))
1606 (defun set-show-unmanaged-window ()
1607 "Show unmanaged windows when frame is not selected"
1608 (when (frame-p (current-child))
1609 (setf (frame-data-slot (current-child) :unmanaged-window-action
) :show
)
1610 (leave-second-mode)))
1612 (defun set-default-hide-unmanaged-window ()
1613 "Set default behaviour to hide or not unmanaged windows when frame is not selected"
1614 (when (frame-p (current-child))
1615 (setf (frame-data-slot (current-child) :unmanaged-window-action
) nil
)
1616 (leave-second-mode)))
1618 (defun set-globally-hide-unmanaged-window ()
1619 "Hide unmanaged windows by default. This is overriden by functions above"
1620 (setf *hide-unmanaged-window
* t
)
1621 (leave-second-mode))
1623 (defun set-globally-show-unmanaged-window ()
1624 "Show unmanaged windows by default. This is overriden by functions above"
1625 (setf *hide-unmanaged-window
* nil
)
1626 (leave-second-mode))
1629 ;;; Speed mouse movement.
1630 (let (minx miny maxx maxy history lx ly
)
1631 (labels ((middle (x1 x2
)
1632 (round (/ (+ x1 x2
) 2)))
1633 (reset-if-moved (x y
)
1634 (when (or (/= x
(or lx x
)) (/= y
(or ly y
)))
1635 (speed-mouse-reset)))
1636 (add-in-history (x y
)
1637 (push (list x y
) history
)))
1638 (defun speed-mouse-reset ()
1639 "Reset speed mouse coordinates"
1640 (setf minx nil miny nil maxx nil maxy nil history nil lx nil ly nil
))
1641 (defun speed-mouse-left ()
1642 "Speed move mouse to left"
1644 (reset-if-moved x y
)
1646 (add-in-history x y
)
1647 (setf lx
(middle (or minx
0) maxx
))
1648 (xlib:warp-pointer
*root
* lx y
)))
1649 (defun speed-mouse-right ()
1650 "Speed move mouse to right"
1652 (reset-if-moved x y
)
1654 (add-in-history x y
)
1655 (setf lx
(middle minx
(or maxx
(xlib:screen-width
*screen
*))))
1656 (xlib:warp-pointer
*root
* lx y
)))
1657 (defun speed-mouse-up ()
1658 "Speed move mouse to up"
1660 (reset-if-moved x y
)
1662 (add-in-history x y
)
1663 (setf ly
(middle (or miny
0) maxy
))
1664 (xlib:warp-pointer
*root
* x ly
)))
1665 (defun speed-mouse-down ()
1666 "Speed move mouse to down"
1668 (reset-if-moved x y
)
1670 (add-in-history x y
)
1671 (setf ly
(middle miny
(or maxy
(xlib:screen-height
*screen
*))))
1672 (xlib:warp-pointer
*root
* x ly
)))
1673 (defun speed-mouse-undo ()
1674 "Undo last speed mouse move"
1676 (let ((h (pop history
)))
1678 (destructuring-bind (bx by
) h
1682 (xlib:warp-pointer
*root
* lx ly
))))))
1683 (defun speed-mouse-first-history ()
1684 "Revert to the first speed move mouse"
1686 (let ((h (first (last history
))))
1690 (xlib:warp-pointer
*root
* lx ly
)))))))
1694 ;;; Notify window functions
1701 (labels ((text-string (tx)
1706 (get-color (typecase tx
1708 (t *notify-window-foreground
*)))))
1709 (defun is-notify-window-p (win)
1710 (when (and (xlib:window-p win
) (xlib:window-p window
))
1711 (xlib:window-equal win window
)))
1713 (defun raise-notify-window ()
1714 (raise-window window
))
1716 (defun refresh-notify-window ()
1717 (add-timer 0.1 #'refresh-notify-window
:refresh-notify-window
)
1718 (when (and window gc font
)
1719 (raise-window window
)
1720 (let ((text-height (- (xlib:font-ascent font
) (xlib:font-descent font
))))
1721 (loop for tx in text
1723 (setf (xlib:gcontext-foreground gc
) (text-color tx
))
1724 (xlib:draw-glyphs window gc
1725 (truncate (/ (- width
(* (xlib:max-char-width font
) (length (text-string tx
)))) 2))
1727 (text-string tx
))))))
1729 (defun close-notify-window ()
1730 (erase-timer :refresh-notify-window
)
1731 (setf *never-managed-window-list
*
1732 (remove (list #'is-notify-window-p
'raise-window
)
1733 *never-managed-window-list
* :test
#'equal
))
1735 (xlib:free-gcontext gc
))
1737 (xlib:destroy-window window
))
1739 (xlib:close-font font
))
1740 (xlib:display-finish-output
*display
*)
1745 (defun open-notify-window (text-list)
1746 (close-notify-window)
1747 (setf font
(xlib:open-font
*display
* *notify-window-font-string
*))
1748 (let ((text-height (- (xlib:font-ascent font
) (xlib:font-descent font
))))
1749 (setf text text-list
)
1750 (setf width
(* (xlib:max-char-width font
) (+ (loop for tx in text-list
1751 maximize
(length (text-string tx
))) 2))
1752 height
(+ (* text-height
(length text-list
) 2) text-height
))
1753 (with-placement (*notify-window-placement
* x y width height
)
1754 (setf window
(xlib:create-window
:parent
*root
*
1759 :background
(get-color *notify-window-background
*)
1760 :border-width
*border-size
*
1761 :border
(get-color *notify-window-border
*)
1762 :colormap
(xlib:screen-default-colormap
*screen
*)
1763 :event-mask
'(:exposure
:key-press
))
1764 gc
(xlib:create-gcontext
:drawable window
1765 :foreground
(get-color *notify-window-foreground
*)
1766 :background
(get-color *notify-window-background
*)
1768 :line-style
:solid
))
1769 (setf (window-transparency window
) *notify-window-transparency
*)
1770 (when (frame-p (current-child))
1771 (setf current-child
(current-child)))
1772 (add-in-never-managed-window-list (list 'is-notify-window-p
'raise-window
))
1774 (refresh-notify-window)
1775 (xlib:display-finish-output
*display
*))))))
1777 (defun notify-message (delay &rest messages
)
1778 (erase-timer :close-notify-window
)
1779 (funcall #'open-notify-window messages
)
1780 (add-timer delay
#'close-notify-window
:close-notify-window
))
1783 (defun display-hello-window ()
1784 (notify-message *notify-window-delay
*
1785 '("Welcome to CLFSWM" "yellow")
1786 "Press Alt+F1 for help"))
1789 ;;; Run or raise functions
1790 (defun run-or-raise (raisep run-fn
&key
(maximized nil
))
1791 (let ((window (with-all-windows (*root-frame
* win
)
1792 (when (funcall raisep win
)
1795 (let ((parent (find-parent-frame window
)))
1796 (setf (current-child) parent
)
1797 (put-child-on-top window parent
)
1799 (change-root (find-root parent
) parent
))
1800 (focus-all-children window parent
)
1801 (show-all-children t
))
1804 ;;; Transparency setting
1805 (defun inc-transparency (window root-x root-y
)
1806 "Increment the child under mouse transparency"
1807 (declare (ignore root-x root-y
))
1808 (unless *in-second-mode
* (stop-button-event))
1809 (incf (child-transparency window
) 0.1))
1811 (defun dec-transparency (window root-x root-y
)
1812 "Decrement the child under mouse transparency"
1813 (declare (ignore root-x root-y
))
1814 (unless *in-second-mode
* (stop-button-event))
1815 (decf (child-transparency window
) 0.1))
1817 (defun inc-transparency-slow (window root-x root-y
)
1818 "Increment slowly the child under mouse transparency"
1819 (declare (ignore root-x root-y
))
1820 (unless *in-second-mode
* (stop-button-event))
1821 (incf (child-transparency window
) 0.01))
1823 (defun dec-transparency-slow (window root-x root-y
)
1824 "Decrement slowly the child under mouse transparency"
1825 (declare (ignore root-x root-y
))
1826 (unless *in-second-mode
* (stop-button-event))
1827 (decf (child-transparency window
) 0.01))
1830 (defun key-inc-transparency ()
1831 "Increment the current window transparency"
1832 (with-current-window
1833 (incf (child-transparency window
) 0.1)))
1835 (defun key-dec-transparency ()
1836 "Decrement the current window transparency"
1837 (with-current-window
1838 (decf (child-transparency window
) 0.1)))
1844 ;;; Geometry change functions
1845 (defun swap-frame-geometry ()
1846 "Swap current brother frame geometry"
1847 (when (frame-p (current-child))
1848 (let ((parent (find-parent-frame (current-child))))
1849 (when (frame-p parent
)
1850 (let ((brother (second (frame-child parent
))))
1851 (when (frame-p brother
)
1852 (rotatef (frame-x (current-child)) (frame-x brother
))
1853 (rotatef (frame-y (current-child)) (frame-y brother
))
1854 (rotatef (frame-w (current-child)) (frame-w brother
))
1855 (rotatef (frame-h (current-child)) (frame-h brother
))
1856 (show-all-children t
)
1857 (leave-second-mode)))))))
1859 (defun rotate-frame-geometry-generic (fun)
1860 "(Rotate brother frame geometry"
1861 (when (frame-p (current-child))
1862 (let ((parent (find-parent-frame (current-child))))
1863 (when (frame-p parent
)
1864 (let* ((child-list (funcall fun
(frame-child parent
)))
1865 (first (first child-list
)))
1866 (dolist (child (rest child-list
))
1867 (when (and (frame-p first
) (frame-p child
))
1868 (rotatef (frame-x first
) (frame-x child
))
1869 (rotatef (frame-y first
) (frame-y child
))
1870 (rotatef (frame-w first
) (frame-w child
))
1871 (rotatef (frame-h first
) (frame-h child
))
1872 (setf first child
)))
1873 (show-all-children t
))))))
1876 (defun rotate-frame-geometry ()
1877 "Rotate brother frame geometry"
1878 (rotate-frame-geometry-generic #'identity
))
1880 (defun anti-rotate-frame-geometry ()
1881 "Anti rotate brother frame geometry"
1882 (rotate-frame-geometry-generic #'reverse
))