1 ;;; --------------------------------------------------------------------------
2 ;;; CLFSWM - FullScreen Window Manager
4 ;;; --------------------------------------------------------------------------
5 ;;; Documentation: Utility
6 ;;; --------------------------------------------------------------------------
8 ;;; (C) 2010 Philippe Brochard <hocwp@free.fr>
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 (pathname-directory (concatenate 'string
(or (getenv "XDG_CONFIG_HOME")
35 (let ((saved-conf-name nil
))
36 (defun conf-file-name (&optional alternate-name
)
37 (unless (and saved-conf-name
(not alternate-name
))
38 (let* ((user-conf (probe-file (merge-pathnames (user-homedir-pathname) #p
".clfswmrc")))
39 (etc-conf (probe-file #p
"/etc/clfswmrc"))
40 (config-user-conf (probe-file (make-pathname :directory
(append (xdg-config-home) '("clfswm"))
42 (alternate-conf (and alternate-name
(probe-file alternate-name
))))
43 (setf saved-conf-name
(or alternate-conf config-user-conf user-conf etc-conf
))))
44 (print saved-conf-name
)
50 (defun load-contrib (file)
51 "Load a file in the contrib directory"
52 (let ((truename (concatenate 'string
*contrib-dir
* "contrib/" file
)))
53 (format t
"Loading contribution file: ~A~%" truename
)
54 (when (probe-file truename
)
55 (load truename
:verbose nil
))))
58 (defun reload-clfswm ()
60 (format t
"~&-*- Reloading CLFSWM -*-~%")
61 (asdf:oos
'asdf
:load-op
:clfswm
)
67 (defun rename-current-child ()
68 "Rename the current child"
69 (let ((name (query-string (format nil
"New child name: (last: ~A)" (child-name *current-child
*))
70 (child-name *current-child
*))))
71 (rename-child *current-child
* name
)
75 (defun renumber-current-frame ()
76 "Renumber the current frame"
77 (when (frame-p *current-child
*)
78 (let ((number (query-number (format nil
"New child number: (last: ~A)" (frame-number *current-child
*))
79 (frame-number *current-child
*))))
80 (setf (frame-number *current-child
*) number
)
81 (leave-second-mode))))
86 (defun add-default-frame ()
87 "Add a default frame in the current frame"
88 (when (frame-p *current-child
*)
89 (let ((name (query-string "Frame name")))
90 (push (create-frame :name name
) (frame-child *current-child
*))))
94 (defun add-placed-frame ()
95 "Add a placed frame in the current frame"
96 (when (frame-p *current-child
*)
97 (let ((name (query-string "Frame name"))
98 (x (/ (query-number "Frame x in percent (%)") 100))
99 (y (/ (query-number "Frame y in percent (%)") 100))
100 (w (/ (query-number "Frame width in percent (%)") 100))
101 (h (/ (query-number "Frame height in percent (%)") 100)))
102 (push (create-frame :name name
:x x
:y y
:w w
:h h
)
103 (frame-child *current-child
*))))
108 (defun delete-focus-window-generic (close-fun)
109 (let ((window (xlib:input-focus
*display
*)))
110 (when (and window
(not (xlib:window-equal window
*no-focus-window
*)))
111 (when (equal window
*current-child
*)
112 (setf *current-child
* *current-root
*))
114 (delete-child-and-children-in-all-frames window close-fun
)
115 (show-all-children))))
117 (defun delete-focus-window ()
118 "Close focus window: Delete the focus window in all frames and workspaces"
119 (delete-focus-window-generic 'delete-window
))
121 (defun destroy-focus-window ()
122 "Kill focus window: Destroy the focus window in all frames and workspaces"
123 (delete-focus-window-generic 'destroy-window
))
125 (defun remove-focus-window ()
126 "Remove the focus window from the current frame"
127 (let ((window (xlib:input-focus
*display
*)))
128 (when (and window
(not (xlib:window-equal window
*no-focus-window
*)))
129 (setf *current-child
* *current-root
*)
131 (remove-child-in-frame window
(find-parent-frame window
))
132 (show-all-children))))
135 (defun unhide-all-windows-in-current-child ()
136 "Unhide all hidden windows into the current child"
138 (dolist (window (get-hidden-windows))
139 (unhide-window window
)
140 (process-new-window window
)
141 (map-window window
)))
147 (defun find-window-under-mouse (x y
)
148 "Return the child window under the mouse"
151 (with-all-windows-frames-and-parent (*current-root
* child parent
)
152 (when (and (or (managed-window-p child parent
) (equal parent
*current-child
*))
153 (<= (xlib:drawable-x child
) x
(+ (xlib:drawable-x child
) (xlib:drawable-width child
)))
154 (<= (xlib:drawable-y child
) y
(+ (xlib:drawable-y child
) (xlib:drawable-height child
))))
156 (when (and (<= (frame-rx child
) x
(+ (frame-rx child
) (frame-rw child
)))
157 (<= (frame-ry child
) y
(+ (frame-ry child
) (frame-rh child
))))
158 (setf win
(frame-window child
))))
162 (defun find-child-under-mouse (x y
&optional first-foundp
)
163 "Return the child under the mouse"
166 (with-all-windows-frames-and-parent (*current-root
* child parent
)
167 (when (and (or (managed-window-p child parent
) (equal parent
*current-child
*))
168 (<= (xlib:drawable-x child
) x
(+ (xlib:drawable-x child
) (xlib:drawable-width child
)))
169 (<= (xlib:drawable-y child
) y
(+ (xlib:drawable-y child
) (xlib:drawable-height child
))))
171 (return-from find-child-under-mouse child
)
173 (when (and (<= (frame-rx child
) x
(+ (frame-rx child
) (frame-rw child
)))
174 (<= (frame-ry child
) y
(+ (frame-ry child
) (frame-rh child
))))
176 (return-from find-child-under-mouse child
)
185 ;;; Selection functions
186 (defun clear-selection ()
187 "Clear the current selection"
188 (setf *child-selection
* nil
)
189 (display-frame-info *current-root
*))
191 (defun copy-current-child ()
192 "Copy the current child to the selection"
193 (pushnew *current-child
* *child-selection
*)
194 (display-frame-info *current-root
*))
197 (defun cut-current-child ()
198 "Cut the current child to the selection"
200 (hide-all *current-child
*)
201 (remove-child-in-frame *current-child
* (find-parent-frame *current-child
* *current-root
*))
202 (setf *current-child
* *current-root
*)
205 (defun remove-current-child ()
206 "Remove the current child from its parent frame"
207 (hide-all *current-child
*)
208 (remove-child-in-frame *current-child
* (find-parent-frame *current-child
* *current-root
*))
209 (setf *current-child
* *current-root
*)
212 (defun delete-current-child ()
213 "Delete the current child and its children in all frames"
214 (hide-all *current-child
*)
215 (delete-child-and-children-in-all-frames *current-child
*)
219 (defun paste-selection-no-clear ()
220 "Paste the selection in the current frame - Do not clear the selection after paste"
221 (let ((frame-dest (typecase *current-child
*
222 (xlib:window
(find-parent-frame *current-child
* *current-root
*))
223 (frame *current-child
*))))
225 (dolist (child *child-selection
*)
226 (unless (find-child-in-parent child frame-dest
)
227 (pushnew child
(frame-child frame-dest
))))
228 (show-all-children))))
230 (defun paste-selection ()
231 "Paste the selection in the current frame"
232 (paste-selection-no-clear)
233 (setf *child-selection
* nil
)
234 (display-frame-info *current-root
*))
239 ;;; Maximize function
240 (defun frame-toggle-maximize ()
241 "Maximize/Unmaximize the current frame in its parent frame"
242 (when (frame-p *current-child
*)
243 (let ((unmaximized-coords (frame-data-slot *current-child
* :unmaximized-coords
)))
244 (if unmaximized-coords
245 (with-slots (x y w h
) *current-child
*
246 (destructuring-bind (nx ny nw nh
) unmaximized-coords
247 (setf (frame-data-slot *current-child
* :unmaximized-coords
) nil
248 x nx y ny w nw h nh
)))
249 (with-slots (x y w h
) *current-child
*
250 (setf (frame-data-slot *current-child
* :unmaximized-coords
)
253 (show-all-children (find-parent-frame *current-child
*))
254 (leave-second-mode)))
264 ;;; CONFIG - Identify mode
265 (defun identify-key ()
268 (font (xlib:open-font
*display
* *identify-font-string
*))
269 (window (xlib:create-window
:parent
*root
*
271 :width
(- (xlib:screen-width
*screen
*) 2)
272 :height
(* 5 (+ (xlib:max-char-ascent font
) (xlib:max-char-descent font
)))
273 :background
(get-color *identify-background
*)
275 :border
(get-color *identify-border
*)
276 :colormap
(xlib:screen-default-colormap
*screen
*)
277 :event-mask
'(:exposure
)))
278 (gc (xlib:create-gcontext
:drawable window
279 :foreground
(get-color *identify-foreground
*)
280 :background
(get-color *identify-background
*)
282 :line-style
:solid
)))
283 (labels ((print-doc (msg hash-table-key pos code state
)
284 (let ((function (find-key-from-code hash-table-key code state
)))
285 (when (and function
(fboundp (first function
)))
286 (xlib:draw-glyphs
*pixmap-buffer
* gc
10 (+ (* pos
(+ (xlib:max-char-ascent font
) (xlib:max-char-descent font
))) 5)
287 (format nil
"~A ~A" msg
(documentation (first function
) 'function
))))))
288 (print-key (code state keysym key modifiers
)
289 (clear-pixmap-buffer window gc
)
290 (setf (xlib:gcontext-foreground gc
) (get-color *identify-foreground
*))
291 (xlib:draw-glyphs
*pixmap-buffer
* gc
5 (+ (xlib:max-char-ascent font
) 5)
292 (format nil
"Press a key to identify. Press 'q' to stop the identify loop."))
294 (xlib:draw-glyphs
*pixmap-buffer
* gc
10 (+ (* 2 (+ (xlib:max-char-ascent font
) (xlib:max-char-descent font
))) 5)
295 (format nil
"Code=~A KeySym=~S Key=~S Modifiers=~A"
296 code keysym key modifiers
))
297 (print-doc "Main mode : " *main-keys
* 3 code state
)
298 (print-doc "Second mode: " *second-keys
* 4 code state
))
299 (copy-pixmap-buffer window gc
))
300 (handle-identify-key (&rest event-slots
&key root code state
&allow-other-keys
)
301 (declare (ignore event-slots root
))
302 (let* ((modifiers (state->modifiers state
))
303 (key (keycode->char code state
))
304 (keysym (keysym->keysym-name
(keycode->keysym code modifiers
))))
305 (setf done
(and (equal key
#\q
) (equal modifiers
*default-modifiers
*)))
306 (dbg code keysym key modifiers
)
307 (print-key code state keysym key modifiers
)
309 (handle-identify (&rest event-slots
&key display event-key
&allow-other-keys
)
310 (declare (ignore display
))
312 (:key-press
(apply #'handle-identify-key event-slots
) t
)
313 (:exposure
(print-key nil nil nil nil nil
)))
315 (xgrab-pointer *root
* 92 93)
317 (format t
"~&Press 'q' to stop the identify loop~%")
318 (print-key nil nil nil nil nil
)
322 (xlib:display-finish-output
*display
*)
323 (xlib:process-event
*display
* :handler
#'handle-identify
:timeout
*loop-timeout
*))
324 (xlib:destroy-window window
)
325 (xlib:close-font font
)
326 (xgrab-pointer *root
* 66 67)))))
333 (defun eval-from-query-string ()
334 "Eval a lisp form from the query input"
335 (let ((form (query-string "Eval:"))
337 (when (and form
(not (equal form
"")))
338 (let ((printed-result
339 (with-output-to-string (*standard-output
*)
340 (setf result
(handler-case
341 (loop for i in
(multiple-value-list
342 (eval (read-from-string form
)))
343 collect
(format nil
"~S" i
))
345 (format nil
"~A" condition
)))))))
346 (info-mode (expand-newline (append (ensure-list (format nil
"> ~A" form
))
347 (ensure-list printed-result
)
348 (ensure-list result
)))
349 :width
(- (xlib:screen-width
*screen
*) 2))
350 (eval-from-query-string)))))
355 (defun run-program-from-query-string ()
356 "Run a program from the query input"
357 (multiple-value-bind (program return
)
358 (query-string "Run:")
359 (when (and (equal return
:return
) program
(not (equal program
"")))
360 (setf *second-mode-program
* program
)
361 (leave-second-mode))))
366 ;;; Frame name actions
367 (defun ask-frame-name (msg)
369 (let ((all-frame-name nil
)
371 (with-all-frames (*root-frame
* frame
)
372 (awhen (frame-name frame
) (push it all-frame-name
)))
373 (labels ((selected-names ()
374 (loop :for str
:in all-frame-name
375 :when
(zerop (or (search name str
:test
#'string-equal
) -
1))
377 (complet-alone (req sel
)
378 (if (= 1 (length sel
)) (first sel
) req
))
380 (let* ((selected (selected-names))
381 (default (complet-alone name selected
)))
382 (multiple-value-bind (str done
)
383 (query-string (format nil
"~A: ~{~A~^, ~}" msg selected
) default
)
385 (when (or (not (string-equal name default
)) (eql done
:complet
))
392 ;;; Focus by functions
393 (defun focus-frame-by (frame)
394 (when (frame-p frame
)
395 (hide-all *current-root
*)
396 (focus-all-children frame
(or (find-parent-frame frame
*current-root
*)
397 (find-parent-frame frame
)
399 (show-all-children *current-root
*)))
402 (defun focus-frame-by-name ()
403 "Focus a frame by name"
404 (focus-frame-by (find-frame-by-name (ask-frame-name "Focus frame")))
407 (defun focus-frame-by-number ()
408 "Focus a frame by number"
409 (focus-frame-by (find-frame-by-number (query-number "Focus frame by number:")))
413 ;;; Open by functions
414 (defun open-frame-by (frame)
415 (when (frame-p frame
)
416 (push (create-frame :name
(query-string "Frame name")) (frame-child frame
))
417 (show-all-children *current-root
*)))
421 (defun open-frame-by-name ()
422 "Open a new frame in a named frame"
423 (open-frame-by (find-frame-by-name (ask-frame-name "Open a new frame in")))
426 (defun open-frame-by-number ()
427 "Open a new frame in a numbered frame"
428 (open-frame-by (find-frame-by-number (query-number "Open a new frame in the group numbered:")))
432 ;;; Delete by functions
433 (defun delete-frame-by (frame)
434 (hide-all *current-root
*)
435 (unless (equal frame
*root-frame
*)
436 (when (equal frame
*current-root
*)
437 (setf *current-root
* *root-frame
*))
438 (when (equal frame
*current-child
*)
439 (setf *current-child
* *current-root
*))
440 (remove-child-in-frame frame
(find-parent-frame frame
)))
441 (show-all-children *current-root
*))
444 (defun delete-frame-by-name ()
445 "Delete a frame by name"
446 (delete-frame-by (find-frame-by-name (ask-frame-name "Delete frame")))
449 (defun delete-frame-by-number ()
450 "Delete a frame by number"
451 (delete-frame-by (find-frame-by-number (query-number "Delete frame by number:")))
456 (defun move-child-to (child frame-dest
)
457 (when (and child
(frame-p frame-dest
))
458 (hide-all *current-root
*)
459 (remove-child-in-frame child
(find-parent-frame child
))
460 (pushnew child
(frame-child frame-dest
))
461 (focus-all-children child frame-dest
)
462 (show-all-children *current-root
*)))
464 (defun move-current-child-by-name ()
465 "Move current child in a named frame"
466 (move-child-to *current-child
*
468 (ask-frame-name (format nil
"Move '~A' to frame" (child-name *current-child
*)))))
471 (defun move-current-child-by-number ()
472 "Move current child in a numbered frame"
473 (move-child-to *current-child
*
474 (find-frame-by-number
475 (query-number (format nil
"Move '~A' to frame numbered:" (child-name *current-child
*)))))
480 (defun copy-child-to (child frame-dest
)
481 (when (and child
(frame-p frame-dest
))
482 (hide-all *current-root
*)
483 (pushnew child
(frame-child frame-dest
))
484 (focus-all-children child frame-dest
)
485 (show-all-children *current-root
*)))
487 (defun copy-current-child-by-name ()
488 "Copy current child in a named frame"
489 (copy-child-to *current-child
*
491 (ask-frame-name (format nil
"Copy '~A' to frame" (child-name *current-child
*)))))
494 (defun copy-current-child-by-number ()
495 "Copy current child in a numbered frame"
496 (copy-child-to *current-child
*
497 (find-frame-by-number
498 (query-number (format nil
"Copy '~A' to frame numbered:" (child-name *current-child
*)))))
505 (defun show-all-frames-info ()
506 "Show all frames info windows"
507 (let ((*show-root-frame-p
* t
))
509 (with-all-frames (*current-root
* frame
)
510 (raise-window (frame-window frame
))
511 (display-frame-info frame
))))
513 (defun hide-all-frames-info ()
514 "Hide all frames info windows"
515 (with-all-windows (*current-root
* window
)
516 (raise-window window
))
517 (hide-child *current-root
*)
520 (defun show-all-frames-info-key ()
521 "Show all frames info windows until a key is release"
522 (show-all-frames-info)
523 (wait-no-key-or-button-press)
524 (hide-all-frames-info))
531 (defun move-frame (frame parent orig-x orig-y
)
532 (when (and frame parent
)
533 (hide-all-children frame
)
534 (with-slots (window) frame
535 (move-window window orig-x orig-y
#'display-frame-info
(list frame
))
536 (setf (frame-x frame
) (x-px->fl
(xlib:drawable-x window
) parent
)
537 (frame-y frame
) (y-px->fl
(xlib:drawable-y window
) parent
)))
538 (show-all-children frame
)))
541 (defun resize-frame (frame parent orig-x orig-y
)
542 (when (and frame parent
)
543 (hide-all-children frame
)
544 (with-slots (window) frame
545 (resize-window window orig-x orig-y
#'display-frame-info
(list frame
))
546 (setf (frame-w frame
) (w-px->fl
(xlib:drawable-width window
) parent
)
547 (frame-h frame
) (h-px->fl
(xlib:drawable-height window
) parent
)))
548 (show-all-children frame
)))
552 (defun mouse-click-to-focus-generic (window root-x root-y mouse-fn
)
553 "Focus the current frame or focus the current window parent
554 mouse-fun is #'move-frame or #'resize-frame"
556 (child (find-child-under-mouse root-x root-y
))
557 (parent (find-parent-frame child
))
558 (root-p (or (equal window
*root
*)
559 (and (frame-p *current-root
*)
560 (equal child
(frame-window *current-root
*))))))
561 (labels ((add-new-frame ()
562 (setf child
(create-frame)
563 parent
*current-root
*
564 mouse-fn
#'resize-frame
)
565 (place-frame child parent root-x root-y
10 10)
566 (map-window (frame-window child
))
567 (pushnew child
(frame-child *current-root
*))))
568 (when (or (not root-p
) *create-frame-on-root
*)
573 (unless (equal (type-of child
) 'frame
)
574 (setf child
(find-frame-window child
*current-root
*)))
575 (setf parent
(find-parent-frame child
)))))
576 (when (equal (type-of child
) 'frame
)
577 (funcall mouse-fn child parent root-x root-y
))
578 (when (and child parent
(focus-all-children child parent
))
579 (when (show-all-children *current-root
*)
580 (setf to-replay nil
))))
582 (replay-button-event)
583 (stop-button-event)))))
586 (defun mouse-click-to-focus-and-move (window root-x root-y
)
587 "Move and focus the current frame or focus the current window parent.
588 Or do actions on corners"
589 (or (do-corner-action root-x root-y
*corner-main-mode-left-button
*)
590 (mouse-click-to-focus-generic window root-x root-y
#'move-frame
)))
592 (defun mouse-click-to-focus-and-resize (window root-x root-y
)
593 "Resize and focus the current frame or focus the current window parent.
594 Or do actions on corners"
595 (or (do-corner-action root-x root-y
*corner-main-mode-right-button
*)
596 (mouse-click-to-focus-generic window root-x root-y
#'resize-frame
)))
598 (defun mouse-middle-click (window root-x root-y
)
599 "Do actions on corners"
600 (declare (ignore window
))
601 (or (do-corner-action root-x root-y
*corner-main-mode-middle-button
*)
602 (replay-button-event)))
607 (defun mouse-focus-move/resize-generic
(root-x root-y mouse-fn window-parent
)
608 "Focus the current frame or focus the current window parent
609 mouse-fun is #'move-frame or #'resize-frame.
610 Focus child and its parents -
611 For window: set current child to window or its parent according to window-parent"
612 (let* ((child (find-child-under-mouse root-x root-y
))
613 (parent (find-parent-frame child
)))
614 (when (and (equal child
*current-root
*)
615 (frame-p *current-root
*))
616 (setf child
(create-frame)
617 parent
*current-root
*
618 mouse-fn
#'resize-frame
)
619 (place-frame child parent root-x root-y
10 10)
620 (map-window (frame-window child
))
621 (pushnew child
(frame-child *current-root
*)))
624 (if (managed-window-p child parent
)
625 (funcall mouse-fn parent
(find-parent-frame parent
) root-x root-y
)
626 (funcall(cond ((eql mouse-fn
#'move-frame
) #'move-window
)
627 ((eql mouse-fn
#'resize-frame
) #'resize-window
))
628 child root-x root-y
)))
629 (frame (funcall mouse-fn child parent root-x root-y
)))
630 (focus-all-children child parent window-parent
)
631 (show-all-children *current-root
*)))
636 (defun test-mouse-binding (window root-x root-y
)
637 (dbg window root-x root-y
)
638 (replay-button-event))
642 (defun mouse-select-next-level (window root-x root-y
)
643 "Select the next level in frame"
644 (declare (ignore root-x root-y
))
645 (let ((frame (find-frame-window window
)))
646 (when (or frame
(xlib:window-equal window
*root
*))
648 (replay-button-event)))
652 (defun mouse-select-previous-level (window root-x root-y
)
653 "Select the previous level in frame"
654 (declare (ignore root-x root-y
))
655 (let ((frame (find-frame-window window
)))
656 (when (or frame
(xlib:window-equal window
*root
*))
657 (select-previous-level))
658 (replay-button-event)))
662 (defun mouse-enter-frame (window root-x root-y
)
663 "Enter in the selected frame - ie make it the root frame"
664 (declare (ignore root-x root-y
))
665 (let ((frame (find-frame-window window
)))
666 (when (or frame
(xlib:window-equal window
*root
*))
668 (replay-button-event)))
672 (defun mouse-leave-frame (window root-x root-y
)
673 "Leave the selected frame - ie make its parent the root frame"
674 (declare (ignore root-x root-y
))
675 (let ((frame (find-frame-window window
)))
676 (when (or frame
(xlib:window-equal window
*root
*))
678 (replay-button-event)))
683 ;;;;;| Various definitions
686 (defun show-help (&optional
(browser "dillo") (tempfile "/tmp/clfswm.html"))
687 "Show current keys and buttons bindings"
689 (produce-doc-html-in-file tempfile
))
691 (do-shell (format nil
"~A ~A" browser tempfile
)))
695 ;;; Bind or jump functions
696 (let ((key-slots (make-array 10 :initial-element nil
))
698 (defun bind-on-slot ()
699 "Bind current child to slot"
700 (setf (aref key-slots current-slot
) *current-child
*))
702 (defun remove-binding-on-slot ()
703 "Remove binding on slot"
704 (setf (aref key-slots current-slot
) nil
))
706 (defun jump-to-slot ()
708 (let ((jump-child (aref key-slots current-slot
)))
709 (when (find-child jump-child
*root-frame
*)
710 (hide-all *current-root
*)
711 (setf *current-root
* jump-child
712 *current-child
* *current-root
*)
713 (focus-all-children *current-child
* *current-child
*)
714 (show-all-children *current-root
*))))
716 (defun bind-or-jump (n)
717 "Bind or jump to a slot (a frame or a window)"
718 (setf current-slot
(- n
1))
719 (let ((default-bind `("b" bind-on-slot
720 ,(format nil
"Bind slot ~A on child: ~A" n
(child-fullname *current-child
*)))))
721 (info-mode-menu (aif (aref key-slots current-slot
)
723 ("BackSpace" remove-binding-on-slot
724 ,(format nil
"Remove slot ~A binding on child: ~A" n
(child-fullname *current-child
*)))
727 ,(format nil
"Jump to child: ~A" (aif (aref key-slots current-slot
)
729 "Not set - Please, bind it with 'b'")))
730 ("Return" jump-to-slot
"Same thing")
731 ("space" jump-to-slot
"Same thing"))
732 (list default-bind
))))))
736 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
737 ;;; Useful function for the second mode ;;;
738 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
739 (defmacro with-movement
(&body body
)
740 `(when (frame-p *current-child
*)
743 (display-all-frame-info)
744 (draw-second-mode-window)
745 (open-menu (find-menu 'frame-movement-menu
))))
749 (defun current-frame-pack-up ()
750 "Pack the current frame up"
751 (with-movement (pack-frame-up *current-child
* (find-parent-frame *current-child
* *current-root
*))))
753 (defun current-frame-pack-down ()
754 "Pack the current frame down"
755 (with-movement (pack-frame-down *current-child
* (find-parent-frame *current-child
* *current-root
*))))
757 (defun current-frame-pack-left ()
758 "Pack the current frame left"
759 (with-movement (pack-frame-left *current-child
* (find-parent-frame *current-child
* *current-root
*))))
761 (defun current-frame-pack-right ()
762 "Pack the current frame right"
763 (with-movement (pack-frame-right *current-child
* (find-parent-frame *current-child
* *current-root
*))))
766 (defun center-current-frame ()
767 "Center the current frame"
768 (with-movement (center-frame *current-child
*)))
771 (defun current-frame-fill-up ()
772 "Fill the current frame up"
773 (with-movement (fill-frame-up *current-child
* (find-parent-frame *current-child
* *current-root
*))))
775 (defun current-frame-fill-down ()
776 "Fill the current frame down"
777 (with-movement (fill-frame-down *current-child
* (find-parent-frame *current-child
* *current-root
*))))
779 (defun current-frame-fill-left ()
780 "Fill the current frame left"
781 (with-movement (fill-frame-left *current-child
* (find-parent-frame *current-child
* *current-root
*))))
783 (defun current-frame-fill-right ()
784 "Fill the current frame right"
785 (with-movement (fill-frame-right *current-child
* (find-parent-frame *current-child
* *current-root
*))))
787 (defun current-frame-fill-all-dir ()
788 "Fill the current frame in all directions"
790 (let ((parent (find-parent-frame *current-child
* *current-root
*)))
791 (fill-frame-up *current-child
* parent
)
792 (fill-frame-down *current-child
* parent
)
793 (fill-frame-left *current-child
* parent
)
794 (fill-frame-right *current-child
* parent
))))
796 (defun current-frame-fill-vertical ()
797 "Fill the current frame vertically"
799 (let ((parent (find-parent-frame *current-child
* *current-root
*)))
800 (fill-frame-up *current-child
* parent
)
801 (fill-frame-down *current-child
* parent
))))
803 (defun current-frame-fill-horizontal ()
804 "Fill the current frame horizontally"
806 (let ((parent (find-parent-frame *current-child
* *current-root
*)))
807 (fill-frame-left *current-child
* parent
)
808 (fill-frame-right *current-child
* parent
))))
812 (defun current-frame-resize-up ()
813 "Resize the current frame up to its half height"
814 (with-movement (resize-half-height-up *current-child
*)))
816 (defun current-frame-resize-down ()
817 "Resize the current frame down to its half height"
818 (with-movement (resize-half-height-down *current-child
*)))
820 (defun current-frame-resize-left ()
821 "Resize the current frame left to its half width"
822 (with-movement (resize-half-width-left *current-child
*)))
824 (defun current-frame-resize-right ()
825 "Resize the current frame right to its half width"
826 (with-movement (resize-half-width-right *current-child
*)))
828 (defun current-frame-resize-all-dir ()
829 "Resize down the current frame"
830 (with-movement (resize-frame-down *current-child
*)))
832 (defun current-frame-resize-all-dir-minimal ()
833 "Resize down the current frame to its minimal size"
834 (with-movement (resize-minimal-frame *current-child
*)))
837 ;;; Children navigation
838 (defun with-movement-select-next-brother ()
839 "Select the next brother frame"
840 (with-movement (select-next-brother)))
842 (defun with-movement-select-previous-brother ()
843 "Select the previous brother frame"
844 (with-movement (select-previous-brother)))
846 (defun with-movement-select-next-level ()
847 "Select the next level"
848 (with-movement (select-next-level)))
850 (defun with-movement-select-previous-level ()
851 "Select the previous levelframe"
852 (with-movement (select-previous-level)))
854 (defun with-movement-select-next-child ()
855 "Select the next child"
856 (with-movement (select-next-child)))
860 ;;; Adapt frame functions
861 (defun adapt-current-frame-to-window-hints-generic (width-p height-p
)
862 "Adapt the current frame to the current window minimal size hints"
863 (when (frame-p *current-child
*)
864 (let ((window (first (frame-child *current-child
*))))
865 (when (xlib:window-p window
)
866 (let* ((hints (xlib:wm-normal-hints window
))
867 (min-width (and hints
(xlib:wm-size-hints-min-width hints
)))
868 (min-height (and hints
(xlib:wm-size-hints-min-height hints
))))
869 (when (and width-p min-width
)
870 (setf (frame-rw *current-child
*) min-width
))
871 (when (and height-p min-height
)
872 (setf (frame-rh *current-child
*) min-height
))
873 (fixe-real-size *current-child
* (find-parent-frame *current-child
*))
874 (leave-second-mode))))))
876 (defun adapt-current-frame-to-window-hints ()
877 "Adapt the current frame to the current window minimal size hints"
878 (adapt-current-frame-to-window-hints-generic t t
))
880 (defun adapt-current-frame-to-window-width-hint ()
881 "Adapt the current frame to the current window minimal width hint"
882 (adapt-current-frame-to-window-hints-generic t nil
))
884 (defun adapt-current-frame-to-window-height-hint ()
885 "Adapt the current frame to the current window minimal height hint"
886 (adapt-current-frame-to-window-hints-generic nil t
))
891 ;;; Managed window type functions
892 (defun current-frame-manage-window-type-generic (type-list)
893 (when (frame-p *current-child
*)
894 (setf (frame-managed-type *current-child
*) type-list
895 (frame-forced-managed-window *current-child
*) nil
896 (frame-forced-unmanaged-window *current-child
*) nil
))
900 (defun current-frame-manage-window-type ()
901 "Change window types to be managed by a frame"
902 (when (frame-p *current-child
*)
903 (let* ((type-str (query-string "Managed window type: (all, normal, transient, maxsize, desktop, dock, toolbar, menu, utility, splash, dialog)"
904 (format nil
"~{~:(~A~) ~}" (frame-managed-type *current-child
*))))
905 (type-list (loop :for type
:in
(split-string type-str
)
906 :collect
(intern (string-upcase type
) :keyword
))))
907 (current-frame-manage-window-type-generic type-list
))))
910 (defun current-frame-manage-all-window-type ()
911 "Manage all window type"
912 (current-frame-manage-window-type-generic '(:all
)))
914 (defun current-frame-manage-only-normal-window-type ()
915 "Manage only normal window type"
916 (current-frame-manage-window-type-generic '(:normal
)))
918 (defun current-frame-manage-no-window-type ()
919 "Do not manage any window type"
920 (current-frame-manage-window-type-generic nil
))
929 ;;; Force window functions
930 (defun force-window-in-frame ()
931 "Force the current window to move in the frame (Useful only for unmanaged windows)"
933 (let ((parent (find-parent-frame window
)))
935 (setf (xlib:drawable-x window
) (frame-rx parent
)
936 (xlib:drawable-y window
) (frame-ry parent
)))))
940 (defun force-window-center-in-frame ()
941 "Force the current window to move in the center of the frame (Useful only for unmanaged windows)"
943 (let ((parent (find-parent-frame window
)))
945 (setf (xlib:drawable-x window
) (truncate (+ (frame-rx parent
)
946 (/ (- (frame-rw parent
)
947 (xlib:drawable-width window
)) 2)))
948 (xlib:drawable-y window
) (truncate (+ (frame-ry parent
)
949 (/ (- (frame-rh parent
)
950 (xlib:drawable-height window
)) 2)))))))
955 (defun display-current-window-info ()
956 "Display information on the current window"
958 (info-mode (list (format nil
"Window: ~A" window
)
959 (format nil
"Window name: ~A" (xlib:wm-name window
))
960 (format nil
"Window class: ~A" (xlib:get-wm-class window
))
961 (format nil
"Window type: ~:(~A~)" (window-type window
))
962 (format nil
"Window id: 0x~X" (xlib:window-id window
)))))
966 (defun manage-current-window ()
967 "Force to manage the current window by its parent frame"
969 (let ((parent (find-parent-frame window
)))
970 (with-slots ((managed forced-managed-window
)
971 (unmanaged forced-unmanaged-window
)) parent
972 (setf unmanaged
(remove window unmanaged
)
973 unmanaged
(remove (xlib:wm-name window
) unmanaged
:test
#'string-equal-p
))
974 (pushnew window managed
))))
977 (defun unmanage-current-window ()
978 "Force to not manage the current window by its parent frame"
980 (let ((parent (find-parent-frame window
)))
981 (with-slots ((managed forced-managed-window
)
982 (unmanaged forced-unmanaged-window
)) parent
983 (setf managed
(remove window managed
)
984 managed
(remove (xlib:wm-name window
) managed
:test
#'string-equal-p
))
985 (pushnew window unmanaged
))))
990 ;;; Moving child with the mouse button
991 (defun mouse-move-child-over-frame (window root-x root-y
)
992 "Move the child under the mouse cursor to another frame"
993 (declare (ignore window
))
994 (let ((child (find-child-under-mouse root-x root-y
)))
995 (unless (equal child
*current-root
*)
997 (remove-child-in-frame child
(find-parent-frame child
))
998 (wait-mouse-button-release 50 51)
999 (multiple-value-bind (x y
)
1000 (xlib:query-pointer
*root
*)
1001 (let ((dest (find-child-under-mouse x y
)))
1002 (when (xlib:window-p dest
)
1003 (setf dest
(find-parent-frame dest
)))
1004 (unless (equal child dest
)
1005 (move-child-to child dest
)
1006 (show-all-children *current-root
*))))))
1007 (stop-button-event))
1012 ;;; Hide/Show frame window functions
1013 (defun hide/show-frame-window
(frame value
)
1014 "Hide/show the frame window"
1015 (when (frame-p frame
)
1016 (setf (frame-show-window-p *current-child
*) value
)
1017 (show-all-children *current-root
*))
1018 (leave-second-mode))
1021 (defun hide-current-frame-window ()
1022 "Hide the current frame window"
1023 (hide/show-frame-window
*current-child
* nil
))
1025 (defun show-current-frame-window ()
1026 "Show the current frame window"
1027 (hide/show-frame-window
*current-child
* t
))
1031 ;;; Hide/Unhide current child
1032 (defun hide-current-child ()
1033 "Hide the current child"
1034 (let ((parent (find-parent-frame *current-child
*)))
1035 (when (frame-p parent
)
1036 (with-slots (child hidden-children
) parent
1037 (hide-all *current-child
*)
1038 (setf child
(remove *current-child
* child
))
1039 (pushnew *current-child
* hidden-children
)
1040 (setf *current-child
* parent
))
1041 (show-all-children)))
1042 (leave-second-mode))
1045 (defun frame-unhide-child (hidden frame-src frame-dest
)
1046 "Unhide a hidden child from frame-src in frame-dest"
1047 (with-slots (hidden-children) frame-src
1048 (setf hidden-children
(remove hidden hidden-children
)))
1049 (with-slots (child) frame-dest
1050 (pushnew hidden child
)))
1054 (defun unhide-a-child ()
1055 "Unhide a child in the current frame"
1056 (when (frame-p *current-child
*)
1057 (with-slots (child hidden-children
) *current-child
*
1058 (info-mode-menu (loop :for i
:from
0
1059 :for hidden
:in hidden-children
1060 :collect
(list (code-char (+ (char-code #\a) i
))
1063 (frame-unhide-child lhd
*current-child
* *current-child
*)))
1064 (format nil
"Unhide ~A" (child-fullname hidden
))))))
1065 (show-all-children))
1066 (leave-second-mode))
1069 (defun unhide-all-children ()
1070 "Unhide all current frame hidden children"
1071 (when (frame-p *current-child
*)
1072 (with-slots (child hidden-children
) *current-child
*
1073 (dolist (c hidden-children
)
1075 (setf hidden-children nil
))
1076 (show-all-children))
1077 (leave-second-mode))
1080 (defun unhide-a-child-from-all-frames ()
1081 "Unhide a child from all frames in the current frame"
1082 (when (frame-p *current-child
*)
1085 (with-all-frames (*root-frame
* frame
)
1086 (when (frame-hidden-children frame
)
1087 (push (format nil
"~A" (child-fullname frame
)) acc
)
1088 (dolist (hidden (frame-hidden-children frame
))
1089 (push (list (code-char (+ (char-code #\a) (incf keynum
)))
1092 (frame-unhide-child lhd frame
*current-child
*)))
1093 (format nil
"Unhide ~A" (child-fullname hidden
)))
1095 (info-mode-menu (nreverse acc
)))
1096 (show-all-children))
1097 (leave-second-mode))
1103 (let ((last-child nil
))
1104 (defun init-last-child ()
1105 (setf last-child nil
))
1106 (defun switch-to-last-child ()
1107 "Store the current child and switch to the previous one"
1108 (let ((current-child *current-child
*))
1110 (hide-all *current-root
*)
1111 (setf *current-root
* last-child
1112 *current-child
* *current-root
*)
1113 (focus-all-children *current-child
* *current-child
*)
1114 (show-all-children *current-root
*))
1115 (setf last-child current-child
))))
1123 ;;; Focus policy functions
1124 (defun set-focus-policy-generic (focus-policy)
1125 (when (frame-p *current-child
*)
1126 (setf (frame-focus-policy *current-child
*) focus-policy
))
1127 (leave-second-mode))
1130 (defun current-frame-set-click-focus-policy ()
1131 "Set a click focus policy for the current frame."
1132 (set-focus-policy-generic :click
))
1134 (defun current-frame-set-sloppy-focus-policy ()
1135 "Set a sloppy focus policy for the current frame."
1136 (set-focus-policy-generic :sloppy
))
1138 (defun current-frame-set-sloppy-strict-focus-policy ()
1139 "Set a (strict) sloppy focus policy only for windows in the current frame."
1140 (set-focus-policy-generic :sloppy-strict
))
1142 (defun current-frame-set-sloppy-select-policy ()
1143 "Set a sloppy select policy for the current frame."
1144 (set-focus-policy-generic :sloppy-select
))
1148 (defun set-focus-policy-generic-for-all (focus-policy)
1149 (with-all-frames (*root-frame
* frame
)
1150 (setf (frame-focus-policy frame
) focus-policy
))
1151 (leave-second-mode))
1154 (defun all-frames-set-click-focus-policy ()
1155 "Set a click focus policy for all frames."
1156 (set-focus-policy-generic-for-all :click
))
1158 (defun all-frames-set-sloppy-focus-policy ()
1159 "Set a sloppy focus policy for all frames."
1160 (set-focus-policy-generic-for-all :sloppy
))
1162 (defun all-frames-set-sloppy-strict-focus-policy ()
1163 "Set a (strict) sloppy focus policy for all frames."
1164 (set-focus-policy-generic-for-all :sloppy-strict
))
1166 (defun all-frames-set-sloppy-select-policy ()
1167 "Set a sloppy select policy for all frames."
1168 (set-focus-policy-generic-for-all :sloppy-select
))
1172 ;;; Ensure unique name/number functions
1173 (defun extract-number-from-name (name)
1174 (when (stringp name
)
1175 (let* ((pos (1+ (or (position #\. name
:from-end t
) -
1)))
1176 (number (parse-integer name
:junk-allowed t
:start pos
)))
1178 (if number
(subseq name
0 (1- pos
)) name
)))))
1183 (defun ensure-unique-name ()
1184 "Ensure that all children names are unique"
1185 (with-all-children (*root-frame
* child
)
1186 (multiple-value-bind (num1 name1
)
1187 (extract-number-from-name (child-name child
))
1188 (declare (ignore num1
))
1191 (with-all-children (*root-frame
* c
)
1192 (unless (equal child c
))
1193 (multiple-value-bind (num2 name2
)
1194 (extract-number-from-name (child-name c
))
1195 (when (string-equal name1 name2
)
1198 (when (> (length acc
) 1)
1199 (setf (child-name child
)
1200 (format nil
"~A.~A" name1
1201 (1+ (find-free-number (loop for i in acc when i collect
(1- i
)))))))))))
1202 (leave-second-mode))
1204 (defun ensure-unique-number ()
1205 "Ensure that all children numbers are unique"
1207 (with-all-frames (*root-frame
* frame
)
1208 (setf (frame-number frame
) (incf num
))))
1209 (leave-second-mode))
1213 ;;; Standard menu functions - Based on the 'update-menus' command
1214 (defun um-extract-value (name line
)
1215 (let* ((fullname (format nil
"~A=\"" name
))
1216 (pos (search fullname line
)))
1218 (let* ((start (+ pos
(length fullname
)))
1219 (end (position #\" line
:start start
)))
1221 (subseq line start end
))))))
1224 (defun um-create-section (menu section-list
)
1226 (let* ((sec (intern (string-upcase (first section-list
)) :clfswm
))
1227 (submenu (find-menu sec menu
)))
1229 (um-create-section submenu
(rest section-list
))
1231 (add-sub-menu (menu-name menu
) :next sec
(format nil
"~A" sec
) menu
)
1232 (um-create-section (find-menu sec menu
) (rest section-list
)))))
1236 (defun update-menus (&optional
(menu (make-menu :name
'main
:doc
"Main menu")))
1237 (let ((output (do-shell "update-menus --stdout")))
1238 (loop for line
= (read-line output nil nil
)
1240 do
(let ((command (um-extract-value "command" line
)))
1242 (let* ((sub-menu (um-create-section menu
(split-string (um-extract-value "section" line
) #\
/)))
1243 (title (um-extract-value " title" line
))
1244 (doc (um-extract-value "description" line
))
1245 (name (intern title
:clfswm
)))
1246 (setf (symbol-function name
) (lambda ()
1248 (leave-second-mode))
1249 (documentation name
'function
) (format nil
"~A~A" title
(if doc
(format nil
" - ~A" doc
) "")))
1250 (add-menu-key (menu-name sub-menu
) :next name sub-menu
)))))
1254 (defun show-standard-menu ()
1256 (let ((menu (update-menus)))
1257 (if (menu-item menu
)
1259 (info-mode '("Command 'update-menus' not found")))))
1263 ;;; Close/Kill focused window
1265 (defun ask-close/kill-current-window
()
1266 "Close or kill the current window (ask before doing anything)"
1267 (let ((window (xlib:input-focus
*display
*)))
1269 (if (and window
(not (xlib:window-equal window
*no-focus-window
*)))
1270 `(,(format nil
"Focus window: ~A" (xlib:wm-name window
))
1271 (#\c delete-focus-window
"Close the focus window")
1272 (#\k destroy-focus-window
"Kill the focus window")
1273 (#\r remove-focus-window
)
1274 (#\u unhide-all-windows-in-current-child
))
1275 `(,(format nil
"Focus window: None")
1276 (#\u unhide-all-windows-in-current-child
))))))
1280 ;;; Other window manager functions
1281 (defun get-proc-list ()
1282 (let ((proc (do-shell "ps x -o pid=" nil nil
))
1285 (loop for line
= (read-line proc nil nil
)
1287 do
(push line proc-list
))
1291 (defun run-other-window-manager ()
1292 (let ((proc-start (get-proc-list)))
1293 (do-shell *other-window-manager
* nil t
)
1294 (let* ((proc-end (get-proc-list))
1295 (proc-diff (set-difference proc-end proc-start
:test
#'equal
)))
1297 (dolist (proc proc-diff
)
1298 (dbg 'killing-sigterm proc
)
1299 (do-shell (format nil
"kill ~A 2> /dev/null" proc
) nil t
))
1301 (dolist (proc proc-diff
)
1302 (dbg 'killing-sigkill proc
)
1303 (do-shell (format nil
"kill -9 ~A 2> /dev/null" proc
) nil t
)))
1304 (setf *other-window-manager
* nil
)))
1307 (defun do-run-other-window-manager (window-manager)
1308 (setf *other-window-manager
* window-manager
)
1309 (throw 'exit-main-loop nil
))
1311 (defmacro def-run-other-window-manager
(name &optional definition
)
1312 (let ((definition (or definition name
)))
1313 `(defun ,(create-symbol "run-" name
) ()
1314 ,(format nil
"Run ~A" definition
)
1315 (do-run-other-window-manager ,(format nil
"~A" name
)))))
1317 (def-run-other-window-manager "xterm")
1318 (def-run-other-window-manager "icewm")
1319 (def-run-other-window-manager "twm")
1320 (def-run-other-window-manager "gnome-session" "Gnome")
1321 (def-run-other-window-manager "startkde" "KDE")
1322 (def-run-other-window-manager "xfce4-session" "XFCE")
1326 (do-run-other-window-manager "lxsession; xterm -e \"echo ' /----------------------------------\\' ; echo ' | CLFSWM Note: |' ; echo ' | Close this window when done. |' ; echo ' \\----------------------------------/'; echo; echo; $SHELL\""))
1329 (defun run-prompt-wm ()
1330 "Prompt for an other window manager"
1331 (let ((wm (query-string "Run an other window manager:" "icewm")))
1332 (do-run-other-window-manager wm
)))