Initial commit before publication.
[berthome:berthome.git] / rc.lua
1 -- Standard awesome library
2 require ("awful")
3 require ("awful.autofocus")     -- <- XXX: I may not need this...
4 require ("awful.rules")
5 require ("beautiful")           -- theme handling
6 require ("naughty")             -- notifications
7 require ("vicious")             -- widgets
8 require ("keychain")            -- custom keychain library
9 require ("shifty")              -- dynamic tagging
10 require ("menu")
11 require ("scratch")        -- scratchpad (XXX: not the behavior I need actually)
12
13 --{{{ Variable definitions
14
15 local amenu     = awful.menu
16 local join      = awful.util.table.join
17 local spawn     = awful.util.spawn
18 local configdir = awful.util.getdir ("config")
19
20 -- Themes define colours, icons, and wallpapers
21 beautiful.init (configdir .. "/theme/theme.lua")
22
23 -- Some custom programs are only loaded by awesome: I put 'em in this
24 -- directory:
25 BIN_DIR                 = configdir .. "/bin/"
26
27 -- This is used later as the default terminal and editor to run.
28 USER                    = os.getenv ("USER")
29 HOME                    = os.getenv ("HOME")
30 HOST                    = os.getenv ("HOST")
31 LANG                    = os.getenv ("LANG") or "en_US.UTF-8"
32 XTERM                   = "urxvt -cr red -bg black -fg white +sb"
33 ETERM_NEW               = BIN_DIR .. "emacs-shell"
34 ETERM_DEFAULT           = BIN_DIR .. "emacs-shell-default"
35 MAIL_READER             = BIN_DIR .. "emacs-gnus"
36 STANDBY_SCREEN          = BIN_DIR .. "force-dpms-standby"
37 STANDBY_AND_LOCK_SCREEN = BIN_DIR .. "force-dpms-standby lock"
38 IRC                     = XTERM .. " -T weechat -e weechat-curses"
39
40 -- Emms global shortcut commands at the window manager level: I use Emms
41 -- commands instead of the mpc ones so that my emms session stay up to date.
42 EMMS_PLAYLIST           = "emacsclient -c -e '(emms-browser)'"
43 EMMS_PAUSE              = "emacsclient -e '(emms-pause)'"
44 EMMS_PREVIOUS           = "emacsclient -e '(emms-previous)'"
45 EMMS_NEXT               = "emacsclient -e '(emms-next)'"
46 EMMS_SEEK_BACKWARD      = "emacsclient -e '(emms-seek-backward)'"
47 EMMS_SEEK_FORWARD       = "emacsclient -e '(emms-seek-forward)'"
48 EMMS_VOLUME_RAISE       = "emacsclient -e '(emms-volume-raise)'"
49 EMMS_VOLUME_LOWER       = "emacsclient -e '(emms-volume-lower)'"
50
51 terminal = XTERM
52 -- editor = os.getenv ("EDITOR") or "nano"
53 -- editor_cmd = terminal.." -e "..editor
54
55 local setup_advanced_keymap
56 local setup_default_keymap
57 if HOST == "adonis" then
58    TERM_GEOMETRY          = "237x67+20+20"
59
60    SET_TO_DEFAULT_KEYMAP  = ""
61    SET_TO_ADVANCED_KEYMAP = ""
62    setup_advanced_keymap = function () end
63    setup_default_keymap = function () end
64 else
65    TERM_GEOMETRY="180x60+20+20"
66
67    -- Keyboard mapping configuration shortcuts
68    SET_TO_DEFAULT_KEYMAP  = "xmodmap "..HOME.."/.xmodmaprc.default"
69    SET_TO_ADVANCED_KEYMAP = "xmodmap "..HOME.."/.xmodmaprc.advanced"
70    setup_advanced_keymap = function () spawn (SET_TO_ADVANCED_KEYMAP) end
71    setup_default_keymap = function () spawn (SET_TO_DEFAULT_KEYMAP) end
72 end
73
74 -- System monitor
75 SYSTEM_MONITOR     = XTERM.." -geometry "..TERM_GEOMETRY.." -e htop"
76 SYSTEM_MONITOR_BIS = XTERM.." -geometry "..TERM_GEOMETRY.." -e htop -u "..USER
77
78 -- Sound mixer (since I do not use a widget for now...)
79 SOUND_MIXER = XTERM.." -e alsamixer"
80
81 -- ---
82
83 -- Default modkey.
84 -- Usually, Mod4 is the key with a logo between Control and Alt.
85 -- If you do not like this or do not have such a key,
86 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
87 -- However, you can use another modifier like Mod1, but it may interact with others.
88 modkey = "Mod4"
89 altkey = "Mod1"
90 -- alias...
91 local mk, ak, ck, sk, ek = modkey, altkey, "Control", "Shift", "Escape"
92
93 -- Table of layouts to cover with awful.layout.inc, order matters.
94 -- 
95 -- XXX: I really miss a custom tiled layout à la emacs/ion3. But that would
96 -- require a unified management of empty screen regions, thus a somehow deep
97 -- modification of the awesome API to make it neat.
98 layouts = {
99    -- I never use the other layouts yet... 'cause they don't fit my needs.
100    awful.layout.suit.floating,
101    awful.layout.suit.max,
102 }
103 -- define some helpers...
104 local function next_layout () awful.layout.inc (layouts,  1) end
105 local function prev_layout () awful.layout.inc (layouts, -1) end
106
107 --}}}
108
109 --{{{ Shifty
110
111 shifty.config.tags = {
112    ["[www]"]   = { position = 1, nopopup = true,  persist = true, init = true, },
113    ["[emacs]"] = { position = 2, nopopup = true,  persist = true, init = true, },
114    ["[irc]"]   = { position = 3, nopopup = true,  persist = false, init = false, },
115    ["[sys]"]   = { position = 9, nopopup = false, persist = false, init = false, exclusive = true, },
116 }
117 for i = 4, 8 do                 -- XXX: do I need them?
118    shifty.config.tags = join (shifty.config.tags,
119                               { ["["..i.."]"] = { position = i, persist = true, }})
120 end
121 shifty.config.apps = {
122    { match = {"Iceweasel.*", "Firefox.*" }, tag = "[www]",   },
123    { match = {"emacs.*"                  }, tag = "[emacs]", },
124    { match = {"htop"                     }, tag = "[sys]",   },
125    { match = {"weechat"                  }, tag = "[irc]",   },
126    { match = {"MPlayer"                  }, float = true,    },
127    { match = {"wsim.*", "wsnet"          }, float = true, nopopup = true, ontop = true, },
128 }
129 shifty.config.defaults = {
130    layout = awful.layout.suit.max,
131    persist = true,
132    run = function (tag) naughty.notify ({ text = tag.name }) end,
133    floatBars = false,
134 }
135 shifty.init ()
136
137 --}}}
138
139 --{{{ Menu
140
141 -- Create a laucher widget and a main menu.
142 --
143 -- XXX: Note this menu is not displayed properly, but as I never use it, I did
144 -- not try to fix that problem...
145 myawesomemenu = {
146    { "manual",  terminal .. " -e man awesome" },
147    { "restart", awesome.restart },
148    { "quit",    awesome.quit },
149 }
150
151 mymenuitems = {
152    { "awesome", myawesomemenu, beautiful.awesome_icon },
153    { "debian", menu.debian_menu },
154    { "open terminal", terminal },
155 }
156 mymainmenu = amenu ({ items = mymenuitems })
157
158 mylauncher_cfg = {
159    image = image (beautiful.awesome_icon),
160    menu = mymainmenu
161 }
162
163 mylauncher = awful.widget.launcher (mylauncher_cfg)
164
165 --}}}
166
167 --{{{ Wibox
168
169 -- Create a textclock widget
170 mytextclock = awful.widget.textclock ()
171
172 -- Create a systray
173 mysystray = widget ({ type = "systray" })
174
175 --{{{ Spacers:
176
177 separator = widget ({ type = "textbox" })
178 separator.text = ""
179 separator.width = 1
180 separator.bg = beautiful.bg_focus
181
182 --}}}
183
184 --{{{ CPU usage:
185
186 cpugraph = awful.widget.graph ()
187 cpugraph:set_width (36)
188 cpugraph:set_background_color (beautiful.bg_normal)
189 cpugraph:set_color ("#FF5656")
190 cpugraph:set_gradient_colors ({ "#FF5656", "#88A175", "#AECF96" })
191 vicious.register (cpugraph, vicious.widgets.cpu, "$1")
192
193 --}}}
194
195 --{{{ Memory usage:
196
197 memprogbar = awful.widget.progressbar ()
198 memprogbar:set_width (8)
199 memprogbar:set_vertical (true)
200 memprogbar:set_background_color (beautiful.bg_normal)
201 memprogbar:set_border_color (nil)
202 memprogbar:set_color ("#AECF96")
203 memprogbar:set_gradient_colors ({ "#AECF96", "#88A175", "#FF5656" })
204 vicious.register (memprogbar, vicious.widgets.mem, "$1", 10)
205
206 --}}}
207
208 --{{{ Per-screen wibox
209
210 -- Create a wibox for each screen and add it
211 mywibox = {}
212 mypromptbox = {}
213 mylayoutbox = {}
214
215 mytaglist = {}
216 mytaglist.buttons =
217    join (
218          awful.button ({     }, 1, awful.tag.viewonly),
219          awful.button ({ mk, }, 1, awful.client.movetotag),
220          awful.button ({     }, 3, awful.tag.viewtoggle),
221          awful.button ({ mk, }, 3, awful.client.toggletag),
222          awful.button ({     }, 4, awful.tag.viewprev),
223          awful.button ({     }, 5, awful.tag.viewnext),
224          {})
225
226 mytasklist = {}
227 mytasklist.buttons =
228    join (
229          awful.button ({ }, 1,
230                        function (c)
231                           if not c:isvisible () then awful.tag.viewonly (c:tags ()[1]) end
232                           client.focus = c
233                           c:raise ()
234                        end),
235          awful.button ({ }, 3,
236                        function ()
237                           if instance then 
238                              instance:hide ()
239                              instance = nil 
240                           else
241                              instance = amenu.clients ({ width = 250 }) 
242                           end
243                        end),
244          awful.button ({ }, 4,
245                        function ()
246                           awful.client.focus.byidx (1)
247                           if client.focus then client.focus:raise () end
248                        end),
249          awful.button ({ }, 5,
250                        function ()
251                           awful.client.focus.byidx (-1)
252                           if client.focus then client.focus:raise () end
253                        end),
254          {})
255
256 local layout_buttons = 
257    join (awful.button ({ }, 1, next_layout),
258          awful.button ({ }, 3, prev_layout),
259          awful.button ({ }, 4, next_layout),
260          awful.button ({ }, 5, prev_layout), 
261          {})
262
263 -- TODO: I really don't like the prompt at the top of the screen. Maybe I should
264 -- use a kind of dedicated infoline at the bottom of the root window, as in
265 -- ion3....
266
267 for s = 1, screen.count () do
268    -- Create a promptbox for each screen
269    mypromptbox[s] = 
270       awful.widget.prompt ({
271                               layout = awful.widget.layout.horizontal.leftright 
272                            })
273
274    -- Create an imagebox widget which will contains an icon indicating which
275    -- layout we're using.  We need one layoutbox per screen.
276    mylayoutbox[s] = awful.widget.layoutbox (s)
277    mylayoutbox[s]:buttons (layout_buttons)
278
279    -- Create a taglist widget
280    mytaglist[s] = awful.widget.taglist (s,
281                                         awful.widget.taglist.label.all,
282                                         mytaglist.buttons)
283
284    -- Create a tasklist widget
285    local function currenttags (c)
286       return awful.widget.tasklist.label.currenttags (c, s)
287    end
288    mytasklist[s] = awful.widget.tasklist (currenttags,
289                                           mytasklist.buttons)
290
291    -- Actually create the wibox
292    mywibox[s] = awful.wibox ({ 
293                                 position = "top", 
294                                 screen = s 
295                              })
296
297    -- Add widgets to the wibox --- note order matters here
298    mywibox[s].widgets = {
299       {                    -- the content of this table is aligned to the left..
300          mylauncher,
301          mytaglist[s],
302          mypromptbox[s],        -- ... and goes left-right:
303          layout = awful.widget.layout.horizontal.leftright
304       },
305       mylayoutbox[s],           -- the remaining is aligned to the right...
306       mytextclock,
307       separator,
308       memprogbar.widget,
309       separator,
310       cpugraph.widget,
311       separator,
312       s == 1 and mysystray or nil,
313       mytasklist[s],            -- ... and goes right-left:
314       layout = awful.widget.layout.horizontal.rightleft
315    }
316 end
317
318 --}}}
319
320 -- Shifty stuff...
321 shifty.promptbox = mypromptbox
322
323 --}}}
324
325 --{{{ Mouse bindings
326
327 local rootbuttons =
328    join (
329          awful.button ({ }, 3, function () mymainmenu:toggle () end),
330          awful.button ({ }, 4, awful.tag.viewnext),
331          awful.button ({ }, 5, awful.tag.viewprev),
332          {})
333
334 root.buttons (rootbuttons)
335
336 --}}}
337
338 --{{{ Keychain initialization
339
340 keychain.init ({
341                   -- configutation table content should go here: default values
342                   -- I chose are here (@see keychain.init documentation for
343                   -- further details):
344                   escapes = {
345                      keychain.keystroke ( {        }, "Escape" ),
346                      keychain.keystroke ( { modkey }, "g"      ), -- <- "emacs-like"
347                   },
348                   -- enable infolines, appearing 2 seconds after the typing of
349                   -- the first prefix keys.
350                   use_bowls = true,
351                   use_timers = true,
352                   timeout = 2,
353                })
354
355 --}}}
356
357 --{{{ Various helpers
358
359 --{{{ Prompts:
360
361 local function run_prompt ()
362    mypromptbox[mouse.screen]:run ()
363 end
364
365 local function lua_prompt ()
366    awful.prompt.run ({ prompt = "Run Lua code: " },
367                      mypromptbox[mouse.screen].widget,
368                      awful.util.eval, nil,
369                      awful.util.getdir ("cache") .. "/history_eval")
370 end
371 -- @see http://awesome.naquadah.org/wiki/Anrxcs_Manual_Prompt
372 local function man_prompt ()
373
374    local function man (page)
375       --  Use GNU Emacs for manual page display
376       spawn ("emacsclient --eval '(manual-entry \"'" .. page .. "'\")'", false)
377       --  Use the KDE Help Center for manual page display
378       -- spawn ("khelpcenter man:" .. page, false)
379       --  Use the terminal emulator for manual page display
380       -- spawn ("urxvt -e man " .. page, false)
381    end
382
383    awful.prompt.run ({ prompt = "Manual: " }, mypromptbox[mouse.screen].widget, 
384                      man)
385 end
386
387 --}}}
388
389 --{{{ Client focus
390
391 local function switch_focus ()
392    awful.client.focus.history.previous ()
393    if client.focus then
394       client.focus:raise ()
395    end
396 end
397
398 local function focus_byidx (i)
399    awful.client.focus.byidx (i)
400    if client.focus then client.focus:raise () end
401 end
402
403 --}}}
404
405 --{{{ Misc.
406
407 local function new_tag (nopopup)
408    shifty.add ({ rel_index = 1, nopopup = nopopup })
409 end
410
411 local function spn (cmd)
412    return function () spawn (cmd) end
413 end
414
415 -- Other client-related facilities
416 local function cli_toggle_fs (c) c.fullscreen = not c.fullscreen  end
417 local function cli_swpmaster (c) c:swap (awful.client.getmaster ()) end
418 local function cli_redraw    (c) c:redraw () end
419 local function cli_kill      (c) c:kill () end
420 local function cli_raise     (c) client.focus = c; c:raise () end
421 local function cli_toggle_maximized (c)
422    c.maximized_horizontal = not c.maximized_horizontal
423    c.maximized_vertical   = not c.maximized_vertical
424 end
425
426 --}}}
427
428 --}}}
429
430 --{{{ Custom part of the configuration goes in another file...
431
432 require ("links")
433
434 --}}}
435
436 --{{{ Key bindings
437
438 -- helpers:
439 local akey = awful.key
440 local kcha = keychain
441 local kkey = keychain.key
442 local ksub = keychain.subchain
443
444 globalkeys =
445    join (
446          -- System monitoring:
447          akey ({ mk,     }, ek, spn (SYSTEM_MONITOR)                                  ),
448          akey ({ mk, ak, }, ek, spn (SYSTEM_MONITOR_BIS)                              ),
449
450          -- Manuals:
451          akey ({ mk,         }, "F1", man_prompt                                      ),
452
453          -- Standard programs:
454          akey ({ mk,         }, "F2", spn (ETERM_DEFAULT)                             ),
455          akey ({ mk, ak,     }, "F2", spn (ETERM_NEW)                                 ),
456          akey ({ mk, ak, sk, }, "F2", spn (XTERM)                                     ),
457          akey ({ mk,         }, "F3", run_prompt                                      ),
458          akey ({ mk, ak,     }, "F3", lua_prompt                                      ),
459          akey ({ mk,         }, "F4", spn (IRC)                                       ),
460          akey ({ mk,         }, "F5", spn (MAIL_READER)                               ),
461
462          -- Sound mixer:
463          -- akey ({ mk,      }, "F7", spn (SOUND_MIXER)                               ),
464          akey ({ mk,         }, "F7",
465                function () 
466                   scratch.drop (SOUND_MIXER, "bottom", "center", 1, 0.33, false)
467                end                                                                    ),
468
469          -- DPMS:
470          akey ({ mk,         }, "F10", spn (STANDBY_SCREEN)                           ),
471          akey ({ mk, ak,     }, "F10", spn (STANDBY_AND_LOCK_SCREEN)                  ),
472
473          -- Menu: (XXX: That's not what I want... I'd like a prompt with the
474          -- global menu encoded in it...)
475          akey ({ mk,         }, "F12", function () mymainmenu:toggle ()            end),
476
477          -- Misc. prompts (translations, etc.):
478          kcha ({ mk,         }, "e", {
479                   kkey ({     }, "f", function () find_translation ("enfr", false) end),
480                   kkey ({ mk, }, "f", function () find_translation ("enfr", true)  end),
481                   kkey ({     }, "s", function () find_synonym ("en", false)       end),
482                   kkey ({ mk, }, "s", function () find_synonym ("en", true)        end),
483                }),
484
485          kcha ({ mk,         }, "f", {
486                   kkey ({     }, "e", function () find_translation ("fren", false) end),
487                   kkey ({ mk, }, "e", function () find_translation ("fren", true)  end),
488                   kkey ({     }, "s", function () find_synonym ("fr", false)       end),
489                   kkey ({ mk, }, "s", function () find_synonym ("fr", true)        end),
490                   kkey ({     }, "c", function () find_conj ("fr", false)          end),
491                   kkey ({ mk, }, "c", function () find_conj ("fr", true)           end),
492                }),
493
494          -- Keymaps
495          kcha ({ mk,         }, "k", {
496                   kkey ({ mk, }, "a", setup_advanced_keymap                           ),
497                   kkey ({     }, "a", setup_advanced_keymap                           ),
498                   kkey ({ mk, }, "d", setup_default_keymap                            ),
499                   kkey ({     }, "d", setup_default_keymap                            ),
500                }),
501
502          -- Custom link manipulation...
503          akey ({ mk,         }, "o", function () query_open_gate6_link (true)      end),
504          akey ({ mk, ak,     }, "o", function () query_open_gate6_link (false)     end),
505
506          -- Disabled cause I can never use it this way... and `scratch.pad'
507          -- cannot come to the rescue for what I want (maybe a `scratch'
508          -- tag?)... (that would require empty regions management actually, as
509          -- for custom tiling):
510          -- 
511          -- akey ({ mk,         }, "space",
512          --  function () scratch.drop (XTERM, "bottom", "center", 1, 0.33, true) end),
513
514          -- Emms global shortcuts
515          akey ({ mk, ak,     }, "p",     spn (EMMS_PLAYLIST)                          ),
516          akey ({ mk, ak,     }, "space", spn (EMMS_PAUSE)                             ),
517          akey ({ mk, ak,     }, "Prior", spn (EMMS_PREVIOUS)                          ),
518          akey ({ mk, ak,     }, "Next",  spn (EMMS_NEXT)                              ),
519          akey ({ mk, ak,     }, "Left",  spn (EMMS_SEEK_BACKWARD)                     ),
520          akey ({ mk, ak,     }, "Right", spn (EMMS_SEEK_FORWARD)                      ),
521          akey ({ mk, ak,     }, "Up",    spn (EMMS_VOLUME_RAISE)                      ),
522          akey ({ mk, ak,     }, "Down",  spn (EMMS_VOLUME_LOWER)                      ),
523
524          -- Tag management...:
525          akey ({ mk,     }, "Left",   awful.tag.viewprev                              ),
526          akey ({ mk,     }, "Right",  awful.tag.viewnext                              ),
527          akey ({ mk, sk, }, "Left",   shifty.shift_prev                               ),
528          akey ({ mk, sk, }, "Right",  shifty.shift_next                               ),
529          kcha ({ mk,     }, "t", {
530                   kkey ({     }, "n", function () new_tag (false)                  end),
531                   kkey ({ mk, }, "n", function () new_tag (true)                   end),
532                   kkey ({     }, "k", shifty.del                                      ),
533                   kkey ({     }, "r", shifty.rename                                   ),
534                }),
535
536          -- Layout manipulation:
537          akey ({ mk, sk,     }, ",", function () awful.client.swap.byidx (-1)      end),
538          akey ({ mk, sk,     }, ".", function () awful.client.swap.byidx ( 1)      end),
539          akey ({ mk, ck,     }, "j", function () awful.screen.focus_relative ( 1)  end),
540          akey ({ mk, ck,     }, "k", function () awful.screen.focus_relative (-1)  end),
541          akey ({ mk,         }, "Tab", function () focus_byidx ( 1) end               ),
542          akey ({ mk, sk,     }, "Tab", function () focus_byidx (-1) end               ),
543          akey ({ mk,         }, "u", awful.client.urgent.jumpto                       ),
544          kcha ({ mk,         }, "l", { 
545                   kkey ({     }, "l", prev_layout                                     ),
546                   kkey ({ mk, }, "l", next_layout                                     ),
547                   kkey ({     }, ",", prev_layout                                     ),
548                   kkey ({     }, ".", next_layout                                     ),
549                }),
550
551          -- Session-mgmt...
552          kcha ({ mk, ak,     }, "x", {
553                   kkey ({ mk, ak, }, "r", awesome.restart                             ),
554                   kkey ({ mk, ak, }, "c", awesome.quit                                ),
555                }),
556
557          {})
558
559 -- Client-related bindings:
560 clientkeys =
561    join (
562          akey ({ mk, sk,     }, "f",      cli_toggle_fs                               ),
563          akey ({ mk, sk,     }, "Return", cli_swpmaster                               ),
564          akey ({ mk, sk,     }, "space",  awful.client.floating.toggle                ),
565          akey ({ mk, sk,     }, "r",      cli_redraw                                  ),
566          kcha ({ mk,         }, "x", {
567                   kkey ({ mk, }, "r", cli_raise                                       ),
568                   kkey ({ mk, }, "c", cli_kill                                        ),
569                   kkey ({     }, "o", switch_focus                                    ),
570                   -- Bound twice:
571                   kkey ({     }, ",", function (c) awful.client.swap.byidx (-1)    end),
572                   kkey ({     }, ".", function (c) awful.client.swap.byidx ( 1)    end),
573                   -- I never use them...:
574                   -- kkey ({     }, "2", function (c) awful.tag.incmaster ( 1)     end),
575                   -- kkey ({     }, "3", function (c) awful.tag.incncol   ( 1)     end),
576                }),
577          -- Ibid.
578          -- akey ({ mk, sk,     }, "o",                   awful.client.movetoscreen   ),
579          -- akey ({ mk,         }, "n",      function (c) c.minimized = not c.minimized end),
580          -- akey ({ mk, sk,     }, "m",                   cli_toggle_maximized        ),
581          -- akey ({ mk, ak,     }, "Up",     function (c) awful.client.focus.bydirection ("up", c)    end),
582          -- akey ({ mk, ak,     }, "Down",   function (c) awful.client.focus.bydirection ("down", c)  end),
583          -- akey ({ mk, ak,     }, "Left",   function (c) awful.client.focus.bydirection ("left", c)  end),
584          -- akey ({ mk, ak,     }, "Right",  function (c) awful.client.focus.bydirection ("right", c) end),
585          {})
586
587 -- Compute the maximum number of digit we need, limited to 9
588 keynumber = 9
589
590 -- Bind all key numbers to tags.
591 -- Be careful: we use keycodes to make it work on any keyboard layout.
592 -- This should map on the top row of your keyboard, usually 1 to 9.
593 for i = 1, keynumber do
594    globalkeys =
595       join (globalkeys,
596             akey ({ mk, }, "#" .. i + 9, -- view tag
597                   function ()
598                      awful.tag.viewonly (shifty.getpos (i))
599                   end),
600             akey ({ mk, ck, }, "#" .. i + 9, -- toggle tag
601                   function ()
602                      local t = shifty.getpos (i)
603                      t.selected = not t.selected
604                   end),
605             akey ({ mk, sk, }, "#" .. i + 9, -- move client to tag and view
606                   function ()
607                      if client.focus then
608                         local t = shifty.getpos (i)
609                         awful.client.movetotag (t)
610                         awful.tag.viewonly (t)
611                      end
612                   end),
613             akey ({ mk, ck, sk, }, "#" .. i + 9, -- add tag to client
614                   function ()
615                      if client.focus then
616                         awful.client.toggletag (shifty.getpos (i))
617                      end
618                   end),
619             {})
620 end
621
622 -- Setup initial keys
623
624 root.keys (globalkeys)
625 shifty.config.clientkeys = clientkeys
626
627 --}}}
628
629 --{{{ Various client bindings and general rules.
630
631 clientbuttons =
632    join (awful.button ({     }, 1, cli_raise),
633          -- TODO: use keygrapbber to move and resize...
634          awful.button ({ mk, }, 1, awful.mouse.client.move),
635          awful.button ({ mk, }, 3, awful.mouse.client.resize),
636          {})
637
638 awful.rules.rules = {
639    -- All clients will match this rule.
640    { 
641       rule = { },
642       properties = {
643          border_width = beautiful.border_width,
644          border_color = beautiful.border_normal,
645          focus = true,
646          keys = clientkeys,
647          buttons = clientbuttons,
648       }, 
649    },
650 }
651
652 --}}}
653
654 --{{{ Signals
655
656 -- Signal function to execute when a new client appears.
657 local function on_client_startup (c, startup)
658    -- No titlebar... (unless I decide to remove the ):
659    -- awful.titlebar.add (c, { modkey = mk })
660
661    -- Enable sloppy focus
662    c:add_signal ("mouse::enter",
663                  function (c)
664                     if awful.layout.get (c.screen) ~= awful.layout.suit.magnifier and
665                        awful.client.focus.filter (c) 
666                     then
667                        client.focus = c
668                     end
669                  end)
670
671    if not startup then
672       -- Set the windows at the slave,
673       -- i.e. put it at the end of others instead of setting it master.
674       -- awful.client.setslave (c)
675
676       -- Put windows in a smart way, only if they does not set an initial
677       -- position.
678       if not c.size_hints.user_position and
679          not c.size_hints.program_position 
680       then
681          awful.placement.no_overlap (c)
682          awful.placement.no_offscreen (c)
683       end
684    end
685 end
686
687 client.add_signal ("manage",  on_client_startup)
688 client.add_signal ("focus",   function (c) c.border_color = beautiful.border_focus end)
689 client.add_signal ("unfocus", function (c) c.border_color = beautiful.border_normal end)
690
691 --}}}
692