All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
3 -- Standard awesome library
4 local gears = require("gears")
5 local awful = require("awful")
6 require("awful.autofocus")
7 -- Widget and layout library
8 local wibox = require("wibox")
9 -- Tyrannical tab handling
10 --local tyrannical = require("tyrannical")
11 -- Theme handling library
12 local beautiful = require("beautiful")
13 local xrdb = beautiful.xresources
14 -- Notification library
15 local naughty = require("naughty")
16 local menubar = require("menubar")
17 local hotkeys_popup = require("awful.hotkeys_popup").widget
18 -- Enable hotkeys help widget for VIM and other apps
19 -- when client with a matching name is opened:
20 require("awful.hotkeys_popup.keys")
22 -- Load Debian menu entries
23 local debian = require("debian.menu")
24 local has_fdo, freedesktop = pcall(require, "freedesktop")
26 local lain = require("lain")
27 local ccwidgets = require("cryptocoin_widgets")
28 local fxwidgets = require("forex_widgets")
29 local clocksarray = require("clocksarray")
30 local dbg = require("debugfunc")
31 local th = require("taghelpers")
35 -- Check if awesome encountered an error during startup and fell back to
36 -- another config (This code will only ever execute for the fallback config)
37 if awesome.startup_errors then
38 naughty.notify({ preset = naughty.config.presets.critical,
39 title = "Oops, there were errors during startup!",
40 text = awesome.startup_errors })
43 -- Handle runtime errors after startup
45 local in_error = false
46 awesome.connect_signal("debug::error", function (err)
47 -- Make sure we don't go into an endless error loop
48 if in_error then return end
51 naughty.notify({ preset = naughty.config.presets.critical,
52 title = "Oops, an error happened!",
53 text = tostring(err) })
59 -- {{{ Variable definitions
60 --xrdb.set_dpi(95, screen[1])
61 --xrdb.set_dpi(120, screen[2])
63 -- Themes define colours, icons, font and wallpapers.
64 beautiful.init(gears.filesystem.get_configuration_dir () .. "theme/theme.lua")
66 -- This is used later as the default terminal and editor to run.
67 terminal = "rxvt-unicode"
68 editor = os.getenv("EDITOR") or "editor"
69 editor_cmd = terminal .. " -e " .. editor
72 -- Usually, Mod4 is the key with a logo between Control and Alt.
73 -- If you do not like this or do not have such a key,
74 -- I suggest you to remap Mod4 to another key using xmodmap or other tools.
75 -- However, you can use another modifier like Mod1, but it may interact with others.
79 -- Table of layouts to cover with awful.layout.inc, order matters.
81 default = awful.layout.suit.fair,
82 default_horiz = awful.layout.suit.fair.horizontal,
83 tiled = awful.layout.suit.tile,
84 tiled_horiz = awful.layout.suit.tile.top,
85 floating = awful.layout.suit.floating,
86 maximised = awful.layout.suit.max
88 awful.layout.layouts = {
93 layouts.default_horiz,
98 -- {{{ Helper functions
99 local function client_menu_toggle_fn()
103 if instance and instance.wibox.visible then
107 instance = awful.menu.clients({ theme = { width = 250 } })
112 local function set_wallpaper(s)
114 if beautiful.wallpaper then
115 local wallpaper = beautiful.wallpaper
116 -- If wallpaper is a function, call it with the screen
117 if type(wallpaper) == "function" then
118 wallpaper = wallpaper(s)
120 gears.wallpaper.maximized(wallpaper, s, true)
124 local function move_mouse_to_area(a)
125 local coords = mouse.coords()
126 if (coords.x < a.x or
127 coords.x > (a.x+a.width) or
129 coords.y > (a.y+a.height)) then
133 y = a.y + a.height/2,
141 -- Create a launcher widget and a main menu
143 { "hotkeys", function() return false, hotkeys_popup.show_help end},
144 { "manual", terminal .. " -e man awesome" },
145 { "edit config", editor_cmd .. " " .. awesome.conffile },
146 { "restart", awesome.restart },
147 { "quit", function() awesome.quit() end}
150 local menu_awesome = { "awesome", myawesomemenu, beautiful.awesome_icon }
151 local menu_terminal = { "open terminal", terminal }
154 mymainmenu = freedesktop.menu.build({
155 before = { menu_awesome },
156 after = { menu_terminal }
159 mymainmenu = awful.menu({
162 { "Debian", debian.menu.Debian_menu.Debian },
169 mylauncher = awful.widget.launcher({ image = beautiful.awesome_icon,
172 -- Menubar configuration
173 menubar.utils.terminal = terminal -- Set the terminal for applications that require it
177 --local spacer = wibox.widget {
178 -- color = beautiful.bg_minimize,
180 -- widget = wibox.widget.separator
182 local function make_spacer(text)
183 local spacer = wibox.widget.textbox()
184 spacer:set_text(text or " │ ")
188 -- Keyboard map indicator and switcher
189 mykeyboardlayout = awful.widget.keyboardlayout()
191 local lain_bat = lain.widget.bat({
192 batteries = {"BAT0", "BAT1"},
193 settings = function()
195 if bat_now.status == "Charging" then delim = "↑"
196 elseif bat_now.status == "Unknown" then delim = "٭" end
197 widget:set_text(bat_now.perc .. "% " .. delim .. " " .. bat_now.time)
201 -- Create a textclock widget
202 clocksarray = clocksarray.get_clocksarray("%a %d %b %H:%M:%S %Z", {
203 -- ["NZ"] = "Pacific/Auckland",
204 ["DE"] = "Europe/Berlin"
207 -- Create a wibox for each screen and add it
208 local taglist_buttons = gears.table.join(
209 awful.button({ }, 1, function(t) t:view_only() end),
210 awful.button({ modkey }, 1, function(t)
212 client.focus:move_to_tag(t)
215 awful.button({ }, 3, awful.tag.viewtoggle),
216 awful.button({ modkey }, 3, function(t)
218 client.focus:toggle_tag(t)
221 awful.button({ }, 4, function(t) awful.tag.viewnext(t.screen) end),
222 awful.button({ }, 5, function(t) awful.tag.viewprev(t.screen) end)
225 local tasklist_buttons = gears.table.join(
226 awful.button({ }, 1, function (c)
227 if c == client.focus then
228 -- I don't like click-minimising
229 -- c.minimized = true
231 -- Without this, the following
232 -- :isvisible() makes no sense
234 if not c:isvisible() and c.first_tag then
235 c.first_tag:view_only()
237 -- This will also un-minimize
238 -- the client, if needed
243 awful.button({ }, 3, client_menu_toggle_fn()),
244 awful.button({ }, 4, function ()
245 awful.client.focus.byidx(1)
247 awful.button({ }, 5, function ()
248 awful.client.focus.byidx(-1)
254 -- Re-set wallpaper when a screen's geometry changes (e.g. different resolution)
255 screen.connect_signal("property::geometry", set_wallpaper)
257 -- {{{ Basic setup for screens
258 local function screen_set_profile(s, profile)
260 s.outputstr = table.concat(gears.table.keys(s.outputs), "+")
261 s.name = s.profile .. "/" .. s.outputstr
264 awful.screen.connect_for_each_screen(function(s)
266 s.set_profile = screen_set_profile
271 -- Create a text widget to display screen name
272 s.namebox = wibox.container.background(wibox.widget.textbox(s.name),
273 beautiful.bg_minimize)
275 -- Create a promptbox for each screen
276 s.mypromptbox = awful.widget.prompt()
277 -- Create an imagebox widget which will contains an icon indicating which layout we're using.
278 -- We need one layoutbox per screen.
279 s.mylayoutbox = awful.widget.layoutbox(s)
280 s.mylayoutbox:buttons(awful.util.table.join(
281 awful.button({ }, 1, function () awful.layout.inc( 1) end),
282 awful.button({ }, 3, function () awful.layout.inc(-1) end),
283 awful.button({ }, 4, function () awful.layout.inc( 1) end),
284 awful.button({ }, 5, function () awful.layout.inc(-1) end)))
285 -- Create a taglist widget
286 s.mytaglist = awful.widget.taglist(s, awful.widget.taglist.filter.all, taglist_buttons)
288 -- Create a tasklist widget
289 s.mytasklist = awful.widget.tasklist(s, awful.widget.tasklist.filter.currenttags, tasklist_buttons)
291 -- Create the wibox, but only if there isn't one yet
292 if not s.mywibox then
293 s.mywibox = awful.wibar({ position = "top", screen = s })
296 -- Add widgets to the wibox
297 local right_widgets = gears.table.join(clocksarray, {
299 wibox.widget.systray(),
301 layout = wibox.layout.fixed.horizontal,
304 -- if s == screen.primary then
305 right_widgets = gears.table.join({
307 ccwidgets.btc_widget,
309 ccwidgets.eth_widget,
311 fxwidgets.ecb_widget,
319 layout = wibox.layout.align.horizontal,
321 layout = wibox.layout.fixed.horizontal,
327 s.mytasklist, -- Middle widget
332 -- {{{ autorandr integration
333 local function find_screen_by_pattern(pattern)
335 print(s.name .. " :: " .. pattern)
336 if s.name:match(pattern) then
342 local function get_target_screen_for_tag(tag)
343 local function primary_screen(reason)
344 local s = screen.primary
345 local msg = " → primary screen \"" .. s.name .. "\""
346 if reason then msg = msg .. " (" .. reason .. ")" end
351 print("Figuring out target screen for tag " .. tag.name .. "…")
353 if type(tag.targets) == "table" then
354 for _,target in ipairs(tag.targets) do
355 local s = find_screen_by_pattern(target:gsub('%-', '%%-'))
357 print(" → screen " .. s.name)
361 elseif tag.targets == "primary" then
362 return primary_screen("explicit request")
364 return primary_screen("no matching target in " .. table.concat(tag.targets, ","))
366 return primary_screen("no targets specified")
370 local function move_tag_to_target_screen(tag)
371 tag.screen = get_target_screen_for_tag(tag)
374 local function move_tags_to_target_screens()
375 for _,tag in ipairs(root.tags()) do
376 move_tag_to_target_screen(tag)
380 tag.connect_signal("request::screen", function(t)
381 -- throw the tag onto any other screen, it'll get reassigned later when
382 -- a new profile has been processed.
384 if s ~= t.screen then
391 title = "Screen removed",
392 text = "Salvaged tab " .. t.name,
396 function handle_new_autorandr_profile(newprofile)
397 -- The main idea here is that autorandr invokes this via awesome-client
398 -- after switching to a new profile. Awesome will have already set up all
399 -- the screens long before this function is called. Therefore, we just do
400 -- the necessary modifications to the existing screens, and move tags
403 if not newprofile then
404 error("Missing new profile name")
408 preset = naughty.config.presets.low,
409 title = "New autorandr profile",
410 text = "Reconfiguring for profile <b>" .. newprofile .. "</b>",
414 s:set_profile(newprofile)
416 move_tags_to_target_screens()
419 local function initialise_to_autorandr_profile()
423 local function process_line(line)
424 if profile then return end
425 local match = string.match(line, "^([^%s]+) %(detected%)")
431 local function output_done()
433 error("autorandr detected no profile")
436 handle_new_autorandr_profile(profile)
439 local function handle_exit(reason, code)
440 if not (reason == "exit" and code == 0) then
441 error("autorandr error: " .. reason .. ": " .. tostring(code))
445 awful.spawn.with_line_callback('autorandr', {
446 stdout = process_line,
447 output_done = output_done,
451 awesome.connect_signal("startup", initialise_to_autorandr_profile)
458 local default_tag = {
461 layout = layouts.default,
465 local default_tags = {}
468 for k,v in pairs(default_tag) do
469 default_tags[i][k] = v
471 default_tags[i].name = tostring(i)
473 default_tags[1].selected = true
475 default_tags = gears.table.join(default_tags, {
480 layout = layouts.tiled,
482 exec_once = { terminal .. " -name irc -e env MOSH_TITLE_NOPREFIX=true mosh --family=all -- irc-host tmux new -As irc irssi" },
483 instance = { "irc" },
484 targets = { "gauting/eDP-?1", "lehel/DisplayPort-2" },
492 layout = layouts.tiled,
494 exec_once = { "revolt" },
495 instance = { "Revolt" },
496 targets = { "gauting/eDP-?1", "lehel/DisplayPort-2" },
502 layout = layouts.floating,
510 layout = layouts.default,
511 exec_once = { "thunderbird" },
512 class = { "thunderbird" },
513 targets = { "gauting/eDP-?1", "lehel/DisplayPort-1" },
519 layout = layouts.default,
520 exec_once = { "chromium" },
521 class = { "Chromium" },
522 targets = { "gauting/eDP-?1", "lehel/DisplayPort-1", "present/HDMI.*" },
528 layout = layouts.default,
529 exec_once = { "firefox" },
530 class = { "Firefox" },
531 targets = { "gauting/eDP-?1", "lehel/DisplayPort-1", "present/HDMI.*" },
535 if not tyrannical then
537 for _,t in ipairs(default_tags) do
539 t.screen = t.screen or screen.primary
540 t.layout = t.layout or layouts.default
541 local newt = th.add_tag(t.name, t, false)
545 else -- {{{ tyrannical is loaded
546 tyrannical.settings.default_layout = layouts.default
547 tyrannical.settings.master_width_factor = 0.5
548 tyrannical.settings.block_children_focus_stealing = true
549 tyrannical.settings.group_children = true
551 tyrannical.tags = default_tags
553 tyrannical.properties.size_hints_honor = { URxvt = false }
555 --XX---- Ignore the tag "exclusive" property for the following clients (matched by classes)
556 --XX--tyrannical.properties.intrusive = {
557 --XX-- "ksnapshot" , "pinentry" , "gtksu" , "kcalc" , "xcalc" ,
558 --XX-- "feh" , "Gradient editor", "About KDE" , "Paste Special", "Background color" ,
559 --XX-- "kcolorchooser" , "plasmoidviewer" , "Xephyr" , "kruler" , "plasmaengineexplorer",
562 --XX---- Ignore the tiled layout for the matching clients
563 --XX--tyrannical.properties.floating = {
564 --XX-- "MPlayer" , "pinentry" , "ksnapshot" , "pinentry" , "gtksu" ,
565 --XX-- "xine" , "feh" , "kmix" , "kcalc" , "xcalc" ,
566 --XX-- "yakuake" , "Select Color$" , "kruler" , "kcolorchooser", "Paste Special" ,
567 --XX-- "New Form" , "Insert Picture" , "kcharselect", "mythfrontend" , "plasmoidviewer"
570 --XX---- Make the matching clients (by classes) on top of the default layout
571 --XX--tyrannical.properties.ontop = {
572 --XX-- "Xephyr" , "ksnapshot" , "kruler"
575 --XX---- Force the matching clients (by classes) to be centered on the screen on init
576 --XX--tyrannical.properties.centered = {
583 -- {{{ Mouse bindings
584 root.buttons(gears.table.join(
585 awful.button({ }, 3, function () mymainmenu:toggle() end),
586 awful.button({ }, 4, awful.tag.viewnext),
587 awful.button({ }, 5, awful.tag.viewprev)
593 local function toggle_tag_by_name(tagname, exclusive)
595 local t = awful.tag.find_by_name(nil, tagname)
600 awful.tag.viewtoggle(t)
602 cf = awful.client.getmaster(t.screen)
610 globalkeys = gears.table.join(
611 awful.key({ modkey, }, "s", hotkeys_popup.show_help,
612 {description="show help", group="awesome"}),
613 awful.key({ modkey, }, "Left", awful.tag.viewprev,
614 {description = "view previous", group = "tag"}),
615 awful.key({ modkey, }, "Right", awful.tag.viewnext,
616 {description = "view next", group = "tag"}),
617 awful.key({ modkey, "Shift" }, "Left", function () awful.screen.focus_relative( 1) end,
618 {description = "focus the next screen", group = "screen"}),
619 awful.key({ modkey, "Shift" }, "Right", function () awful.screen.focus_relative(-1) end,
620 {description = "focus the previous screen", group = "screen"}),
621 awful.key({ modkey, }, "Escape", awful.tag.history.restore,
622 {description = "go back", group = "tag"}),
624 awful.key({ modkey, }, "k",
626 awful.client.focus.byidx( 1)
628 {description = "focus next by index", group = "client"}
630 awful.key({ modkey, }, "j",
632 awful.client.focus.byidx(-1)
634 {description = "focus previous by index", group = "client"}
637 -- Layout manipulation
638 awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( 1) end,
639 {description = "swap with next client by index", group = "client"}),
640 awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx( -1) end,
641 {description = "swap with previous client by index", group = "client"}),
642 awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
643 {description = "focus the next screen", group = "screen"}),
644 awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
645 {description = "focus the previous screen", group = "screen"}),
646 awful.key({ modkey, "Shift" }, "Return", awful.client.urgent.jumpto,
647 {description = "jump to urgent client", group = "client"}),
648 awful.key({ modkey, }, "Tab",
650 awful.client.focus.history.previous()
655 {description = "go back", group = "client"}),
658 awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end,
659 {description = "open a terminal", group = "launcher"}),
660 awful.key({ modkey, }, "r", function()
661 package.loaded.rc = nil
664 {description = "reload rc.lua", group = "awesome"}),
665 awful.key({ modkey, "Control" }, "r", awesome.restart,
666 {description = "reload awesome", group = "awesome"}),
667 awful.key({ modkey, "Shift" }, "q", awesome.quit,
668 {description = "quit awesome", group = "awesome"}),
670 awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
671 {description = "increase master width factor", group = "layout"}),
672 awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
673 {description = "decrease master width factor", group = "layout"}),
674 awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end,
675 {description = "increase the number of master clients", group = "layout"}),
676 awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end,
677 {description = "decrease the number of master clients", group = "layout"}),
678 awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end,
679 {description = "increase the number of columns", group = "layout"}),
680 awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end,
681 {description = "decrease the number of columns", group = "layout"}),
682 awful.key({ modkey, }, "space", function () awful.layout.inc( 1) end,
683 {description = "select next", group = "layout"}),
684 awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end,
685 {description = "select previous", group = "layout"}),
687 awful.key({ modkey, "Control" }, "n",
689 local c = awful.client.restore()
690 -- Focus restored client
696 {description = "restore minimized", group = "client"}),
699 awful.key({ cmdkey }, "r",
701 local widget = awful.screen.focused().mypromptbox.widget
702 local function spawn(command, args)
703 gears.debug.dump(args)
704 awful.spawn(command, args)
709 bg_cursor = '#ff0000',
711 history_path = awful.util.get_cache_dir() .. "/history",
712 completion_callback = awful.completion.shell,
714 -- Replace the 'normal' Return with a custom one
715 {{ }, 'Return', function(command)
718 -- Spawn method to spawn in the current tag
719 {{'Mod1' }, 'Return', function(command)
722 tag = mouse.screen.selected_tag
725 -- Spawn in the current tag as floating and on top
726 {{'Shift' }, 'Return', function(command)
730 tag = mouse.screen.selected_tag
733 -- Spawn in a new tag
734 {{'Control'}, 'Return', function(command)
737 layout = layouts.default,
742 {{ }, 'Escape', function(_) return end},
746 {description = "run prompt", group = "launcher"}),
748 awful.key({ modkey }, "x",
752 bg_cursor = '#ff0000',
753 textbox = awful.screen.focused().mypromptbox.widget,
754 exe_callback = awful.util.eval,
755 history_path = awful.util.get_cache_dir() .. "/history_eval"
758 {description = "lua execute prompt", group = "awesome"}),
760 awful.key({ modkey }, "w", function() menubar.show() end,
761 {description = "show the menubar", group = "launcher"}),
764 awful.key({ modkey, }, "a", function()
765 th.add_tag(nil, {layout=layouts.default} ,true)
767 {description = "add a tag", group = "tag"}),
768 awful.key({ modkey, }, "d", th.delete_tag,
769 {description = "delete the current tag", group = "tag"}),
770 awful.key({ modkey, "Shift", }, "a", function()
771 th.move_to_new_tag(nil, nil, { layout = layouts.maximised },true,true,true)
773 {description = "add a volatile tag with the focused client", group = "tag"}),
774 awful.key({ modkey, "Shift", "Control" }, "a", function()
775 th.move_to_new_tag(nil, nil, { layout = layouts.maximised },false,true,true)
777 {description = "add a permanent tag with the focused client", group = "tag"}),
778 awful.key({ modkey, "Mod1" }, "a", th.copy_tag,
779 {description = "create a copy of the current tag", group = "tag"}),
780 awful.key({ modkey, "Control" }, "a", th.rename_tag,
781 {description = "rename the current tag", group = "tag"}),
782 awful.key({ modkey, "Control", "Shift", "Mod1" }, "a", th.collect_orphan_clients_to_tag,
783 {description = "collect all orphaned clients", group = "client"}),
785 awful.key({ modkey }, "y", toggle_tag_by_name("irc", true),
786 {description = "view tag 'irc'", group = "tag"}),
787 awful.key({ modkey, "Control" }, "y", toggle_tag_by_name("irc"),
788 {description = "toggle tag 'irc'", group = "tag"}),
789 awful.key({ modkey }, "u", toggle_tag_by_name("[]", true),
790 {description = "view tag '[]'", group = "tag"}),
791 awful.key({ modkey, "Control" }, "u", toggle_tag_by_name("[]"),
792 {description = "toggle tag '[]'", group = "tag"}),
793 awful.key({ modkey }, "i", toggle_tag_by_name("cal", true),
794 {description = "view tag 'cal'", group = "tag"}),
795 awful.key({ modkey, "Control" }, "i", toggle_tag_by_name("cal"),
796 {description = "toggle tag 'cal'", group = "tag"}),
797 awful.key({ modkey }, "o", toggle_tag_by_name("chr", true),
798 {description = "view tag 'chr'", group = "tag"}),
799 awful.key({ modkey, "Control" }, "o", toggle_tag_by_name("chr"),
800 {description = "toggle tag 'chr'", group = "tag"}),
801 awful.key({ modkey }, "p", toggle_tag_by_name("ffx", true),
802 {description = "view tag 'ff'", group = "tag"}),
803 awful.key({ modkey, "Control" }, "p", toggle_tag_by_name("ffx"),
804 {description = "toggle tag 'ff'", group = "tag"}),
807 clientkeys = gears.table.join(
808 awful.key({ modkey, }, "f",
810 c.fullscreen = not c.fullscreen
813 {description = "toggle fullscreen", group = "client"}),
814 awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end,
815 {description = "close", group = "client"}),
816 awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ,
817 {description = "toggle floating", group = "client"}),
818 awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
819 {description = "move to master", group = "client"}),
820 awful.key({ modkey, }, "z", function (c) c:move_to_screen() end,
821 {description = "move to screen", group = "client"}),
822 awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end,
823 {description = "toggle keep on top", group = "client"}),
824 awful.key({ modkey, }, "n",
826 -- The client currently has the input focus, so it cannot be
827 -- minimized, since minimized clients can't have the focus.
830 {description = "minimize", group = "client"}),
831 awful.key({ modkey, }, "m",
833 c.maximized = not c.maximized
834 c.maximized_horizontal = false
835 c.maximized_vertical = false
838 {description = "(un)maximize", group = "client"}),
839 awful.key({ modkey, "Control" }, "m",
841 c.maximized_vertical = not c.maximized_vertical
844 {description = "(un)maximize vertically", group = "client"}),
845 awful.key({ modkey, "Shift" }, "m",
847 c.maximized_horizontal = not c.maximized_horizontal
850 {description = "(un)maximize horizontally", group = "client"})
853 -- Bind all key numbers to tags.
854 -- Be careful: we use keycodes to make it work on any keyboard layout.
855 -- This should map on the top row of your keyboard, usually 1 to 9.
857 globalkeys = gears.table.join(globalkeys,
859 awful.key({ modkey }, "#" .. i + 9, toggle_tag_by_name(tostring(i), true),
860 {description = "view tag #"..i, group = "tag"}),
861 -- Toggle tag display.
862 awful.key({ modkey, "Control" }, "#" .. i + 9, toggle_tag_by_name(tostring(i)),
863 {description = "toggle tag #" .. i, group = "tag"}),
864 -- Move client to tag.
865 awful.key({ modkey, "Shift" }, "#" .. i + 9,
868 local tag = awful.tag.find_by_name(screen.primary, tostring(i))
870 client.focus:move_to_tag(tag)
874 {description = "move focused client to tag #"..i, group = "tag"}),
875 -- Toggle tag on focused client.
876 awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
879 local tag = awful.tag.find_by_name(screen.primary, tostring(i))
881 client.focus:toggle_tag(tag)
885 {description = "toggle focused client on tag #" .. i, group = "tag"})
889 clientbuttons = gears.table.join(
890 awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
891 awful.button({ modkey }, 1, awful.mouse.client.move),
892 awful.button({ modkey }, 3, awful.mouse.client.resize))
895 globalkeys = awful.util.table.join(globalkeys,
896 awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
897 awful.key({ cmdkey }, "c", function () awful.spawn("chromium --enable-remote-extensions") end),
898 awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e ipython3") end),
899 awful.key({ cmdkey }, "m", function () awful.spawn(terminal .. " -name mutt -e mutt") end),
900 awful.key({ cmdkey }, "t", function () awful.spawn("thunderbird") end),
901 awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
902 awful.key({ cmdkey }, "v", function () awful.spawn("virt-manager") end),
903 awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
904 awful.key({ cmdkey }, "p", function () awful.spawn("pavucontrol") end),
905 awful.key({ cmdkey }, "i", function () awful.spawn(terminal .. " -name irc -e env MOSH_TITLE_NOPREFIX=true mosh --family=all -- irc-host tmux new -As irc irssi") end),
906 awful.key({ cmdkey }, "x", function ()
907 awful.spawn("/usr/bin/xscreensaver -no-capture-stderr")
908 os.execute("sleep 5")
909 awful.spawn("xscreensaver-command -lock")
911 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xscreensaver-command -exit") end),
913 awful.key({ cmdkey }, "BackSpace", function () awful.spawn("pkill -USR1 offlineimap") end),
916 awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
917 awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") end),
918 awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") end),
919 awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ -2%") end),
920 awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ -2%") end),
921 awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ +2%") end),
922 awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ +2%") end),
923 awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute @DEFAULT_SOURCE@ toggle") end),
924 awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute @DEFAULT_SOURCE@ toggle") end),
925 awful.key({ cmdkey }, "Insert", function () awful.spawn("pa_cycle_default source") end),
926 awful.key({ cmdkey }, "Delete", function () awful.spawn("pa_cycle_default sink") end),
927 awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 5%") end),
928 awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 5%") end),
929 awful.key(nil, "XF86Display", function () awful.spawn("autorandr --change --force"); initialise_to_autorandr_profile() end),
930 awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
931 awful.key(nil, "XF86Tools", function () awful.spawn("") end),
932 awful.key(nil, "XF86Search", function () awful.spawn("") end),
933 awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
934 awful.key(nil, "XF86Explorer", function () awful.spawn("") end),
935 awful.key(nil, "XF86Favorites", function () awful.spawn("systemctl suspend") end),
937 awful.key({ cmdkey }, "Multi_key", function () run_output_notify("flameshot gui", "Output") end),
938 awful.key({ cmdkey, "Shift" }, "Multi_key", function () run_output_notify("flameshot full --delay 2000 --clipboard", "Output") end),
940 awful.key({ cmdkey }, "Up", function () awful.spawn("pap prev") end),
941 awful.key({ cmdkey }, "Left", function () awful.spawn("pap seek -10") end),
942 awful.key({ cmdkey, "Shift" }, "Left", function () awful.spawn("pap seek -60") end),
943 awful.key({ cmdkey }, "Down", function () awful.spawn("pap next") end),
944 awful.key({ cmdkey }, "Right", function () awful.spawn("pap seek +10") end),
945 awful.key({ cmdkey, "Shift" }, "Right", function () awful.spawn("pap seek +60") end),
946 awful.key({ cmdkey }, "space", function () awful.spawn("pap pause") end),
947 awful.key({ cmdkey }, "\\", function () run_output_notify("pap info", "Track info") end),
948 awful.key({ cmdkey }, "]", function () run_output_notify("pap list", "Playlist") end)
951 function run_output_notify(cmd, title)
952 awful.spawn.easy_async(cmd, function(stdout, stderr, reason, exit_code)
955 preset = naughty.config.presets.low,
963 root.keys(globalkeys)
967 -- Rules to apply to new clients (through the "manage" signal).
969 local function float_client_in_the_middle_with_margins(client, leftright, topbottom)
970 local wa = client.screen.workarea
972 client.y = wa.y + topbottom
973 client.height = wa.height - 2*topbottom
975 client.y = wa.y + (wa.height - client.height)/2
978 client.x = wa.x + leftright
979 client.width = wa.width - 2*leftright
981 client.x = wa.x + (wa.width - client.width)/2
985 local function move_to_tag_by_name(s, tagname)
987 local t = awful.tag.find_by_name(s, tagname)
989 error("No tag by the name of " .. tagname)
996 local function move_to_tag_or_create_volatile(s, tagname)
998 local t = awful.tag.find_by_name(s, tagname)
1002 th.move_to_new_tag(c, tagname, {}, true, true, true)
1007 awful.rules.rules = {
1008 -- All clients will match this rule.
1010 properties = { border_width = beautiful.border_width,
1011 border_color = beautiful.border_normal,
1012 focus = awful.client.focus.filter,
1015 buttons = clientbuttons,
1016 screen = awful.screen.preferred,
1017 placement = awful.placement.no_overlap+awful.placement.no_offscreen,
1022 { rule = { type = "dialog" },
1023 properties = { floating = true,
1025 skip_taskbar = true,
1028 --switchtotag = true,
1029 placement = awful.placement.centered
1032 { rule = { class = "URxvt" },
1033 properties = { size_hints_honor = false, }
1035 { rule = { instance = "irc" },
1036 callback = move_to_tag_by_name(nil, "irc"),
1038 { rule = { class = "scrcpy" },
1039 callback = move_to_tag_by_name(nil, "[]"),
1041 { rule_any = { class = { "Firefox", "firefox" } },
1042 callback = move_to_tag_by_name(nil, "ffx"),
1044 { rule = { class = "Chromium" },
1045 callback = move_to_tag_by_name(nil, "chr"),
1047 { rule_any = { class = { "thunderbird", "Thunderbird" } },
1048 callback = move_to_tag_by_name(nil, "cal"),
1050 { rule = { instance = "mutt" },
1054 layout = awful.layout.suit.fair.horizontal,
1060 { rule_any = { class = { "zoom" } },
1061 callback = move_to_tag_or_create_volatile(nil, "Zoom"),
1063 { rule_any = { class = { "Ssvnc.tcl" },
1064 class = { "Ssvnc" },
1065 name = { "SSL/SSH VNC Viewer.-" },
1067 callback = move_to_tag_or_create_volatile(nil, "SSVNC"),
1069 { rule_any = { class = {
1073 properties = { floating = true,
1076 placement = awful.placement.centered,
1079 { rule_any = { instance = {
1085 properties = { floating = true,
1088 placement = awful.placement.centered,
1091 { rule_any = { class = {
1097 "Microsoft Teams - Preview",
1103 except_any = { type = { "dialog" } },
1104 properties = { new_tag = {
1105 layout = layouts.maximised,
1108 --switchtotag = true,
1112 --XX-- { rule = { class = "Gscan2pdf" },
1113 --XX-- properties = {
1114 --XX-- switchtotag = true
1116 --XX-- callback = move_to_tag(1, 5)
1118 --XX-- { rule = { name = "gscan2pdf .*" },
1119 --XX-- properties = {
1120 --XX-- floating = false,
1123 --XX-- { rule = { class = "Thunar", type = "normal" },
1124 --XX-- properties = {
1125 --XX-- floating = false,
1128 --XX-- { rule = { class = "Pinentry", instance = "pinentry" },
1129 --XX-- properties = {
1130 --XX-- floating = true,
1133 --XX-- { rule = { class = "Gxmessage" },
1134 --XX-- properties = {
1135 --XX-- floating = true,
1143 -- Signal function to execute when a new client appears.
1144 client.connect_signal("manage", function (c)
1145 -- Set the windows at the slave,
1146 -- i.e. put it at the end of others instead of setting it master.
1147 -- if not awesome.startup then awful.client.setslave(c) end
1148 --if not awesome.startup then
1149 -- local t = awful.screen.focused().selected_tag
1150 -- if t.name == "xmutt" then
1151 -- awful.client.setslave(c)
1155 if awesome.startup and
1156 not c.size_hints.user_position
1157 and not c.size_hints.program_position then
1158 -- Prevent clients from being unreachable after screen count changes.
1159 awful.placement.no_offscreen(c)
1162 c.maximized_horizontal = false
1163 c.maximized_vertical = false
1166 -- Add a titlebar if titlebars_enabled is set to true in the rules.
1167 client.connect_signal("request::titlebars", function(c)
1168 -- buttons for the titlebar
1169 local buttons = gears.table.join(
1170 awful.button({ }, 1, function()
1173 awful.mouse.client.move(c)
1175 awful.button({ }, 3, function()
1178 awful.mouse.client.resize(c)
1182 awful.titlebar(c) : setup {
1184 awful.titlebar.widget.iconwidget(c),
1186 layout = wibox.layout.fixed.horizontal
1191 widget = awful.titlebar.widget.titlewidget(c)
1194 layout = wibox.layout.flex.horizontal
1197 awful.titlebar.widget.floatingbutton (c),
1198 awful.titlebar.widget.maximizedbutton(c),
1199 awful.titlebar.widget.stickybutton (c),
1200 awful.titlebar.widget.ontopbutton (c),
1201 awful.titlebar.widget.closebutton (c),
1202 layout = wibox.layout.fixed.horizontal()
1204 layout = wibox.layout.align.horizontal
1208 -- Enable sloppy focus, so that focus follows mouse.
1209 client.connect_signal("mouse::enter", function(c)
1210 if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
1211 and awful.client.focus.filter(c) then
1214 --17 18:03 < psychon> madduck: yes. In the default config at the very end there is code that actives a client on mouse::enter. Just add if c.class == "whatever virt-viewer uses" then return end to that, or
1215 -- something like this
1218 client.connect_signal("focus", function(c)
1219 c.border_color = beautiful.border_focus
1221 client.connect_signal("unfocus", function(c)
1222 c.border_color = beautiful.border_normal
1225 awful.ewmh.add_activate_filter(function(c, context, hints)
1226 if context == "ewmh" then
1227 if (c.class == "Firefox-esr" or c.class == "Firefox") then
1233 client.connect_signal("request::activate", function(c, context, hints)
1234 if gears.table.hasitem({
1235 "client.focus.byidx",
1237 "autofocus.check_focus",
1241 gears.timer.delayed_call(function()
1242 -- we need a delayed call so that we execute *after layout changes
1243 if hints.raise and c == client.focus and client.focus:isvisible() then
1244 move_mouse_to_area(client.focus)
1250 -- vim:ft=lua:sw=4:sts=4:ts=4:et