1 ;;; xwem-launcher.el --- Program launcher for XWEM.
3 ;; Copyright (C) 2003-2005 by XWEM Org.
5 ;; Author: Zajcev Evgeny <zevlg@yandex.ru>
6 ;; Created: Thu Dec 4 16:32:11 MSK 2003
7 ;; Keywords: xwem, xlib
8 ;; X-CVS: $Id: xwem-launcher.el,v 1.11 2005-04-04 19:54:13 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 ;; External programs launcher for XWEM.
34 ;; * Assume argument in quotas as single argument, i.e. do not make
35 ;; splitting inside quotas.
42 (autoload 'executable-find "executable")
51 (defgroup xwem-launcher nil
52 "Group to customize XWEM's programs launcher."
56 (defcustom xwem-launcher-beep-done nil
57 "*Non-nil mean beep when execution of program done.
58 Beep performed using \(xwem-play-sound 'ready\)."
60 :group 'xwem-launcher)
62 (defcustom xwem-launcher-function 'xwem-execute-program
63 "Function to be used to execute external program."
65 :group 'xwem-launcher)
67 (defcustom xwem-launcher-abbrev-table nil
68 "Abbrev table used by `xwem-launcher-query'."
70 :group 'xwem-launcher)
72 (defcustom xwem-launcher-history nil
73 "History of `xwem-launcher-query'ies."
75 :group 'xwem-launcher)
77 (defcustom xwem-launcher-split-type 'xwem-execute-program-other-win-vertical
78 "Window split type, when launching program in other window."
80 (const :tag "Horizontal" xwem-execute-program-other-win-horizontal)
81 (const :tag "Vertical" xwem-execute-program-other-win-vertical))
82 :group 'xwem-launcher)
84 (defcustom xwem-launcher-frame-type 'xwem-execute-program-other-frame
85 "Type of frame, when launching program in other frame."
87 (const :tag "Normal frame" xwem-execute-program-other-frame)
88 (const :tag "Embedded frame" xwem-execute-program-embedded-frame))
89 :group 'xwem-launcher)
91 (defcustom xwem-xterm-program "xterm"
92 "Name of terminal emulator program."
94 :group 'xwem-launcher)
96 (defcustom xwem-xterm-font-argument "-fn"
97 "Program key to specify in order to change font."
99 :group 'xwem-launcher)
101 (defcustom xwem-xterm-font1 ""
102 "Default xterm font."
104 :group 'xwem-launcher)
106 (defcustom xwem-xterm-font2 "10x20"
109 :group 'xwem-launcher)
111 (defcustom xwem-xterm-font3 "9x15"
114 :group 'xwem-launcher)
116 (defcustom xwem-xterm-font4 "fixed"
119 :group 'xwem-launcher)
121 (defcustom xwem-lupe-program "lupe"
122 "Xmag like mignifier program."
124 :group 'xwem-launcher)
126 (defcustom xwem-lupe-arguments "-noshape -nohud"
127 "Argument to pass to `xwem-lupe-program'."
129 :group 'xwem-launcher)
131 (defcustom xwem-xlock-program "xlock"
132 "Program to run in order to lock X display."
134 :group 'xwem-launcher)
136 (defcustom xwem-xlock-arguments "-mode image"
137 "Arguments to supply `xwem-xlock-program'."
139 :group 'xwem-launcher)
141 ;;; Launcher dockapp button
142 (defcustom xwem-launch-dock-width 24
143 "*Launcher dockapp width."
145 :group 'xwem-launcher)
147 (defcustom xwem-launch-dock-height 24
148 "*Launcher dockapp height."
150 :group 'xwem-launcher)
152 (defcustom xwem-launch-dock-thick 2
153 "*Launcher dockapp border thickness."
155 :group 'xwem-launcher)
157 ;;; Internal variables
159 (defvar xwem-launcher-shell-completion-table nil
160 "*Completion table in used by `xwem-completer'.")
163 (defun xwem-launcher-build-shell-completion-table (&optional rehash)
164 "Scan `exec-path' to build completion table of executables."
165 (if (and xwem-launcher-shell-completion-table (not rehash))
166 xwem-launcher-shell-completion-table
168 (setq xwem-launcher-shell-completion-table
170 (mapcar #'(lambda (dir)
171 (mapcar 'list (directory-files dir nil nil t t)))
174 (defun xwem-launcher-shell-complete (&optional undo mode)
175 "Complete the previous command or display possibilities if done
176 twice in a row. If called with a prefix, undo the last completion."
181 (setq completer-string nil)
182 (if (string-match ".*[ \t].*" (buffer-substring (point-min) (point-max)))
183 (comint-dynamic-complete-filename)
185 ;; Complete application
186 (completer-complete-goto "^ \t\n\"" completer-words
187 (xwem-launcher-build-shell-completion-table)
189 (executable-find (car w)))))))
191 (defun xwem-launcher-read-command (prompt &optional initial-input)
192 "Read command name prompting PROMPT.
193 Just linke `read-shell-command', but installs
194 `xwem-launcher-abbrev-table' as abbrev table, `xwem-launcher-history'
195 as history of commands and `xwem-launcher-shell-completion-table' as table
196 to performe completions.
197 INITIAL-INPUT is self-described."
198 (let ((minibuffer-completion-table nil)
199 (keymap (copy-keymap read-shell-command-map)))
202 (define-key read-shell-command-map
203 (kbd "TAB") 'xwem-launcher-shell-complete)
204 (xwem-read-from-minibuffer
205 prompt initial-input read-shell-command-map
206 nil 'xwem-launcher-history xwem-launcher-abbrev-table))
207 (setq read-shell-command-map keymap))))
209 (defun xwem-launcher-parse-arguments (cmd-str &optional keep-quotes-p)
210 "Parse CMD-STR by spliting it to arguments list.
211 If optional KEEP-QUOTES-P is non-nil, quotes in quoted arguments are kept."
212 (let ((scmd (split-string cmd-str " "))
215 (if (string-match "^['\"]" (car scmd))
216 (setq qarg (car scmd))
218 (setq qarg (concat qarg " " (car scmd)))))
219 (if (and (stringp qarg)
220 (string-match "['\"]$" (car scmd)))
221 (setq args (cons (if keep-quotes-p
223 (substring qarg 1 (1- (length qarg))))
226 (setq args (cons (car scmd) args)))
227 (setq scmd (cdr scmd)))
228 ;; Pre-normalise command and its arguments
229 (setq args (remove "" (nreverse args))
230 cmd (executable-find (car args)))
232 (cons cmd (cdr args)))))
234 (defun xwem-launcher-normalize-cmd (cmd)
235 "Normalize command CMD string.
236 Return normalized command string, or signal error if CMD can't be
238 (let ((pargs (xwem-launcher-parse-arguments cmd t)))
240 (error 'xwem-error (format "Can't normalize command: %S" cmd)))
241 (mapconcat #'identity pargs " ")))
244 (defun xwem-launcher-query (&optional prompt)
245 "Query for command to launch using PROMPT."
246 (let ((cmd (xwem-launcher-read-command (or prompt "XWEM-Run: "))))
247 (xwem-launcher-normalize-cmd cmd)))
249 ;;;###autoload(autoload 'xwem-run-program "xwem-launcher" "" t)
250 (define-xwem-command xwem-run-program (command)
252 (xwem-interactive "eRun command: ")
253 (xwem-execute-program command))
255 (defun xwem-next-job-number ()
256 "Return next job number for use by xwem."
257 (let ((job-number 1))
258 (while (get-process (format "xwem-run-%d" job-number))
259 (setq job-number (1+ job-number)))
263 (defun xwem-execute-program (command &optional buffer-name)
264 "Execute COMMAND in buffer with BUFFER-NAME.
265 Unlike `background' do not use shell."
267 ;; Do it under `condition-case', due to split-string
268 ;; args-out-of-range bug.
270 (xwem-launcher-parse-arguments command)
274 (emacs-env (getenv "EMACS"))
275 (job-number (xwem-next-job-number))
276 (job-name (format "xwem-run-%d" job-number))
280 (setq buffer-name (format " *%s*" job-name)))
282 (with-current-buffer (get-buffer-create buffer-name)
283 ;; Sometimes `default-directory' became nil for some reason, I
284 ;; don't know why. Maybe XEmacs bug? --lg
285 (unless default-directory
286 (setq default-directory (expand-file-name "~/")))
289 (insert (format "--- Working directory: %S\n%% %S\n"
290 default-directory command))
292 ;; Set our EMACS environment variable so comint-exec doesn't do it
293 ;; for us. Note that if the environment is already set, we may
294 ;; not want to do it again.
296 (setenv "EMACS" "xwem"))
298 (setq proc (get-buffer-process
299 (comint-exec buffer-name job-name prg nil args)))
301 ;; COND because the proc may have died before the G-B-P is called.
302 (cond (proc (set-process-sentinel proc 'xwem-program-sentinel)
303 (xwem-message 'note "Job [%d] '%s' PID=%d"
304 job-number command (process-id proc))))
305 (setq mode-name "XWEM-Run")
307 ;; Restore our Emacs environment variable to its previous state.
308 (setenv "EMACS" emacs-env)
312 (defun xwem-program-sentinel (process msg)
313 "Called when PROCESS changed state to MSG."
314 (let ((ms (match-data))) ; barf
316 (let ((msg (cond ((string= msg "finished\n") "Done")
317 ((string-match "^exited" msg)
318 (concat "Exit " (substring msg 28 -1)))
319 ((zerop (length msg)) "Continuing")
320 (t (concat (upcase (substring msg 0 1))
321 (substring msg 1 -1))))))
322 (when xwem-launcher-beep-done
323 (xwem-play-sound 'ready))
324 (xwem-message 'note "Job [%s] %s '%s'" (process-name process)
325 msg (mapconcat #'identity
326 (process-command process) " "))
327 (if (null (buffer-name (process-buffer process)))
328 (set-process-buffer process nil) ; WHY? Olin.
330 (if (memq (process-status process) '(signal exit))
331 (with-current-buffer (process-buffer process)
332 (let ((at-end (eobp)))
334 (goto-char (point-max))
335 (insert ?\n msg ?\x20
336 (substring (current-time-string) 11 19) ?\n))
337 (if at-end (goto-char (point-max))))
338 (set-buffer-modified-p nil)))))
339 (store-match-data ms))))
342 (defun xwem-execute-program-expecting (cmd &optional manage-type cl-plist non-block)
343 "Execute CMD expecting till client will be managed.
344 MANAGE-TYPE specifies which manage type to use in expectance.
345 CL-PLIST is properties for expected client.
346 Return managed client unless NON-BLOCK is non-nil."
347 (setq cmd (xwem-launcher-normalize-cmd cmd))
349 (let* ((job-num (xwem-next-job-number))
350 (expt (list manage-type
351 (nconc (list 'job-num job-num) cl-plist)
354 (xwem-manda-add-expectance expt)
355 (xwem-execute-program cmd)
357 (while (memq expt xwem-manage-expectances)
358 (dispatch-event (next-event)))
361 (setq ccls xwem-clients)
362 (while (and ccls (not (= job-num
363 (or (xwem-client-property (car ccls) 'job-num) -1))))
364 (setq ccls (cdr ccls)))
366 (xwem-client-set-property (car ccls) 'executed-command cmd))
369 (defun xwem-execute-program-other-win (cmd type &optional select-p)
370 "Execute CMD in other XWEM window, making TYPE split if needed.
371 TYPE is one of 'horizontal of 'vertical.
372 If SELECT-P is non-nil - select newly created client.
373 Return newly created client."
374 (let ((own (xwem-window-other 1))
376 ;; Check is there split needed
377 (when (eq own (xwem-win-selected))
378 (if (eq type 'horizontal)
379 (xwem-window-split-horizontally 0)
380 (xwem-window-split-vertically 0))
381 (setq own (xwem-win-next (xwem-win-selected))))
383 (setq cl (xwem-execute-program-expecting
384 cmd nil `(expect-win ,(xwem-win-id own))))
386 (xwem-select-client cl))
389 (defun xwem-execute-program-other-win-horizontal (cmd &optional select-p)
390 "Execute CMD in other XWEM window, making horizontal split if needed."
391 (xwem-execute-program-other-win cmd 'horizontal select-p))
393 (defun xwem-execute-program-other-win-vertical (cmd &optional select-p)
394 "Execute CMD in other XWEM window, making vertical split if needed."
395 (xwem-execute-program-other-win cmd 'vertical select-p))
397 (defun xwem-execute-program-other-frame (cmd &optional select-p)
398 "Execute CMD in other XWEM frame.
399 If SELECT-P is non-nil select newly managed client."
400 (let* ((oframe (or (xwem-frame-other (xwem-frame-selected))
401 (xwem-make-frame-1 'desktop :noselect t)))
402 (cl (xwem-execute-program-expecting
403 cmd nil `(expect-win ,(xwem-win-id (xwem-frame-selwin oframe))))))
405 (xwem-select-client cl))
408 (defun xwem-execute-program-embedded-frame (cmd &optional select-p)
409 "Execute CMD in linkaged frame or in embedded XWEM frame."
410 (let* ((oframe (or (xwem-frame-other (xwem-frame-selected) 'linkage)
411 (xwem-make-frame-1 'embedded :noselect t)))
412 (cl (xwem-execute-program-expecting
413 cmd nil `(expect-win ,(xwem-win-id (xwem-frame-selwin oframe))))))
415 (xwem-select-client cl))
420 ;;;###autoload(autoload 'xwem-launcher-turn-on-horizontal-split-type "xwem-launcher" "" t)
421 (define-xwem-command xwem-launcher-turn-on-horizontal-split-type ()
422 "Set `xwem-launcher-split-type' to `xwem-execute-program-other-win-horizontal'."
425 (setq xwem-launcher-split-type 'xwem-execute-program-other-win-horizontal)
426 (xwem-message 'info "Launcher split type HORIZONTAL on."))
428 ;;;###autoload(autoload 'xwem-launcher-turn-on-vertical-split-type "xwem-launcher" "" t)
429 (define-xwem-command xwem-launcher-turn-on-vertical-split-type ()
430 "Set `xwem-launcher-split-type' to `xwem-execute-program-other-win-vertical'."
433 (setq xwem-launcher-split-type 'xwem-execute-program-other-win-vertical)
434 (xwem-message 'info "Launcher split type VERTICAL on."))
436 ;;;###autoload(autoload 'xwem-launcher-toggle-split-type "xwem-launcher" "" t)
437 (define-xwem-command xwem-launcher-toggle-split-type (arg)
438 "Toggle `xwem-launcher-split-type'.
439 Without prefix ARG set it to vertical, with prefix ARG set it to horizontal."
440 (xwem-interactive "P")
443 (xwem-launcher-turn-on-horizontal-split-type)
444 (xwem-launcher-turn-on-vertical-split-type)))
446 ;;;###autoload(autoload 'xwem-launcher-turn-on-normal-frame-type "xwem-launcher" "" t)
447 (define-xwem-command xwem-launcher-turn-on-normal-frame-type ()
448 "Set `xwem-launcher-frame-type' to `xwem-execute-program-other-frame', aka normal frame type."
451 (setq xwem-launcher-frame-type 'xwem-execute-program-other-frame)
452 (xwem-message 'info "Other frame NORMAL type on."))
454 ;;;###autoload(autoload 'xwem-launcher-turn-on-embedded-frame-type "xwem-launcher" "" t)
455 (define-xwem-command xwem-launcher-turn-on-embedded-frame-type ()
456 "Set `xwem-launcher-frame-type' to `xwem-execute-program-embedded-frame' aka embedded frame type."
459 (setq xwem-launcher-frame-type 'xwem-execute-program-embedded-frame)
460 (xwem-message 'info "Other frame EMBEDDED type on."))
462 ;;;###autoload(autoload 'xwem-launcher-toggle-frame-type "xwem-launcher" "" t)
463 (define-xwem-command xwem-launcher-toggle-frame-type (arg)
464 "Toggle `xwem-launcher-frame-type'.
465 Without prefix ARG set it to normal, with prefix ARG set it to embedded."
466 (xwem-interactive "P")
469 (xwem-launcher-turn-on-normal-frame-type)
470 (xwem-launcher-turn-on-embedded-frame-type)))
472 ;;;###autoload(autoload 'xwem-launch-program "xwem-launcher" "" t)
473 (define-xwem-command xwem-launch-program (cmd &optional arg)
474 "Run CMD program in background.
475 If used with prefix ARG (\\<xwem-global-map>\\[xwem-universal-argument]), installs
476 expectance on selected window (i.e. when client window performe
477 MapWindow, it will be managed to window where expectance setuped
478 regardless selected window at map moment. It is usefull to do so when
479 you start application with large start time, such as Mozilla or
480 AcrobatReader, and you want continue doing things not wainting untill
481 application window maps.
482 If used with numeric prefix ARG, then that number specifies how many
484 (xwem-interactive "_eLaunch program: \nP")
487 (xwem-execute-program-expecting
488 cmd nil `(expect-win ,(xwem-win-id (xwem-win-selected)))))
492 (xwem-execute-program cmd)
493 (setq arg (1- arg))))
494 (t (error 'xwem-error "Invalid arg: %s" arg))))
496 ;;;###autoload(autoload 'xwem-launch-program-other-win "xwem-launcher" "" t)
497 (define-xwem-command xwem-launch-program-other-win (cmd &optional arg)
498 "Run program in other window.
499 If prefix ARG is specified - select newly created client.
500 Window spliting (if needed) is controled by `xwem-launcher-split-type'."
501 (xwem-interactive "_eLaunch Other Win: \nP")
503 (funcall xwem-launcher-split-type cmd arg))
505 ;;;###autoload(autoload 'xwem-launch-program-other-frame "xwem-launcher" "" t)
506 (define-xwem-command xwem-launch-program-other-frame (cmd &optional arg)
507 "Run programm in other frame.
508 If prefix ARG is specified - select newly created client."
509 (xwem-interactive "_eLaunch Other Frame: \nP")
511 (funcall xwem-launcher-frame-type cmd arg))
513 (defsubst xwem-launch (cmd)
514 "Execute CMD using `xwem-launcher'."
515 (funcall xwem-launcher-function cmd))
518 (defun xwem-launch-generic-program (cmd sarg)
519 "Run generic program CMD with arguments SARG."
520 (xwem-launch (mapconcat #'identity (list cmd sarg) " ")))
523 (defun xwem-xterm-construct-cmd (arg)
524 "Construct xterm command according to ARG."
525 (let ((fn (symbol-value
526 (intern-soft (concat "xwem-xterm-font" (int-to-string arg)))))
527 (cmd xwem-xterm-program))
529 (when (and (stringp fn) (> (length fn) 0))
530 (setq cmd (concat cmd " " xwem-xterm-font-argument " " fn)))
533 ;;;###autoload(autoload 'xwem-launch-xterm "xwem-launcher" "" t)
534 (define-xwem-command xwem-launch-xterm (arg)
535 "Run xterm program `xwem-xterm-program' with ARG as font argument."
536 (xwem-interactive "p")
538 (let ((cmd (xwem-xterm-construct-cmd arg)))
541 ;;;###autoload(autoload 'xwem-launch-xterm-other-win "xwem-launcher" "" t)
542 (define-xwem-command xwem-launch-xterm-other-win (arg)
543 "Execute xterm in other window, ARG have same meaning as in `xwem-launch-xterm'."
544 (xwem-interactive "p")
546 (let ((xwem-launcher-function xwem-launcher-split-type))
547 (xwem-launch-xterm arg)))
549 ;;;###autoload(autoload 'xwem-launch-xterm-other-frame "xwem-launcher" "" t)
550 (define-xwem-command xwem-launch-xterm-other-frame (arg)
551 "Execute xterm in other frame, ARG have same meaning as in `xwem-launch-xterm'."
552 (xwem-interactive "p")
554 (let ((xwem-launcher-function xwem-launcher-frame-type))
555 (xwem-launch-xterm arg)))
558 ;;;###autoload(autoload 'xwem-launch-lupe "xwem-launcher" "" t)
559 (define-xwem-command xwem-launch-lupe (arg)
560 "Run lupe `xwem-lupe-program' with `xwem-lupe-arguments'.
561 Prefix ARG is actually unused."
562 (xwem-interactive "P")
564 (xwem-launch-generic-program xwem-lupe-program xwem-lupe-arguments))
566 ;;;###autoload(autoload 'xwem-launch-lupe-other-win "xwem-launcher" "" t)
567 (define-xwem-command xwem-launch-lupe-other-win (arg)
568 "Run lupe in other window.
569 Prefix ARG is actually unused."
570 (xwem-interactive "P")
572 (let ((xwem-launcher-function xwem-launcher-split-type))
573 (xwem-launch-lupe arg)))
575 ;;;###autoload(autoload 'xwem-launch-lupe-other-frame "xwem-launcher" "" t)
576 (define-xwem-command xwem-launch-lupe-other-frame (arg)
577 "Run lupe in other frame.
578 Prefix ARG is actually unused."
579 (xwem-interactive "P")
581 (let ((xwem-launcher-function xwem-launcher-frame-type))
582 (xwem-launch-lupe arg)))
584 ;;;###autoload(autoload 'xwem-launch-xlock "xwem-launcher" "" t)
585 (define-xwem-command xwem-launch-xlock ()
586 "Launch `xwem-xlock-program' with `xwem-xlock-arguments'."
589 (xwem-launch-generic-program xwem-xlock-program xwem-xlock-arguments))
591 ;;;; Launcher dockapp
592 (define-xwem-face xwem-launch-dock-face
593 `(((medium) (:foreground "gray70"))
594 ((light) (:foreground "white"))
595 ((dark) (:foreground "black"))
596 (t (:foreground "gray70" :background "black")))
597 "Default background face for launcher docks."
598 :group 'xwem-launcher
601 (defvar xwem-launch-dock-keymap
602 (let ((map (make-sparse-keymap)))
603 (define-key map [button1] 'xwem-launch-dock-down)
604 (define-key map [button1up] 'xwem-launch-dock-launch)
605 (define-key map [button3] 'xwem-launch-dock-menu)
607 "Keymap for launch docks.")
609 ;; Macroses to access ladock internals
610 (defmacro xwem-ladock-state (win)
611 `(X-Win-get-prop ,win 'ladock-state))
612 (defsetf xwem-ladock-state (win) (state)
613 `(X-Win-put-prop ,win 'ladock-state ,state))
614 (defmacro xwem-ladock-action (win)
615 `(X-Win-get-prop ,win 'ladock-action))
616 (defsetf xwem-ladock-action (win) (action)
617 `(X-Win-put-prop ,win 'ladock-action ,action))
618 (defmacro xwem-ladock-pixmap (win)
619 `(X-Win-get-prop ,win 'ladock-pixmap))
620 (defsetf xwem-ladock-pixmap (win) (action)
621 `(X-Win-put-prop ,win 'ladock-pixmap ,action))
623 ;;;###autoload(autoload 'xwem-launch-dock-down "xwem-launcher" "" t)
624 (define-xwem-command xwem-launch-dock-down (ev)
625 "Default command when button is down."
626 (xwem-interactive (list xwem-last-event))
627 (unless (button-event-p ev)
628 (error 'xwem-error "`xwem-launch-dock-down' must be bound to mouse event"))
631 (setf (xwem-ladock-state (X-Event-win xwem-last-xevent)) 'down)
632 (xwem-ladock-redraw (X-Event-win xwem-last-xevent)))
634 ;;;###autoload(autoload 'xwem-launch-dock-launch "xwem-launcher" "" t)
635 (define-xwem-command xwem-launch-dock-launch (ev)
636 "Launch command for launch dock."
637 (xwem-interactive (list xwem-last-event))
638 (unless (button-event-p ev)
639 (error 'xwem-error "`xwem-launch-dock-up' must be bound to mouse event"))
642 (setf (xwem-ladock-state (X-Event-win xwem-last-xevent)) 'up)
643 (xwem-ladock-redraw (X-Event-win xwem-last-xevent))
645 (when (and (< (X-Event-xbutton-event-x xwem-last-xevent)
646 xwem-launch-dock-width)
647 (< (X-Event-xbutton-event-y xwem-last-xevent)
648 xwem-launch-dock-height))
649 ;; React on ButtonRelease only if it released within ladock
651 (let* ((action (xwem-ladock-action (X-Event-win xwem-last-xevent)))
654 (cond ((eq atype 'elisp) (eval (read acmd)))
655 ((eq atype 'cmd) (xwem-execute-program acmd))
656 (t (xwem-message 'warning "Unknown action type=`%s'" atype))))))
658 ;;;###autoload(autoload 'xwem-launch-dock-menu "xwem-launcher" "" t)
659 (define-xwem-command xwem-launch-dock-menu (action)
661 (xwem-interactive (list (xwem-ladock-action (X-Event-win xwem-last-xevent))))
663 (let ((cls (delq nil (mapcar #'(lambda (cl)
664 (and (string-match (cdr action)
665 (xwem-cl-wm-command cl))
671 (setq cls (sort cls #'(lambda (cl1 cl2)
672 (and (xwem-frame-p (xwem-cl-frame cl1))
673 (xwem-frame-p (xwem-cl-frame cl2))
674 (> (xwem-frame-num (xwem-cl-frame cl1))
675 (xwem-frame-num (xwem-cl-frame cl2)))))))
678 (list "Clients" :filter
681 (mapcar #'(lambda (cl)
682 (let ((frame (xwem-cl-frame cl))
683 (name (xwem-cl-wm-name cl)))
685 (if (xwem-frame-p frame)
686 (format "[%d](%s): %s"
687 (xwem-frame-num (xwem-cl-frame cl))
688 (xwem-frame-name (xwem-cl-frame cl))
691 `(xwem-cl-pop-to-client ,cl)
692 :active (xwem-non-dummy-client-p cl))))
697 `(xwem-launch-button-stop
698 ,(X-Event-win xwem-last-xevent) t)))))))
699 (xwem-popup-menu menu)))
701 (define-xwem-deffered xwem-ladock-redraw (xwin)
702 "Redraw launcher button dock XWIN."
703 (xwem-misc-draw-shadow
704 (X-Win-dpy xwin) (xwem-ladock-pixmap xwin)
705 (xwem-face-get-gc 'xwem-launch-dock-face
706 (if (eq (xwem-ladock-state xwin) 'down) '(dark) '(light)))
707 (xwem-face-get-gc 'xwem-launch-dock-face
708 (if (eq (xwem-ladock-state xwin) 'down) '(light) '(dark)))
709 0 0 xwem-launch-dock-width xwem-launch-dock-height xwem-launch-dock-thick)
711 (XCopyArea (xwem-dpy) (xwem-ladock-pixmap xwin) xwin
712 (XDefaultGC (xwem-dpy)) 0 0
713 xwem-launch-dock-width xwem-launch-dock-height 0 0))
715 (defun xwem-ladock-evhandler (xdpy xwin xev)
716 "On XDPY and launcher dock XWIN handle event XEV."
718 ((:X-Expose :X-MapNotify)
719 (xwem-ladock-redraw xwin))
721 ((:X-ButtonPress :X-ButtonRelease)
722 (xwem-overriding-local-map xwem-launch-dock-keymap
723 (xwem-dispatch-command-xevent xev)))
726 (xwem-launch-button-stop
727 (X-Event-xdestroywindow-window xev)))))
729 (defun xwem-launch-button-stop (xwin &optional force)
730 "Destoy launch dockapp button XWIN.
731 If FORCE is non-nil also destroy XWIN."
732 (XFreePixmap (X-Win-dpy xwin) (xwem-ladock-pixmap xwin))
734 (setf (xwem-ladock-pixmap xwin) nil
735 (xwem-ladock-state xwin)nil
736 (xwem-ladock-action xwin)nil)
738 ;; Remove events handler
739 (X-Win-EventHandler-rem xwin 'xwem-ladock-evhandler)
742 (XDestroyWindow (X-Win-dpy xwin) xwin)))
745 (defun xwem-launch-button-start (xpm-file action &optional dockid
747 "Create new dockapp button with XPM-FILE image and doing ACTION on click.
748 ACTION is cons cell wher car is one of 'elisp or 'cmd and cdr is string.
749 For 'elisp car, cdr is real elisp expression, to evaluate on click.
750 For 'cmd car, cdr is cmd to run on click."
751 (let ((xwin (XCreateWindow (xwem-dpy) nil 0 0
752 xwem-launch-dock-width
753 xwem-launch-dock-height
756 :event-mask (Xmask-or XM-Exposure XM-StructureNotify
757 XM-ButtonPress XM-ButtonRelease)
758 :override-redirect t))))
761 (setf (xwem-ladock-pixmap xwin)
763 (xwem-dpy) (make-X-Pixmap :dpy (xwem-dpy)
764 :id (X-Dpy-get-id (xwem-dpy)))
765 xwin (XDefaultDepth (xwem-dpy))
766 xwem-launch-dock-width xwem-launch-dock-height)
767 (xwem-ladock-state xwin) 'up
768 (xwem-ladock-action xwin) action)
770 ;; Initial pixmaps setup
771 (XFillRectangle (xwem-dpy) (xwem-ladock-pixmap xwin)
772 (xwem-face-get-gc 'xwem-launch-dock-face '(medium)) 0 0
773 (X-Pixmap-width (xwem-ladock-pixmap xwin))
774 (X-Pixmap-height (xwem-ladock-pixmap xwin)))
775 (let* ((ipix (X:xpm-pixmap-from-file
776 (xwem-dpy) xwin (expand-file-name xpm-file xwem-icons-dir)))
777 (imask (X:xpm-pixmap-from-file
778 (xwem-dpy) xwin (expand-file-name xpm-file xwem-icons-dir) t))
779 (x-orig (/ (- xwem-launch-dock-width (X-Pixmap-width ipix)) 2))
780 (y-orig (/ (- xwem-launch-dock-height (X-Pixmap-height ipix)) 2))
783 (make-X-Gc :dpy (xwem-dpy)
784 :id (X-Dpy-get-id (xwem-dpy))
785 :clip-x-origin x-orig
786 :clip-y-origin y-orig
788 ;; Copy to our pixmap
789 (XCopyArea (xwem-dpy) ipix (xwem-ladock-pixmap xwin) clgc
790 0 0 (X-Pixmap-width ipix) (X-Pixmap-height ipix)
793 (XFreeGC (xwem-dpy) clgc)
794 (XFreePixmap (xwem-dpy) imask)
795 (XFreePixmap (xwem-dpy) ipix))
797 (when xwem-misc-turbo-mode
798 (XSetWindowBackgroundPixmap (xwem-dpy) xwin (xwem-ladock-pixmap xwin)))
800 ;; Install events handler
801 (X-Win-EventHandler-add xwin 'xwem-ladock-evhandler nil
802 (list X-Expose X-MapNotify X-ButtonPress
803 X-ButtonRelease X-DestroyNotify))
805 (xwem-XTrayInit (xwem-dpy) xwin dockid dockgroup dockalign)
811 (defcustom xwem-open-file-commands-alist
812 '(("\\.\\(ps\\|ps_pages\\|eps\\)\\'" . "gv")
813 ("\\.pdf\\'" . "xpdf")
814 ("\\.\\(jpe?g\\|gif\\|png\\)\\'" . "display")
815 ("\\.dvi\\'" . "xdvi")
816 ("\\.chm\\'" . "xchm")
817 ("\\.djvu\\'" . "djview")
818 ("\\.txt\\'" . "xterm -e less"))
819 "*Alist specifying how to view special types of files.
820 `xwem-open-file-commands-alist' can be dynamically changed by
821 `xwemw-open-file' when registering new file extensions, so we
822 recommend to use `xwem-desktop' package to save/restore
823 `xwem-open-file-commands-alist' value between sessions."
824 :group 'xwem-launcher
825 :type '(repeat (cons (string :tag "Regexp")
826 (string :tag "Command"))))
828 (defcustom xwem-open-file-registration 'query
829 "*Defines the behaviour of `xwem-open-file' when file extension is
830 not defined in `xwem-open-file-commands-alist'.
833 t - Register new extensions in `xwem-open-file-commands-alist'.
834 query - Query about registration."
835 :group 'xwem-launcher
836 :type '(choice (const :tag "No registration" nil)
837 (const :tag "Auto registration" t)
838 (const :tag "Query for registration" query)))
841 (defun xwem-file-find-command (filename)
842 "Find appropriate command to open FILENAME file."
843 (let ((cmds xwem-open-file-commands-alist))
844 (while (and cmds (not (string-match (caar cmds) filename)))
845 (setq cmds (cdr cmds)))
848 ;;;###autoload(autoload 'xwem-open-file "xwem-launcher" "Open file with appopriate command" t)
849 (define-xwem-command xwem-open-file (file &optional command)
850 "Open FILE with command specified by COMMAND.
851 If prefix arg is specified, expicitely query for the COMMAND."
853 (let* ((file (expand-file-name (xwem-read-filename "Find File: ")))
854 (cmd (xwem-file-find-command file)))
855 (when (or xwem-prefix-arg
857 (setq cmd (xwem-read-external-command "Command: "))
858 ;; Try to register FILE extension in
859 ;; `xwem-open-file-commands-alist'.
860 (when (and (not xwem-prefix-arg)
861 xwem-open-file-registration)
862 (let ((fext (and (string-match "\\.\\([^.]+\\)\\'" file)
863 (match-string 1 file))))
865 (or (eq xwem-open-file-registration t)
866 (xwem-under-minibuffer
867 (y-or-n-p (format "Register '%s' extension?: "
869 (push (cons (concat "\\." fext "\\'") cmd)
870 xwem-open-file-commands-alist)))))
873 ;; Fixate FILE in case `xwem-open-file' called non-interactively
874 (setq file (expand-file-name file))
876 (setq command (xwem-file-find-command file)))
878 (xwem-launch (format "%s '%s'" command file)))
881 (provide 'xwem-launcher)
883 ;;; xwem-launcher.el ends here