1 ;;; xwem-win.el --- Windows ops for XWEM.
3 ;; Copyright (C) 2003-2005 by XWEM Org.
5 ;; Author: Zajcev Evgeny <zevlg@yandex.ru>
6 ;; Created: 21 Mar 2003
7 ;; Keywords: xlib, xwem
8 ;; X-CVS: $Id: xwem-win.el,v 1.9 2005-04-04 19:54:17 lg Exp $
10 ;; This file is part of XWEM.
12 ;; XWEM is free software; you can redistribute it and/or modify it
13 ;; under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; XWEM is distributed in the hope that it will be useful, but WITHOUT
18 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
20 ;; License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with XEmacs; see the file COPYING. If not, write to the Free
24 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 ;;; Synched up with: Not in FSF
31 ;; This file contain operations on XWEM windows. Window is part of
32 ;; Frame, Window holds X client - CL.
40 (defgroup xwem-win nil
41 "Group to customize XWEM windows."
46 (defcustom xwem-win-min-width 80
47 "*Minimal width for window"
52 (defcustom xwem-win-min-height 80
53 "*Minimal height for window"
58 (defcustom xwem-win-vertical-delim-width '(8 . 1)
59 "*Width in pixels for vertical delimiters.
60 car is delimiter width, cdr is shadow thickness."
61 :type '(cons number number)
65 (defcustom xwem-win-horizontal-delim-width '(6 . 1)
66 "*Width in pixels for horizontal delimiters.
67 car is delimiter width, cdr is shadow thickness."
68 :type '(cons number number)
71 (defcustom xwem-win-default-border-width 1
72 "*Default border width for newly created windows."
76 (defcustom xwem-win-default-properties
77 (list 'attachable nil)
78 "*Default properties list for frame windows.
80 dead - window that referenced but not workable.
81 deleted - deleted window have this equal to t
82 frame - frame window attached to.
83 next - next window in windows double linked list.
84 prev - previous window.
85 hchild - child window after horizontal split.
86 vchild - child window after vertical split.
87 parent - parent window (window in which we do split).
88 client - client currently active in window. (index in clients-list)
89 attachable - if non-nil then frame may be attached to some frame's
90 window. (not yet implemented [is it will be usefull?])
91 expectances - list of expectances for window.
93 :type '(restricted-sexp :match-alternatives (valid-plist-p))
96 (defcustom xwem-win-winmove-allow-jumping t
97 "*Non-nil allows jumping to opposite edge, when no window founded."
101 (defcustom xwem-win-collect-deleted-clients t
102 "*Non-nil mean clients managed in window that are deleting now, will
103 be placed in `xwem-window-other' window."
107 (defcustom xwem-win-max-clients 32
108 "*Maximum number of clients in window.
115 (defcustom xwem-win-switch-hook nil
116 "Hooks to be called when window switching occurs.
117 Function will receive two arguments OLD-WIN and NEW-WIN."
121 (defcustom xwem-win-delete-hook nil
122 "Hooks called with one arg - window when deleting window."
126 (defcustom xwem-win-clients-change-hook nil
127 "Hooks called when win's clients list changed."
132 (defcustom xwem-win-split-hook nil
133 "Hook to be called after window split.
134 Functions will be called with two arguments: SPLIT-WIN, NEW-WIN."
138 (define-xwem-face xwem-window-outline-face
139 `(((frame-selected win-selected)
140 (:foreground "green" :background "green4" :line-width 4))
141 ((frame-selected win-nonselected)
142 (:foreground "gray70" :background "gray70" :line-width 4))
143 ((frame-nonselected win-selected)
144 (:foreground "green3" :background "green4" :line-width 4))
145 ((frame-nonselected win-nonselected)
146 (:foreground "gray60" :background "gray40" :line-width 4)))
147 "Face to outline frame windows."
151 (define-xwem-face xwem-window-delimiter-face
153 (:foreground "royalblue"))
155 (:foreground "blue4"))
156 ((horizontal light shadow)
157 (:foreground "cyan"))
159 (:foreground "royalblue"))
161 (:foreground "blue4"))
162 ((light shadow vertical)
163 (:foreground "cyan"))
164 (t (:foreground "gray20" :background "black")))
165 "Face to draw window delimiter."
169 ;;; Internal variables
173 (defmacro xwem-win-child (window)
174 "Return child of WINDOW, hchild checked first then if not set vchild
176 `(or (xwem-win-hchild ,window) (xwem-win-vchild ,window)))
178 (defmacro xwem-win-mark-deleted (win)
179 "Mark WIN as deleted window."
180 `(setf (xwem-win-deleted ,win) t))
183 (defun xwem-win-delim-width (window)
184 "Return WIN's delimiter width."
185 (let ((pwin (xwem-win-parent window)))
186 (or (and pwin (xwem-win-hchild pwin) (car xwem-win-horizontal-delim-width))
187 (and pwin (xwem-win-vchild pwin) (car xwem-win-vertical-delim-width))
191 (defun xwem-win-delim-shadow-thickness (window)
192 "Return WIN's delimiter width."
193 (let ((pwin (xwem-win-parent window)))
194 (or (and pwin (xwem-win-hchild pwin) (cdr xwem-win-horizontal-delim-width))
195 (and pwin (xwem-win-vchild pwin) (cdr xwem-win-vertical-delim-width))
201 (defun xwem-win-make-list-by-next (window)
202 "Create list of WINDOW and all next windows."
205 (while (xwem-win-p wins)
206 (setq rlist (cons wins rlist))
207 (setq wins (xwem-win-next wins)))
211 (defun xwem-win-num (win)
212 "Return relative WIN's number in logical window list."
213 (let ((ch (xwem-win-child (xwem-frame-rootwin (xwem-win-frame win))))
215 (when (xwem-win-p ch)
216 (while (not (xwem-win-alive-p ch))
217 (setq ch (xwem-win-child ch)))
218 ;; CH is very first window in frame
219 (while (not (eq ch win))
221 ch (xwem-window-next ch))))
225 (defun xwem-win-find-by-num (frame num)
226 "In FRAME find window for which `xwem-win-num' returns NUM."
227 (let* ((fch (xwem-win-child (xwem-frame-rootwin frame)))
229 (if (not (xwem-win-p ch))
230 (and (= num 0) (xwem-frame-rootwin frame))
232 (while (not (xwem-win-alive-p ch))
233 (setq ch (xwem-win-child ch)))
234 ;; CH is very first window in frame
235 (while (and (> num 0) ch)
236 (setq ch (xwem-window-next ch))
242 ;; We do want closures in emacs lisp
243 (defvar xwem-win-next-id 0)
244 (defun xwem-win-gen-id ()
245 "Generate new window id."
246 (truncate (X-Dpy-get-id (xwem-dpy))))
248 (defun xwem-win-hacked-or (&rest args)
249 "Like `or', but can by used under `apply'."
250 (while (and args (null (car args)))
251 (setq args (cdr args)))
255 (defun xwem-win-find-by-id (win-id &optional win)
256 "Find a window with WIN-ID."
257 (cond ((and (xwem-win-p win)
258 (= (xwem-win-id win) win-id))
262 (or (apply 'xwem-win-hacked-or
263 (mapcar #'(lambda (w)
264 (xwem-win-find-by-id win-id w))
265 (xwem-win-make-list-by-next (xwem-win-child win))))
266 (apply 'xwem-win-hacked-or
267 (mapcar #'(lambda (w)
268 (xwem-win-find-by-id win-id w))
269 (delq win (xwem-win-make-list-by-next win))))))
271 (t (apply 'xwem-win-hacked-or
272 (mapcar #'(lambda (w)
273 (xwem-win-find-by-id win-id w))
274 (mapcar #'xwem-frame-rootwin
275 xwem-frames-list))))))
278 (defun xwem-cl-set-win (cl win)
279 "Associate CL with WIN.
280 WIN is valid WIN or nil."
281 (unless (eq (xwem-cl-win cl) win)
282 (let ((owin (xwem-cl-win cl)))
283 ;; Deactivate CL, when changing window
286 (setf (xwem-cl-win cl) win)
288 ;; Set also client property
289 (xwem-client-set-property
290 cl 'client-window (and (xwem-win-p win) (xwem-win-id win)))
292 ;; Remove CL from OWIN's clients list
293 (when (xwem-win-p owin)
294 (xwem-win-rem-cl owin cl))))
296 ;; Add CL to WIN's clients list
297 (when (xwem-win-p win)
298 (xwem-win-add-cl win cl)))
301 (defun xwem-win-add-cl (win cl)
302 "Into WIN's clients list add new client CL."
303 (unless (or (not (xwem-cl-p cl))
304 (memq cl (xwem-win-clients win)))
306 (when (and (xwem-frame-dedicated-p (xwem-win-frame win))
307 (xwem-win-clients win))
308 (error 'xwem-error "Window in dedicted frame already has client"))
310 ;; Insert CL in WIN's clients list in proper place (as in
312 (let ((wcls (xwem-win-clients win)))
313 (while (and wcls (memq cl (memq (car wcls) xwem-clients)))
314 (setq wcls (cdr wcls)))
316 (setf (xwem-win-clients win)
317 (append (xwem-win-clients win) (list cl)))
318 (setcdr wcls (cons (car wcls) (cdr wcls)))
321 (run-hook-with-args 'xwem-win-clients-change-hook win)))
324 (defun xwem-win-rem-cl (win cl)
325 "From WIN's clients list remove client CL."
326 (when (and (xwem-cl-p cl)
327 (memq cl (xwem-win-clients win)))
328 (setf (xwem-win-clients win)
329 (delq cl (xwem-win-clients win)))
331 ;; If CL is current client in WIN, also unset it
332 (when (eq cl (xwem-win-cl win))
333 (xwem-win-set-cl win nil))
335 (run-hook-with-args 'xwem-win-clients-change-hook win)))
338 (defun xwem-win-set-cl (win cl)
339 "Associate WIN with CL as current client in WIN."
340 ;; When CL isnt in WIN's clients list yet, add it.
341 (unless (eq (xwem-win-cl win) cl)
343 (xwem-cl-set-win cl win))
345 (let ((ocl (xwem-win-cl win)))
346 (setf (xwem-win-cl win) cl)
348 (when (xwem-cl-alive-p (xwem-win-cl win))
349 (xwem-activate (xwem-win-cl win)))
350 (when (xwem-cl-alive-p ocl)
351 (xwem-deactivate ocl))
353 (when (or (null ocl) (null (xwem-win-cl win)))
354 (xwem-win-redraw-win win)))))
357 (defun xwem-win-new (&optional params props)
358 "Create new window with properties PROPS."
359 (let ((nwin (apply 'make-xwem-win :id (xwem-win-gen-id) params))
360 (rplist (copy-list xwem-win-default-properties)))
362 ;; Prepare window properties
363 (setq rplist (xwem-misc-merge-plists rplist props))
365 (setf (xwem-win-geom nwin)
366 (make-X-Geom :x 0 :y 0 :width 1 :height 1
367 :border-width xwem-win-default-border-width))
368 (setf (xwem-win-clients nwin) nil) ; list of clients
369 (setf (xwem-win-cl nwin) nil) ; no visible client yet
370 (setf (xwem-win-plist nwin) rplist) ; window properties
374 (defun xwem-win-replace (old new)
375 "Replace OLD window with contents of NEW window."
376 (when (not (and (xwem-win-p old) (xwem-win-p new)))
377 (error 'xwem-error "Hmm .. one of OLD or NEW is not a xwem window"))
379 (when (eq (xwem-frame-rootwin (xwem-win-frame old)) old)
380 (setf (xwem-frame-rootwin (xwem-win-frame old)) new))
382 (setf (xwem-win-x new) (xwem-win-x old))
383 (setf (xwem-win-y new) (xwem-win-y old))
384 (setf (xwem-win-width new) (xwem-win-width old))
385 (setf (xwem-win-height new) (xwem-win-height old))
388 (setq tem (xwem-win-next old))
389 (setf (xwem-win-next new) tem)
390 (when (xwem-win-p tem)
391 (setf (xwem-win-prev tem) new))
393 (setq tem (xwem-win-prev old))
394 (setf (xwem-win-prev new) tem)
395 (when (xwem-win-p tem)
396 (setf (xwem-win-next tem) new))
398 (setq tem (xwem-win-parent old))
399 (setf (xwem-win-parent new) tem)
400 (when (xwem-win-p tem)
401 (when (eq (xwem-win-vchild tem) old)
402 (setf (xwem-win-vchild tem) new))
403 (when (eq (xwem-win-hchild tem) old)
404 (setf (xwem-win-hchild tem) new))
407 (defun xwem-win-make-parent (window)
408 "Make dummy parent for WINDOW."
409 (let ((pwin (xwem-win-new
410 (list :frame (xwem-win-frame window)
411 :dead t ; XXX dead mean that window
412 ; can't contain clients
415 (xwem-win-replace window pwin)
417 (setf (xwem-win-next window) nil)
418 (setf (xwem-win-prev window) nil)
419 (setf (xwem-win-hchild window) nil)
420 (setf (xwem-win-vchild window) nil)
421 (setf (xwem-win-parent window) pwin)
425 (defun xwem-window-next (&optional window)
426 "Return next window after WINDOW in canonical ordering of windows.
427 If omitted, WINDOW defaults to the `(xwem-win-selected)'."
428 (let ((win (or window (xwem-win-selected)))
431 (while (and (not while-exit)
432 (null (setq tem (xwem-win-next win))))
433 (if (xwem-win-p (setq tem (xwem-win-parent win)))
437 (setq tem (xwem-frame-rootwin (xwem-win-frame win)))
438 (setq while-exit t) ;break from loop
443 ;; now if we have a horizontal or vertical combination - find the
445 (while (cond ((xwem-win-p (xwem-win-child win))
446 (progn (setq win (xwem-win-child win)) t))
451 (defun xwem-window-next-vertical (&optional window)
452 "Return next window which is vertically after WINDOW.
453 If WINDOW is not given `(xwem-win-selected)' will be used."
454 (let* ((win (or window (xwem-win-selected)))
455 (root-win (xwem-frame-rootwin (xwem-win-frame win)))
458 (when (eq root-win win)
459 (while (cond ((xwem-win-p (xwem-win-hchild win))
460 (progn (setq win (xwem-win-hchild win)) t))
461 ((xwem-win-p (xwem-win-vchild win))
462 (progn (setq win (xwem-win-vchild win)) t))
463 (t (progn (setq rwin win) nil)))))
467 ;; TODO: check for root window in frame
469 (if (and (xwem-win-p (xwem-win-parent win))
470 (xwem-win-p (xwem-win-vchild (xwem-win-parent win))))
471 (if (xwem-win-p (xwem-win-next win))
472 (setq rwin (xwem-win-next win))
473 (setq win (xwem-win-parent win)))
474 (setq win (xwem-win-parent win)))
475 (and (null rwin) (not (eq win root-win)))))
480 (if (xwem-win-p (xwem-win-hchild win))
481 (setq win (xwem-win-hchild win))
482 (if (xwem-win-p (xwem-win-vchild win))
483 (setq win (xwem-win-vchild win))
489 (defun xwem-window-prev (&optional window)
490 "Retrun previous window before WINDOW in canonical ordering of windows.
491 If ommitted, WINDOW defaults to the `(xwem-win-selected)'."
492 (let* ((win (or window (xwem-win-selected)))
495 (while (and (not while-exit)
496 (null (setq tem (xwem-win-prev win))))
498 (if (xwem-win-p (setq tem (xwem-win-parent win)))
501 (setq tem (xwem-frame-rootwin (xwem-win-frame win)))
502 (setq while-exit t) ;break from loop
507 ;; now if we have a horizontal or vertical combination find
510 (cond ((xwem-win-p (xwem-win-child win))
511 (progn (setq win (xwem-win-child win)) t))
514 (while (xwem-win-p (xwem-win-next win))
515 (setq win (xwem-win-next win)))
520 (defun xwem-window-other (cnt &optional window)
521 "Return CNT's next window for WINDOW if CNT is greater then zero and
522 previous if negative."
523 (let ((ofn (if (>= cnt 0) 'xwem-window-next 'xwem-window-prev))
525 (win (or window (xwem-win-selected))))
527 (setq win (funcall ofn win))
531 (defun xwem-win-xy-in-p (x y win &optional inc-gutter)
532 "Returns non-nil if X Y lies in WIN.
533 If INC-GUTTER is non-nil, than include gutters width as WIN area."
534 (let ((edges (xwem-win-pixel-edges win))
535 (gw (if inc-gutter (xwem-win-delim-width win) 0)))
536 (and (>= x (- (nth 0 edges) gw))
537 (<= x (+ (nth 2 edges) gw))
538 (>= y (- (nth 1 edges) gw))
539 (<= y (+ (nth 3 edges) gw)))))
541 (defun xwem-window-at (x y &optional frame)
542 "Returns window where X and Y lies in it."
544 (xwem-win-map #'(lambda (win)
545 (when (xwem-win-xy-in-p x y win t)
547 (xwem-frame-selwin (or frame (xwem-frame-selected))))
550 ;;; -- Moving around windows --
552 (defun xwem-winmove-distance (&optional win)
553 "Returns distance between windows."
555 (+ (xwem-win-delim-width (or win (xwem-win-selected))) 2))
557 (defun xwem-winmove-refloc (&optional arg window)
558 "Calculates the reference location for directional window selection.
559 Returns cons cell in form (hpos . vpos)."
560 (let* ((effarg (if (null arg) 0 (prefix-numeric-value arg)))
561 (edges (xwem-win-pixel-edges window))
562 (top-left (cons (nth 0 edges) (nth 1 edges)))
563 (bot-right (cons (1- (nth 2 edges)) (1- (nth 3 edges)))))
564 (cond ((> effarg 0) top-left)
565 ((< effarg 0) bot-right)
567 ;; As if point in center of WINDOW
568 (cons (+ (nth 0 edges) (/ (- (nth 2 edges) (nth 0 edges)) 2))
569 (+ (nth 1 edges) (/ (- (nth 3 edges) (nth 1 edges)) 2)))))
572 (defun xwem-winmove-other-window (dir &optional arg window)
573 "Calculates location of window to be moved to.
574 Returns cons cell (x . y)."
575 (let ((edges (xwem-win-pixel-edges window))
576 (refpoint (xwem-winmove-refloc arg window)))
577 (cond ((eq dir 'left)
578 (cons (- (nth 0 edges)
579 (xwem-winmove-distance))
584 (xwem-winmove-distance))))
586 (cons (+ (nth 2 edges)
587 (xwem-winmove-distance))
592 (xwem-winmove-distance))))
593 (t (error 'xwem-error "`xwem-winmove-other-window': Invalid direction %s" dir)))))
595 (defun xwem-winmove-select (dir &optional arg window)
596 "Moves to the window in DIR direction."
597 (let* ((frame (xwem-win-frame (or window (xwem-win-selected))))
598 (owin-loc (xwem-winmove-other-window dir arg window))
601 (owin (xwem-window-at x y frame)))
603 (when xwem-win-winmove-allow-jumping
604 (let ((rwin (xwem-frame-rootwin
605 (xwem-win-frame (or window (xwem-win-selected))))))
606 (when (not (xwem-win-xy-in-p x y rwin))
607 ;; we are outside root window
609 (cond ((eq dir 'left)
610 (cons (- (nth 2 (xwem-win-pixel-edges rwin))
613 (cons (- x (nth 2 (xwem-win-pixel-edges rwin)))
616 (cons x (- (nth 3 (xwem-win-pixel-edges rwin))
619 (cons x (+ (- y (nth 3 (xwem-win-pixel-edges rwin)))
620 (nth 1 (xwem-win-pixel-edges rwin)))))
621 (t (error 'xwem-error "Invalid direction"))))
622 (setq owin (xwem-window-at (car owin-loc) (cdr owin-loc) frame)))))
624 (if (not (xwem-win-p owin))
625 (xwem-message 'error "No window at %S" dir)
626 (xwem-select-window owin))
629 ;;;###autoload(autoload 'xwem-other-window "xwem-win" "Switch to other window." t)
630 (defalias 'xwem-other-window 'xwem-frame-goto-next)
632 ;;;###autoload(autoload 'xwem-winmove-up "xwem-win" "" t)
633 (define-xwem-command xwem-winmove-up (arg)
634 "Selects window that up for selected."
635 (xwem-interactive "P")
636 (xwem-winmove-select 'up arg))
637 (put 'xwem-winmove-up 'xwem-frame-command t)
639 ;;;###autoload(autoload 'xwem-winmove-down "xwem-win" "" t)
640 (define-xwem-command xwem-winmove-down (arg)
641 "Selects window that down for selected."
642 (xwem-interactive "P")
643 (xwem-winmove-select 'down arg))
644 (put 'xwem-winmove-down 'xwem-frame-command t)
646 ;;;###autoload(autoload 'xwem-winmove-left "xwem-win" "" t)
647 (define-xwem-command xwem-winmove-left (arg)
648 "Selects window that left for selected."
649 (xwem-interactive "P")
650 (xwem-winmove-select 'left arg))
651 (put 'xwem-winmove-left 'xwem-frame-command t)
653 ;;;###autoload(autoload 'xwem-winmove-right "xwem-win" "" t)
654 (define-xwem-command xwem-winmove-right (arg)
655 "Selects window that right for selected."
656 (xwem-interactive "P")
657 (xwem-winmove-select 'right arg))
658 (put 'xwem-winmove-right 'xwem-frame-command t)
660 ;;; Windows oriented drawers
661 (define-xwem-deffered xwem-win-redraw-delims (win)
662 "Draw delimetrs in window WIN."
663 (when (xwem-win-p win)
664 (let ((wf (xwem-win-frame win))
665 (hc (xwem-win-hchild win))
666 (vc (xwem-win-vchild win)))
668 (while (xwem-win-p hc)
669 ;; For horizontal split
670 (when (xwem-win-p (xwem-win-next hc))
672 (xwem-dpy) (xwem-frame-xwin wf)
673 (xwem-face-get-gc 'xwem-window-delimiter-face
675 (xwem-face-get-gc 'xwem-window-delimiter-face
676 '(horizontal shadow light) hc)
677 (xwem-face-get-gc 'xwem-window-delimiter-face
678 '(horizontal shadow) hc)
679 (+ (xwem-win-x hc) (xwem-win-width hc))
681 (xwem-win-delim-width hc)
683 (xwem-win-delim-shadow-thickness hc)))
685 (xwem-win-redraw-delims-1 hc)
686 (setq hc (xwem-win-next hc)))
688 (while (xwem-win-p vc)
689 ;; For vertical split
690 (when (xwem-win-p (xwem-win-next vc))
692 (xwem-dpy) (xwem-frame-xwin wf)
693 (xwem-face-get-gc 'xwem-window-delimiter-face
695 (xwem-face-get-gc 'xwem-window-delimiter-face
696 '(light shadow vertical) vc)
697 (xwem-face-get-gc 'xwem-window-delimiter-face
698 '(shadow vertical) vc)
700 (+ (xwem-win-y vc) (xwem-win-height vc))
702 (xwem-win-delim-width vc)
703 (xwem-win-delim-shadow-thickness vc)))
705 (xwem-win-redraw-delims-1 vc)
706 (setq vc (xwem-win-next vc)))
709 (defun xwem-win-choose-outline-gc (win)
710 "Choose X-Gc according to WIN's current state."
711 (xwem-face-get-gc 'xwem-window-outline-face
712 (list (if (xwem-frame-selected-p (xwem-win-frame win))
715 (if (xwem-win-selwin-p win)
720 (define-xwem-deffered xwem-win-redraw-win (win)
721 "Redraw only one WIN in WIN's frame."
722 (when (and (xwem-win-p win)
723 (xwem-frame-p (xwem-win-frame win)))
724 (XClearArea (xwem-dpy) (xwem-frame-xwin (xwem-win-frame win))
725 (xwem-win-x win) (xwem-win-y win)
726 (xwem-win-width win) (xwem-win-height win) nil)
727 (if (xwem-win-cl win)
729 (xwem-dpy) (xwem-frame-xwin (xwem-win-frame win))
730 (xwem-win-choose-outline-gc win)
731 (list (make-X-Rect :x (xwem-win-x win)
733 :width (xwem-win-width win)
734 :height (xwem-win-border-width win))
735 (make-X-Rect :x (xwem-win-x win)
737 :width (xwem-win-border-width win)
738 :height (xwem-win-height win))
739 (make-X-Rect :x (+ (xwem-win-x win)
741 (- (xwem-win-border-width win)))
743 :width (xwem-win-border-width win)
744 :height (xwem-win-height win))
745 (make-X-Rect :x (xwem-win-x win)
746 :y (+ (xwem-win-y win)
747 (xwem-win-height win)
748 (- (xwem-win-border-width win)))
749 :width (xwem-win-width win)
750 :height (xwem-win-border-width win))))
752 (let ((cgc (xwem-win-choose-outline-gc win)))
753 (XSetClipRectangles (xwem-dpy) cgc 0 0
754 (list (X-Geom-to-X-Rect (xwem-win-geom win))))
755 (XDrawRectangle (xwem-dpy) (xwem-frame-xwin (xwem-win-frame win))
757 (xwem-win-x win) (xwem-win-y win)
758 (xwem-win-width win) (xwem-win-height win))
759 (setf (X-Gc-clip-mask cgc) X-None)
760 (XChangeGC (xwem-dpy) cgc)))))
762 (define-xwem-deffered xwem-win-redraw-frame (frame)
763 "Outline windows in FRAME if needed."
764 (when (and (xwem-frame-alive-p frame)
765 (eq (xwem-frame-state frame) 'mapped))
766 (xwem-win-map 'xwem-win-redraw-win (xwem-frame-selwin frame))
767 (xwem-win-redraw-delims (xwem-frame-rootwin frame))))
770 (defun xwem-select-window (window)
771 "Set WINDOW to be selected window."
772 (when (xwem-win-alive-p window)
773 (let* ((wframe (xwem-win-frame window))
774 (ow (xwem-frame-selwin wframe))
775 (cl (xwem-win-cl window))
777 (unless (xwem-frame-selected-p wframe)
778 ;; Select client in case WFRAME is embedded client
780 (setq emcl (xwem-frame-get-prop wframe 'xwem-embedded-cl)))
781 (xwem-select-client emcl))
783 (run-hooks 'xwem-frame-deselect-hook)
784 (setq xwem-current-frame wframe)
785 (run-hooks 'xwem-frame-select-hook))
787 (xwem-frame-raise wframe)
788 (unless (eq ow window)
789 (setf (xwem-frame-selwin wframe) window)
790 (run-hook-with-args 'xwem-win-switch-hook ow window))
792 (unless (xwem-cl-selected-p cl)
793 (xwem-select-client cl)))))
796 (defun xwem-window-set-pixsize (window nsize nodelete is-height)
797 "Set pixsize for WINDOW."
798 (let ((old-pixsize (if is-height
799 (xwem-win-height window)
800 (xwem-win-width window)))
801 (min-size (if is-height
806 (if (and (null nodelete)
807 (xwem-win-parent window) ; not top level window
811 (setf (xwem-win-height window) nsize)
812 (setf (xwem-win-width window) nsize))
813 ;; If size will be not enought even after everything is
814 ;; complete - delete window.
815 ;; In case when balancing window, some windows resizes to
816 ;; nsize < min-size temporary, but then resizes again to
817 ;; better size, so we will not delete them.
818 (xwem-deffered-funcall
820 (when (< (if ,is-height
821 (xwem-win-height window)
822 (xwem-win-width window))
826 (xwem-window-delete window)))
831 (setf (xwem-win-height window) nsize)
832 (setq machild (xwem-win-vchild window))
833 (setq michild (xwem-win-hchild window)))
835 (setf (xwem-win-width window) nsize)
836 (setq machild (xwem-win-hchild window))
837 (setq michild (xwem-win-vchild window))))
839 ;; Also refit window's client
840 (when (xwem-cl-p (xwem-win-cl window))
841 (xwem-deffered-funcall 'xwem-refit (xwem-win-cl window)))
843 (cond ((xwem-win-p michild)
844 (mapc (lambda (child)
846 (setf (xwem-win-y child) (xwem-win-y window))
847 (setf (xwem-win-x child) (xwem-win-x window)))
848 (xwem-window-set-pixsize child nsize nodelete is-height))
849 (xwem-win-make-list-by-next michild)))
851 ((xwem-win-p machild)
852 ;; TODO: adjust geom for major child
853 (let* ((last-pos (if is-height
855 (xwem-win-x window)))
860 (mchils (xwem-win-make-list-by-next machild)))
862 ;; Calculate width sum of all delimetrs
864 (when (xwem-win-p (xwem-win-next el))
866 (+ delims-size (xwem-win-delim-width el)))))
869 (mapc #'(lambda (child)
874 (xwem-win-height child)))
875 (setf (xwem-win-y child) last-pos))
877 (setq old-pos (+ last-old-pos
878 (xwem-win-width child)))
879 (setf (xwem-win-x child) last-pos)))
881 (setq pos (/ (+ (* old-pos
882 (if (xwem-win-p (xwem-win-next child))
883 (- nsize delims-size)
886 (- old-pixsize delims-size))
887 (* 2 (- old-pixsize delims-size))))
889 (xwem-window-set-pixsize
890 child (- (+ pos first) last-pos) t is-height)
893 (+ pos first (xwem-win-delim-width child))
894 last-old-pos old-pos))
897 ;; Now delete any children that became too small.
899 (mapc #'(lambda (child)
901 (xwem-window-set-pixsize
902 child (xwem-win-height child) nil t)
903 (xwem-window-set-pixsize
904 child (xwem-win-width child) nil nil)))
905 (xwem-win-make-list-by-next machild)))
908 ;; Normal window, just outdraw
909 (t (xwem-win-redraw-win window)))
911 ;; Redraw WINDOW's frame
912 (xwem-win-redraw-delims (xwem-frame-rootwin (xwem-win-frame window)))
916 (defun xwem-win-set-width (win new-width)
917 "Set window's WIN width to NEW-WIDTH."
918 (xwem-window-set-pixsize win new-width nil nil))
921 (defun xwem-win-set-height (win new-height)
922 "Set window's WIN height to NEW-HEIGHT."
923 (xwem-window-set-pixsize win new-height nil t))
925 ;;;###autoload(autoload 'xwem-window-delete "xwem-win" "Delete selected WINDOW." t)
926 (define-xwem-command xwem-window-delete (win)
928 (xwem-interactive (list (xwem-win-selected)))
930 (unless (xwem-win-p win)
931 (error 'xwem-error "Invalid window" win))
933 (when (xwem-win-only-one-p win)
934 (error 'xwem-error "Can't delete window, because it is only one."))
936 (let ((frame (xwem-win-frame win))
937 dclients owin par pwin ccl)
939 (if (null (xwem-win-parent win))
941 ;; win is top level window
942 ;; TODO: should I delete frame?
945 ;; Normal window - delete it
946 (setq par (xwem-win-parent win))
947 (setq pwin (xwem-frame-selwin frame))
948 (while (and (xwem-win-p pwin) (not (eq pwin win)))
949 (setq pwin (xwem-win-parent pwin)))
951 ;; If we're going to delete selected window then we should
952 ;; update selected window and demanage client, and maybe
953 ;; collect its clients to other window.
954 (setq dclients (xwem-win-clients win))
955 (setq owin (xwem-window-other 1 win))
957 (xwem-cl-change-window cl owin))
961 ;; If there no clients in window manage our client
962 (when (and (not (xwem-cl-p (xwem-win-cl owin)))
963 (xwem-cl-p (setq ccl (xwem-win-cl win))))
964 (xwem-cl-change-window ccl owin)
966 (xwem-select-window owin))
968 ;; close that hole in list
969 ;; XXX: check h v h split then delete right win ...
970 (when (xwem-win-p (xwem-win-next win))
971 (setf (xwem-win-prev (xwem-win-next win)) (xwem-win-prev win)))
972 (when (xwem-win-p (xwem-win-prev win))
973 (setf (xwem-win-next (xwem-win-prev win)) (xwem-win-next win)))
974 (when (eq win (xwem-win-hchild par))
975 (setf (xwem-win-hchild par) (xwem-win-next win)))
976 (when (eq win (xwem-win-vchild par))
977 (setf (xwem-win-vchild par) (xwem-win-next win)))
979 ;; TODO: adjust the geometry
980 (let ((sib (xwem-win-prev win)))
982 (setq sib (xwem-win-next win))
983 (setf (xwem-win-x sib) (xwem-win-x win))
984 (setf (xwem-win-y sib) (xwem-win-y win)))
986 (when (xwem-win-p (xwem-win-vchild par))
987 (xwem-window-set-pixsize
989 (+ (xwem-win-height sib)
990 (xwem-win-height win)
991 (car xwem-win-vertical-delim-width))
994 (when (xwem-win-p (xwem-win-hchild par))
995 (xwem-window-set-pixsize
997 (+ (xwem-win-width sib)
999 (car xwem-win-horizontal-delim-width))
1002 ;; If parent now has only one child put child into parent
1004 (when (null (xwem-win-next (xwem-win-child par)))
1005 (xwem-win-replace par (xwem-win-child par))
1006 (xwem-win-mark-deleted par))
1008 ;; Since we deleting combination of windows we should delete
1010 (when (xwem-win-p (xwem-win-child win))
1011 (xwem-win-delete-subwindows (xwem-win-child win)))
1013 (xwem-win-mark-deleted win)
1015 ;; Redraw WIN's frame
1016 (xwem-win-redraw-frame (xwem-win-frame win))
1018 ;; Now run on-delete hooks
1019 (run-hook-with-args 'xwem-win-delete-hook win))
1021 (put 'xwem-window-delete 'xwem-frame-command t)
1023 ;;;###autoload(autoload 'xwem-window-delete-others "xwem-win" nil t)
1024 (define-xwem-command xwem-window-delete-others (window)
1025 "Delete all xwem windows other then WINDOW."
1026 (xwem-interactive (list (xwem-win-selected)))
1028 (unless (xwem-win-p window)
1029 (error 'xwem-error "Invalid window" window))
1031 (xwem-win-map #'(lambda (ww)
1032 (unless (eq ww window)
1033 (xwem-window-delete ww)))
1035 (put 'xwem-window-delete-others 'xwem-frame-command t)
1037 (defun xwem-win-delete-subwindows (win)
1038 "Delete all childs of WIN."
1039 (when (xwem-win-p (xwem-win-next win))
1040 (xwem-win-delete-subwindows (xwem-win-next win)))
1041 (when (xwem-win-child win)
1042 (xwem-win-delete-subwindows (xwem-win-child win)))
1044 (xwem-win-mark-deleted win))
1047 (defun xwem-win-map (fn &optional window)
1048 "Apply FN to FRAME-WIN and each subwindow.
1049 FN will be called with a window as argument.
1050 If ommitted, WINDOW defaults to the `(xwem-win-selected)'."
1051 (let* ((start-win (or window (xwem-win-selected)))
1055 (setq res (cons (funcall fn start-win) res))
1056 (setq cur-win (xwem-window-next start-win)))
1058 (while (not (eq cur-win start-win))
1059 (setq res (cons (funcall fn cur-win) res))
1060 (setq cur-win (xwem-window-next cur-win)))
1063 (defun xwem-win-count (&optional window)
1066 (xwem-win-map #'(lambda (win) (setq cnt (+ cnt 1))) window)
1069 ;;;###autoload(autoload 'xwem-balance-windows "xwem-win" "" t)
1070 (define-xwem-command xwem-balance-windows (&optional win)
1071 "Make all WIN's parent children windows to be same height or width.
1072 If WIN is ommited, selected window is used."
1073 (xwem-interactive (list (xwem-win-selected)))
1074 (unless (xwem-win-p win)
1075 (error 'xwem-error "invalid window" win))
1077 (when (xwem-win-p (setq win (xwem-win-parent win)))
1078 (let* ((height-p (xwem-win-p (xwem-win-vchild win)))
1079 (getsizefn (if height-p
1080 'xwem-win-pixel-height
1081 'xwem-win-pixel-width))
1082 (wins (xwem-win-make-list-by-next (xwem-win-child win)))
1086 (setq size (/ (funcall getsizefn win) (length wins)))
1088 (xwem-window-enlarge
1089 (- size (funcall getsizefn w) (xwem-win-delim-width w))
1093 (xwem-window-enlarge
1094 (- size (funcall getsizefn w) (xwem-win-delim-width w))
1098 (put 'xwem-balance-windows 'xwem-frame-command t)
1100 ;;;###(autoload 'xwem-transpose-windows "xwem-win" nil t)
1101 (define-xwem-command xwem-transpose-windows (arg)
1102 "Transpose selected window with other window.
1103 Prefix ARG directly passed to `xwem-window-other' to findout other
1105 (xwem-interactive "p")
1107 (let ((cw (xwem-win-selected))
1108 (ow (xwem-window-other arg)))
1109 (when (or (eq cw ow)
1110 (not (xwem-win-p cw))
1111 (not (xwem-win-p ow)))
1112 (error 'xwem-error "Can't transpose windows"))
1114 (let ((cwcl (xwem-win-cl cw))
1115 (cwcls (xwem-win-clients cw))
1116 (owcl (xwem-win-cl ow))
1117 (owcls (xwem-win-clients ow)))
1119 (xwem-win-set-cl cw owcl)
1120 (mapc #'(lambda (cl) (xwem-cl-set-win cl cw)) (nreverse owcls))
1122 (xwem-win-set-cl ow cwcl)
1123 (mapc #'(lambda (cl) (xwem-cl-set-win cl ow)) (nreverse cwcls))
1125 (xwem-select-window cw))))
1126 (put 'xwem-transpose-windows 'xwem-frame-command t)
1129 (defun xwem-win-only-one-p (&optional window)
1130 "Return non-nil if WINDOW is only one in chain.
1131 If WINDOW ommitted `(xwem-win-selected)' used."
1132 (= 1 (xwem-win-count (or window (xwem-win-selected)))))
1134 (defun xwem-window-list (&optional frame)
1135 "Return list of windows for FRAME.
1136 Default FRAME is selected frame."
1137 (let* ((wlf (or frame (xwem-frame-selected)))
1138 (win (xwem-frame-rootwin wlf))
1140 (xwem-win-map #'(lambda (win)
1141 (setq rlist (cons win rlist)))
1145 (defun xwem-win-pixel-edges (&optional window)
1146 "Return a list of the pixel edge coordinates of WINDOW.
1147 \\(LEFT TOP RIGHT BOTTOM\\), all relative to 0, 0 at top left corner of
1148 frame. The frame title are considered to be outside of this area."
1150 (setq window (xwem-win-selected)))
1151 (list (xwem-win-x window)
1153 (+ (xwem-win-x window) (xwem-win-width window))
1154 (+ (xwem-win-y window) (xwem-win-height window))))
1156 (defun xwem-win-pixel-width (&optional window)
1157 "Retrun width in pixels of WINDOW."
1158 (xwem-win-width (or window (xwem-win-selected))))
1160 (defun xwem-win-pixel-height (&optional window)
1161 "Return height in pixels of WINDOW."
1162 (xwem-win-height (or window (xwem-win-selected))))
1164 (defun xwem-win-pixels-steps (&optional window)
1165 "Convert size in pixels to size in steps for WINDOW."
1166 (error 'xwem-error "`xwem-win-pixels-steps' not yet implemented."))
1168 (defun xwem-win-steps-pixels (&optional window)
1169 "Convert size in steps to size in pixels for WINDOW."
1170 (error 'xwem-error "`xwem-win-steps-pixels' not yet implemented."))
1172 ;;; START: Window configurations section
1175 (defun xwem-window-configuration (&optional frame)
1176 "Return an object representing the current window configuration of xwem FRAME.
1177 If FRAME is nil or ommited, use the sected frame."
1178 (let ((frm (or frame (xwem-frame-selected))))
1179 (when (xwem-frame-p frm)
1180 (make-xwem-win-config
1182 :frame-xgeom (copy-X-Geom (xwem-frame-xgeom frm))
1183 :frame-properties (xwem-frame-properties frm)
1184 :current-cl (xwem-win-cl (xwem-frame-selwin frm))
1185 :min-width xwem-win-min-width :min-height xwem-win-min-height
1186 :saved-root-window (xwem-win-root->saved-win (xwem-frame-rootwin frm))))))
1188 (defun xwem-win-root->saved-win (win)
1189 "Convert an xwem root WIN into a tree of saved-window structures."
1191 (make-xwem-win-saved
1192 :id (xwem-win-id win)
1193 :geom (copy-X-Geom (xwem-win-geom win))
1194 :clients (copy-list (xwem-win-clients win))
1195 :cl (xwem-win-cl win)
1196 :plist (xwem-win-properties win)
1197 :selwin-p (xwem-win-selwin-p win)
1198 :first-hchild (and (xwem-win-p (xwem-win-hchild win))
1199 (xwem-win-root->saved-win (xwem-win-hchild win)))
1200 :first-vchild (and (xwem-win-p (xwem-win-vchild win))
1201 (xwem-win-root->saved-win (xwem-win-vchild win)))
1203 :next (and (xwem-win-p (xwem-win-next win))
1204 (xwem-win-root->saved-win (xwem-win-next win)))
1208 (defun xwem-win-config-equal (win-cfg0 win-cfg1)
1209 "Return non-nil if two window configurations WIN-CFG0 and WIN-CFG1 are equal."
1210 (equal win-cfg0 win-cfg1))
1213 (defun xwem-set-window-configuration (config &optional select-frame-p)
1214 "Set window to CONFIG.
1215 If optional argument SELECT-FRAME-P is non-nil also select frame for
1216 which window CONFIG was generated."
1217 (let ((frame (xwem-win-config-frame config)))
1218 (when (and (xwem-frame-alive-p frame)
1219 (not (xwem-win-config-equal
1220 config (xwem-window-configuration frame))))
1222 (xwem-frame-reduce-to-one-window frame)
1223 (xwem-frame-set-win-config-frame-params config)
1225 (xwem-win-restore-saved-win
1226 config (xwem-frame-rootwin frame)
1227 (xwem-win-config-saved-root-window config) 'vertical)
1229 ;; XXX what is this?
1230 (setq xwem-win-min-width (xwem-win-config-min-width config))
1231 (setq xwem-win-min-height (xwem-win-config-min-height config)))
1233 ;; Time to select frame
1234 (when (and select-frame-p (xwem-frame-alive-p frame))
1235 (xwem-select-frame frame))))
1237 (defun xwem-frame-reduce-to-one-window (frame)
1238 "Delete all windows except the one."
1239 (let ((swin (xwem-frame-selwin frame)))
1240 (xwem-win-map #'(lambda (ww)
1241 (when (not (eq ww swin))
1242 (xwem-window-delete ww)))
1245 (defun xwem-frame-set-win-config-frame-params (config)
1246 "Restore FRAME size of a window configuration CONFIG."
1247 (setf (xwem-frame-xgeom (xwem-win-config-frame config))
1248 (copy-X-Geom (xwem-win-config-frame-xgeom config)))
1249 (xwem-frame-apply-xgeom-1 (xwem-win-config-frame config))
1250 (xwem-frame-set-properties (xwem-win-config-frame config)
1251 (xwem-win-config-frame-properties config)))
1253 (defun xwem-win-restore-saved-win (config win saved-win direction)
1254 "Within CONFIG, restore WIN to the state of SAVED-WIN."
1255 (if (xwem-win-saved-next saved-win)
1257 (xwem-win-split win direction)
1258 (xwem-win-restore-win-params config win saved-win)
1259 (xwem-win-restore-saved-win config (xwem-win-next win)
1260 (xwem-win-saved-next saved-win) direction))
1262 ;; [else] No next saved
1263 (xwem-win-restore-win-params config win saved-win))
1265 (when (xwem-win-saved-first-hchild saved-win)
1266 (xwem-win-restore-saved-win config win
1267 (xwem-win-saved-first-hchild saved-win)
1269 (when (xwem-win-saved-first-vchild saved-win)
1270 (xwem-win-restore-saved-win config win
1271 (xwem-win-saved-first-vchild saved-win)
1274 (defun xwem-win-subr-first-member (l1 l2)
1275 "Return first element in L1, which also in L2.
1276 Comparison done using `eq'."
1277 (while (and l1 (not (memq (car l1) l2)))
1281 (defun xwem-reorder-clients (clients clients-list)
1282 "Reorder CLIENTS to be in same order as in CLIENTS-LIST.
1283 This is destructive function, it will modify CLIENTS list directly."
1288 (when (setq t1 (memq (car scls) cls))
1289 (setq t2 (xwem-win-subr-first-member cls scls))
1290 (xwem-list-exchange-els clients (car t1) (car t2))
1294 (setq scls (cdr scls))
1295 (setq cls (cdr cls)))))
1297 (defun xwem-win-reorder-clients (saved-win)
1298 "Reorder `xwem-clients' in SAVED-WIN clients order."
1299 (let ((cls xwem-clients)
1300 (scls (xwem-win-saved-clients saved-win))
1303 (when (setq t1 (memq (car scls) cls))
1304 (setq t2 (xwem-win-subr-first-member cls scls))
1305 (xwem-list-exchange-els xwem-clients (car t1) (car t2))
1309 (setq scls (cdr scls))
1310 (setq cls (cdr cls)))))
1312 (defun xwem-win-restore-win-params (config win saved-win)
1313 "Restore the windown parameters stored in SAVED-WIN on WIN."
1314 (let ((cln (xwem-win-saved-cl saved-win)))
1315 ;; Restore ID and PLIST
1316 (setf (xwem-win-id win) (xwem-win-saved-id saved-win)
1317 (xwem-win-plist win) (copy-list (xwem-win-saved-plist saved-win)))
1319 ;; Resort clients in WIN's order
1320 (xwem-win-reorder-clients saved-win)
1322 ;; Collect clients to WIN
1323 (mapc #'(lambda (cl)
1324 (when (xwem-cl-alive-p cl)
1325 (xwem-cl-set-win cl win)))
1326 (xwem-win-saved-clients saved-win))
1328 ;; Restore window geometry
1329 (when (and (not (xwem-win-saved-first-hchild saved-win))
1330 (not (xwem-win-saved-first-vchild saved-win)))
1331 (when (not (eq win (xwem-frame-rootwin (xwem-win-frame win))))
1332 (xwem-window-enlarge (- (X-Geom-width (xwem-win-saved-geom saved-win))
1333 (xwem-win-width win)) nil win)
1334 (xwem-window-enlarge (- (X-Geom-height (xwem-win-saved-geom saved-win))
1335 (xwem-win-height win)) t win)))
1337 ;; Remanage current WIN's client
1338 (when (xwem-cl-alive-p cln)
1340 (xwem-cl-change-window cln win)
1341 (xwem-activate cln))
1343 (when (xwem-win-saved-selwin-p saved-win)
1344 (setf (xwem-frame-selwin (xwem-win-frame win)) win))))
1348 ;;;###autoload(autoload 'xwem-window-split-horizontally "xwem-win" nil t)
1349 (define-xwem-command xwem-window-split-horizontally (arg &optional window)
1350 "Split WINDOW horizontally."
1351 (xwem-interactive (list (prefix-numeric-value xwem-prefix-arg)
1352 (xwem-win-selected)))
1355 (setq window (xwem-win-selected)))
1356 (unless (xwem-win-p window)
1357 (error 'xwem-error "Invalid window" window))
1359 (when (xwem-frame-dedicated-p (xwem-win-frame window))
1360 (error 'xwem-error "Can't split dedicated frame"))
1362 (xwem-win-split window 'horizontal arg))
1363 (put 'xwem-window-split-horizontally 'xwem-frame-command t)
1365 ;;;###autoload(autoload 'xwem-window-split-vertically "xwem-win" nil t)
1366 (define-xwem-command xwem-window-split-vertically (arg &optional window)
1367 "Split WINDOW horizontally."
1368 (xwem-interactive (list (prefix-numeric-value xwem-prefix-arg)
1369 (xwem-win-selected)))
1371 (setq window (xwem-win-selected)))
1372 (unless (xwem-win-p window)
1373 (error 'xwem-error "Invalid window" window))
1375 (when (xwem-frame-dedicated-p (xwem-win-frame window))
1376 (error 'xwem-error "Can't split dedicated frame."))
1378 (xwem-win-split window 'vertical arg))
1379 (put 'xwem-window-split-vertically 'xwem-frame-command t)
1381 ;;;###autoload(autoload 'xwem-window-enlarge-horizontally "xwem-win" nil t)
1382 (define-xwem-command xwem-window-enlarge-horizontally (n window)
1383 "Enlarge horizontally WINDOW by N pixels."
1384 (xwem-interactive (list (prefix-numeric-value xwem-prefix-arg)
1385 (xwem-win-selected)))
1386 (unless (xwem-win-p window)
1387 (error 'xwem-error "Invalid window" window))
1389 (xwem-window-enlarge n nil window))
1390 (put 'xwem-window-enlarge-horizontally 'xwem-frame-command t)
1392 ;;;###autoload(autoload 'xwem-window-enlarge-vertically "xwem-win" nil t)
1393 (define-xwem-command xwem-window-enlarge-vertically (n window)
1394 "Enlarge vertically WINDOW by N pixels."
1395 (xwem-interactive (list (prefix-numeric-value xwem-prefix-arg)
1396 (xwem-win-selected)))
1397 (unless (xwem-win-p window)
1398 (error 'xwem-error "Invalid window" window))
1400 (xwem-window-enlarge n t window))
1401 (put 'xwem-window-enlarge-vertically 'xwem-frame-command t)
1403 (defun xwem-win-split (&optional window how new-size)
1405 When WINDOW is ommitted `(xwem-win-selected)' used.
1406 HOW is 'vertical of 'horizontal, default is 'horizontal.
1407 If NEW-SIZE is given make WINDOW NEW-SIZE pixels bigger after split."
1408 (let* ((sp-win (or window (xwem-win-selected)))
1409 (sp-how (or how 'horizontal))
1410 (hor (equal sp-how 'horizontal))
1411 (nwin (xwem-win-new (list :frame (xwem-win-frame sp-win))))
1412 (nsiz (or new-size 0))
1413 psize psize1 psize2 remd)
1417 (setq psize (/ (- (xwem-win-width sp-win)
1418 (car xwem-win-horizontal-delim-width)) 2))
1419 (setq remd (% (- (xwem-win-width sp-win)
1420 (car xwem-win-horizontal-delim-width)) 2)))
1422 (setq psize (/ (- (xwem-win-height sp-win)
1423 (car xwem-win-vertical-delim-width)) 2))
1424 (setq remd (% (- (xwem-win-height sp-win)
1425 (car xwem-win-vertical-delim-width)) 2))))
1427 (setq psize1 (+ psize nsiz))
1428 (setq psize2 (+ psize remd (- nsiz)))
1429 ;; Check that minimal widht or height is not exceeded
1430 (xwem-debug 'xwem-misc "Doing split hor=%s psize=%d" 'hor 'psize)
1433 (if (or (< psize1 xwem-win-min-width)
1434 (< psize2 xwem-win-min-width))
1435 (error 'xwem-error "Can't do split.")
1438 (when (or (null (xwem-win-parent sp-win))
1439 (null (xwem-win-hchild (xwem-win-parent sp-win))))
1440 (xwem-win-make-parent sp-win)
1441 (setf (xwem-win-hchild (xwem-win-parent sp-win)) sp-win)))
1444 (if (or (< psize1 xwem-win-min-height)
1445 (< psize2 xwem-win-min-height))
1446 (error 'xwem-error "Can't do split.")
1448 (when (or (null (xwem-win-parent sp-win))
1449 (null (xwem-win-vchild (xwem-win-parent sp-win))))
1450 (xwem-win-make-parent sp-win)
1451 (setf (xwem-win-vchild (xwem-win-parent sp-win)) sp-win))))
1453 (setf (xwem-win-frame nwin) (xwem-win-frame sp-win))
1454 (setf (xwem-win-next nwin) (xwem-win-next sp-win))
1455 (when (xwem-win-p (xwem-win-next nwin))
1456 (setf (xwem-win-prev (xwem-win-next nwin)) nwin))
1457 (setf (xwem-win-prev nwin) sp-win)
1458 (setf (xwem-win-next sp-win) nwin)
1459 (setf (xwem-win-parent nwin) (xwem-win-parent sp-win))
1461 ;; TODO: adjust geometry
1464 (setf (xwem-win-width sp-win) psize1)
1465 (setf (xwem-win-x nwin)
1466 (+ (xwem-win-delim-width sp-win)
1468 (xwem-win-width sp-win)))
1469 (setf (xwem-win-y nwin) (xwem-win-y sp-win))
1470 (setf (xwem-win-width nwin) psize2)
1471 (setf (xwem-win-height nwin) (xwem-win-height sp-win)))
1473 (setf (xwem-win-height sp-win) psize1)
1474 (setf (xwem-win-x nwin) (xwem-win-x sp-win))
1475 (setf (xwem-win-y nwin)
1476 (+ (xwem-win-delim-width sp-win)
1478 (xwem-win-height sp-win)))
1479 (setf (xwem-win-width nwin) (xwem-win-width sp-win))
1480 (setf (xwem-win-height nwin) psize2)))
1482 ;; Client refitting if needed
1483 (when (xwem-cl-p (xwem-win-cl sp-win))
1484 (xwem-deffered-funcall 'xwem-refit (xwem-win-cl sp-win)))
1486 ;; NOTE: nwin is (xwem-win-next sp-win)
1487 (run-hook-with-args 'xwem-win-split-hook sp-win nwin)
1489 ;; Redraw window delimiters and outline
1490 (xwem-win-redraw-delims (xwem-win-parent nwin))
1491 (xwem-win-redraw-win nwin)
1492 (xwem-win-redraw-win sp-win)
1495 (defvar xwem-allow-resize-frame-when-resizing-root-window t
1496 "Non-nil mean win's frame can be resized if resizing frame's root window.")
1498 (defun xwem-window-change-size (win delta height-p)
1499 "Change WIN size to old-size plus DELTA."
1500 (let ((getsizefn (if height-p 'xwem-win-pixel-height 'xwem-win-pixel-width))
1501 (setsizefn (if height-p 'xwem-win-set-height 'xwem-win-set-width))
1503 wsize minsize maxdelta)
1505 (if (eq win (xwem-frame-rootwin (xwem-win-frame win)))
1507 (if xwem-allow-resize-frame-when-resizing-root-window
1508 (xwem-frame-set-size (xwem-win-frame win)
1510 (xwem-frame-xgeom (xwem-win-frame win)))
1511 (if height-p 0 delta))
1513 (xwem-frame-xgeom (xwem-win-frame win)))
1514 (if height-p delta 0)))
1515 (error 'xwem-error "Can't change size of frame's root window"))
1517 (setq par (xwem-win-parent win))
1518 (while (and par (not (if height-p
1519 (xwem-win-vchild par)
1520 (xwem-win-hchild par))))
1522 (setq par (xwem-win-parent win)))
1524 (setq wsize (funcall getsizefn win))
1525 (setq minsize (if height-p xwem-win-min-height xwem-win-min-width))
1526 (when (< (+ wsize delta) minsize)
1528 "Minimum size exceeded while in `xwem-window-change-size'"))
1530 (setq maxdelta (if par (- (funcall getsizefn par) wsize)
1531 (if (xwem-win-next win)
1532 (- (funcall getsizefn (xwem-win-next win))
1534 (if (xwem-win-prev win)
1535 (- (funcall getsizefn (xwem-win-prev win))
1538 (when (> delta maxdelta)
1539 (setq delta maxdelta))
1542 (if (and (xwem-win-p (xwem-win-next win))
1543 (>= (- (funcall getsizefn (xwem-win-next win)) delta) minsize))
1546 'xwem-misc "HERE IN xwem-window-change-size: delta=%d" 'delta)
1548 (setf (xwem-win-y (xwem-win-next win))
1549 (+ (xwem-win-y (xwem-win-next win)) delta))
1550 (setf (xwem-win-x (xwem-win-next win))
1551 (+ (xwem-win-x (xwem-win-next win)) delta)))
1552 (funcall setsizefn (xwem-win-next win)
1553 (- (funcall getsizefn (xwem-win-next win)) delta))
1554 (funcall setsizefn win (+ (funcall getsizefn win) delta)))
1556 (if (and (xwem-win-p (xwem-win-prev win))
1557 (>= (- (funcall getsizefn (xwem-win-prev win)) delta)
1560 (funcall setsizefn (xwem-win-prev win)
1561 (- (funcall getsizefn (xwem-win-prev win)) delta))
1563 (setf (xwem-win-y win) (- (xwem-win-y win) delta))
1564 (setf (xwem-win-x win) (- (xwem-win-x win) delta)))
1565 (funcall setsizefn win (+ (funcall getsizefn win) delta)))
1567 ;; If we are here than changing window size possible
1568 ;; causes changing parent size.
1569 (let ((opht (funcall getsizefn par))
1571 (if (<= opht (+ delta wsize))
1572 (setq delta1 (* opht opht 2))
1574 (setq delta1 (/ (* delta opht 100)
1575 (* (- opht wsize delta) 100))))
1578 (setf (xwem-win-height par) (+ opht delta1))
1579 (setf (xwem-win-width par) (+ opht delta1)))
1581 (funcall setsizefn win (+ wsize delta1))
1582 (funcall setsizefn par opht)
1586 (defun xwem-window-enlarge (n &optional height-p window)
1587 "Make WINDOW N pixels bigger.
1588 If HEIGHT-P is non-nil then enlarge vertically.
1589 If WINDOW is ommited then selected window will be used."
1590 (xwem-window-change-size (or window (xwem-win-selected)) n height-p))
1592 (defun xwem-window-shrink (n &optional height-p window)
1593 "Make WINDON N pixels smaller.
1594 If HEIGHT-P is non-nil then shrink vertically.
1595 If WINDOW is ommited then selected window will be used."
1596 (xwem-window-change-size (or window (xwem-win-selected)) (- n) height-p))
1599 (defun xwem-window-set-size (win new-width new-height)
1600 "Set WIN's size to be NEW-WIDTH, NEW-HEIGHT."
1601 (xwem-window-change-size win (- new-width (xwem-win-width win)) nil)
1602 (xwem-window-change-size win (- new-height (xwem-win-height win)) t))
1604 (defsubst xwem-win-redraw-selected-frame ()
1605 "Redraw selected frame."
1606 (xwem-win-redraw-frame (xwem-frame-selected)))
1608 (defun xwem-win-init ()
1609 "Initialize xwem windows."
1610 (add-hook 'xwem-win-switch-hook
1611 #'(lambda (owin nwin)
1612 (when (xwem-win-p owin)
1613 (xwem-win-redraw-win owin))
1614 (when (xwem-win-p nwin)
1615 (xwem-win-redraw-win nwin))))
1617 (add-hook 'xwem-frame-select-hook 'xwem-win-redraw-selected-frame)
1618 (add-hook 'xwem-frame-deselect-hook 'xwem-win-redraw-selected-frame)
1619 (add-hook 'xwem-frame-redraw-hook 'xwem-win-redraw-frame)
1623 (defvar xwem-win-supported-properties '(domain-faces)
1624 "List of supported window properties.")
1626 (defun xwem-win-properties (win)
1627 "Return list of win's properties."
1628 (let ((wplist (xwem-win-plist win))
1631 (when (memq (car wplist) xwem-win-supported-properties)
1632 (setq rplist (plist-put rplist (car wplist) (cadr wplist))))
1633 (setq wplist (cddr wplist)))
1639 ;;;; On-load actions:
1640 ;; - Initialize windows
1643 ;;; xwem-win.el ends here