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 local function move_tags_to_screen_relative(direction)
611 local s = awful.screen.focused()
612 for _,tag in ipairs(s.selected_tags) do
613 print("index: " .. s.index .. " count: " .. screen:count())
614 tag.screen = screen[(s.index + screen:count() + direction) % screen.count()]
618 globalkeys = gears.table.join(
619 awful.key({ modkey, }, "s", hotkeys_popup.show_help,
620 {description="show help", group="awesome"}),
621 awful.key({ modkey, }, "Left", awful.tag.viewprev,
622 {description = "view previous", group = "tag"}),
623 awful.key({ modkey, }, "Right", awful.tag.viewnext,
624 {description = "view next", group = "tag"}),
625 awful.key({ modkey, }, "Escape", awful.tag.history.restore,
626 {description = "go back", group = "tag"}),
628 awful.key({ modkey, }, "k",
630 awful.client.focus.byidx( 1)
632 {description = "focus next by index", group = "client"}
634 awful.key({ modkey, }, "j",
636 awful.client.focus.byidx(-1)
638 {description = "focus previous by index", group = "client"}
641 -- Layout manipulation
642 awful.key({ modkey, "Shift" }, "k", function () awful.client.swap.byidx( 1) end,
643 {description = "swap with next client by index", group = "client"}),
644 awful.key({ modkey, "Shift" }, "j", function () awful.client.swap.byidx(-1) end,
645 {description = "swap with previous client by index", group = "client"}),
646 awful.key({ modkey, "Control" }, "k", function () awful.screen.focus_relative( 1) end,
647 {description = "focus the next screen", group = "screen"}),
648 awful.key({ modkey, "Control" }, "j", function () awful.screen.focus_relative(-1) end,
649 {description = "focus the previous screen", group = "screen"}),
650 awful.key({ modkey, "Shift", "Control" }, "k", function () move_tags_to_screen_relative( 1) end,
651 {description = "move tags to the next screen", group = "screen"}),
652 awful.key({ modkey, "Shift", "Control" }, "j", function () move_tags_to_screen_relative(-1) end,
653 {description = "move tags to the previous screen", group = "screen"}),
654 awful.key({ modkey, "Shift" }, "Return", awful.client.urgent.jumpto,
655 {description = "jump to urgent client", group = "client"}),
656 awful.key({ modkey, }, "Tab",
658 awful.client.focus.history.previous()
663 {description = "go back", group = "client"}),
666 awful.key({ modkey, }, "Return", function () awful.spawn(terminal) end,
667 {description = "open a terminal", group = "launcher"}),
668 awful.key({ modkey, }, "r", function()
669 package.loaded.rc = nil
672 {description = "reload rc.lua", group = "awesome"}),
673 awful.key({ modkey, "Control" }, "r", awesome.restart,
674 {description = "reload awesome", group = "awesome"}),
675 awful.key({ modkey, "Shift" }, "q", awesome.quit,
676 {description = "quit awesome", group = "awesome"}),
678 awful.key({ modkey, }, "l", function () awful.tag.incmwfact( 0.05) end,
679 {description = "increase master width factor", group = "layout"}),
680 awful.key({ modkey, }, "h", function () awful.tag.incmwfact(-0.05) end,
681 {description = "decrease master width factor", group = "layout"}),
682 awful.key({ modkey, "Shift" }, "h", function () awful.tag.incnmaster( 1, nil, true) end,
683 {description = "increase the number of master clients", group = "layout"}),
684 awful.key({ modkey, "Shift" }, "l", function () awful.tag.incnmaster(-1, nil, true) end,
685 {description = "decrease the number of master clients", group = "layout"}),
686 awful.key({ modkey, "Control" }, "h", function () awful.tag.incncol( 1, nil, true) end,
687 {description = "increase the number of columns", group = "layout"}),
688 awful.key({ modkey, "Control" }, "l", function () awful.tag.incncol(-1, nil, true) end,
689 {description = "decrease the number of columns", group = "layout"}),
690 awful.key({ modkey, }, "space", function () awful.layout.inc( 1) end,
691 {description = "select next", group = "layout"}),
692 awful.key({ modkey, "Shift" }, "space", function () awful.layout.inc(-1) end,
693 {description = "select previous", group = "layout"}),
695 awful.key({ modkey, "Control" }, "n",
697 local c = awful.client.restore()
698 -- Focus restored client
704 {description = "restore minimized", group = "client"}),
707 awful.key({ cmdkey }, "r",
709 local widget = awful.screen.focused().mypromptbox.widget
710 local function spawn(command, args)
711 gears.debug.dump(args)
712 awful.spawn(command, args)
717 bg_cursor = '#ff0000',
719 history_path = awful.util.get_cache_dir() .. "/history",
720 completion_callback = awful.completion.shell,
722 -- Replace the 'normal' Return with a custom one
723 {{ }, 'Return', function(command)
726 -- Spawn method to spawn in the current tag
727 {{'Mod1' }, 'Return', function(command)
730 tag = mouse.screen.selected_tag
733 -- Spawn in the current tag as floating and on top
734 {{'Shift' }, 'Return', function(command)
738 tag = mouse.screen.selected_tag
741 -- Spawn in a new tag
742 {{'Control'}, 'Return', function(command)
745 layout = layouts.default,
750 {{ }, 'Escape', function(_) return end},
754 {description = "run prompt", group = "launcher"}),
756 awful.key({ modkey }, "x",
760 bg_cursor = '#ff0000',
761 textbox = awful.screen.focused().mypromptbox.widget,
762 exe_callback = awful.util.eval,
763 history_path = awful.util.get_cache_dir() .. "/history_eval"
766 {description = "lua execute prompt", group = "awesome"}),
768 awful.key({ modkey }, "w", function() menubar.show() end,
769 {description = "show the menubar", group = "launcher"}),
772 awful.key({ modkey, }, "a", function()
773 th.add_tag(nil, {layout=layouts.default} ,true)
775 {description = "add a tag", group = "tag"}),
776 awful.key({ modkey, }, "d", th.delete_tag,
777 {description = "delete the current tag", group = "tag"}),
778 awful.key({ modkey, "Shift", }, "a", function()
779 th.move_to_new_tag(nil, nil, { layout = layouts.maximised },true,true,true)
781 {description = "add a volatile tag with the focused client", group = "tag"}),
782 awful.key({ modkey, "Shift", "Control" }, "a", function()
783 th.move_to_new_tag(nil, nil, { layout = layouts.maximised },false,true,true)
785 {description = "add a permanent tag with the focused client", group = "tag"}),
786 awful.key({ modkey, "Mod1" }, "a", th.copy_tag,
787 {description = "create a copy of the current tag", group = "tag"}),
788 awful.key({ modkey, "Control" }, "a", th.rename_tag,
789 {description = "rename the current tag", group = "tag"}),
790 awful.key({ modkey, "Control", "Shift", "Mod1" }, "a", th.collect_orphan_clients_to_tag,
791 {description = "collect all orphaned clients", group = "client"}),
793 awful.key({ modkey }, "y", toggle_tag_by_name("irc", true),
794 {description = "view tag 'irc'", group = "tag"}),
795 awful.key({ modkey, "Control" }, "y", toggle_tag_by_name("irc"),
796 {description = "toggle tag 'irc'", group = "tag"}),
797 awful.key({ modkey }, "u", toggle_tag_by_name("[]", true),
798 {description = "view tag '[]'", group = "tag"}),
799 awful.key({ modkey, "Control" }, "u", toggle_tag_by_name("[]"),
800 {description = "toggle tag '[]'", group = "tag"}),
801 awful.key({ modkey }, "i", toggle_tag_by_name("cal", true),
802 {description = "view tag 'cal'", group = "tag"}),
803 awful.key({ modkey, "Control" }, "i", toggle_tag_by_name("cal"),
804 {description = "toggle tag 'cal'", group = "tag"}),
805 awful.key({ modkey }, "o", toggle_tag_by_name("chr", true),
806 {description = "view tag 'chr'", group = "tag"}),
807 awful.key({ modkey, "Control" }, "o", toggle_tag_by_name("chr"),
808 {description = "toggle tag 'chr'", group = "tag"}),
809 awful.key({ modkey }, "p", toggle_tag_by_name("ffx", true),
810 {description = "view tag 'ff'", group = "tag"}),
811 awful.key({ modkey, "Control" }, "p", toggle_tag_by_name("ffx"),
812 {description = "toggle tag 'ff'", group = "tag"}),
815 clientkeys = gears.table.join(
816 awful.key({ modkey, }, "f",
818 c.fullscreen = not c.fullscreen
821 {description = "toggle fullscreen", group = "client"}),
822 awful.key({ modkey, "Shift" }, "c", function (c) c:kill() end,
823 {description = "close", group = "client"}),
824 awful.key({ modkey, "Control" }, "space", awful.client.floating.toggle ,
825 {description = "toggle floating", group = "client"}),
826 awful.key({ modkey, "Control" }, "Return", function (c) c:swap(awful.client.getmaster()) end,
827 {description = "move to master", group = "client"}),
828 awful.key({ modkey, }, "z", function (c) c:move_to_screen() end,
829 {description = "move to screen", group = "client"}),
830 awful.key({ modkey, }, "t", function (c) c.ontop = not c.ontop end,
831 {description = "toggle keep on top", group = "client"}),
832 awful.key({ modkey, }, "n",
834 -- The client currently has the input focus, so it cannot be
835 -- minimized, since minimized clients can't have the focus.
838 {description = "minimize", group = "client"}),
839 awful.key({ modkey, }, "m",
841 c.maximized = not c.maximized
842 c.maximized_horizontal = false
843 c.maximized_vertical = false
846 {description = "(un)maximize", group = "client"}),
847 awful.key({ modkey, "Control" }, "m",
849 c.maximized_vertical = not c.maximized_vertical
852 {description = "(un)maximize vertically", group = "client"}),
853 awful.key({ modkey, "Shift" }, "m",
855 c.maximized_horizontal = not c.maximized_horizontal
858 {description = "(un)maximize horizontally", group = "client"})
861 -- Bind all key numbers to tags.
862 -- Be careful: we use keycodes to make it work on any keyboard layout.
863 -- This should map on the top row of your keyboard, usually 1 to 9.
865 globalkeys = gears.table.join(globalkeys,
867 awful.key({ modkey }, "#" .. i + 9, toggle_tag_by_name(tostring(i), true),
868 {description = "view tag #"..i, group = "tag"}),
869 -- Toggle tag display.
870 awful.key({ modkey, "Control" }, "#" .. i + 9, toggle_tag_by_name(tostring(i)),
871 {description = "toggle tag #" .. i, group = "tag"}),
872 -- Move client to tag.
873 awful.key({ modkey, "Shift" }, "#" .. i + 9,
876 local tag = awful.tag.find_by_name(screen.primary, tostring(i))
878 client.focus:move_to_tag(tag)
882 {description = "move focused client to tag #"..i, group = "tag"}),
883 -- Toggle tag on focused client.
884 awful.key({ modkey, "Control", "Shift" }, "#" .. i + 9,
887 local tag = awful.tag.find_by_name(screen.primary, tostring(i))
889 client.focus:toggle_tag(tag)
893 {description = "toggle focused client on tag #" .. i, group = "tag"})
897 clientbuttons = gears.table.join(
898 awful.button({ }, 1, function (c) client.focus = c; c:raise() end),
899 awful.button({ modkey }, 1, awful.mouse.client.move),
900 awful.button({ modkey }, 3, awful.mouse.client.resize))
903 globalkeys = awful.util.table.join(globalkeys,
904 awful.key({ cmdkey }, "n", function () awful.spawn("firefox") end),
905 awful.key({ cmdkey }, "c", function () awful.spawn("chromium --enable-remote-extensions") end),
906 awful.key({ cmdkey }, "y", function () awful.spawn(terminal .. " -e ipython3") end),
907 awful.key({ cmdkey }, "m", function () awful.spawn(terminal .. " -name mutt -e mutt") end),
908 awful.key({ cmdkey }, "t", function () awful.spawn("thunderbird") end),
909 awful.key({ cmdkey }, "g", function () awful.spawn("gscan2pdf") end),
910 awful.key({ cmdkey, "Shift" }, "v", function () awful.spawn("virt-manager") end),
911 awful.key({ cmdkey }, "l", function () awful.spawn("libreoffice") end),
912 awful.key({ cmdkey }, "v", function () awful.spawn("remmina") end),
913 awful.key({ cmdkey }, "p", function () awful.spawn("pavucontrol") end),
914 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),
915 awful.key({ cmdkey }, "x", function ()
916 awful.spawn("xautolock -enable")
917 awful.spawn("xautolock -locknow")
919 awful.key({ cmdkey, "Shift" }, "x", function () awful.spawn("xautolock -disable") end),
921 awful.key({ cmdkey }, "BackSpace", function () awful.spawn("pkill -USR1 offlineimap") end),
924 awful.key(nil, "XF86ScreenSaver", function () awful.spawn("xset dpms force off") end),
925 awful.key(nil, "XF86AudioMute", function () awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") end),
926 awful.key({ cmdkey }, "End", function () awful.spawn("pactl set-sink-mute @DEFAULT_SINK@ toggle") end),
927 awful.key(nil, "XF86AudioLowerVolume", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ -2%") end),
928 awful.key({ cmdkey }, "Next", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ -2%") end),
929 awful.key(nil, "XF86AudioRaiseVolume", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ +2%") end),
930 awful.key({ cmdkey }, "Prior", function () awful.spawn("pactl set-sink-volume @DEFAULT_SINK@ +2%") end),
931 awful.key(nil, "XF86AudioMicMute", function () awful.spawn("pactl set-source-mute @DEFAULT_SOURCE@ toggle") end),
932 awful.key({ cmdkey }, "Home", function () awful.spawn("pactl set-source-mute @DEFAULT_SOURCE@ toggle") end),
933 awful.key({ cmdkey }, "Insert", function () awful.spawn("pa_cycle_default source") end),
934 awful.key({ cmdkey }, "Delete", function () awful.spawn("pa_cycle_default sink") end),
935 awful.key(nil, "XF86MonBrightnessDown", function () awful.spawn("xbacklight -dec 5%") end),
936 awful.key(nil, "XF86MonBrightnessUp", function () awful.spawn("xbacklight -inc 5%") end),
937 awful.key(nil, "XF86Display", function () awful.spawn("autorandr --change --force"); initialise_to_autorandr_profile() end),
938 awful.key(nil, "XF86WLAN", function () awful.spawn("") end),
939 awful.key(nil, "XF86Tools", function () awful.spawn("") end),
940 awful.key(nil, "XF86Search", function () awful.spawn("") end),
941 awful.key(nil, "XF86LaunchA", function () awful.spawn("") end),
942 awful.key(nil, "XF86Explorer", function () awful.spawn("") end),
943 awful.key(nil, "XF86Favorites", function () awful.spawn("systemctl suspend") end),
945 awful.key({ cmdkey }, "Multi_key", function () run_output_notify("flameshot gui", "Output") end),
946 awful.key({ cmdkey, "Shift" }, "Multi_key", function () run_output_notify("flameshot full --delay 2000 --clipboard", "Output") end),
948 awful.key({ cmdkey }, "Up", function () awful.spawn("pap prev") end),
949 awful.key({ cmdkey }, "Left", function () awful.spawn("pap seek -10") end),
950 awful.key({ cmdkey, "Shift" }, "Left", function () awful.spawn("pap seek -60") end),
951 awful.key({ cmdkey }, "Down", function () awful.spawn("pap next") end),
952 awful.key({ cmdkey }, "Right", function () awful.spawn("pap seek +10") end),
953 awful.key({ cmdkey, "Shift" }, "Right", function () awful.spawn("pap seek +60") end),
954 awful.key({ cmdkey }, "space", function () awful.spawn("pap pause") end),
955 awful.key({ cmdkey }, "\\", function () run_output_notify("pap info", "Track info") end),
956 awful.key({ cmdkey }, "]", function () run_output_notify("pap list", "Playlist") end)
959 function run_output_notify(cmd, title)
960 awful.spawn.easy_async(cmd, function(stdout, stderr, reason, exit_code)
963 preset = naughty.config.presets.low,
971 root.keys(globalkeys)
975 -- Rules to apply to new clients (through the "manage" signal).
977 local function float_client_in_the_middle_with_margins(client, leftright, topbottom)
978 local wa = client.screen.workarea
980 client.y = wa.y + topbottom
981 client.height = wa.height - 2*topbottom
983 client.y = wa.y + (wa.height - client.height)/2
986 client.x = wa.x + leftright
987 client.width = wa.width - 2*leftright
989 client.x = wa.x + (wa.width - client.width)/2
993 local function move_to_tag_by_name(s, tagname)
995 local t = awful.tag.find_by_name(s, tagname)
997 error("No tag by the name of " .. tagname)
1004 local function move_to_tag_or_create_volatile(s, tagname)
1006 local t = awful.tag.find_by_name(s, tagname)
1010 th.move_to_new_tag(c, tagname, {}, true, true, true)
1015 awful.rules.rules = {
1016 -- All clients will match this rule.
1018 properties = { border_width = beautiful.border_width,
1019 border_color = beautiful.border_normal,
1020 focus = awful.client.focus.filter,
1023 buttons = clientbuttons,
1024 screen = awful.screen.preferred,
1025 placement = awful.placement.no_overlap+awful.placement.no_offscreen,
1030 { rule = { type = "dialog" },
1031 properties = { floating = true,
1033 skip_taskbar = true,
1036 --switchtotag = true,
1037 placement = awful.placement.centered
1040 { rule = { class = "URxvt" },
1041 properties = { size_hints_honor = false, }
1043 { rule = { instance = "irc" },
1044 callback = move_to_tag_by_name(nil, "irc"),
1046 { rule = { class = "scrcpy" },
1047 callback = move_to_tag_by_name(nil, "[]"),
1049 { rule_any = { class = { "Firefox", "firefox" } },
1050 callback = move_to_tag_by_name(nil, "ffx"),
1052 { rule = { class = "Chromium" },
1053 callback = move_to_tag_by_name(nil, "chr"),
1055 { rule_any = { class = { "thunderbird", "Thunderbird" } },
1056 callback = move_to_tag_by_name(nil, "cal"),
1058 { rule = { instance = "mutt" },
1062 layout = awful.layout.suit.fair.horizontal,
1068 { rule_any = { class = { "zoom" } },
1069 callback = move_to_tag_or_create_volatile(nil, "Zoom"),
1071 { rule_any = { class = { "Ssvnc.tcl" },
1072 class = { "Ssvnc" },
1073 name = { "SSL/SSH VNC Viewer.-" },
1075 callback = move_to_tag_or_create_volatile(nil, "SSVNC"),
1077 { rule_any = { class = {
1081 properties = { floating = true,
1084 placement = awful.placement.centered,
1087 { rule_any = { instance = {
1093 properties = { floating = true,
1096 placement = awful.placement.centered,
1099 { rule_any = { class = {
1104 "Microsoft Teams - Preview",
1105 "org.remmina.Remmina",
1111 except_any = { type = { "dialog" } },
1112 properties = { new_tag = {
1113 layout = layouts.maximised,
1116 --switchtotag = true,
1120 { rule_any = { class = {
1124 except_any = { type = { "dialog" } },
1125 properties = { new_tag = {
1126 layout = layouts.default,
1132 placement = awful.placement.centered,
1137 --XX-- { rule = { class = "Gscan2pdf" },
1138 --XX-- properties = {
1139 --XX-- switchtotag = true
1141 --XX-- callback = move_to_tag(1, 5)
1143 --XX-- { rule = { name = "gscan2pdf .*" },
1144 --XX-- properties = {
1145 --XX-- floating = false,
1148 --XX-- { rule = { class = "Thunar", type = "normal" },
1149 --XX-- properties = {
1150 --XX-- floating = false,
1153 --XX-- { rule = { class = "Pinentry", instance = "pinentry" },
1154 --XX-- properties = {
1155 --XX-- floating = true,
1158 --XX-- { rule = { class = "Gxmessage" },
1159 --XX-- properties = {
1160 --XX-- floating = true,
1168 -- Signal function to execute when a new client appears.
1169 client.connect_signal("manage", function (c)
1170 -- Set the windows at the slave,
1171 -- i.e. put it at the end of others instead of setting it master.
1172 -- if not awesome.startup then awful.client.setslave(c) end
1173 --if not awesome.startup then
1174 -- local t = awful.screen.focused().selected_tag
1175 -- if t.name == "xmutt" then
1176 -- awful.client.setslave(c)
1180 if awesome.startup and
1181 not c.size_hints.user_position
1182 and not c.size_hints.program_position then
1183 -- Prevent clients from being unreachable after screen count changes.
1184 awful.placement.no_offscreen(c)
1187 c.maximized_horizontal = false
1188 c.maximized_vertical = false
1191 -- Add a titlebar if titlebars_enabled is set to true in the rules.
1192 client.connect_signal("request::titlebars", function(c)
1193 -- buttons for the titlebar
1194 local buttons = gears.table.join(
1195 awful.button({ }, 1, function()
1198 awful.mouse.client.move(c)
1200 awful.button({ }, 3, function()
1203 awful.mouse.client.resize(c)
1207 awful.titlebar(c) : setup {
1209 awful.titlebar.widget.iconwidget(c),
1211 layout = wibox.layout.fixed.horizontal
1216 widget = awful.titlebar.widget.titlewidget(c)
1219 layout = wibox.layout.flex.horizontal
1222 awful.titlebar.widget.floatingbutton (c),
1223 awful.titlebar.widget.maximizedbutton(c),
1224 awful.titlebar.widget.stickybutton (c),
1225 awful.titlebar.widget.ontopbutton (c),
1226 awful.titlebar.widget.closebutton (c),
1227 layout = wibox.layout.fixed.horizontal()
1229 layout = wibox.layout.align.horizontal
1233 -- Enable sloppy focus, so that focus follows mouse.
1234 client.connect_signal("mouse::enter", function(c)
1235 if awful.layout.get(c.screen) ~= awful.layout.suit.magnifier
1236 and awful.client.focus.filter(c) then
1239 --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
1240 -- something like this
1243 client.connect_signal("focus", function(c)
1244 c.border_color = beautiful.border_focus
1246 client.connect_signal("unfocus", function(c)
1247 c.border_color = beautiful.border_normal
1250 awful.ewmh.add_activate_filter(function(c, context, hints)
1251 if context == "ewmh" then
1252 if (c.class == "Firefox-esr" or c.class == "Firefox") then
1258 client.connect_signal("request::activate", function(c, context, hints)
1259 if gears.table.hasitem({
1260 "client.focus.byidx",
1262 "autofocus.check_focus",
1266 gears.timer.delayed_call(function()
1267 -- we need a delayed call so that we execute *after layout changes
1268 if hints.raise and c == client.focus and client.focus:isvisible() then
1269 move_mouse_to_area(client.focus)
1275 -- vim:ft=lua:sw=4:sts=4:ts=4:et