1 ;;; xwem-tray.el --- Tray support for XWEM.
3 ;; Copyright (C) 2003-2005 by XWEM Org.
5 ;; Author: Zajcev Evgeny <zevlg@yandex.ru>
7 ;; Keywords: xlib, xwem
8 ;; X-CVS: $Id: xwem-tray.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 ;; We should implement something like dockapp handler(or system tray),
32 ;; that will be placed on free space of xwem-minibuffer or xwem-frame
33 ;; and handle external X applications. It may receive some
34 ;; ClientMessages and process them. Some of this ClientMessage should
35 ;; be used to run elisp code.
37 ;; See how mbdock from matchbox made.
39 ;; xwem tray creates fake window which is only used to hold selection
40 ;; needed for communicatio, xwem minibuffer window will be used for
44 ;; - Proper possition in `xwem-minibuffer' calculation.
45 ;; - Run elisp support(almost already done).
53 (require 'xwem-manage)
55 ;;; xwem tray constants
56 (defconst xwem-tc-dock-req 0 "Dock place request.")
57 (defconst xwem-tc-message 1 "Message from dock app.")
58 (defconst xwem-tc-cancel-message 2 "Cancels message.")
59 (defconst xwem-tc-run-lisp 3 "Evaluate emacs lisp string")
61 (defvar xwem-tray-message-hook 'xwem-tray-message-defhook
62 "*Hook to be called whin new message from dock app.
63 Function will be called with arg - dockapp.")
65 (defcustom xwem-tray-id 0 "System tray identificator.")
67 (defcustom xwem-tray-name "xwem-tray"
68 "X Name for xwem tray.")
70 (defcustom xwem-tray-class '("xwem-tray" "xwem-tray")
71 "X Class for xwem tray")
73 (defconst xwem-tray-evmask (Xmask-or XM-SubstructureNotify
76 XM-SubstructureRedirect
81 ;;; Configuration for xwem system tray
82 (defgroup xwem-tray nil
83 "Group to customize XWEM system tray."
87 (defcustom xwem-tray-use-groups nil
88 "*Non-nil mean systray with use EXPERIMENTAL dockapp grouping.
89 Set it to non-nil on your own risk."
93 (defcustom xwem-tray-default-align 'right
94 "*Position in minibuffer where dockapps will placed."
95 :type '(choice (const :tag "At Right" right)
96 (const :tag "At Left" left))
99 (defcustom xwem-tray-minib-start-offset 4
100 "*Start offset in pixels."
104 (defcustom xwem-tray-minib-dock-offset 5
105 "*Offset in pixels between dockapps."
109 (defcustom xwem-tray-groups-distance 5
110 "*Minimum distance between systray groups."
114 (defcustom xwem-tray-cursor-shape 'X-XC-right_ptr
115 "*Cursor shape which will be used when pointer is over dock app."
116 :type (xwem-cursor-shape-choice)
117 :set (xwem-cus-set-cursor-shape
119 (and (xwem-tray-p xwem-tray) (xwem-tray-xwin xwem-tray)))
120 :initialize 'custom-initialize-default
123 (defcustom xwem-tray-cursor-foreground-color "#000075"
124 "*Cursor's foreground color used when poniter is on dock app."
126 :set (xwem-cus-set-cursor-foreground xwem-tray-cursor)
127 :initialize 'custom-initialize-default
130 (defcustom xwem-tray-cursor-background-color "#000039"
131 "*Cursor's background color used when poniter is on dock app."
133 :set (xwem-cus-set-cursor-background xwem-tray-cursor)
134 :initialize 'custom-initialize-default
137 (define-xwem-face xwem-tray-group-face
138 `(((light) (:foreground "white"))
139 ((medium) (:foreground "gray50"))
140 ((dark) (:foreground "black")))
141 "*Face to outline dockapp groups."
146 (defcustom xwem-tray-delimiter-width 4
151 (defcustom xwem-tray-delimiter-height-reminder 2
152 "*How many pixels on top/bottom from xwem minibuffer.."
156 (define-xwem-face xwem-tray-delimiter-face
157 `(((background light)
158 (:foreground "gray40"))
159 ((background light shadow)
160 (:foreground "gray30"))
162 (:foreground "gray70"))
163 ((background dark shadow)
164 (:foreground "gray80"))
165 (t (:foreground "gray55")))
166 "Face to draw systray delimiter."
170 ;;; Internal variables
172 (defvar xwem-tray-groups '("desktop" "launch" "misc" "default")
173 "List of valid dockapp groups.")
175 (defconst xwem-tray-align-left 1)
176 (defconst xwem-tray-align-right 2)
179 ;;; Internal variables
180 (defvar xwem-tray nil
181 "Default xwem system tray.")
183 (defvar xwem-tray-cursor nil
184 "Cursor used when pointer is over dock app.")
185 (defvar xwem-tray-curroffset 0
186 "Current offset in pixels.")
188 ;;; Dock applications
190 ;; Dock is array in form:
191 ;; [x-window geom-after-reparent]
192 (defvar xwem-tray-dapp-list nil "List of dockapp X windows.")
196 xwin ; Tray's X window
197 xgeom ; Tray's X geometry
200 groups ; list of groups
201 dockapps ; compatible with old style
202 plist) ; tray properties
204 (defmacro xwem-tray-rem-prop (tray prop)
205 "From TRAY's property list, remove property PROP."
206 `(setf (xwem-tray-plist ,tray)
207 (plist-remprop (xwem-tray-plist ,tray) ,prop)))
208 (defmacro xwem-tray-put-prop (tray prop val)
209 "In TRAY's plist put PROP with VAL."
211 (setf (xwem-tray-plist ,tray)
212 (plist-put (xwem-tray-plist ,tray) ,prop ,val))
213 (xwem-tray-rem-prop ,tray ,prop)))
214 (defmacro xwem-tray-get-prop (tray prop)
215 "Get TRAY's property PROP."
216 `(plist-get (xwem-tray-plist ,tray) ,prop))
218 (defstruct xwem-tray-group
222 xgeom ; group window geometry
233 plist ; dockapp properties
235 ;; for xembed messaging
241 (defmacro xwem-dapp-alive-p (dapp)
242 "Return non-nil if DAPP is alive dock application."
243 `(and (xwem-dapp-p ,dapp)
244 (memq ,dapp xwem-tray-dapp-list)))
246 (defmacro xwem-dapp-rem-prop (dapp prop)
247 `(setf (xwem-dapp-plist ,dapp)
248 (plist-remprop (xwem-dapp-plist dapp) ,prop)))
250 (defmacro xwem-dapp-put-prop (dapp prop val)
252 (setf (xwem-dapp-plist ,dapp)
253 (plist-put (xwem-dapp-plist ,dapp) ,prop ,val))
254 (xwem-dapp-rem-prop ,dapp ,prop)))
256 (defmacro xwem-dapp-get-prop (dapp prop)
257 `(plist-get (xwem-dapp-plist ,dapp) ,prop))
259 (defmacro xwem-dapp-group-name (dapp)
260 `(xwem-dapp-get-prop ,dapp 'group))
261 (defsetf xwem-dapp-group-name (dapp) (group)
262 `(xwem-dapp-put-prop ,dapp 'group ,group))
264 (defmacro xwem-dapp-id (dapp)
265 `(xwem-dapp-get-prop ,dapp 'id))
266 (defsetf xwem-dapp-id (dapp) (id)
267 `(xwem-dapp-put-prop ,dapp 'id ,id))
269 (defmacro xwem-dapp-align (dapp)
270 `(xwem-dapp-get-prop ,dapp 'align))
271 (defsetf xwem-dapp-align (dapp) (align)
272 `(xwem-dapp-put-prop ,dapp 'align ,align))
274 (defmacro xwem-dapp-state (dapp)
275 `(xwem-dapp-get-prop ,dapp 'state))
276 (defsetf xwem-dapp-state (dapp) (state)
277 `(xwem-dapp-put-prop ,dapp 'state ,state))
279 ;; Message is vector in form:
280 ;; [message-type message-waitlen message-currlen message-string]
282 ;; message-type is one of `xwem-tc-message', `xwem-tc-cancel-message'
283 ;; or `xwem-tc-run-lisp'.
289 (defun xwem-tray-group-get-position (group)
290 "Get good position in system tray for tray GROUP."
291 (let ((groups (xwem-tray-groups xwem-tray))
292 (dtlen xwem-tray-minib-start-offset))
294 (when (eq (xwem-tray-group-align (car groups))
295 (xwem-tray-group-align group))
296 (incf dtlen (X-Geom-width (xwem-tray-group-xgeom (car groups))))
297 (incf dtlen xwem-tray-groups-distance))
298 (setq groups (cdr groups)))
300 (ecase (xwem-tray-group-align group)
302 (- (X-Geom-width (xwem-minib-xgeom xwem-minibuffer))
303 dtlen (X-Geom-width (xwem-tray-group-xgeom group))))
305 (+ (X-Geom-width (xwem-minib-cl-xgeom xwem-minibuffer))
308 (defun xwem-tray-group-find (name)
309 "Search for tray group with NAME."
310 (let ((groups (xwem-tray-groups xwem-tray)))
312 (not (string= (xwem-tray-group-name (car groups)) name)))
313 (setq groups (cdr groups)))
316 (defun xwem-tray-group-create (name &rest params)
317 "Create and return new systray group, giving it NAME.
318 Additional PARAMS can be specified."
319 (let ((xtg (apply 'make-xwem-tray-group :name name params)))
320 (unless (xwem-tray-group-align xtg)
321 (setf (xwem-tray-group-align xtg)
322 xwem-tray-default-align))
323 (unless (xwem-tray-group-xgeom xtg)
324 (setf (xwem-tray-group-xgeom xtg)
325 (make-X-Geom :x 0 :y 0 :width 16 :height 16)))
327 (setf (X-Geom-x (xwem-tray-group-xgeom xtg))
328 (xwem-tray-group-get-position xtg))
329 (setf (xwem-tray-group-xwin xtg)
331 (xwem-dpy) (xwem-tray-xwin xwem-tray)
332 (X-Geom-x (xwem-tray-group-xgeom xtg))
333 (X-Geom-y (xwem-tray-group-xgeom xtg))
334 (X-Geom-width (xwem-tray-group-xgeom xtg))
335 (X-Geom-height (xwem-tray-group-xgeom xtg))
336 (X-Geom-border-width (xwem-tray-group-xgeom xtg))
338 (make-X-Attr :override-redirect t
341 (xwem-face-get-gc 'xwem-tray-group-face '(medium)))
342 :event-mask (Xmask-or XM-ButtonPress
345 ;; Add to tray's groups
346 (setf (xwem-tray-groups xwem-tray)
347 (cons xtg (xwem-tray-groups xwem-tray)))
350 (defun xwem-tray-group-same-align-sorted (group)
351 "Return list of groups with same align as GROUP."
352 (sort (delq nil (mapcar #'(lambda (g)
353 (and (eql (xwem-tray-group-align g)
354 (xwem-tray-group-align g)) g))
355 (xwem-tray-groups xwem-tray)))
357 (> (X-Geom-x (xwem-tray-group-xgeom g1))
358 (X-Geom-x (xwem-tray-group-xgeom g2))))))
360 (defun xwem-tray-group-resize (group new-width new-height)
361 "Resize tray GROUP to NEW-WIDTH and NEW-HEIGHT."
362 (let ((glist (xwem-tray-group-same-align-sorted group))
364 (X-Geom-width (xwem-tray-group-xgeom group)))))
365 (if (eq (xwem-tray-group-align group) 'left)
366 (setq glist (cdr (memq group glist)))
367 (setq glist (cdr (memq group (nreverse glist)))
371 (incf (X-Geom-x (xwem-tray-group-xgeom g)) off)
372 (XMoveWindow (xwem-dpy) (xwem-tray-group-xwin g)
373 (X-Geom-x (xwem-tray-group-xgeom g))
374 (X-Geom-y (xwem-tray-group-xgeom g))))
376 (incf (X-Geom-width (xwem-tray-group-xgeom group)) off)
377 (XResizeWindow (xwem-dpy) (xwem-tray-group-xwin group)
378 (X-Geom-width (xwem-tray-group-xgeom group))
379 (X-Geom-height (xwem-tray-group-xgeom group)))
382 (defun xwme-tray-group-repositionate-dapps (group)
383 "Repositionate GROUP's dock applications."
384 (let ((gdapps (xwem-tray-group-dockapps group))
388 (setf (X-Geom-x (xwem-dapp-geom (car gdapps))) coff)
389 ;; XXX do it deffering
390 (XMoveWindow (xwem-dpy) (xwem-dapp-xwin (car gdapps))
391 (X-Geom-x (xwem-dapp-geom (car gdapps)))
392 (X-Geom-y (xwem-dapp-geom (car gdapps))))
393 (incf coff (X-Geom-width (xwem-dapp-geom (car gdapps))))
395 (setq gdapps (cdr gdapps)))
397 (when (> coff (X-Geom-width (xwem-tray-group-xgeom group)))
398 (xwem-tray-group-resize
400 (X-Geom-height (xwem-tray-group-xgeom group))))))
402 (defun xwem-tray-group-attach-dapp (group dapp)
403 "To tray GROUP attach dock application DAPP."
404 (let ((gdapps (xwem-tray-group-dockapps group)))
405 (XReparentWindow (xwem-dpy) (xwem-tray-group-xwin group)
406 (xwem-dapp-xwin dapp) 0 0)
408 (> (xwem-dapp-id (car gdapps))
409 (xwem-dapp-id dapp)))
410 (setq gdapps (cdr gdapps)))
412 (setf (xwem-tray-group-dockapps group)
413 (append (xwem-tray-group-dockapps group)
415 (setcdr gdapps (cons (car gdapps) (cdr gdapps)))
416 (setcar gdapps dapp))
418 (xwme-tray-group-repositionate-dapps group)))
420 (defun xwem-tray-group-find-create (name)
421 "Find existing or create new group."
422 (or (xwem-tray-group-find name)
423 (xwem-tray-group-create name)))
428 (defun xwem-XTrayInit (xdpy xwin &optional dockid dockgroup dockalign)
429 "Same as `XTrayInit'.
430 You should use this function instead of direct calls to `XTrayInit',
431 because in time you doing it xwem-tray may be uninitialised."
432 (xwem-tray-startit xdpy) ; make sure systray initialized
435 (XChangeProperty xdpy xwin (XInternAtom xdpy "XWEM_DOCK_ID")
436 XA-integer X-format-16 X-PropModeReplace dockid))
438 (XChangeProperty xdpy xwin (XInternAtom xdpy "XWEM_DOCK_GROUP")
439 XA-string X-format-8 X-PropModeReplace dockgroup))
441 (XChangeProperty xdpy xwin (XInternAtom xdpy "XWEM_DOCK_ALIGN")
442 XA-integer X-format-16 X-PropModeReplace dockalign))
444 (XTrayInit xdpy xwin))
447 (defun xwem-tray-find-dapp (xwin)
448 "Finds dock application by X window XWIN."
449 (car (member* xwin xwem-tray-dapp-list
450 :test #'(lambda (xwin dapp)
451 (X-Win-equal xwin (xwem-dapp-xwin dapp))))))
453 (defun xwem-tray-message-defhook (dapp)
454 "Default function for message from dock apps handling."
455 (if (featurep 'xwem-special)
456 (xwem-help-display "tray message"
457 (insert (xwem-dapp-mess dapp)))
458 (xwem-message 'error "Message arrived from dock app, but special frames not enabled.")))
460 ;;; XXX these three functions:
462 ;; - xwem-tray-remove-dapp
463 ;; - xwem-tray-hide-dapp
464 ;; - xwem-tray-show-dapp
466 ;; Has many of common code, get rid of it --lg
468 (defun xwem-tray-remove-dapp (dapp)
469 "Remove dock application DAPP from xwem tray dockapps list."
470 (let ((dgeom (xwem-dapp-geom dapp))
471 (state (xwem-dapp-state dapp)))
472 ;; Remove from dapps list
473 (setq xwem-tray-dapp-list
474 (delq dapp xwem-tray-dapp-list))
475 (X-invalidate-cl-struct dapp)
477 ;; Move other dapps to fill free space
478 (unless (eq state 'hidden)
479 (mapc #'(lambda (dapp)
480 (ecase xwem-tray-default-align
482 (when (< (X-Geom-x (xwem-dapp-geom dapp))
484 (xwem-tray-move-dapp dapp
485 (+ (X-Geom-x (xwem-dapp-geom dapp))
487 xwem-tray-minib-dock-offset)
488 (X-Geom-y (xwem-dapp-geom dapp)))))
491 (when (> (X-Geom-x (xwem-dapp-geom dapp))
493 (xwem-tray-move-dapp dapp
494 (- (X-Geom-x (xwem-dapp-geom dapp))
496 xwem-tray-minib-dock-offset)
497 (X-Geom-y (xwem-dapp-geom dapp)))))))
498 xwem-tray-dapp-list))))
500 (defun xwem-tray-hide-dapp (hide-dapp &optional unmap-p)
501 "Hide dockapp DAPP temporary.
502 Non-nil UNMAP-P mean dockapp already unmapped."
503 (unless (eq (xwem-dapp-state hide-dapp) 'hidden)
505 (XUnmapWindow (xwem-dpy) (xwem-dapp-xwin hide-dapp)))
506 (setf (xwem-dapp-state hide-dapp) 'hidden)
508 (let ((dgeom (xwem-dapp-geom hide-dapp)))
509 (mapc #'(lambda (dapp)
510 (unless (eq dapp hide-dapp)
511 (ecase xwem-tray-default-align
513 (when (< (X-Geom-x (xwem-dapp-geom dapp))
515 (xwem-tray-move-dapp dapp
516 (+ (X-Geom-x (xwem-dapp-geom dapp))
518 xwem-tray-minib-dock-offset)
519 (X-Geom-y (xwem-dapp-geom dapp)))))
522 (when (> (X-Geom-x (xwem-dapp-geom dapp))
524 (xwem-tray-move-dapp dapp
525 (- (X-Geom-x (xwem-dapp-geom dapp))
527 xwem-tray-minib-dock-offset)
528 (X-Geom-y (xwem-dapp-geom dapp))))))))
529 xwem-tray-dapp-list))))
531 (defun xwem-tray-show-dapp (show-dapp &optional map-p)
532 "Show dockapp SHOW-DAPP that was hidden temporary.
533 Non-nil MAP-P mean dock app already mapped."
534 (unless (eq (xwem-dapp-state show-dapp) 'shown)
536 (XMapWindow (xwem-dpy) (xwem-dapp-xwin show-dapp)))
537 (setf (xwem-dapp-state show-dapp) 'shown)
539 (let ((dgeom (xwem-dapp-geom show-dapp)))
540 (mapc #'(lambda (dapp)
541 (unless (eq dapp show-dapp)
542 (ecase xwem-tray-default-align
544 (when (< (X-Geom-x (xwem-dapp-geom dapp))
545 (+ (X-Geom-x dgeom) (X-Geom-width dgeom)))
546 (xwem-tray-move-dapp dapp
547 (- (X-Geom-x (xwem-dapp-geom dapp))
549 xwem-tray-minib-dock-offset)
550 (X-Geom-y (xwem-dapp-geom dapp)))))
553 (when (> (X-Geom-x (xwem-dapp-geom dapp))
554 (+ (X-Geom-x dgeom) (X-Geom-width dgeom)))
555 (xwem-tray-move-dapp dapp
556 (+ (X-Geom-x (xwem-dapp-geom dapp))
558 xwem-tray-minib-dock-offset)
559 (X-Geom-y (xwem-dapp-geom dapp))))))))
560 xwem-tray-dapp-list))))
562 (defun xwem-tray-get-proper-position (width)
563 "Get good position in system tray for dapp with WIDTH."
564 (let ((dapps xwem-tray-dapp-list)
565 (dtlen xwem-tray-minib-start-offset))
567 (when (eq (xwem-dapp-state (car dapps)) 'shown)
568 (incf dtlen (X-Geom-width (xwem-dapp-geom (car dapps))))
569 (incf dtlen xwem-tray-minib-dock-offset))
570 (setq dapps (cdr dapps)))
572 (ecase xwem-tray-default-align
574 (- (X-Geom-width (xwem-minib-xgeom xwem-minibuffer))
577 (+ (X-Geom-width (xwem-minib-cl-xgeom xwem-minibuffer))
580 (define-xwem-deffered xwem-tray-apply-dapp-position (dapp)
581 "Apply DAPP's position to life."
582 (when (xwem-dapp-alive-p dapp)
583 (XMoveWindow (xwem-dpy) (xwem-dapp-xwin dapp)
584 (X-Geom-x (xwem-dapp-geom dapp))
585 (X-Geom-y (xwem-dapp-geom dapp)))))
587 (defun xwem-tray-move-dapp (dapp new-x new-y)
588 "Move DAPP to NEW-X, NEW-Y position.
589 If NEW-X or NEW-Y is nil - corresponding value is retained."
591 (setf (X-Geom-x (xwem-dapp-geom dapp)) new-x))
593 (setf (X-Geom-y (xwem-dapp-geom dapp)) new-y))
594 (xwem-tray-apply-dapp-position dapp))
596 (defun xwem-tray-new-dapp (xwin)
597 "New dock application XWIN wants to be managed."
598 (let* ((minb-hei (X-Geom-height (xwem-minib-xgeom xwem-minibuffer)))
599 (wgeom (XGetGeometry (xwem-dpy) xwin))
600 (w-wid (X-Geom-width wgeom))
601 (w-hei (X-Geom-height wgeom))
602 (dapp-geom (make-X-Geom
603 :x (xwem-tray-get-proper-position w-wid)
604 :y (/ (- minb-hei w-hei) 2)
605 :width w-wid :height w-hei))
606 (dapp (make-xwem-dapp :xwin xwin :geom dapp-geom)))
608 ;; Set DAPP's window gravity
609 (XChangeWindowAttributes
610 (xwem-dpy) xwin (make-X-Attr :win-gravity
611 (if (eq xwem-tray-default-align 'right)
615 ;; Dockapp properties
616 (setf (xwem-dapp-id dapp)
617 (nth 2 (XGetWindowProperty
618 (xwem-dpy) xwin (XInternAtom (xwem-dpy) "XWEM_DOCK_ID"))))
619 (setf (xwem-dapp-group-name dapp)
620 (XGetPropertyString (xwem-dpy) xwin
621 (XInternAtom (xwem-dpy) "XWEM_DOCK_GROUP")))
622 (setf (xwem-dapp-align dapp)
623 (nth 2 (XGetWindowProperty
624 (xwem-dpy) xwin (XInternAtom (xwem-dpy) "XWEM_DOCK_ALIGN"))))
626 (add-to-list 'xwem-tray-dapp-list dapp)
628 (X-Win-EventHandler-add-new xwin 'xwem-dapp-handle-xevent
629 100 (list X-ClientMessage))
631 (if xwem-tray-use-groups
632 (xwem-tray-group-attach-dapp
633 (xwem-tray-group-find-create (xwem-dapp-group-name dapp))
635 (XReparentWindow (xwem-dpy) xwin (xwem-tray-xwin xwem-tray)
637 (X-Geom-y dapp-geom)))
638 (XMapWindow (xwem-dpy) xwin)
639 (setf (xwem-dapp-state dapp) 'shown)))
641 (defun xwem-dapp-handle-client-message (xev)
642 "Handle ClientMessage from dock application."
643 (xwem-debug 'xwem-tray "DOCK APP: ClientMessage")
645 (let ((dapp (xwem-tray-find-dapp (X-Event-xclient-window xev)))
646 (mes-type (X-Atom-id (X-Event-xclient-atom xev))))
647 (cond ((= mes-type (X-Atom-id (aref (xwem-tray-atoms xwem-tray) 9)))
648 ;; part of some message arrived
649 (let* ((len (- (xwem-dapp-mess-waitlen dapp)
650 (xwem-dapp-mess-currlen dapp)))
651 (ltgo (if (> len 20) 20 len))) ;length to go
652 (setf (xwem-dapp-mess dapp)
653 (concat (xwem-dapp-mess dapp)
655 (mapcar 'car (X-Event-xclient-msg xev)) ltgo)))
656 (setf (xwem-dapp-mess-currlen dapp)
657 (+ (xwem-dapp-mess-currlen dapp) ltgo)))
659 (when (= (xwem-dapp-mess-currlen dapp)
660 (xwem-dapp-mess-waitlen dapp))
661 ;; message accomplished
662 (let ((dtype (xwem-dapp-mess-type dapp)))
663 (cond ((= dtype xwem-tc-message)
665 (when xwem-tray-message-hook
666 (funcall xwem-tray-message-hook dapp)))
668 ((= dtype xwem-tc-run-lisp)
669 (xwem-debug 'xwem-tray "DOCK APP: ELISP: '%s'"
670 '(xwem-dapp-mess dapp))
672 (insert (xwem-dapp-mess dapp))
675 (xwem-message 'info "evaling: %S"
676 (xwem-dapp-mess dapp))
681 ((= mes-type (X-Atom-id (aref (xwem-tray-atoms xwem-tray) 3)))
683 (let ((opc (truncate (car (nth 1 (X-Event-xclient-msg xev))))))
684 (cond ((= opc xwem-tc-dock-req) nil)
685 (t (setf (xwem-dapp-mess dapp) "")
686 (setf (xwem-dapp-mess-currlen dapp) 0)
687 (setf (xwem-dapp-mess-waitlen dapp)
688 (truncate (car (nth 3 (X-Event-xclient-msg xev)))))
689 (setf (xwem-dapp-mess-type dapp) opc))
692 'warning "Unknown mes-type %d from dock app." mes-type)))
695 (defun xwem-dapp-handle-xevent (xdpy xwin xev)
696 "X Events handler for dockapps."
697 (xwem-debug 'xwem-tray "DAPP: X Event: %S" '(X-Event-name xev))
701 (xwem-dapp-handle-client-message xev))
704 (defun xwem-tray-create (dpy)
705 "Creates new XWEM system tray on DPY.
706 Window is InputOnly to be transparent."
708 (setq win (XCreateWindow
712 (make-X-Attr :override-redirect t
713 :event-mask xwem-tray-evmask)))
715 (X-Win-EventHandler-add-new win 'xwem-tray-handle-client-message
716 100 (list X-ClientMessage))
718 ;; Setup various hints
719 (XSetWMClass dpy win xwem-tray-class)
720 (XSetWMName dpy win xwem-tray-name)
722 (setf (xwem-tray-xwin xwem-tray) win)
723 (setf (xwem-tray-plist xwem-tray) nil)
725 ;; TODO: install Selections and properties we will need
728 (defun xwem-tray-init (dpy)
729 "Initialize xwem tray."
731 (make-xwem-tray :atoms (make-vector 40 nil)
732 :xwin (xwem-minib-xwin xwem-minibuffer)))
734 (let ((xwem-atoms (xwem-tray-atoms xwem-tray)))
735 (aset xwem-atoms 0 (XInternAtom dpy "_NET_WM_WINDOW_TYPE"))
736 (aset xwem-atoms 1 (XInternAtom dpy "_NET_WM_WINDOW_TYPE_DOCK"))
737 (aset xwem-atoms 3 (XInternAtom dpy "_NET_SYSTEM_TRAY_OPCODE"))
738 (aset xwem-atoms 4 (XInternAtom dpy "_XEMBED_INFO"))
739 (aset xwem-atoms 5 (XInternAtom dpy "_XEMBED"))
740 (aset xwem-atoms 6 (XInternAtom dpy "MANAGER"))
741 (aset xwem-atoms 9 (XInternAtom dpy "_NET_SYSTEM_TRAY_MESSAGE_DATA"))
742 (aset xwem-atoms 10 (XInternAtom dpy "_NET_WM_WINDOW_TYPE_SPLASH"))
743 (aset xwem-atoms 15 (XInternAtom dpy "_NET_WM_STRUT"))
744 (aset xwem-atoms 18 (XInternAtom dpy "_NET_WM_ICON"))
745 (aset xwem-atoms 19 (XInternAtom dpy "_NET_WM_PID"))
746 (aset xwem-atoms 20 (XInternAtom dpy "_XROOTPMAP_ID"))
748 (aset xwem-atoms 30 (XInternAtom dpy "XWEM_DOCK_ID"))
749 (aset xwem-atoms 31 (XInternAtom dpy "XWEM_DOCK_GROUP"))
750 (aset xwem-atoms 32 (XInternAtom dpy "XWEM_DOCK_ALIGN"))
752 ;; Use emacs pid as tray identificator
754 (XInternAtom dpy (format "_NET_SYSTEM_TRAY_S%i" xwem-tray-id))))
756 (setenv "SYSTEM_TRAY_ID" (format "%i" xwem-tray-id))
758 ;; Subscribe on substructure change events for xwem tray window.
759 (XSelectInput (xwem-dpy) (xwem-tray-xwin xwem-tray)
760 (Xmask-or XM-SubstructureNotify XM-StructureNotify
762 (XGetWindowAttributes
763 (xwem-dpy) (xwem-tray-xwin xwem-tray)))))
764 (X-Win-EventHandler-add-new (xwem-tray-xwin xwem-tray)
765 'xwem-tray-handle-xevent -1
766 (list X-MapNotify X-UnmapNotify
767 X-DestroyNotify X-ConfigureNotify))
768 (X-Win-EventHandler-add-new (xwem-tray-xwin xwem-tray)
769 'xwem-tray-handle-xevent 100
770 (list X-ClientMessage))
772 ;; Configure systray cursor
773 (setq xwem-tray-cursor
774 (xwem-make-cursor xwem-tray-cursor-shape
775 xwem-tray-cursor-foreground-color
776 xwem-tray-cursor-background-color))
777 (XSetWindowCursor (xwem-dpy) (xwem-tray-xwin xwem-tray)
780 (defun xwem-tray-handle-xevent (xdpy xwin xev)
781 "X Events handler for xwem systray."
782 (xwem-debug 'xwem-tray "TRAY X Event: %S" '(X-Event-name xev))
786 (let* ((mes-type (X-Atom-id (X-Event-xclient-atom xev)))
787 (mes-data (X-Event-xclient-msg xev))
788 (mes-win (X-Win-find-or-make (xwem-dpy) (car (nth 2 mes-data))))
789 (data-type (truncate (car (nth 1 mes-data)))))
790 (cond ((= mes-type (X-Atom-id (aref (xwem-tray-atoms xwem-tray) 3)))
791 (cond ((= data-type xwem-tc-dock-req)
792 (xwem-debug 'xwem-tray "Creating new dockapp ..")
793 (xwem-tray-new-dapp mes-win))
795 'warning "Unknown data-type %d in clientmessage."
797 (t (xwem-message 'warning "Unknown mes-type %d" mes-type)))))
800 (let ((dapp (xwem-tray-find-dapp (X-Event-xdestroywindow-window xev))))
801 (when (xwem-dapp-alive-p dapp)
802 (xwem-message 'note "Removing dockapp ..")
803 (xwem-tray-remove-dapp dapp))))
806 (let ((dapp (xwem-tray-find-dapp (X-Event-xunmap-window xev))))
807 (when (xwem-dapp-alive-p dapp)
808 (xwem-tray-hide-dapp dapp t))))
811 (let ((dapp (xwem-tray-find-dapp (X-Event-xunmap-window xev))))
812 (when (xwem-dapp-alive-p dapp)
813 (xwem-tray-show-dapp dapp t))))
816 (when (eq (X-Event-xconfigure-window xev)
817 (xwem-tray-xwin xwem-tray))
818 (let ((height (X-Event-xconfigure-height xev)))
819 (when (not (eql height
820 (xwem-tray-get-prop xwem-tray 'xwem-saved-height)))
821 (xwem-tray-put-prop xwem-tray 'xwem-saved-height height)
822 (mapc #'(lambda (dapp)
823 (setf (X-Geom-y (xwem-dapp-geom dapp))
824 (/ (- height (X-Geom-height (xwem-dapp-geom dapp))) 2))
825 (xwem-tray-apply-dapp-position dapp))
826 xwem-tray-dapp-list)))))))
828 (defun xwem-tray-startit (&optional dpy)
829 "Start xwew tray on display DPY."
830 (unless (get 'xwem-tray 'initialized)
831 (unless dpy (setq dpy (xwem-dpy)))
834 (XSetSelectionOwner dpy (aref (xwem-tray-atoms xwem-tray) 2)
835 (xwem-tray-xwin xwem-tray))
836 (XMapWindow dpy (xwem-tray-xwin xwem-tray))
838 ;; Add finialization hook
839 (add-hook 'xwem-exit-hook 'xwem-tray-fini)
840 (put 'xwem-tray 'initialized t)))
842 (defun xwem-tray-fini ()
843 "Finialize xwem-tray."
844 (mapc #'(lambda (dapp)
845 (XDestroyWindow (xwem-dpy) (xwem-dapp-xwin dapp)))
848 (setq xwem-tray-dapp-list nil)
849 (setq xwem-tray-cursor nil)
853 (defun xwem-tray-delimeter (&optional w h bgcol)
854 "Add delimiter to dockapp.
855 W and H specifies delimiter width and height.
856 BGCOL - background color."
858 (setq w xwem-tray-delimiter-width))
860 (setq h (- (X-Geom-height (xwem-minib-cl-xgeom xwem-minibuffer))
861 (* 2 xwem-tray-delimiter-height-reminder))))
863 (let* ((bgmode (xwem-tray-background-mode))
864 (bgcol (or bgcol (xwem-face-foreground 'xwem-tray-delimiter-face
865 (list 'background bgmode))))
867 (xwem-dpy) nil 0 0 w h
871 :cursor (xwem-make-cursor X-XC-sb_h_double_arrow)
873 (XAllocNamedColor (xwem-dpy) (XDefaultColormap (xwem-dpy))
875 :event-mask (Xmask-or XM-ButtonPress
876 XM-ButtonRelease XM-ButtonMotion)))))
877 (xwem-XTrayInit (xwem-dpy) xwin)
881 (defun xwem-tray-background-mode ()
882 "Return background mode(`dark' or `light') for system tray."
883 (xwem-get-background-mode
884 (face-background-instance 'default (xwem-minib-frame xwem-minibuffer))))
886 ;;; System tray managing model
888 (defun xwem-manage-systray (cl)
889 "Manage method for systray dockaps."
890 (xwem-XTrayInit (xwem-dpy) (xwem-cl-xwin cl)))
895 ;;;; On-load actions:
897 ;; Systray manage type
898 (define-xwem-manage-model systray
899 "Managing model for systray utilities."
900 :manage-method 'xwem-manage-systray)
902 ;; - Register xwem system tray
905 (add-hook 'xwem-after-init-hook 'xwem-tray-startit))
907 ;;; xwem-tray.el ends here