diff --git a/libs/parser_test.lua b/libs/parser_test.lua index caa453e..53dc96a 100644 --- a/libs/parser_test.lua +++ b/libs/parser_test.lua @@ -30,23 +30,22 @@ shell = "zsh" # Format: (++...)+ = "" # "modkey" as modifier will be substituted for modkey variable in [global] [keys] -modkey+Up = ":root.client_next" -modkey+Down = ":root.client_previous" -modkey+Control+Up = ":root.screen_next" -modkey+Control+Down = ":root.screen_previous" -modkey+Tab = ":root.client_swap" -modkey+Return = ":root.spawn_terminal" -modkey+Shift+Return = ":root.spawn_browser" +"modkey+Up" = ":root.client_next" +"modkey+Down" = ":root.client_previous" +"modkey+Control+Up" = ":root.screen_next" +"modkey+Control+Down" = ":root.screen_previous" +"modkey+Tab" = ":root.client_swap" +"modkey+Return" = ":root.spawn_terminal" +"modkey+Shift+Return" = ":root.spawn_browser" # Client keys only work if a focused client exists -modkey+Shift+c = ":client.kill" -modkey+t = ":client.cycle_screen" -modkey+o = ":client.ontop" -modkey+b = ":client.below" -modkey+f = ":client.fullscreen" -modkey+n = ":client.minimize" -modkey+m = ":client.maximize" - +"modkey+Shift+c" = ":client.kill" +"modkey+t" = ":client.cycle_screen" +"modkey+o" = ":client.ontop" +"modkey+b" = ":client.below" +"modkey+f" = ":client.fullscreen" +"modkey+n" = ":client.minimize" +"modkey+m" = ":client.maximize" ]] for k,v in pairs(parsers.conf(data)) do print("Block: ["..k.."]") diff --git a/libs/parsers.lua b/libs/parsers.lua index 275c790..088a6cf 100644 --- a/libs/parsers.lua +++ b/libs/parsers.lua @@ -10,7 +10,7 @@ local parsers = {} local function split_strings(text) - -- probably the cleanest function to split by strings i've written + -- probably the cleanest function to split by strings i've written to date local split = {} while text:find("\"") do local strstart = text:find("\"") @@ -86,48 +86,74 @@ parsers.yaml_pseudo = function(cfgtext) return struct end +local function quotestrip(txt) + if (txt:sub(1,1):match("['\"]")) + and (txt:sub(-1,-1) == txt:sub(1,1)) then + return txt:sub(2,-2) + else + return txt + end +end + + parsers.conf = function(cfgtext) -- Conf style parser (not exactly TOML) cfgtext = cfgtext:gsub("#[^\n]*","") local split_by_strings,err = split_strings(cfgtext) - if not split_by_strings then - error(err) + if not split_by_strings then error(err) end + local full_split = {{}} + local current_line = full_split[1] + -- tokenizer + for _,v in pairs(split_by_strings) do + v = v:match("^[ \t]*(.*)[ \t]*$") + if (not (v == "")) then + if not v:match("^\".*\"$") then + v:gsub("[^ \t]+",function(text) + while text:match("\n") do + local before,after = text:match("([^\n]*)\n(.*)") + if before ~= "" then + table.insert(current_line,before) + end + if #current_line > 0 then + table.insert(full_split,{}) + current_line = full_split[#full_split] + end + text = after + end + if text ~= "" then + table.insert(current_line,text) + end + end) + else + table.insert(current_line,v) + end + end end + table.remove(full_split,#full_split) local struct = {global = {}} local block = "global" - local last_string_key = nil - local err - for k,v in pairs(split_by_strings) do - if not v:match("^\".*\"$") then - v:gsub("[^\n]*",function(line) - -- Nothing - if line:match("^%s*$") then - return - end - -- Namespace block - if line:match("^%s*%[[^%]]-%]%s*$") then - block = line:match("%[([^%]]-)%]") - struct[block] = {} - return - end - -- String/Multiline string assignment - if line:match("^%s*[^=]-%s*=%s*$") then - last_string_key = line:match("^%s*([^=]-)%s*=%s*$") - return - end - -- Number/boolean assignment - local key,value = line:match("^%s*([^=]-)%s*=%s*(.-)%s*$") - -- number - if value:match("^[%d%.]*$") then - value = tonumber(value) - -- bool - elseif (value:lower() == "yes") or (value:lower() == "no") then - value = (value:lower() == "yes") - end - struct[block][key] = value - end) - else - struct[block][last_string_key] = v:sub(2,-2) + -- parser + for _,line in pairs(full_split) do + if line[1] and line[1]:match("^%[[^%]]+%]$") then -- block + block = line[1]:match("^%[([^%]]+)%]$") + struct[block] = {} + elseif #line == 3 then -- assignment + if (line[3]:sub(1,1):match("['\"]")) -- string + and (line[3]:sub(-1,-1) == line[3]:sub(1,1)) then + struct[block][quotestrip(line[1])] = quotestrip(line[3]) + elseif line[3]:match("^%d+$") then -- number + struct[block][quotestrip(line[1])] = tonumber(line[3]) + elseif (line[3] == "true") or (line[3] == "false") then -- boolean + struct[block][quotestrip(line[1])] = (line[3] == "true") + else + error("Invalid assignment expression: "..line[3]) + end + else -- invalid + local textline = "" + for _,v in pairs(line) do + textline = textline..v.." " + end + error("Invalid config expression: "..textline:sub(1,-2)) end end return struct diff --git a/modules/autostart.lua b/modules/autostart.lua index 7369869..2b1dc55 100644 --- a/modules/autostart.lua +++ b/modules/autostart.lua @@ -5,11 +5,82 @@ -- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see . --- XFCE style autostart system +-- XFCE style autostart system with a system to automatically kill children just to fuck over Steam. (now with SMЯT targeting software package!) local awful = require("awful") local gears = require("gears") local gfs = gears.filesystem local menu_utils = require("menubar.utils") +local hide_ids = {} +local related_ids = {} +local settings = config.autostart +local stop_checking = false +-- I know this is linux specific, blame Steam for creating a triple-forking launcher with no startup id. +-- I love the fact that valve is supportive of linux and thinks it's the future of gaming and all that +-- but you could've just done the due diligence and, yk, maybe research how things work with XDG? +-- P.S. if you know how to make this function work in similar vein on BSD, feel free to contribute +local function is_child_of(pid,related) + related = related or pid + local ppidfile = io.open("/proc/"..tostring(pid).."/status","rb") + if not ppidfile then return false end + local ppid = ppidfile:read("*a"):match("PPid:%s*(%d+)") + ppidfile:close() + if (not ppid) or (ppid == "1") then return false end + if hide_ids[tonumber(ppid)] then + related_ids[related] = tonumber(ppid) + return true + else + return is_child_of(ppid,related) + end +end +-- Play whack-a-mole with the clients that match ids to hide +-- NO MORE MR NICE GUY, until the user EXPLICITLY activates the client, +-- it's being hidden. +local callback = function(c) + if not settings.minimize_enable then return end + if stop_checking then return end + gears.timer.delayed_call(function() + local kill_later = false + if c.pid and hide_ids[c.pid] then + kill_later = true + end + if c.startup_id and hide_ids[c.startup_id] then + kill_later = true + end + if c.pid and is_child_of(c.pid) then + kill_later = true + end + if kill_later then + c.minimized = true + end + end) +end +client.connect_signal("focus",callback) +client.connect_signal("manage",callback) +-- if the client has been mouse pressed we no longer hide it or any of its siblings - user needs the client to be active. +client.connect_signal("request::activate",function(c,reason) + if (reason ~= "mouse_click") and (reason ~= "tasklist") then + return + end + if c.pid then + hide_ids[c.pid] = nil + if related_ids[c.pid] then + hide_ids[related_ids[c.pid]] = nil + end + end + if c.startup_id then + hide_ids[c.startup_id] = nil + end +end) +-- this ain't happy hour - stop hitting everything in sight. +gears.timer { + timeout = settings.minimize_timeout or 30, + autostart = true, + single_shot = true, + callback = function() + stop_checking = true + hide_ids = {} + end +} local stdir = os.getenv("XDG_RUNTIME_DIR").."/.awesome_startup/" gfs.make_directories(stdir) awful.spawn.with_line_callback("find "..gfs.get_xdg_config_home().."autostart/ -name *.desktop",{ @@ -17,8 +88,16 @@ awful.spawn.with_line_callback("find "..gfs.get_xdg_config_home().."autostart/ - local data = menu_utils.parse_desktop_file(line) if (data.RunHook == "0") or (data.RunHook == nil) then if not gfs.file_readable(stdir..line:match("[^/]*$")) then - io.open(stdir..line:match("[^/]*$"),"w"):close() - awful.spawn(data.Exec:gsub("%%%w","")) + local npid,nsnid = awful.spawn(data.Exec:gsub("%%%w","")) + io.open(stdir..line:match("[^/]*$"),"w"):write(npid):close() + if data.Hidden then + if npid then + hide_ids[npid] = true + end + if nsnid then + hide_ids[nsnid] = true + end + end end end end diff --git a/modules/rules_stub.lua b/modules/rules_stub.lua index ae1d402..d4cec7a 100644 --- a/modules/rules_stub.lua +++ b/modules/rules_stub.lua @@ -1,10 +1,3 @@ --- This file is part of Reno desktop. --- --- Reno desktop is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. --- --- Reno desktop is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License along with Reno desktop. If not, see . local awful = require("awful") local gears = require("gears") awful.rules.rules = gears.table.join(awful.rules.rules, { @@ -16,14 +9,10 @@ awful.rules.rules = gears.table.join(awful.rules.rules, { }}, properties = {inhibit_compositor = true}, }, - { rule_any = { class = { - "thunderbird" - }}, - properties = {callback = function(c) - gears.timer.delayed_call(function() - c.minimized = true - end) - end} + { rule = { name = "notificationtoasts.*" }, + properties = { + focusable = false + } }, { rule = { fullscreen = true }, properties = { diff --git a/rc.lua b/rc.lua index 5e8b65d..e2c3855 100644 --- a/rc.lua +++ b/rc.lua @@ -18,11 +18,11 @@ require("modules.collect_garbage") require("modules.global") require("modules.powermanX") require("modules.base") +require("modules.autostart") require("modules.rules_stub") require("modules.compositor") require("modules.binds") require("modules.xdg_data") -require("modules.autostart") require("modules.static_tags") require("modules.tiling") require("modules.desktop")