1 ;;; xwem-tabbing.el --- Tabs in XWEM frames.
3 ;; Copyright (C) 2003-2005 by XWEM Org.
5 ;; Author: Zajcev Evgeny <zevlg@yandex.ru>
6 ;; Created: Sun Dec 7 18:35:15 MSK 2003
7 ;; Keywords: xwem, xlib
8 ;; X-CVS: $Id: xwem-tabbing.el,v 1.8 2005-04-04 19:54:16 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 ;; Tab format may contain one of escape seqs:
32 ;; %n - Client's name (WM_NAME)
33 ;; %c - Client's class instance (WM_CLASS)
34 ;; %C - Client's class name (WM_CLASS)
36 ;; %u - Client's uptime
37 ;; %U - Cilent's Uptime
38 ;; %s - Client's size in pixels
39 ;; %S - Client's size in units
40 ;; %f - Client's Frame number
41 ;; %F - Client's Frame name
42 ;; %* - "*" when client marked and "-" when not.
43 ;; %# - "#" when client support WM_DELETE and "-" when not.
47 ;; "L" - Locally Active
48 ;; "G" - Globally Active
50 ;; %{ - starts emacs lisp
51 ;; %} - ends emacs lisp
53 ;; %0 - begin using default face
54 ;; %[1-9] - start using additional `xwem-tabber-face[num]' defined
55 ;; using `define-xwem-face'.
57 ;; Note that while running elisp within %{ and %} symbol `cl' refers
60 ;; Also `X-use-queryfont' is highly recommended to be `t' if you are
64 ;; Supported clients properties:
66 ;; `xwem-tab-format' - Tab format for certain client.
76 (defgroup xwem-tab nil
77 "Group to customize tabs."
82 (defcustom xwem-tab-default-format " %i %*%# %n"
83 "*Default format for tab item."
87 (defcustom xwem-tab-empty-format "<empty>"
88 "What to show when there no client."
92 (defcustom xwem-tab-delim-interval 2
93 "*Number of clients to group, will draw largeer delimeter."
97 (defcustom xwem-tab-show-cl-info-on-click t
98 "*Non-nil mean show client info when `xwem-tabber-switch-cl' called."
102 (define-xwem-face xwem-tabber-face
103 `(((frame-selected tab-selected)
104 (:foreground "white" :background "green4" :bold t))
105 ((delimiter-left frame-selected tab-selected)
106 (:foreground "white"))
107 ((delimiter-right frame-selected tab-selected)
108 (:foreground "black"))
110 ((frame-selected tab-nonselected)
111 (:foreground "black" :background "gray80"))
112 ((delimiter-left frame-selected tab-nonselected)
113 (:foreground "white"))
114 ((delimiter-right frame-selected tab-nonselected)
115 (:foreground "black"))
117 ((frame-nonselected tab-selected)
118 (:foreground "gray80" :background "DarkGreen" :bold t))
119 ((delimiter-left frame-nonselected tab-selected)
120 (:foreground "white"))
121 ((delimiter-right frame-nonselected tab-selected)
122 (:foreground "black"))
124 ((frame-nonselected tab-nonselected)
125 (:foreground "black" :background "gray40"))
126 ((delimiter-left frame-nonselected tab-nonselected)
127 (:foreground "white"))
128 ((delimiter-right frame-nonselected tab-nonselected)
129 (:foreground "black"))
131 (t (:foreground "white")))
136 ;; Another interface to customize tabber fonts
137 (defcustom xwem-tabber-font:frame.selected-tab.selected nil
138 "Font to be used in selected tab of selected frame."
139 :type '(restricted-sexp :match-alternatives (nil try-font-name))
140 :set (lambda (sym val)
144 (or val (xwem-face-font 'xwem-tabber-face '(default)))
145 '(frame-selected tab-selected)))
146 :initialize 'custom-initialize-default
149 (defcustom xwem-tabber-font:frame.selected-tab.nonselected nil
150 "Font to be used in selected tab of selected frame."
151 :type '(restricted-sexp :match-alternatives (nil try-font-name))
152 :set (lambda (sym val)
156 (or val (xwem-face-font 'xwem-tabber-face '(default)))
157 '(frame-selected tab-nonselected)))
158 :initialize 'custom-initialize-default
161 (defcustom xwem-tabber-font:frame.nonselected-tab.selected nil
162 "Font to be used in selected tab of selected frame."
163 :type '(restricted-sexp :match-alternatives (nil try-font-name))
164 :set (lambda (sym val)
168 (or val (xwem-face-font 'xwem-tabber-face '(default)))
169 '(frame-nonselected tab-selected)))
170 :initialize 'custom-initialize-default
173 (defcustom xwem-tabber-font:frame.nonselected-tab.nonselected nil
174 "Font to be used in selected tab of selected frame."
175 :type '(restricted-sexp :match-alternatives (nil try-font-name))
176 :set (lambda (sym val)
180 (or val (xwem-face-font 'xwem-tabber-face '(default)))
181 '(frame-nonselected tab-nonselected)))
182 :initialize 'custom-initialize-default
185 ;;; Internal variables
187 (defvar xwem-tabber-map
188 (let ((map (make-sparse-keymap)))
189 (define-key map [button1] 'xwem-tabber-smart-drag-frame)
190 (define-key map [button1up] 'xwem-tabber-switch-cl)
191 (define-key map [button3] 'xwem-tabber-popup-cl-menu)
193 "Keymap used when accessing `xwem-tabber'.")
195 (defvar xwem-tabber-dedicated-map
196 (let ((map (make-sparse-keymap)))
197 (define-key map [button1] 'xwem-tabber-drag-frame)
198 (define-key map [button3] 'xwem-tabber-popup-cl-menu)
200 "Keymap for dedicated clients.")
203 (defvar xwem-tabber-click-frame nil
204 "Will be binded to frame when tabber clicked.")
206 (defvar xwem-tabber-click-cl nil
207 "Will be binded to cl when tabber clicked.")
211 ;; Margin is some area in tabber, which is drawed specially.
212 ;; Margin is a list in form (rect format face)
215 (defstruct xwem-tabber
216 frame ; xwem-frame, our parent
217 xgeom ; Tabber's geometry
218 clients ; clients list
220 xwin ; Tabber's X-Win
221 xpreparer ; Tabber's X-Pixmap to prepare tab items
222 xpix-copy ; Tabber's X-Pixmap used to copy to xwin
225 margins ; list of margins
231 (defmacro xwem-frame-tabber (frame)
232 `(xwem-frame-get-prop ,frame 'xwem-tabber))
233 (defsetf xwem-frame-tabber (frame) (tabber)
234 `(xwem-frame-put-prop ,frame 'xwem-tabber ,tabber))
236 (defmacro xwem-cl-tabber (cl)
237 `(let ((win (xwem-cl-win ,cl)))
238 (and win (xwem-frame-tabber (xwem-win-frame win)))))
240 (defmacro xwem-cl-tab-rect (cl)
241 `(xwem-cl-get-sys-prop ,cl 'xwem-tab-rect))
242 (defsetf xwem-cl-tab-rect (cl) (tab-rect)
243 `(xwem-cl-put-sys-prop ,cl 'xwem-tab-rect ,tab-rect))
245 (defmacro xwem-cl-tab-face (cl)
246 `(or (and cl (xwem-client-property ,cl 'xwem-tab-face))
248 (defsetf xwem-cl-tab-face (cl) (tab-face)
249 `(xwem-client-set-property ,cl 'xwem-tab-face ,tab-face))
251 (define-xwem-client-property xwem-tab-format nil
254 :get 'xwem-tab-get-xwem-tab-format
255 :set 'xwem-tab-set-xwem-tab-format)
257 (defun xwem-tab-get-xwem-tab-format (cl tprop)
258 "Get tab format for CL."
259 (or (xwem-cl-get-prop cl 'xwem-tab-format)
260 xwem-tab-default-format))
262 (defun xwem-tab-set-xwem-tab-format (cl tprop tval)
263 "Set CL's tab format property TPROP to TVAL."
264 (xwem-cl-put-prop cl tprop tval)
265 (xwem-tabber-on-cl-change cl))
270 (defsubst xwem-tabber-put-prop (tabber prop val)
271 (setf (xwem-tabber-plist tabber)
272 (plist-put (xwem-tabber-plist tabber) prop val)))
273 (put 'xwem-tabber-put-prop 'lisp-indent-function 2)
275 (defsubst xwem-tabber-get-prop (tabber prop)
276 (plist-get (xwem-tabber-plist tabber) prop))
278 (defsubst xwem-tabber-rm-prop (tabber prop)
279 (setf (xwem-tabber-plist tabber)
280 (plist-remprop (xwem-tabber-plist tabber) prop)))
282 (defun xwem-tabber-init ()
283 "Initialize tabbing."
284 (xwem-message 'init "Initializing tabbing ...")
287 (add-hook 'xwem-frame-creation-hook 'xwem-tabber-on-frame-creation)
288 (add-hook 'xwem-frame-resize-hook 'xwem-tabber-on-frame-resize)
289 (add-hook 'xwem-frame-select-hook 'xwem-tabber-on-frame-select-deselect)
290 (add-hook 'xwem-frame-deselect-hook 'xwem-tabber-on-frame-select-deselect)
292 ;; Frame properties notifier
293 (xwem-frame-add-property-notifier 'title-height 'xwem-tabber-frame-prop-notifier)
294 (xwem-frame-add-property-notifier 'title-layout 'xwem-tabber-frame-prop-notifier)
295 (xwem-frame-add-property-notifier 'inner-border-width 'xwem-tabber-frame-prop-notifier)
298 (add-hook 'xwem-win-switch-hook 'xwem-tabber-on-win-switch)
299 (add-hook 'xwem-win-clients-change-hook 'xwem-tabber-on-win-change)
302 (add-hook 'xwem-cl-create-hook 'xwem-tabber-on-cl-creation)
303 (add-hook 'xwem-cl-state-change-hook 'xwem-tabber-on-cl-change)
304 (add-hook 'xwem-cl-change-hook 'xwem-tabber-on-cl-change)
306 (xwem-message 'init "Initializing tabbing ... done"))
308 ;;;###autoload(autoload 'xwem-tabber-switch-cl "xwem-tabber" "" t)
309 (define-xwem-command xwem-tabber-switch-cl ()
310 "Switch to client which tab item was clicked."
313 (when (xwem-cl-alive-p xwem-tabber-click-cl)
314 (xwem-activate xwem-tabber-click-cl)
315 ;; Select client only if switching in current window.
316 (when (eq (xwem-cl-win xwem-tabber-click-cl) (xwem-win-selected))
317 (xwem-select-client xwem-tabber-click-cl))
319 (when xwem-tab-show-cl-info-on-click
320 (xwem-client-info xwem-tabber-click-cl))
323 (define-xwem-command xwem-tabber-drag-frame ()
324 "Interactively move frame."
327 (xwem-frame-imove-internal
328 xwem-tabber-click-frame
329 (X-Event-xbutton-root-x xwem-last-xevent)
330 (X-Event-xbutton-root-y xwem-last-xevent)))
332 (define-xwem-command xwem-tabber-smart-drag-frame ()
333 "Interactively move dedicated client.
334 Move frame. If no moving occured and button is released, bypass it as
338 (let ((xev (xwem-next-event nil (list X-ButtonRelease X-MotionNotify))))
341 (xwem-frame-imove-internal
342 xwem-tabber-click-frame
343 (X-Event-xmotion-root-x xev)
344 (X-Event-xmotion-root-y xev)))
346 (xwem-dispatch-command-xevent xev)))))
347 (put 'xwem-tabber-smart-drag-frame 'xwem-frame-command t)
349 ;;;###autoload(autoload 'xwem-tabber-popup-cl-menu "xwem-tabber" "" t)
350 (define-xwem-command xwem-tabber-popup-cl-menu ()
351 "Popup clients menu."
354 (if (xwem-cl-alive-p xwem-tabber-click-cl)
355 (xwem-popup-menu (xwem-generate-cl-menu xwem-tabber-click-cl))
357 ; (xwem-popup-menu nil
360 (defun xwem-tabber-cl-at (tabber x y)
361 "Return client of TABBER which rectangle covers point at X Y."
362 (let ((clients (xwem-tabber-clients tabber))
363 (tmp-rect (xwem-tabber-rect->xpix-rect
364 tabber (make-X-Rect :x x :y y :width 0 :height 0)))
367 (setq x (X-Rect-x tmp-rect)
368 y (X-Rect-y tmp-rect))
370 (setq rect (xwem-cl-tab-rect (car clients)))
372 (<= (X-Rect-x rect) x)
373 (>= (+ (X-Rect-x rect) (X-Rect-width rect)) x)
374 (<= (X-Rect-y rect) y)
375 (>= (+ (X-Rect-y rect) (X-Rect-height rect)) y))
376 (setq ret-cl (car clients)
378 (setq clients (cdr clients))))
381 (defun xwem-tabber-regeom (tabber)
382 "Adjust tab items geometries in TABBER."
383 ;; TODO: handle margins
384 (let* ((twidth (X-Geom-width (xwem-tabber-xgeom tabber)))
385 (theight (X-Geom-height (xwem-tabber-xgeom tabber)))
386 (clients (xwem-tabber-clients tabber))
387 (clsn (length clients )) ; number of clients
392 (setq tiw (/ twidth clsn)
393 twrem (% twidth clsn))
396 ;; Setup CL's tab rectangle rectangle
397 (unless (xwem-cl-tab-rect (car clients))
398 (setf (xwem-cl-tab-rect (car clients))
399 (make-X-Rect :x 0 :y 0 :width 0 :height 0)))
400 (setq rect (xwem-cl-tab-rect (car clients)))
401 (setf (X-Rect-x rect) off)
402 (setf (X-Rect-width rect) (+ tiw (if (cdr clients) 0 twrem)))
403 (setf (X-Rect-height rect) theight)
405 (setq off (+ off (X-Rect-width rect)))
406 (setq clients (cdr clients))))))
408 (defsubst xwem-tabber-safe-regeom (tabber &optional draw-p)
409 "Saf variant of `xwem-tabber-regeom'."
410 (and (xwem-tabber-p tabber)
411 (xwem-tabber-regeom tabber)))
414 (defun xwem-tabber-xpix-rect->rect (tabber rect)
415 (let ((x0 (X-Rect-x rect))
417 (w0 (X-Rect-width rect))
418 (h0 (X-Rect-height rect))
420 (case (xwem-frame-property (xwem-tabber-frame tabber) 'title-layout)
423 x (- (X-Geom-width (xwem-tabber-xgeom tabber)) y0 h0)
428 y (- (X-Geom-height (xwem-tabber-xgeom tabber)) x0 w0)
435 (make-X-Rect :x x :y y :width w :height h)))
437 (defun xwem-tabber-rect->xpix-rect (tabber rect)
438 (xwem-tabber-xpix-rect->rect tabber rect))
440 (define-xwem-deffered xwem-tabber-redraw (tabber &optional x y width height)
441 "Redraw TABBER's rectangle specified by X, Y, WIDTH and HEIGHT.
442 If one of optional arguments ommited, full redraw."
443 (when (xwem-tabber-p tabber)
444 (let* ((xgeom (xwem-tabber-xgeom tabber))
447 (width (or width (X-Geom-width xgeom)))
448 (height (or height (X-Geom-height xgeom)))
449 (tl (xwem-frame-property (xwem-tabber-frame tabber) 'title-layout)))
450 (cond ((memq tl '(top bottom))
451 (XCopyArea (xwem-dpy) (xwem-tabber-xpix-copy tabber)
452 (xwem-tabber-xwin tabber)
453 (XDefaultGC (xwem-dpy)) x y width height x y))
454 ((memq tl '(left right))
455 (let* ((ximg (XGetImage (xwem-dpy) (xwem-tabber-xpix-copy tabber)
456 x y width height X-AllPlanes X-ZPixmap))
457 (rxd (xwem-misc-rotate-data
458 (nth 4 ximg) width height
459 (XGetDepth (xwem-dpy) (xwem-tabber-xpix-copy tabber))
460 (if (eq tl 'left) 'left 'right)))
466 dst-y (- (X-Geom-width xgeom) x width))
467 (setq dst-x (- (X-Geom-height xgeom) y height)
469 (XPutImage (xwem-dpy) (xwem-tabber-xwin tabber)
470 (XDefaultGC (xwem-dpy))
471 (XGetDepth (xwem-dpy) (xwem-tabber-xpix-copy tabber))
473 dst-x dst-y nil X-ZPixmap rxd)))))))
475 (define-xwem-deffered xwem-tabber-redraw-xrect (tabber &optional xrect)
476 "Redraw part of TABBER.
477 XRECT specifies geometry to redraw.
478 Defaultly full redraw."
479 (when (xwem-tabber-p tabber)
481 (setq xrect (X-Geom-to-X-Rect (xwem-tabber-xgeom tabber))))
483 (xwem-tabber-redraw tabber
484 (X-Rect-x xrect) (X-Rect-y xrect)
485 (X-Rect-width xrect) (X-Rect-height xrect))))
487 (defsubst xwem-tabber-frame-win-clients (tabber)
488 "Return list of managed clients in TABBER's window."
489 (delq nil (mapcar #'(lambda (cl)
490 (and (xwem-cl-managed-p cl '(active inactive)) cl))
492 (xwem-frame-selwin (xwem-tabber-frame tabber))))))
494 (defsubst xwem-tabber-clients-equal (cls1 cls2)
495 "Return non-nil if each element of CLS1 and CLS2 is `eq'."
496 (and (= (length cls1) (length cls2))
497 (not (memq nil (or (mapcar* 'eq cls1 cls2))))))
499 (define-xwem-deffered xwem-tabber-draw-format (cl &optional tabber force-update)
501 If FORCE-UPDATE is non-nil also copy to TABBER x window."
502 (when (or (null cl) (xwem-cl-alive-p cl))
503 ;; Either empty or valid client
504 (let* ((tabber (or tabber (xwem-cl-tabber cl)))
505 (rect (or (and (xwem-cl-p cl) (xwem-cl-tab-rect cl))
506 (let ((xgeom (xwem-tabber-xgeom tabber)))
507 (make-X-Rect :x 0 :y 0 :width (X-Geom-width xgeom)
508 :height (X-Geom-height xgeom)))))
509 (fmt (or (and (xwem-cl-p cl)
510 (xwem-client-property cl 'xwem-tab-format))
511 xwem-tab-empty-format))
512 (xprep (xwem-tabber-xpreparer tabber))
513 (xpcop (xwem-tabber-xpix-copy tabber))
514 (xoff (X-Rect-x rect))
515 (yoff (X-Rect-y rect))
516 tag-set currgc fi item fmt-index sfg)
519 (if (xwem-frame-selected-p (xwem-tabber-frame tabber))
521 (if (xwem-win-cl-current-p cl)
522 (setq tag-set (list 'frame-selected 'tab-selected))
523 (setq tag-set (list 'frame-selected 'tab-nonselected)))
526 (setq tag-set (list 'frame-selected 'tab-selected)))
529 (if (xwem-win-cl-current-p cl)
530 (setq tag-set (list 'frame-nonselected 'tab-selected))
531 (setq tag-set (list 'frame-nonselected 'tab-nonselected)))
534 (setq tag-set (list 'frame-nonselected 'tab-selected))))
536 ;; Setup currgc, xprep, tabxwin
537 (setq currgc (xwem-face-get-gc (xwem-cl-tab-face cl) tag-set cl))
538 (XSetClipRectangles (xwem-dpy) currgc 0 0 (list rect))
540 (setq sfg (X-Gc-foreground currgc))
543 (setf (X-Gc-foreground currgc) (X-Gc-background currgc))
544 (XChangeGC (xwem-dpy) currgc)
545 (XFillRectangles (xwem-dpy) xprep currgc (list rect))
546 (XFillRectangles (xwem-dpy) xpcop currgc (list rect)))
547 (setf (X-Gc-foreground currgc) sfg)
548 (XChangeGC (xwem-dpy) currgc))
550 ;; Process format string
552 (while (and (< xoff (+ (X-Rect-x rect) (X-Rect-width rect)))
553 (< fmt-index (length fmt)))
556 (setq fi (aref fmt fmt-index))
560 (setq fi (aref fmt fmt-index))
562 (cond ((= fi ?n) (xwem-client-name cl))
563 ((= fi ?c) (car (xwem-hints-wm-class
564 (xwem-cl-hints cl))))
565 ((= fi ?C) (cdr (xwem-hints-wm-class
566 (xwem-cl-hints cl))))
567 ((= fi ?i) (xwem-icons-cl-icon
568 cl (and (not (xwem-frame-selected-p
571 ((= fi ?s) (xwem-cl-get-psize cl))
572 ((= fi ?S) (xwem-cl-get-usize cl))
573 ((= fi ?u) (xwem-cl-get-uptime cl))
574 ((= fi ?U) (xwem-cl-get-uptime cl))
575 ((= fi ?f) (int-to-string
576 (xwem-frame-num (xwem-cl-frame cl))))
577 ((= fi ?F) (xwem-frame-name (xwem-cl-frame cl)))
578 ((= fi ?*) (if (xwem-cl-marked-p cl) "*" "-"))
579 ((= fi ?#) (if (XWMProtocol-set-p
581 (xwem-hints-wm-protocols
585 ((= fi ?I) (let ((ip (X-WMHints-input-p
587 (xwem-cl-hints cl))))
588 (tf (XWMProtocol-set-p
590 (xwem-hints-wm-protocols
593 (cond ((and ip tf) "L")
601 (let ((substr (substring fmt (1+ fmt-index)))
603 (unless (string-match
604 "\\(\\([^%]\\|%[^}]\\)*\\)%}" substr)
605 (signal 'search-failed fmt "%}"))
607 ;; extract lisp code and update fmt indexer
608 (setq elstr (match-string 1 substr))
609 (incf fmt-index (match-end 0))
611 ;; Now time to run emacs lisp.
615 ;; - Due to dynamic scoping, emacs
616 ;; lisp code that is in ELSTR can
617 ;; access any locally bounded
618 ;; variable for example `cl'.
620 ;; - It should return string, cons
621 ;; cell(image) or nil.
622 (eval (read elstr))))
624 ;; Ditig is number of aditional GC
625 ((and (> (Xforcenum fi) 47) (< (Xforcenum fi) 57))
626 (let* ((n (string-to-int (char-to-string fi)))
627 (gc (xwem-face-get-gc
629 (xwem-cl-tab-face cl)
631 (concat "xwem-tabber-face"
636 (XSetClipRectangles (xwem-dpy) currgc
640 (t (error 'xwem-error "Unknown token in tabi format"))))
642 (when (and (consp item)
644 (numberp (cdr item)))
645 (setq item (concat (int-to-string (car item))
647 (int-to-string (cdr item)))))
651 (setq item (char-to-string fi))
652 (while (and (< fmt-index (length fmt))
653 (not (= (aref fmt fmt-index) ?%)))
654 (setq item (concat item (char-to-string (aref fmt fmt-index))))
658 (cond ((stringp item)
660 (let* ((font (X-Gc-font currgc))
661 (ta (X-Text-ascent (xwem-dpy) font item))
662 (td (X-Text-descent (xwem-dpy) font item))
663 (hei (X-Rect-height rect))
664 (ty (+ yoff (/ (- hei (+ ta td)) 2) ta)))
666 (XDrawString (xwem-dpy) xprep currgc xoff ty item)
667 (setq xoff (+ xoff (X-Text-width
668 (xwem-dpy) (X-Gc-font currgc) item)))
672 (X-Pixmap-p (car item))
673 (X-Pixmap-p (cdr item)))
675 (let ((ty (/ (- (X-Rect-height rect)
676 (X-Pixmap-height (car item))) 2)))
677 ; (ximg-mask (X-Pixmap-get-prop (cdr item) 'ximg)))
680 (setf (X-Gc-clip-mask currgc) (cdr item))
681 (setf (X-Gc-clip-x-origin currgc) xoff)
682 (setf (X-Gc-clip-y-origin currgc) (+ yoff ty))
683 (XChangeGC (xwem-dpy) currgc)
685 (XCopyArea (xwem-dpy) (car item) xprep currgc 0 0
686 (X-Pixmap-width (car item))
687 (X-Pixmap-height (car item))
689 (setf (X-Gc-clip-mask currgc) X-None)
690 (setf (X-Gc-clip-x-origin currgc) 0)
691 (setf (X-Gc-clip-y-origin currgc) 0)
692 (XChangeGC (xwem-dpy) currgc)
693 (XSetClipRectangles (xwem-dpy) currgc 0 0 (list rect)))
695 (setq xoff (+ xoff (X-Pixmap-width (car item))))))
698 (eq item 'skip)) nil)
700 (t (error 'xwem-error "Unknown Item" item)))
704 (when (> xoff (+ (X-Rect-x rect) (X-Rect-width rect)))
705 (setq xoff (+ (X-Rect-x rect) (X-Rect-width rect))))
707 (XCopyArea (xwem-dpy) xprep xpcop currgc
708 (X-Rect-x rect) (X-Rect-y rect)
709 (X-Rect-width rect) (X-Rect-height rect)
711 (/ (- (+ (X-Rect-x rect) (X-Rect-width rect)) xoff) 2))
714 (let ((ldgc (xwem-face-get-gc (xwem-cl-tab-face cl)
715 (cons 'delimiter-left tag-set) cl))
716 (rdgc (xwem-face-get-gc (xwem-cl-tab-face cl)
717 (cons 'delimiter-right tag-set) cl)))
718 (XDrawLine (xwem-dpy) xpcop ldgc
719 (X-Rect-x rect) (X-Rect-y rect)
720 (X-Rect-x rect) (+ (X-Rect-y rect) (X-Rect-height rect)))
721 (XDrawLine (xwem-dpy) xpcop rdgc
722 (+ -1 (X-Rect-x rect) (X-Rect-width rect))
724 (+ -1 (X-Rect-x rect) (X-Rect-width rect))
725 (+ (X-Rect-y rect) (X-Rect-height rect))))
727 ;; Finally apply change to xwin
729 (xwem-tabber-redraw-xrect-1 tabber rect))
731 ;; Unmark client as need to be redrawed
733 (xwem-cl-rem-sys-prop cl 'xwem-tab-need-redraw))
736 (defun xwem-tabber-regeom-p (tabber)
737 "Return non-nil if TABBER is regeomed."
738 (let ((old-clients (xwem-tabber-clients tabber))
739 (new-clients (xwem-tabber-frame-win-clients tabber)))
740 (unless (xwem-tabber-clients-equal old-clients new-clients)
741 (setf (xwem-tabber-clients tabber) new-clients)
743 (xwem-tabber-regeom tabber))
746 (define-xwem-deffered xwem-tabber-draw (tabber &optional force-draw)
747 "On TABBER draw client's tabs.
748 If FORCE-DRAW is non-nil redraw tabber even if it logically does not
749 need to be redrawed."
750 (when (and (xwem-tabber-p tabber)
751 (xwem-frame-p (xwem-tabber-frame tabber))
752 ;; none layout does not need to be redrawn
753 (not (eq (xwem-frame-property
754 (xwem-tabber-frame tabber) 'title-layout)
756 (let ((cls-to-draw nil)
759 (unless (eq (xwem-tabber-get-prop tabber 'xwem-frame-selected-p)
760 (xwem-frame-selected-p (xwem-tabber-frame tabber)))
761 (xwem-tabber-put-prop tabber 'xwem-frame-selected-p
762 (xwem-frame-selected-p (xwem-tabber-frame tabber)))
765 (if (or (xwem-tabber-regeom-p tabber) force-draw)
766 (setq cls-to-draw (or (xwem-tabber-clients tabber) (list nil))
767 need-draw-p t) ; all clients
769 (delq nil (mapcar #'(lambda (cl)
770 (and (xwem-cl-get-sys-prop
771 cl 'xwem-tab-need-redraw) cl))
772 (xwem-tabber-clients tabber)))
773 need-draw-p cls-to-draw))
777 (xwem-tabber-draw-format-1 cl tabber))
779 (xwem-tabber-redraw-1 tabber)))))
781 (defun xwem-tabber-event-handler (xdpy xwin xev)
782 "On display XDPY and window XWIN handle event XEV."
783 (let ((tabber (X-Win-get-prop xwin 'xwem-tabber)))
784 (when (xwem-tabber-p tabber)
787 (xwem-tabber-redraw-xrect
788 tabber (xwem-tabber-rect->xpix-rect
790 (make-X-Rect :x (X-Event-xexpose-x xev)
791 :y (X-Event-xexpose-y xev)
792 :width (X-Event-xexpose-width xev)
793 :height (X-Event-xexpose-height xev)))))
796 (when (xwem-tabber-p tabber)
797 (XFreePixmap (xwem-dpy) (xwem-tabber-xpreparer tabber))
798 (XFreePixmap (xwem-dpy) (xwem-tabber-xpix-copy tabber))
799 (X-invalidate-cl-struct tabber)))
801 ((:X-ButtonPress :X-ButtonRelease)
802 ;; Handle button press/release event
803 (let* ((x (X-Event-xbutton-event-x xev))
804 (y (X-Event-xbutton-event-y xev))
805 (xwem-tabber-click-frame (xwem-tabber-frame tabber))
806 (xwem-tabber-click-cl (xwem-tabber-cl-at tabber x y))
807 (xwem-keyboard-echo-keystrokes nil)) ; XXX
808 (xwem-overriding-local-map
809 (if (xwem-frame-dedicated-p (xwem-tabber-frame tabber))
810 xwem-tabber-dedicated-map
812 (xwem-dispatch-command-xevent xev))))
815 (defun xwem-tabber-create (frame)
816 "Create new tabber for FRAME."
817 (let* ((xgeom (make-X-Geom :x 0 :y 0
819 :border-width 0)) ; XXX
820 (tabber (make-xwem-tabber :frame frame
825 (xwem-frame-xwin frame)
826 (X-Geom-x xgeom) (X-Geom-y xgeom)
827 (X-Geom-width xgeom) (X-Geom-height xgeom)
828 (X-Geom-border-width xgeom)
829 nil nil nil ;X-InputOutput nil
830 (make-X-Attr :background-pixel (XWhitePixel (xwem-dpy))
831 :bit-gravity X-StaticGravity
832 :backing-store X-Always))))
834 (setf (xwem-tabber-xwin tabber) w)
835 (X-Win-put-prop w 'xwem-tabber tabber)
838 (Xmask-or XM-Exposure XM-StructureNotify
839 XM-ButtonPress XM-ButtonRelease XM-ButtonMotion))
840 (X-Win-EventHandler-add w 'xwem-tabber-event-handler 0
841 (list X-Expose X-DestroyNotify X-ButtonPress
842 X-ButtonRelease X-MotionNotify))
844 ;; Adjust XGEOM and create Preparer and xpix-copy
845 ; (setf (xwem-tabber-xpreparer tabber)
846 ; (XCreatePixmap xdpy (make-X-Pixmap :dpy xdpy :id (X-Dpy-get-id xdpy))
847 ; w (XDefaultDepth xdpy) (X-Geom-width xgeom) (X-Geom-height xgeom)))
848 ; (setf (xwem-tabber-xpix-copy tabber)
849 ; (XCreatePixmap xdpy (make-X-Pixmap :dpy xdpy :id (X-Dpy-get-id xdpy))
850 ; w (XDefaultDepth xdpy) (X-Geom-width xgeom) (X-Geom-height xgeom)))
851 (xwem-tabber-resize tabber)
853 ;; Draw tabber contents and map its window
854 (xwem-tabber-draw-1 tabber t)
855 (XMapWindow (X-Win-dpy w) w)
858 (defun xwem-tabber-move-resize (tabber)
859 "Move TABBER to its place according to title-layout, etc,"
860 (let* ((frame (xwem-tabber-frame tabber))
861 (th (xwem-frame-property frame 'title-height))
862 (ibw (xwem-frame-property frame 'inner-border-width))
863 (xgeom (xwem-tabber-xgeom tabber))
865 (when (xwem-frame-p frame)
866 (case (xwem-frame-property frame 'title-layout)
868 (setf (X-Geom-width xgeom) (- (xwem-frame-width frame) ibw ibw)
869 (X-Geom-height xgeom) th)
872 w (X-Geom-width xgeom)
873 h (X-Geom-height xgeom)))
875 (setf (X-Geom-width xgeom) (- (xwem-frame-width frame) ibw ibw)
876 (X-Geom-height xgeom) th)
878 y (- (xwem-frame-height frame) th ibw)
879 w (X-Geom-width xgeom)
880 h (X-Geom-height xgeom)))
882 (setf (X-Geom-width xgeom) (- (xwem-frame-height frame) ibw ibw)
883 (X-Geom-height xgeom) th)
886 w (X-Geom-height xgeom)
887 h (X-Geom-width xgeom)))
890 (setf (X-Geom-width xgeom) (- (xwem-frame-height frame) ibw ibw)
891 (X-Geom-height xgeom) th)
892 (setq x (- (xwem-frame-width frame) th ibw)
894 w (X-Geom-height xgeom)
895 h (X-Geom-width xgeom))))
897 (XMoveResizeWindow (xwem-dpy) (xwem-tabber-xwin tabber) x y w h))))
899 (defun xwem-tabber-resize (tabber)
900 "Resize TABBER to WIDTH, HEIGHT."
901 (let* ((xgeom (xwem-tabber-xgeom tabber))
902 (owidth (X-Geom-width xgeom))
903 (oheight (X-Geom-height xgeom)))
905 (xwem-tabber-move-resize tabber)
907 (when (or (> (X-Geom-width xgeom) owidth)
908 (> (X-Geom-height xgeom) oheight))
909 ;; Recreate xpreparer
910 (when (X-Pixmap-p (xwem-tabber-xpreparer tabber))
911 (XFreePixmap (xwem-dpy) (xwem-tabber-xpreparer tabber)))
912 (when (X-Pixmap-p (xwem-tabber-xpix-copy tabber))
913 (XFreePixmap (xwem-dpy) (xwem-tabber-xpix-copy tabber)))
914 (setf (xwem-tabber-xpreparer tabber)
915 (XCreatePixmap (xwem-dpy)
916 (make-X-Pixmap :dpy (xwem-dpy)
917 :id (X-Dpy-get-id (xwem-dpy)))
918 (xwem-tabber-xwin tabber) (XDefaultDepth (xwem-dpy))
919 (X-Geom-width xgeom) (X-Geom-height xgeom)))
920 (setf (xwem-tabber-xpix-copy tabber)
921 (XCreatePixmap (xwem-dpy)
922 (make-X-Pixmap :dpy (xwem-dpy)
923 :id (X-Dpy-get-id (xwem-dpy)))
924 (xwem-tabber-xwin tabber) (XDefaultDepth (xwem-dpy))
925 (X-Geom-width xgeom) (X-Geom-height xgeom)))
926 (when xwem-misc-turbo-mode
927 (XSetWindowBackgroundPixmap (xwem-dpy) (xwem-tabber-xwin tabber)
928 (xwem-tabber-xpix-copy tabber))))
929 (xwem-tabber-regeom tabber)))
932 (defun xwem-tabber-on-frame-select-deselect ()
933 "Redraw tabbers when switching frames."
934 (when (xwem-frame-p (xwem-frame-selected))
935 (xwem-tabber-draw (xwem-frame-tabber (xwem-frame-selected)))))
937 (defun xwem-tabber-on-frame-resize (frame)
938 "FRAME just resized, apply changes to tabber, if any."
939 (let ((tabber (xwem-frame-tabber frame)))
940 (when (xwem-tabber-p tabber)
941 (xwem-tabber-resize tabber)
942 (xwem-tabber-draw tabber t))))
944 (defun xwem-tabber-on-frame-creation (frame)
945 "FRAME just created."
946 (setf (xwem-frame-tabber frame) (xwem-tabber-create frame)))
948 (defun xwem-tabber-frame-prop-notifier (frame prop value)
949 "FRAME just changed property PROP to VALUE."
950 (let ((tabber (xwem-frame-tabber frame)))
951 (when (xwem-tabber-p tabber)
955 (XUnmapWindow (xwem-dpy) (xwem-tabber-xwin tabber))
956 (XMapWindow (xwem-dpy) (xwem-tabber-xwin tabber))))
958 (xwem-tabber-on-frame-resize frame))))
961 (defun xwem-tabber-on-win-switch (owin nwin)
962 "Window switch occured OWIN -> NWIN."
963 (and (xwem-win-selwin-p nwin)
964 (xwem-tabber-draw (xwem-frame-tabber (xwem-win-frame nwin)))))
966 (defun xwem-tabber-on-win-change (win)
967 "WIN's clients list changed."
968 (and (xwem-win-selwin-p win)
969 (xwem-tabber-draw (xwem-frame-tabber (xwem-win-frame win)))))
971 (defun xwem-tabber-on-win-ccl-change (win old-cl new-cl)
972 "WIN's current client just changed."
973 (when (xwem-cl-p old-cl)
974 (xwem-tabber-on-cl-change old-cl))
975 (when (xwem-cl-p new-cl)
976 (xwem-tabber-on-cl-change new-cl)))
979 (defun xwem-tabber-on-cl-creation (cl)
981 ;; Make tab rect for CL
982 (unless (xwem-cl-tab-rect cl)
983 (setf (xwem-cl-tab-rect cl)
984 (make-X-Rect :x 0 :y 0 :width 0 :height 0)))
987 (defun xwem-tabber-on-cl-change (cl &rest args)
988 "CL just changed its component."
989 (let ((tabber (xwem-cl-tabber cl)))
991 (memq cl (xwem-tabber-clients tabber))
992 (xwem-win-selwin-p (xwem-cl-win cl)))
993 ;; mark cl as need to be redraw
994 (xwem-cl-put-sys-prop cl 'xwem-tab-need-redraw t)
995 (xwem-tabber-draw tabber))))
998 (provide 'xwem-tabbing)
1000 ;;;; On-load actions:
1001 ;; - Initialize tabber
1004 ;;; xwem-tabbing.el ends here