source: project/wiki/eggref/4/wmiirc @ 32241

Last change on this file since 32241 was 32241, checked in by felix winkelmann, 6 years ago

removed some call/cc.org links

File size: 28.0 KB
Line 
1[[tags: egg]]
2
3== wmiirc
4
5[[toc:]]
6
7=== Description
8
9A library for writing configuration scripts for [[http://wmii.suckless.org|wmii, window manager improved 2]].
10
11See also the [[/wmiirc snippets|wmiirc snippets]] page for useful code snippets you can
12use in your own wmiirc scripts.
13
14=== Author
15
16[[/users/peter-bex|Peter Bex]]
17
18=== Requirements
19
20Requires the [[http://wiki.call-cc.org/eggref/4/9p|9p]] egg.
21
22Works with wmii 3.6 (and possibly 3.5) only.
23
24=== Documentation
25
26[[http://wmii.suckless.org|wmii]] is a minimalist windowmanager for
27the X window system that, instead of implementing a lot of policy in
28the WM, allows you to control it completely through a virtual
29filesystem it exports over the [[9p]] protocol. Because of this, you
30can script it using any language or tool that can speak this protocol
31and define (almost) any behaviour you want.
32
33This egg is an attempt to make an abstraction that lets you write
34scripts that can control wmii without having to study the structure of
35the 9p filesystem that wmii exports.  Instead, you can do everything
36by calling procedures from this egg.  Of course, if you know the
37filesystem structure you can still choose to access the filesystem
38directly if you need to do something extreme.
39
40==== Concepts
41
42Because wmii works slightly different than most other window managers,
43it is useful to start by exploring its fundamental concepts.  There's
44an official guide that explains these concepts at
45[[http://www.suckless.org/wmii/guide.html]] but it is not very complete
46at the time of this writing.
47
48First off, wmii is a so-called ''dynamic'' window manager.  This means
49it manages the windows for you, so you don't have to bother about
50placing them on your screen.  In default mode, it will divide the
51screen up in equal parts and tile the windows so they are not
52obscured.  However, it also has a ''floated'' mode, which is the only
53mode classic window managers support.  This will simply place the
54windows somewhere on the screen such that they can overlap.  You will
55have to drag them around and/or resize them manually (or write a smart
56script that can position them sanely).
57
58===== Tags and views
59
60wmii manages windows (or ''clients'' in X speak) by ''tagging'' them.
61Any window can have several tags, but it always displays the contents
62of only one tag on the screen.  This is called a ''view'' on that tag.
63This feature provides a superset of the functionality that other
64window managers offer with ''virtual desktops''.  Because windows can
65have multiple tags, it is possible for one window to show up in
66multiple views, effectively causing it to be "sticky" for only a
67selected number of views.
68
69===== Modes
70
71As explained above, wmii supports dynamic management as well as
72floated window management.  Floating windows all live in a special tag
73sometimes identified by the name '~' (tilde).  In dynamic mode there
74are three "submodes".  In 'default' mode the windows are tiled, or
75divided equally across the screen.  When a new window is created, the
76other windows are made smaller to accommodate for the new one, which
77is given an equal amount of space as all the other windows, and the
78window is placed such that it does not obscure any of the other
79windows.  In 'stacked' mode, all windows are placed behind eachother
80in a staircased fashion so '''only''' their titlebars show.  The
81window that has focus is placed in front of all the others, so it
82takes up almost all of your screen.  Clicking on any titlebar sends
83that window to the front, and restacks such that all other windows'
84titlebars are still visible.  In 'maximized' mode you only see one
85window with its titlebar.
86
87===== States
88
89Individual windows can also have different states.  When a window is
90in the 'fullscreen' state, '''all''' window decoration and other stuff
91is hidden so your entire screen is used by one window of one application.
92When a window has the 'urgent' state, it has its "urgent hint" set, which
93is a hint to the window manager that this window's state demands immediate
94attention from the user (for example, in an IM client a private message
95may have arrived).  Wmii can take action when this state is set and it can
96distinguish between client-requested urgency and manager-requested urgency.
97
98===== Columns
99
100The screen is further divided up into columns.  When you first start wmii,
101the screen has only one column so you don't see it.  However, when you send
102a window to the right or the left, it will create a new column it will live
103in from then on.  The first column will be resized so the columns can fit
104next to eachother.  Wmii allows you to define rules what the sizes of these
105columns will be.  Each column has its own mode, so you can have one column
106maximized or stacked while the column next to it is in tiled mode.
107
108===== Bars and tabs
109
110The bottom of the screen contains a bar, which is actually ''two'' bars: one
111on the left and one on the right (''lbar'' and ''rbar'').  These bars consist
112of ''tabs''.  Tabs can contain text in a given color and are clickable.
113Their name does not have to match their text contents, but it is advisable
114to keep these matched for your own sanity.  In the default config, the left
115tab shows a list of available tags/views, with the current one highlighted.
116When you click a tab, a view on the corresponding tag is shown.  By default
117the right bar shows a status that is continuously updated with the current
118time and system load.
119
120===== Events
121
122Whenever anything happens in wmii, an event is fired which your wmiirc
123can catch and act upon.  Events are fired when a key is pressed (but
124only when it is grabbed by the WM, otherwise it goes to applications),
125when a window is (de)selected, when a tag is (de)selected, when a tag
126is created/destroyed etc.  The exact events are listed with the
127{{event-handlers}} procedure.
128
129===== Special names and limitations
130
131wmii reserves a couple of names and syntaxes, which means you can't
132use arbitrary names for tags, tabs and some other things.  It uses the
133plus symbol (+) as a separator for tag names.  This cannot be escaped
134in any way, which means the + can simply not be used inside names.
135The special name ''sel'' is reserved for the currently selected
136tag/view/client etc. This has an alias as the exclamation mark, but
137its use is deprecated.  Contents of tabs can be prefixed with three
1386-digit hexadecimal numbers which are prefixed with a pound sign (#).
139If they are, this indicates the colors of that tab.  This egg tries to
140take care of doing the formatting of this so you can simply pass
141integer values as colorcodes instead.  Spaces are not allowed in
142several names either.  It's probably safest to avoid all these special
143characters and names altogether.
144
145==== Initialization
146
147To get a connection to the server, call the following:
148
149  procedure: (connect [inport outport])
150
151If you provide an inport and outport, it will connect to a 9p server
152on those input/output ports.  If you do not provide them, it will try
153to connect to the wmii 9p server on the default location, namely a unix
154domain socket named {{/tmp/ns.USERNAME.DISPLAY/wmii}}, where USERNAME
155is your Unix username and DISPLAY is the current X display string.
156
157After initializing, you can set up column rules, tag rules and event
158handlers.  After having done this, you can enter the event loop using
159
160  procedure: (event-loop [kill-others])
161
162This procedure will only return when another wmiirc wants to take over
163from the current one.  The {{kill-others}} parameter tells wmiirc to
164tell other wmiirc scripts (whether written using this egg or not) to
165quit.  It defaults to {{#t}}.
166
167==== wmii operations
168
169  procedure: (quit)
170
171Tells wmii to quit.
172
173  procedure: (exec cmdline)
174
175Tells wmii to execute the given commandline, replacing the wmii
176process.  This can be used to change to a different window manager.
177
178  procedure: (global-settings)
179
180Returns an alist of the current global settings.
181
182  procedure: (global-settings-set! alist)
183
184Change the global settings.  Example:
185
186<enscript highlight=scheme>
187(global-settings-set!
188 `((font . "-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*")
189   (focuscolors . (#xffffff #x285577 #x4c7899))
190   (normcolors . (#x888888 #x222222 #x333333))
191   (grabmod . "Mod1")
192   (border . "1")))
193</enscript>
194
195This sets the default font (used in titlebars, for example) to the
196one in the string, sets the colors of a window that is focused to the
197given colorcodes in {{focuscolors}}, the default colors to the one in
198{{normcolors}} and grabs Mod1 for dragging windows around.  The border
199thickness is set to one pixel.
200
201==== Column rules
202
203You can define the percentage of the screen each column should take up
204by setting up column rules.  This can be done per view, using a simple
205alist and the following procedure:
206
207  procedure: (colrules-set! alist)
208
209The keys of the alist are strings that are interpreted by wmii as a
210regular expression of view names on which the column rules should
211apply.  The values of the alist are integers or lists of integers
212which represent percentages of the screen width the columns can take.
213The percentages apply to the columns in the same order, from left to
214right.
215
216Example:
217
218<enscript highlight=scheme>
219  (colrules-set! '(("www" . (20 80))
220                        ("email" . (10 20 70))
221                        ("graphics" . 100) ;; can also be (100)
222                        (".*" . (30 50 20))))
223</enscript>
224
225You can request the current column rules with the following procedure:
226
227  procedure: (colrules)
228
229This returns an alist of the same type as accepted by colrules-set!.
230
231==== Tag rules
232
233Tag rules work much like column rules, except they specify which
234tags a client should get when it's first created.
235
236  procedure: (tagrules-set! alist)
237
238The alist here takes again strings as keys which are interpreted as
239regexes by wmii.  The values are either strings or lists of strings
240which are taken to be tagnames. Example:
241
242<enscript highlight=scheme>
243  (tagrules-set! `(("XMMS.*" . ("music" "~"))
244                        ("display.*" . ("graphics" "~"))
245                        ("Gimp.*" . ("graphics" "~"))
246                        ("xjump.*" . ("games" "~"))
247                        ("MPlayer.*" . "~")
248                        ("VICE.*" . ("games" "~"))
249                        (".*" . "sel") ;; Default to current tag
250                        (".*" . "1"))) ;; If no tag exists yet, start with '1'
251</enscript>
252
253Just like colrules, tagrules can be listed:
254
255  procedure: (tagrules)
256
257Returns an alist that looks just like the one from {{tagrules-set!}}.
258
259==== Event handlers
260
261The core of wmiirc script writing is in the event handlers.  You can register
262those with this procedure:
263
264  procedure: (event-handlers-set! alist [grab-keys])
265
266The alist has keys that are either simply symbols that name the event
267or lists that provide a full match for the incoming event.  The first
268rule that matches an incoming event is used, the others are ignored.
269The values of the alist are lambdas which handle the event.  The
270{{grab-keys}} parameter defaults to {{#t}} and indicates if key
271handlers should be filtered from the event handlers and the keys used
272by them should be grabbed.  If a key is not grabbed, it will never be
273visible by the wmiirc script; it will be passed to the client directly
274without being passed to the script by wmii.
275
276The events that you can expect are as follows:
277
278; {{(create-tag TAGNAME)}} : The tag with the name {{TAGNAME}} has just been created.
279
280; {{(destroy-tag TAGNAME)}} : The tag with name {{TAGNAME}} has just been destroyed.
281
282; {{(focus-tag TAGNAME)}} : The focus was changed to the tag with name {{TAGNAME}}
283
284; {{(unfocus-tag TAGNAME)}} : The tag with name {{TAGNAME}} which had focus is now not in focus anymore.
285
286; {{urgent CLIENT CLIENT-REQUEST?}} : The client with identifier {{CLIENT}} just got the ''urgency hint'' set. {{CLIENT-REQUEST?}} is #{{t}} if the client requested it, {{#f}} if the window manager did.
287
288; {{not-urgent CLIENT CLIENT-REQUEST?}} : The client with identifier {{CLIENT}} just got the ''urgency hint'' removed. {{CLIENT-REQUEST?}} is #{{t}} if the client removed it, {{#f}} if the window manager did.
289
290; {{urgent-tag TAGNAME CLIENT-REQUEST?}} : The tag with name {{TAGNAME}} has a client which just got the ''urgency hint'' set.  {{CLIENT-REQUEST}} is {{#t}} if the client requested it, {{#f}} if the urgency hint was set by the window manager itself.
291
292; {{not-urgent-tag TAGNAME CLIENT-REQUEST?}} : The tag with name {{TAGNAME}} has a client which just lost the ''urgency hint''.  {{CLIENT}} is {{#t}} if the client removed it, {{#f}} if the urgency hint was removed by the window manager itself.
293
294; {{left-bar-click BUTTON TAB}} : The user clicked on the left bar. {{BUTTON}} is an integer which indicates the mouse button the user pressed (1 = left, 2 = middle, 3 = right).  {{TAB}} is the name of the tab on which was clicked.
295
296; {{right-bar-click BUTTON TAB}} : The user clicked on the right bar. {{BUTTON}} is an integer which indicates the mouse button the user pressed (1 = left, 2 = middle, 3 = right).  {{TAB}} is the name of the tab on which was clicked.
297
298; {{client-mouse-down CLIENT BUTTON}} : The user pressed a mouse button while his mouse cursor was on the titlebar of a window. {{CLIENT}} indicates the client on which was clicked, {{BUTTON}} is an integer which indicates the mouse button the user pressed (1 = left, 2 = middle, 3 = right).
299
300; {{client-mouse-click CLIENT BUTTON}} : The user completed a mouse click on the titlebar of a window (he did not leave the titlebar before releasing the button).  {{CLIENT}} indicates the client on which was clicked, {{BUTTON}} is an integer which indicates the mouse button the user pressed (1 = left, 2 = middle, 3 = right).
301
302; {{(key keys ...)}} : A key was pressed.  The exact key pressed is encoded as several strings with key names.  Usually it is easiest to handle the keys with rest arg notation to capture them in a list.
303
304See the [[#Example|example section]] for a good example of how to use
305these events.
306
307You can also use the following procedure to get the current event handlers:
308
309  procedure: (event-handlers)
310
311Note that this procedure can not return event handlers in other processes.
312It's simply a getter for the current wmiirc instance's list of event handlers.
313
314=== Keys
315
316  procedure: (grabbed-keys)
317
318Get a list of currently grabbed keys.
319
320  procedure: (grabbed-keys-set! keys)
321
322Sets the keys grabbed by wmii.  {{keys}} is a list of key descriptions.
323Keys must be grabbed or they won't be passed to the wmiirc event loop.
324Example:
325
326<enscript highlight="scheme">
327  (grabbed-keys-set! '(("Mod1" "x")
328                            ("Mod2" "Space")
329                            ("Mod1" "Shift" "Space")))
330</enscript>
331
332This grabs the key combinations Mod1-x, Mod2-space and Mod1-shift-space.
333Key names of "special" keys are always capitalized in wmii.  Normal literal
334keys like the x in the example are always lower case.  If you would like
335to hook shift-x, that would not be ("X"), but ("Shift" "x").
336
337  procedure: (key-code->string)
338  procedure: (string->key-code)
339
340Translate a chicken-wmiirc keycode to a string that can be written to wmii's
341{{/keys}} file.  Example:
342
343  (key-code->string '("Mod1" "Shift" "x")) => "Mod1-Shift-x"
344  (string->keycode "Mod1-Shift-x") => ("Mod1" "Shift" "x")
345
346=== Navigating
347
348  procedure: (goto-tag tag)
349
350Switch the view to the named {{tag}}.
351
352  procedure: (navigate-to direction [tag])
353
354Navigate to the given {{direction}} in the given {{tag}}.  Tag
355defaults to "sel", the current tag.  {{where}} can be "up", "down",
356"left", "right" or "toggle".  If one of the directions, the client
357above, below, to the left or to the right of the current client is
358selected.  If the direction is toggle, clients in float mode are
359selected if currently a client in normal mode is selected, or the
360other way around.  If tag is not the current tag, the currently
361selected client on that tag is changed, but nothing happens in the
362current view, unless the current view just happens to be a view on
363that tag.
364
365  procedure: (send-to direction [client] [tag])
366
367Send the given {{client}} (defaults to "sel", the currently selected
368client) into the given {{direction}}, as described above.  If {{tag}}
369is given, the client is sent to the given direction on that tag.  It
370is ''not'' sent to that tag.
371
372=== Tags
373
374  procedure: (tags)
375 
376This procedure returns a list of all the tags known to wmii, as strings.
377
378  procedure: (tag-settings-set! alist [tag])
379
380Change the settings for the named {{tag}}, which defaults to "sel",
381the current tag.  {{alist}} is an alist with setting names (strings)
382as keys, and setting lists as values. Example:
383
384  (tag-settings-set! '(("colmode" . ("sel" "stack"))))
385
386This sets the current tag's column mode to stacked.
387 
388  procedure: (tag-settings [tag])
389
390Returns an alist of the settings for the named {{tag}}.  {{tag}} defaults
391to {{"sel"}}, that is the current tag.
392
393=== Bars
394
395  procedure: (tabs bar)
396
397Return a list of all tabs on the {{bar}}.  {{bar}} can be {{"lbar"}}
398(the left bar) or {{"rbar"}} (the right bar).
399
400  procedure: (write-tab bar tab contents [colors])
401
402Change the string {{contents}} of a {{tab}} on the indicated
403{{bar}}. Creates the tab if it doesn't exist yet.  If {{colors}}
404is given and not {{#f}} it should be a list of three numbers which
405represent in hexadecimal the color values of the foreground,
406background and border, respectively.
407
408Example:
409
410  (write-tab "lbar" "hello" "hello there")
411
412Creates a tab called "hello" on the left bar, which displays the
413string "hello there".
414
415  procedure: (destroy-tab bar tab)
416
417Destroy {{tab}} on {{bar}}.
418
419=== Clients
420
421  procedure: (client=? client1 client2)
422
423Are two clients one and the same?  Currently clients are represented
424as simple strings, the way wmii returns them, but in the future
425clients may have more information-rich representations, so always use
426this to compare them to be forwards-compatible.  These "opaque" client
427objects can be obtained by event handlers from the various events that
428operate on a client, or by {{clients}}, for example.
429
430  procedure: (clients [tag ...])
431
432Returns a list of all the clients that have any of the named tags.
433If no tags are given, returns all clients.
434
435  procedure: (client-tags [client])
436
437Return a list of all tags on {{client}}.  Defaults to the
438currently selected client ("sel").
439
440  procedure: (client-tags-set! tags [client])
441
442Set the {{tags}} (a list of strings) on the {{client}}.
443
444=== Low-level procedures
445
446If you would like access to the 9p filesystem exported by wmii, you
447can use the following procedures:
448
449  procedure: (write file data)
450
451Write the string contents of {{data}} to the named {{file}}.  If the
452file does not exist, it is created.
453
454  procedure: (read file)
455
456Read the given {{file}} into a string.
457
458  procedure: (read-lines file)
459
460Read the given {{file}} line by line and create a list with an entry
461per line.
462
463  procedure: (directory path)
464
465Show the directory contents of the named {{path}}.
466
467 
468=== Example
469
470This example simply translates the default wmiirc script that's shipped
471with wmii from shell to Chicken:
472
473<enscript highlight=scheme>
474#!/usr/pkg/bin/csi -s
475
476(require-library wmiirc srfi-18)
477(import scheme chicken (prefix wmiirc wmii:) srfi-18)
478
479(wmii:connect)
480
481(define modkey "Mod2")
482
483(define directions
484  `((up . "k")
485    (down . "j")
486    (left . "h")
487    (right . "l")))
488
489(define wmii-normcolors  '(#x888888 #x222222 #x333333))
490(define wmii-focuscolors '(#xffffff #x285577 #x4c7899))
491
492(define wmii-background #x333333)
493(define wmii-font "-*-fixed-medium-r-*-*-13-*-*-*-*-*-*-*")
494
495(define (wmii9menu options . rest)
496  (let-optionals rest ((default #f))
497    (receive (in out pid)
498             (process
499              "wmii9menu"
500              `(,@(if default (list "-initial" default) '())
501                "-sf" ,(wmii:color->string (first wmii-focuscolors))
502                "-sb" ,(wmii:color->string (second wmii-focuscolors))
503                "-nf" ,(wmii:color->string (first wmii-normcolors))
504                "-nb" ,(wmii:color->string (second wmii-normcolors))
505                "-font" ,wmii-font
506                ,@options))
507             (close-output-port out)
508             (let ((chosen (read-line in)))
509               (close-input-port in)
510               (and (string? chosen) chosen)))))
511
512(define (dmenu options . rest)
513  (receive (in out pid)
514           (process
515            "dmenu"
516            `("-b"
517              "-sf" ,(wmii:color->string (first wmii-focuscolors))
518              "-sb" ,(wmii:color->string (second wmii-focuscolors))
519              "-nf" ,(wmii:color->string (first wmii-normcolors))
520              "-nb" ,(wmii:color->string (second wmii-normcolors))
521              "-fn" ,wmii-font))
522           (display (string-join options "\n") out)
523           (close-output-port out)
524           (let ((chosen (read-line in)))
525             (close-input-port in)
526             (and (string? chosen) chosen))))
527
528(define client-menu
529 (let ((last-option "nonexistingoption"))
530   (lambda (client)
531     (and-let* ((option (wmii9menu '("Nop" "Delete" "Fullscreen") last-option)))
532       (cond
533        ((string=? option "Delete") (wmii:kill client))
534        ((string=? option "Fullscreen") (wmii:change-state "Fullscreen" #t client)))
535       (set! last-option option)))))
536
537(define wmii-term "xterm")
538
539(wmii:colrules-set! `((".*" . (58 42))))
540
541(wmii:tagrules-set! `(("XMMS.*" . "~")
542                      ("MPlayer.*" . "~")
543                      (".*" . "sel")
544                      (".*" . "1")))
545
546;; We need to do this in order to avoid getting lots of zombie processes
547(define (run . args) (process-wait (process-fork (lambda () (apply process-run args)))))
548
549(define status
550  (let ((status-thread #f))
551    (lambda ()
552      (and status-thread (thread-terminate! status-thread))
553      (set! status-thread
554            (thread-start!
555             (make-thread
556              (lambda ()
557                (let loop ()
558                  (wmii:write-tab "rbar" "status"
559                                  (with-input-from-pipe "echo -n $(uptime | sed 's/.*://; s/,//g') '|' $(date)" read-string))
560                  (thread-sleep! 1)
561                  (loop)))))))))
562
563(wmii:event-handlers-set!
564 `((create-tag
565    . ,(lambda (event tag) (wmii:write-tab "lbar" tag tag wmii-normcolors)))
566   (destroy-tag
567    . ,(lambda (event tag) (wmii:destroy-tab "lbar" tag)))
568   (focus-tag
569    . ,(lambda (event tag)
570         (if (member tag (wmii:tabs "lbar"))
571             (wmii:write-tab "lbar" tag tag wmii-focuscolors))))
572   (unfocus-tag
573    . ,(lambda (event tag)
574         (if (member tag (wmii:tabs "lbar"))
575             (wmii:write-tab "lbar" tag tag wmii-normcolors))))
576   (urgent-tag
577    . ,(lambda (event tag client?) (wmii:write-tab "lbar" tag (string-append "*" tag))))
578   (not-urgent-tag
579    . ,(lambda (event tag client?) (wmii:write-tab "lbar" tag tag)))
580   (left-bar-click
581    . ,(lambda (event button tab) (wmii:goto-tag tab)))
582   (client-mouse-down
583    . ,(lambda (event client button)
584         (case button
585           ((3) (client-menu client)))))
586   ((key ,modkey "Control" "t")
587    . ,(let ((prev #f))
588         (lambda _
589           (let ((keys (wmii:grabbed-keys)))
590             (if prev
591                 (begin (wmii:grabbed-keys-set! prev)
592                        (set! prev #f))
593                 (begin (set! prev keys)
594                        (wmii:grabbed-keys-set! `((,modkey "Control" "t")))))))))
595   ((key ,modkey "space")
596    . ,(lambda _ (wmii:navigate-to "toggle")))
597   ((key ,modkey "d")
598    . ,(lambda _ (wmii:tag-settings-set! '(("colmode" . ("sel" "default"))))))
599   ((key ,modkey "s")
600    . ,(lambda _ (wmii:tag-settings-set! '(("colmode" . ("sel" "stack"))))))
601   ((key ,modkey "m")
602    . ,(lambda _ (wmii:tag-settings-set! '(("colmode" . ("sel" "max"))))))
603   ((key ,modkey "a")
604    . ,(lambda _
605         (and-let* ((action (dmenu (append
606                                 `("rehash" "exec" "status" "quit")
607                                 (proglist (string-split (get-environment-variable "WMII_CONFPATH") ":"))))))
608           (cond
609            ((string=? action "rehash") (update-programs))
610            ((string-prefix? "exec " action)
611             (wmii:exec (string-drop action 5)))
612            ((string=? action "status") (status))
613            ((string=? action "quit")
614             (wmii:quit)
615             (exit))
616            (else (run (sprintf "env PATH=${WMII_CONFPATH}:${PATH} ~A" action)))))))
617   ((key ,modkey "p")
618    . ,(lambda _
619         (and-let* ((program (dmenu programs))) (run program))))
620   ((key ,modkey "t")
621    . ,(lambda _
622         (and-let* ((tag (dmenu (wmii:tags)))) (wmii:goto-tag tag))))
623   ((key ,modkey "Return")
624    . ,(lambda _ (run wmii-term)))
625   ((key ,modkey "Shift" "space")
626    . ,(lambda _ (wmii:send-to "toggle")))
627   ((key ,modkey "f")
628    . ,(lambda _ (wmii:change-state "Fullscreen" 'toggle)))
629   ((key ,modkey "Shift" "c")
630    . ,(lambda _ (wmii:kill)))
631   ((key ,modkey "Shift" "t")
632    . ,(lambda _
633         (and-let* ((tag (dmenu (wmii:tags)))) (wmii:client-tags-set! (list tag)))))
634   ,@(map (lambda (x)
635            `((key ,modkey ,(cdr x))
636              . ,(lambda _ (wmii:navigate-to (->string (car x))))))
637          directions)
638   ,@(map (lambda (x)
639            `((key ,modkey "Shift" ,(cdr x))
640              . ,(lambda _ (wmii:send-to (->string (car x))))))
641          directions)   
642   ,@(map (lambda (x)
643            `((key ,modkey ,(->string x))
644              . ,(lambda _ (wmii:goto-tag x))))
645          (iota 10))
646   ,@(map (lambda (x)
647            `((key ,modkey "Shift" ,(->string x))
648              . ,(lambda _ (wmii:client-tags-set! (list (->string x)))))) (iota 10))))
649
650(wmii:global-settings-set!
651 `((font . ,wmii-font)
652   (focuscolors . ,wmii-focuscolors)
653   (normcolors . ,wmii-normcolors)
654   (grabmod . ,modkey)
655   (border . "1")))
656
657(define (proglist path)
658  (sort!
659   (delete-duplicates!
660    (flatten
661     (map (lambda (dir)
662            (if ((conjoin directory? file-execute-access? file-read-access?) dir)
663                (map pathname-strip-directory
664                     (find-files dir test: (conjoin (complement directory?) file-execute-access?)
665                     action: cons seed: '() limit: 0))
666                '()))
667          path))
668    string=?)
669   string<?))
670
671(define programs '())
672(define (update-programs)
673  (thread-start!
674   (make-thread
675    (lambda () (set! programs (proglist (string-split (get-environment-variable "PATH") ":")))))))
676(update-programs)
677
678(let ((curtag (wmii:tag)))
679  (for-each (cut wmii:destroy-tab "lbar" <>) (wmii:tabs "lbar"))
680  (for-each (lambda (t)
681              (if (string=? curtag t)
682                  (wmii:write-tab "lbar" t t wmii-focuscolors)
683                  (wmii:write-tab "lbar" t t wmii-normcolors)))
684            (wmii:tags)))
685
686(run (sprintf "xsetroot -solid '~A'" (wmii:color->string wmii-background)))
687
688(status)
689(wmii:event-loop)
690</enscript>
691
692For some other cool snippets, have a look at the [[/wmiirc snippets|wmiirc snippets]] page.
693
694=== Changelog
695
696* 0.5 Convert deprecated {{getenv}} calls to {{get-environment-variable}} so it works with new Chicken versions (thanks to Christian Kellermann).
697* 0.4 Fix crash in {{colrules}} procedure, remove dependency on matchable egg
698* 0.3 Improvement in {{clients}} procedure
699* 0.2 Port to hygienic Chicken
700* 0.1 Initial release
701
702=== License
703
704  Copyright (c) 2008-2011, Peter Bex
705  All rights reserved.
706 
707  Redistribution and use in source and binary forms, with or without
708  modification, are permitted provided that the following conditions are
709  met:
710 
711  Redistributions of source code must retain the above copyright
712  notice, this list of conditions and the following disclaimer.
713 
714  Redistributions in binary form must reproduce the above copyright
715  notice, this list of conditions and the following disclaimer in the
716  documentation and/or other materials provided with the distribution.
717 
718  Neither the name of the author nor the names of its contributors may
719  be used to endorse or promote products derived from this software
720  without specific prior written permission.
721 
722  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
723  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
724  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
725  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
726  COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
727  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
728  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
729  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
730  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
731  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
732  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
733  OF THE POSSIBILITY OF SUCH DAMAGE.
Note: See TracBrowser for help on using the repository browser.