1 ;;; --------------------------------------------------------------------------
2 ;;; CLFSWM - FullScreen Window Manager
4 ;;; --------------------------------------------------------------------------
5 ;;; Documentation: Main functions
6 ;;; --------------------------------------------------------------------------
8 ;;; (C) 2005-2015 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 ;;; --------------------------------------------------------------------------
28 (defparameter *clfswm-initializing
* nil
)
30 (define-handler main-mode
:key-press
(code state
)
31 (funcall-key-from-code *main-keys
* code state
))
33 (define-handler main-mode
:button-press
(code state window root-x root-y
)
34 (unless (funcall-button-from-code *main-mouse
* code state window root-x root-y
*fun-press
*)
35 (replay-button-event)))
37 (define-handler main-mode
:button-release
(code state window root-x root-y
)
38 (unless (funcall-button-from-code *main-mouse
* code state window root-x root-y
*fun-release
*)
39 (replay-button-event)))
41 (define-handler main-mode
:motion-notify
(window root-x root-y
)
42 (unless (compress-motion-notify)
43 (funcall-button-from-code *main-mouse
* 'motion
44 (modifiers->state
*default-modifiers
*)
45 window root-x root-y
*fun-press
*)))
48 (define-handler main-mode
:configure-request
(stack-mode window x y width height border-width value-mask
)
50 (labels ((has-x (mask) (= 1 (logand mask
1)))
51 (has-y (mask) (= 2 (logand mask
2)))
52 (has-w (mask) (= 4 (logand mask
4)))
53 (has-h (mask) (= 8 (logand mask
8)))
54 (has-bw (mask) (= 16 (logand mask
16)))
55 (has-stackmode (mask) (= 64 (logand mask
64)))
56 (adjust-from-request ()
57 (when (has-x value-mask
) (setf (x-drawable-x window
) x
59 (when (has-y value-mask
) (setf (x-drawable-y window
) y
61 (when (has-h value-mask
) (setf (x-drawable-height window
) height
63 (when (has-w value-mask
) (setf (x-drawable-width window
) width
66 (xlib:with-state
(window)
67 (let ((current-root (find-current-root)))
68 (if (find-child window current-root
)
69 (let ((parent (find-parent-frame window current-root
)))
70 (if (and parent
(managed-window-p window parent
))
71 (setf change
(adapt-child-to-parent window parent
))
72 (adjust-from-request)))
73 (adjust-from-request)))
74 (when (has-bw value-mask
)
75 (setf (x-drawable-border-width window
) border-width
77 (when (has-stackmode value-mask
)
80 (when (or (child-equal-p window
(current-child))
81 (is-in-current-child-p window
))
82 (setf change
(or change
:moved
))
85 (when (focus-all-children window
(find-parent-frame window
(find-current-root)))
86 (show-all-children))))))))
87 (unless (eq change
:resized
)
88 ;; To be ICCCM compliant, send a fake configuration notify event only when
89 ;; the window has moved and not when it has been resized or the border width has changed.
90 (send-configuration-notify window
(x-drawable-x window
) (x-drawable-y window
)
91 (x-drawable-width window
) (x-drawable-height window
)
92 (x-drawable-border-width window
)))))))
95 (define-handler main-mode
:map-request
(window send-event-p
)
97 (unless (find-child window
*root-frame
*)
98 (unhide-window window
)
99 (process-new-window window
)
101 (multiple-value-bind (never-managed raise
)
102 (never-managed-window-p window
)
103 (unless (and never-managed raise
)
104 (show-all-children))))))
108 (define-handler main-mode
:unmap-notify
(send-event-p event-window window
)
109 (unless (and (not send-event-p
)
110 (not (xlib:window-equal window event-window
)))
111 (when (find-child window
*root-frame
*)
112 (setf (window-state window
) +withdrawn-state
+)
113 (remove-child-in-all-frames window
)
114 ;;(xlib:unmap-window window)
115 (show-all-children))))
118 (define-handler main-mode
:destroy-notify
(send-event-p event-window window
)
119 (unless (or send-event-p
120 (xlib:window-equal window event-window
))
121 (when (find-child window
*root-frame
*)
122 (delete-child-in-all-frames window
)
123 (xlib:destroy-window window
)
124 (show-all-children))))
127 (define-handler main-mode
:enter-notify
(window root-x root-y
)
128 (unless (and (> root-x
(- (screen-width) 3))
129 (> root-y
(- (screen-height) 3)))
130 (manage-focus window root-x root-y
)))
133 (define-handler main-mode
:focus-in
(window)
134 (unless (child-equal-p window
(focused-window))
135 (set-focus-to-current-child)))
138 (define-handler main-mode
:exposure
(window)
139 (awhen (find-frame-window window
)
140 (display-frame-info it
)))
143 (define-handler main-mode
:configure-notify
(window)
144 (when (child-equal-p window
*root
*)
145 (unless (eql (place-frames-from-xinerama-infos) :update
)
146 (finish-configuring-root))
148 (call-hook *root-size-change-hook
*)))
151 (defun error-handler (display error-key
&rest key-vals
&key asynchronous
&allow-other-keys
)
154 ;; ignore asynchronous window errors
156 (find error-key
'(xlib:window-error xlib
:drawable-error xlib
:match-error
)))
157 #+:xlib-debug
(format t
"~&Ignoring XLib asynchronous error: ~s~%" error-key
))
158 ((eq error-key
'xlib
:access-error
)
159 (if *clfswm-initializing
*
161 (format t
"~3&Another window manager is running. Exiting...~%")
162 (throw 'exit-clfswm nil
))
164 (format t
"~&Ignoring XLib asynchronous access error: ~s~%" error-key
)))
165 ;; all other asynchronous errors are printed.
167 #+:xlib-debug
(format t
"~&Caught Asynchronous X Error: ~s ~s" error-key key-vals
))
168 ;;((find error-key '(xlib:window-error xlib:drawable-error xlib:match-error))
169 ;; (format t "~&Ignoring Xlib error: ~S ~S~%" error-key key-vals))
171 (apply 'error error-key
:display display
:error-key error-key key-vals
))))
178 (with-xlib-protect (:main-loop nil
)
179 (call-hook *loop-hook
*)
181 (when (xlib:event-listen
*display
* *loop-timeout
*)
182 (xlib:process-event
*display
* :handler
#'handle-event
))
183 (xlib:display-finish-output
*display
*)
184 (setf *x-error-count
* 0))))
189 (defun open-display (display-str protocol
)
190 (multiple-value-bind (host display-num
) (parse-display-string display-str
)
191 (setf *display
* (xlib:open-display host
:display display-num
:protocol protocol
)
192 (xlib:display-error-handler
*display
*) 'error-handler
193 (getenv "DISPLAY") display-str
)))
197 (defun default-init-hook ()
198 (place-frames-from-xinerama-infos)
199 (finish-configuring-root))
202 (defun init-display ()
204 (reset-last-head-size)
205 (reset-bind-or-jump-slots)
207 (fill-handle-event-fun-symbols)
208 (assoc-keyword-handle-event 'main-mode
)
209 (setf *screen
* (first (xlib:display-roots
*display
*))
210 *root
* (xlib:screen-root
*screen
*)
211 *no-focus-window
* (xlib:create-window
:parent
*root
* :x
0 :y
0 :width
1 :height
1)
212 *default-font
* (xlib:open-font
*display
* *default-font-string
*)
213 *pixmap-buffer
* (xlib:create-pixmap
:width
(screen-width)
214 :height
(screen-height)
215 :depth
(xlib:screen-root-depth
*screen
*)
219 *expose-child-list
* nil
)
220 (store-root-background)
223 (xgrab-init-keyboard)
225 (call-hook *binding-hook
*)
227 (map-window *no-focus-window
*)
229 (setf (xlib:window-event-mask
*root
*) (xlib:make-event-mask
:substructure-redirect
238 (xlib:display-finish-output
*display
*)
239 ;;(intern-atoms *display*)
240 (netwm-set-properties)
241 (xlib:display-force-output
*display
*)
242 (setf *child-selection
* nil
)
243 (setf *root-frame
* (create-frame :name
"Root" :number
0)
244 (current-child) *root-frame
*)
245 (call-hook *init-hook
*)
246 (process-existing-windows *screen
*)
249 (xlib:display-finish-output
*display
*)
250 (optimize-event-hook))
255 (defun read-conf-file ()
256 (let* ((conf (conf-file-name)))
258 (handler-case (load conf
)
260 (format t
"~2%*** Error loading configuration file: ~A ***~&~A~%" conf c
)
261 (values nil
(format nil
"~s" c
) conf
))
262 (:no-error
(&rest args
)
263 (declare (ignore args
))
264 (values t nil conf
)))
265 (values t nil nil
))))
272 (defun exit-clfswm ()
274 (throw 'exit-clfswm nil
))
276 (defun reset-clfswm ()
278 (throw 'exit-main-loop nil
))
283 (defun main-unprotected (&key
(display (or (getenv "DISPLAY") ":0")) protocol
284 (read-conf-file-p t
) (alternate-conf nil
)
286 (setf *clfswm-initializing
* t
)
287 (conf-file-name alternate-conf
)
288 (when read-conf-file-p
290 (create-configuration-menu :clear t
)
291 (call-hook *main-entrance-hook
*)
293 (open-display display protocol
)
294 (xlib:access-error
(c)
295 (format t
"~&~A~&Maybe another window manager is running. [1]~%" c
)
300 (xlib:access-error
(c)
302 (xlib:destroy-window
*no-focus-window
*)
303 (xlib:close-display
*display
*)
304 (format t
"~&~A~&Maybe another window manager is running. [2]~%" c
)
308 (info-mode error-msg
))
309 (setf *clfswm-initializing
* nil
)
310 (catch 'exit-main-loop
315 (xlib:destroy-window
*no-focus-window
*)
316 (xlib:free-pixmap
*pixmap-buffer
*)
317 (destroy-all-frames-window)
318 (call-hook *close-hook
*)
320 (xlib:close-display
*display
*)
322 (format t
"~2&Unhandled events: ~A~%" *unhandled-events
*)))))
326 (defun main (&key
(display (or (getenv "DISPLAY") ":0")) protocol
328 (alternate-conf nil
))
333 (if *other-window-manager
*
334 (run-other-window-manager)
335 (main-unprotected :display display
:protocol protocol
336 :read-conf-file-p read-conf-file-p
337 :alternate-conf alternate-conf
338 :error-msg error-msg
))
340 (let ((msg (format nil
"CLFSWM Error: ~A." c
)))
341 (format t
"~&~A~%Reinitializing...~%" msg
)
342 (setf error-msg
(list (list msg
*info-color-title
*)
343 "Reinitializing...")))))))))