;;; xwem-pager.el --- Simple frame pager. ;; Copyright (C) 2004,2005 by XWEM Org. ;; Author: Richard Klinda ;; Zajcev Evgeny ;; Created: Wed Aug 18 08:05:09 MSD 2004 ;; Keywords: xwem ;; X-CVS: $Id: xwem-pager.el,v 1.2 2005-04-04 19:54:15 lg Exp $ ;; This file is part of XWEM. ;; XWEM is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; XWEM is distributed in the hope that it will be useful, but WITHOUT ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public ;; License for more details. ;; You should have received a copy of the GNU General Public License ;; along with XEmacs; see the file COPYING. If not, write to the Free ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA ;; 02111-1307, USA. ;;; Synched up with: Not in FSF ;;; Commentary: ;; Simple dockapp to show xwem frames. Somekind of extension of ;; xwem-framei.el ;;; Code: (require 'xwem-load) (require 'xlib-xshape) ;; veryvery simple pager / 2d viewport support ;; the code works, do the following: ;; ;; add to XWEM-after-init-hook: ;; ;; (setq *pager-dockapp* (xwem-2dframes-start-dockapp)) ;; ;; ugly i know, that starts the dockapp ;; ;; (xwem-2dframes-make-frames) ;; ;; that will create the frames ;; ;; load this code, restart your XWEM and be happy. If you want to try it ;; out without restarting then MAKE SURE you have only 1 frame, load the ;; code then: ;; M-x xwem-2dframes-make-frames ;; ;; eval (setq *pager-dockapp* (xwem-2dframes-start-dockapp)) ;; ;; change viewports / frames somehow so the dockapp gets updated ;; ;; i know this code is hackis, but if you rename the variables / sturcture ;; the code like you want it to be i'll work on it to make it full featured ;; + add more comments / docstrings. ;;; ////////////////////////////////////////////////////////////////////// ;;;; Pager (defgroup xwem-pager nil "Group to customize xwem pager." :prefix "xwem-pager-" :group 'xwem-tray) (defcustom xwem-pager-dim (cons '(2 . 3) '(4 . 4)) "Minimum and maximum viewports to show at X and Y." :type '(cons (cons :tag "Minimum" (number :tag "X") (number :tag "Y")) (cons :tag "Maximum" (number :tag "X") (number :tag "Y"))) :set (lambda (sym val) (set sym val) (when (xwem-pager-xwin) (xwem-pager-redimentionize))) :initialize 'custom-initialize-default :group 'xwem-pager) (defcustom xwem-pager-prefer-horizontal t "*Non-nil mean pager will prefer horizontal increment when redimentinizing." :type 'boolean :set (lambda (sym val) (set sym val) (when (xwem-pager-xwin) (xwem-pager-redimentionize))) :initialize 'custom-initialize-default :group 'xwem-pager) (defcustom xwem-pager-viewport-size '(12 . 6) "\(X . Y\) where X*Y pixel will represent one viewport." :type '(cons (number :tag "X") (number :tag "Y")) :set (lambda (sym val) (set sym val) (when (xwem-pager-xwin) (xwem-pager-redimentionize))) :initialize 'custom-initialize-default :group 'xwem-pager) (defcustom xwem-pager-grid-p t "*Set to non-nil if you want visible grid." :type 'boolean :set (lambda (sym val) (set sym val) (when (xwem-pager-xwin) (xwem-pager-redraw (xwem-pager-xwin) t))) :initialize 'custom-initialize-default :group 'xwem-pager) (define-xwem-face xwem-pager-face `(((selected) (:foreground "grey30")) ((border selected) (:foreground "grey10")) ((deselected) (:foreground "grey55")) ((border deselected) (:foreground "grey35")) ((unavailable) (:foreground "grey80")) ((border unavailable) (:foreground "grey100"))) "Face for pager." :group 'xwem-pager) (defvar xwem-pager-keymap (let ((map (make-sparse-keymap))) (define-key map [button1] 'xwem-pager-iswitch) (define-key map [button3] 'xwem-pager-popup-menu) map) "Keymap for pager operations.") ;; Macroses (defvar xwem-pager-xwin nil "XWIN of xwem pager.") ;; Pager xwin (defmacro xwem-pager-xwin (&optional xwin) "Return pager's dockapp X window." `(or ,xwin xwem-pager-xwin)) (defsetf xwem-pager-xwin () (xwin) `(setq xwem-pager-xwin ,xwin)) ;; Pager pixmap (defmacro xwem-pager-xpix (&optional xwin) "Return pager's dockapp X window." `(X-Win-get-prop (xwem-pager-xwin ,xwin) 'xwem-pager-xpixmap)) (defsetf xwem-pager-xpix (&optional xwin) (pix) `(X-Win-put-prop (xwem-pager-xwin ,xwin) 'xwem-pager-xpixmap ,pix)) ;; Pager dimentions (X . Y (defmacro xwem-pager-dim (&optional xwin) `(X-Win-get-prop (xwem-pager-xwin ,xwin) 'xwem-pager-dim)) (defsetf xwem-pager-dim (&optional xwin) (dim) `(X-Win-put-prop (xwem-pager-xwin ,xwin) 'xwem-pager-dim ,dim)) ;; Functions (define-xwem-deffered xwem-pager-redraw-for-frame (frame-num &optional xwin) "Redraw FRAME." (when (< frame-num (apply '* (xwem-pager-dim xwin))) ;; FRAME shows in pager (let* ((frame (nth frame-num xwem-frames-list)) (dim (xwem-pager-dim xwin)) (tags (cond ((not (xwem-frame-alive-p frame)) '(unavailable)) ((xwem-frame-selected-p frame) '(selected)) (t '(deselected)))) (gc (xwem-face-get-gc 'xwem-pager-face tags)) (col (% frame-num (car dim))) (row (/ frame-num (car dim)))) (XFillRectangle (xwem-dpy) (xwem-pager-xpix xwin) gc (* col (car xwem-pager-viewport-size)) (* row (cdr xwem-pager-viewport-size)) (car xwem-pager-viewport-size) (cdr xwem-pager-viewport-size)) (when xwem-pager-grid-p (XDrawRectangle (xwem-dpy) (xwem-pager-xpix xwin) (xwem-face-get-gc 'xwem-pager-face `(border ,@tags)) (* col (car xwem-pager-viewport-size)) (* row (cdr xwem-pager-viewport-size)) (1- (car xwem-pager-viewport-size)) (1- (cdr xwem-pager-viewport-size)))) (xwem-pager-redraw (xwem-pager-xwin xwin))))) (define-xwem-deffered xwem-pager-redraw (xwin &optional full) "Redraw pager XWIN." (let* ((geom (XGetGeometry (xwem-dpy) (xwem-pager-xpix xwin))) (w (X-Geom-width geom)) (h (X-Geom-height geom))) (if (not full) (XCopyArea (xwem-dpy) (xwem-pager-xpix xwin) xwin (XDefaultGC (xwem-dpy)) 0 0 w h 0 0) (XFillRectangle (xwem-dpy) (xwem-pager-xpix xwin) (XDefaultGC (xwem-dpy)) 0 0 w h) (loop for fnum from 0 to (apply '* (xwem-pager-dim xwin)) do (xwem-pager-redraw-for-frame-1 fnum xwin))))) (defun xwem-pager-redimentionize (&optional non-used-argument xwin) "Check is pager need redimentionisation." (let ((frames (length xwem-frames-list)) (min-ddim (list (car (cdr xwem-pager-dim)) (cdr (cdr xwem-pager-dim))))) ;; Calculate new dimention (mapc (lambda (ddim) (let ((dval (- (apply '* ddim) frames)) (mval (- (apply '* min-ddim) frames))) ;; Change min-ddim only if: ;; - DVAL is positive or zero and MVAL is negative ;; - DVAL and MVAL of same sign and DVAL abs is lesser ;; - DVAL and MVAL of same sign and DVAL is equal to MVAL, but ;; DVAL's X and Y components differs lesser. (when (or (and (>= dval 0) (< mval 0)) (and (or (zerop dval) (= (signum dval) (signum mval))) (or (< (abs dval) (abs mval)) (and (= (abs dval) (abs mval)) (< (abs (- (car ddim) (cadr ddim))) (abs (- (car min-ddim) (cadr min-ddim))))) (and xwem-pager-prefer-horizontal (= (abs dval) (abs mval)) (= (abs (- (car ddim) (cadr ddim))) (abs (- (car min-ddim) (cadr min-ddim)))) (> (car ddim) (car min-ddim)))))) (setq min-ddim ddim)))) ;; Create a list of all possible dimentions (loop for i from (car (car xwem-pager-dim)) to (car (cdr xwem-pager-dim)) nconc (loop for j from (cdr (car xwem-pager-dim)) to (cdr (cdr xwem-pager-dim)) collect (list i j)))) (setf (xwem-pager-dim xwin) min-ddim) (let ((w (* (car min-ddim) (car xwem-pager-viewport-size))) (h (* (cadr min-ddim) (cdr xwem-pager-viewport-size)))) (XResizeWindow (xwem-dpy) (xwem-pager-xwin xwin) w h) ;; Recreate pixmap (if necessary) (when (xwem-pager-xpix xwin) (XFreePixmap (xwem-dpy) (xwem-pager-xpix xwin))) (setf (xwem-pager-xpix xwin) (XCreatePixmap (xwem-dpy) (make-X-Pixmap :id (X-Dpy-get-id (xwem-dpy))) (xwem-pager-xwin xwin) (XDefaultDepth (xwem-dpy)) w h)) (when xwem-misc-turbo-mode (XSetWindowBackgroundPixmap (xwem-dpy) (xwem-pager-xwin xwin) (xwem-pager-xpix xwin)))) (xwem-pager-redraw (xwem-pager-xwin xwin) t))) (defun xwem-pager-frame-redraw (&optional frame) "Update xwem pager dockapp, because FRAME just selected/deselected." (unless frame (setq frame (xwem-frame-selected))) (xwem-pager-redraw-for-frame (xwem-frame-num frame))) (defun xwem-pager-remove (xwin &optional need-destroy) "Destroy pager's XWIN." (XFreePixmap (xwem-dpy) (xwem-pager-xpix xwin)) (setf (xwem-pager-xpix xwin) nil) ;; Remove pager events handler (X-Win-EventHandler-rem xwin 'xwem-pager-event-handler) ;; Destroy pager xwin if needed (when need-destroy (XDestroyWindow (xwem-dpy) xwin)) ;; Unset default pager xwin (when (eq (xwem-pager-xwin) xwin) (setf (xwem-pager-xwin) nil)) (remove-hook 'xwem-frame-select-hook 'xwem-pager-frame-redraw) (remove-hook 'xwem-frame-deselect-hook 'xwem-pager-frame-redraw) (remove-hook 'xwem-frame-creation-hook 'xwem-pager-redimentionize) (remove-hook 'xwem-frame-destroy-hook 'xwem-pager-redimentionize)) (defun xwem-pager-event-handler (xdpy xwin xev) "X Events handler for xwem pager dockapp." (X-Event-CASE xev (:X-Expose (xwem-pager-redraw xwin)) (:X-DestroyNotify (xwem-pager-remove xwin)) ((:X-ButtonPress :X-ButtonRelease) (let ((xwem-override-local-map xwem-pager-keymap)) (xwem-dispatch-command-xevent xev))))) ;;;###autoload (defun xwem-pager (&optional dockid dockgroup dockalign) "Start xwem pager dockapp. DOCKID, DOCKGROUP and DOCKALIGN specifies pager placement in xwem tray." (interactive) (let* ((pwin (XCreateWindow (xwem-dpy) nil 0 0 1 1 0 nil nil nil (make-X-Attr :event-mask (Xmask-or XM-Exposure XM-StructureNotify XM-ButtonPress XM-ButtonRelease) :override-redirect t)))) ;; Set default pager window (unless (X-Win-p (xwem-pager-xwin)) (setf (xwem-pager-xwin) pwin)) ;; Initialize sizes and stuff (xwem-pager-redimentionize nil pwin) ;; Install events handler (X-Win-EventHandler-add pwin 'xwem-pager-event-handler nil (list X-Expose X-DestroyNotify X-ButtonPress X-ButtonRelease)) ;; Initialize wd in sys tray (xwem-XTrayInit (xwem-dpy) pwin dockid dockgroup dockalign) (add-hook 'xwem-frame-select-hook 'xwem-pager-frame-redraw) (add-hook 'xwem-frame-deselect-hook 'xwem-pager-frame-redraw) (add-hook 'xwem-frame-creation-hook 'xwem-pager-redimentionize) (add-hook 'xwem-frame-destroy-hook 'xwem-pager-redimentionize) pwin)) (defun xwem-pager-frame-at (xwin x y) "Return frame that is under X Y position in XWIN pager." (let* ((dim (xwem-pager-dim xwin)) (col (/ x (car xwem-pager-viewport-size))) (row (/ y (cdr xwem-pager-viewport-size))) (num (+ (* row (car dim)) col))) (nth num xwem-frames-list))) ;; Commands (define-xwem-command xwem-pager-iswitch (ev) "Switch to frame." (xwem-interactive (list xwem-last-event)) (unless (button-event-p ev) (error 'xwem-error "`xwem-pager-iswitch-frame' must be bound to mouse event")) (let ((frame (xwem-pager-frame-at (X-Event-win xwem-last-xevent) (X-Event-xbutton-event-x xwem-last-xevent) (X-Event-xbutton-event-y xwem-last-xevent)))) (when (xwem-frame-p frame) (xwem-select-frame frame)))) (define-xwem-command xwem-pager-popup-menu (ev) "Popup menu." (xwem-interactive (list xwem-last-event)) (unless (button-event-p ev) (error 'xwem-error "`xwem-pager-popup-menu' must be bound to mouse event")) (xwem-popup-menu (list "Pager" "---" (vector "Destroy" `(xwem-pager-remove ,(X-Event-win xwem-last-xevent) t))))) ;;;; 2D Frames ;;;###autoload (defun xwem-pager-make-frames () "Make the frames, call from XWEM-AFTER-INIT-HOOK!" (dotimes (it (- (* (car (cdr xwem-pager-dim)) (cdr (cdr xwem-pager-dim))) (length (xwem-frames-list 'desktop)))) (xwem-make-frame-1 'desktop :noselect t))) ;;;###autoload(autoload 'xwem-pager-move-up "xwem-pager" nil t) (define-xwem-command xwem-pager-move-up (&optional arg) "Move one viewport up." (xwem-interactive "p") (xwem-pager-move 'up arg)) ;;;###autoload(autoload 'xwem-pager-move-down "xwem-pager" nil t) (define-xwem-command xwem-pager-move-down (&optional arg) "Move one viewport down." (xwem-interactive "p") (xwem-pager-move 'down arg)) ;;;###autoload(autoload 'xwem-pager-move-left "xwem-pager" nil t) (define-xwem-command xwem-pager-move-left (&optional arg) "Move one viewport left." (xwem-interactive "p") (xwem-pager-move 'left arg)) ;;;###autoload(autoload 'xwem-pager-move-right "xwem-pager" nil t) (define-xwem-command xwem-pager-move-right (&optional arg) "Move one viewport right." (xwem-interactive "p") (xwem-pager-move 'right arg)) (defun xwem-pager-move (dir &optional arg) "Generic function to move to frame in DIR direction. DIR is one of `up', `down', `right' or `left'." (unless arg (setq arg 1)) (xwem-frame-switch-nth (case dir (up (- (xwem-frame-num (xwem-frame-selected)) (* arg (car (xwem-pager-dim))))) (down (+ (xwem-frame-num (xwem-frame-selected)) (* arg (car (xwem-pager-dim))))) (left (- (xwem-frame-num (xwem-frame-selected)) arg)) (right (+ (xwem-frame-num (xwem-frame-selected)) arg))))) ;;;###autoload (defun xwem-pager-install-bindings () "Install default bindings for 2D frames commands." (xwem-global-set-key [(super h)] 'xwem-pager-move-left) (xwem-global-set-key [(super t)] 'xwem-pager-move-down) (xwem-global-set-key [(super n)] 'xwem-pager-move-up) (xwem-global-set-key [(super s)] 'xwem-pager-move-right)) (provide 'xwem-pager) ;;; xwem-pager.el ends here