diff --git a/user/.chezmoidata/packages.yaml b/user/.chezmoidata/packages.yaml index 33d6d40..4000882 100644 --- a/user/.chezmoidata/packages.yaml +++ b/user/.chezmoidata/packages.yaml @@ -106,13 +106,16 @@ packages: - bitwarden - chezmoi - chromium + - evince - fastfetch - figlet - firefox - fzf - go - grim + - jre-openjdk - jq + - kdeconnect - kitty - librewolf-bin - meld @@ -160,3 +163,8 @@ packages: work_env: yay: - teams-for-linux-bin + - docker + - claude + - claude-code + - webstorm + - webstorm-jre diff --git a/user/.chezmoiignore b/user/.chezmoiignore index 9abc05a..9339ae0 100644 --- a/user/.chezmoiignore +++ b/user/.chezmoiignore @@ -12,6 +12,14 @@ thunderbird .lesshst .thunderbird .bash_history +.camera_driver +.claude +.claude.json +.claude.json.backup +.java +.jbr +.junie +.node_repl_history .config/Signal .config/chezmoi @@ -30,6 +38,13 @@ thunderbird .config/Bitwarden .config/autostart .config/teams-for-linux +.config/Claude +.config/chromium +.config/filezilla +.config/kdeconnect +.config/kitty/kitty.conf.bak +.config/lftp +.config/spicetify .gnupg/crls.d .gnupg/openpgp-revocs.d diff --git a/user/dot_bashrc.tmpl b/user/dot_bashrc.tmpl index acb2fde..e0fdc09 100644 --- a/user/dot_bashrc.tmpl +++ b/user/dot_bashrc.tmpl @@ -72,6 +72,8 @@ alias pcat='bat -pp' # top / htop alias top='btop' alias htop='btop' +# work +alias ia='cd ~/Projects/inso-automation' # ssh [ "$TERM" = "xterm-kitty" ] && alias kssh="kitty +kitten ssh" diff --git a/user/dot_config/DankMaterialShell/settings.json b/user/dot_config/DankMaterialShell/settings.json index 5fafc8f..3851e00 100644 --- a/user/dot_config/DankMaterialShell/settings.json +++ b/user/dot_config/DankMaterialShell/settings.json @@ -364,13 +364,13 @@ "acLockTimeout": 300, "acSuspendTimeout": 0, "acSuspendBehavior": 0, - "acProfileName": "", + "acProfileName": "1", "acPostLockMonitorTimeout": 30, "batteryMonitorTimeout": 600, "batteryLockTimeout": 300, "batterySuspendTimeout": 7200, "batterySuspendBehavior": 2, - "batteryProfileName": "", + "batteryProfileName": "0", "batteryPostLockMonitorTimeout": 60, "batteryChargeLimit": 100, "batteryNotifyChargeLimit": false, @@ -614,13 +614,13 @@ "enabled": true, "clockCompactMode": false }, - "weather" - ], - "rightWidgets": [ + "weather", { "id": "privacyIndicator", "enabled": true - }, + } + ], + "rightWidgets": [ { "id": "capsLockIndicator", "enabled": true diff --git a/user/dot_config/git/ignore b/user/dot_config/git/ignore new file mode 100644 index 0000000..66d62f8 --- /dev/null +++ b/user/dot_config/git/ignore @@ -0,0 +1 @@ +**/.claude/settings.local.json diff --git a/user/dot_config/gtk-3.0/bookmarks b/user/dot_config/gtk-3.0/bookmarks index dd522a7..a867c60 100644 --- a/user/dot_config/gtk-3.0/bookmarks +++ b/user/dot_config/gtk-3.0/bookmarks @@ -2,4 +2,5 @@ file:///home/frank/Documents Documents file:///home/frank/Downloads Downloads file:///home/frank/Pictures Pictures file:///home/frank/Projects Projects +file:///home/frank/Projects/inso-automation inso-automation smb://10.10.10.5/ HOMESERVER diff --git a/user/dot_config/hypr/hyprland-monitors.lua b/user/dot_config/hypr/hyprland-monitors.lua index e27727b..3f93957 100644 --- a/user/dot_config/hypr/hyprland-monitors.lua +++ b/user/dot_config/hypr/hyprland-monitors.lua @@ -1,267 +1,162 @@ --- Monitor configuration and automatic and manual switching-- - ------------------- ----- PROFILES ---- ------------------- - --- Profiles: --- Key of the profile is the name of the profile --- Profiles are ordered by priority, higher number takes precedence over smaller number --- First (by priority) profile that matches will be applied, all others will be ignored --- --- A profile matches the current setup if _ALL_ of its match criteria are fulfilled --- If there are no match criteria, it will match always -local PROFILES = { - -- The most basic fallback if nothing else ever works - fallback = { - priority = -999, - matches = {}, +-- if multiple profiles match, profile with highest priority wins. +-- if no profile match at all, the fallback_profile will be applied anyways. +local fallback_profile="laptop" +local profiles = { + home = { + priority = 10, monitors = { - { - output = "", - mode = "preferred", - position = "auto", - scale = 1, - disabled = false, - }, + "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52", + "desc:Dell Inc. DELL U2724D DL7R834", + "desc:Dell Inc. DELL U2414H 292K475V26JL", + }, + disable_other_monitors = true, + monitor_config = { + ["desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52"] = {disabled=false, scale=1, position="0x0", mode="3440x1440@60"}, + ["desc:Dell Inc. DELL U2724D DL7R834"] = {disabled=false, scale=1, position="3440x0", mode="2556x1440@60"}, + ["desc:Dell Inc. DELL U2414H 292K475V26JL"] = {disabled=false, scale=1, position="760x-1080", mode="1920x1080@60"}, + }, + workspace_rules = { + }, + }, + work = { + priority = 10, + monitors = { + "eDP-1", + "desc:Dell Inc. DELL U2724DE BD19MF4", + "desc:Dell Inc. DELL U2724D 1CQFMF4", + }, + disable_other_monitors = false, + monitor_config = { + ["eDP-1"] = {disabled=false, scale=1, position="0x0", mode="1920x1200@120"}, + ["desc:Dell Inc. DELL U2724DE BD19MF4"] = {disabled=false, scale=1, position="1920x0", mode="2560x1440@120"}, + ["desc:Dell Inc. DELL U2724D 1CQFMF4"] = {disabled=false, scale=1, position="4480x0", mode="2560x1440@120"}, + }, + workspace_rules = { + }, }, laptop = { priority = 0, - matches = {{ output = "eDP-1" }}, monitors = { - { - output = "eDP-1", - mode = "1920x1200@120", - position = "0x0", - scale = 1, - disabled = false, - }, + "eDP-1", }, - }, - home_docked = { - priority = 10, - matches = { - { output = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52" }, - { output = "desc:Dell Inc. DELL U2414H 292K475V26JL" }, - { output = "desc:Dell Inc. DELL U2724D DL7R834" }, + disable_other_monitors = false, + monitor_config = { + ["eDP-1"] = {disabled=false, scale=1, position="0x0", mode="1920x1200@120"}, }, - monitors = { - { - output = "eDP-1", - mode = "preferred", - position = "0x0", - scale = 1, - disabled = true, - }, - { - output = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52", - mode = "3440x1440@60", - position = "0x0", - scale = 1, - disabled = false, - }, - { - output = "desc:Dell Inc. DELL U2414H 292K475V26JL", - mode = "1920x1080@60", - position = "760x-1080", - scale = 1, - disabled = false, - }, - { - output = "desc:Dell Inc. DELL U2724D DL7R834", - mode = "2560x1440@60", - position = "3440x0", - scale = 1, - disabled = false, - }, - }, - postprocess = function() - debug_notify("now applying workspace rules") - for i = 1,5 do - hl.workspace_rule({ workspace = string.format("%d", i), monitor = "desc:GIGA-BYTE TECHNOLOGY CO. LTD. M34WQ 0x00000B52"}) - end - hl.workspace_rule({ workspace = "1", default = true, persistent = true}) - for i = 6,9 do - hl.workspace_rule({ workspace = string.format("%d", i), monitor = "desc:Dell Inc. DELL U2724D DL7R834"}) - end - hl.workspace_rule({ workspace = "9", default = true, persistent = true}) - hl.workspace_rule({ workspace = "10", monitor = "desc:Dell Inc. DELL U2414H 292K475V26JL", default = true, persistent = true}) - - hl.dispatch(hl.dsp.focus({workspace = 10})) - hl.dispatch(hl.dsp.focus({workspace = 9})) - hl.dispatch(hl.dsp.focus({workspace = 1})) - end - }, + workspace_rules = { + } + } } -local function refresh_monitors() - hl.exec_cmd("hyprctl monitors all -j | jq -r '.[] | [.name, .description] | @tsv' > /tmp/hypr_monitors.tsv") -end -local function get_monitors() - -- FIXME: Use hl.get_monitors({all=true}) as soon as it is released - local handle = io.open("/tmp/hypr_monitors.tsv", "r") - if handle ~= nil then - local out = handle:read("*a") - handle:close() - local result = {} - for line in out:gmatch("[^\n]+") do - local name, desc = line:match("([^\t]+)\t(.+)") - table.insert(result, { name = name, description = desc }) - end - return result - end - return {} -end +local apply_monitor_request_queue = {} -local function get_matching_profile() - local monitors = get_monitors() - local profiles = {} or {} +local function apply_selected_profile(profile_name, profile) + -- do we want to disable other monitors that are not used in this profile? + if profile.disable_other_monitors then + local monitors = hl.get_monitors() + table.insert(monitors, hl.get_monitor("eDP-1")) - local monitor_debug = map(monitors, function(monitor) - return monitor.name .. ": "..monitor.description - end) - debug_notify("Currently " .. #monitors .. " connected: " .. table.concat(monitor_debug, "; ")) - - for profile_name, profile in pairs(PROFILES) do - profile.name = profile_name or "unknown" - table.insert(profiles, profile) - end - table.sort(profiles, function(a, b) return (a.priority or 0) > (b.priority or 0) end) - - for _, profile in ipairs(profiles) do - local matches = profile.matches or {} - local has_matched = {} - for _, match in ipairs(matches) do - if starts_with(match.output, "desc:") then - table.insert(has_matched, any(monitors, function(m) return "desc:" .. m.description == match.output end)) - else - table.insert(has_matched, any(monitors, function(m) return m.name == match.output end)) + for _, monitor in ipairs(monitors) do + if monitor ~= nil then + local name = monitor.name + local description = monitor.description + if not any( + profile.monitors, + function(wanted) + return + wanted == name or + wanted == "desc:"..description + end + ) then + debug_notify("Disabling output "..name.." ("..description..")") + hl.monitor({output = name, disabled = true}) + end end end - - if #has_matched == 0 then - debug_notify("Monitor profile " .. profile.name .. " is active because it does not require any matches (fallback)") - return profile - elseif all(has_matched, function(v) return v end) then - return profile - else - local failed = map(has_matched, function(v, i) - if not v then - return matches[i].output - else - return "" - end - end) - local failedmsg = table.concat(failed, " ") - debug_notify("Monitor profile " .. profile.name .. " does not match, could not match " .. failedmsg) - end end - return nil + + -- use the configuration in the profile and apply it to hyprland + for _, monitor_selector in ipairs(profile.monitors) do + local config = profile.monitor_config[monitor_selector] or {} + config.output = monitor_selector + hl.monitor(config) + end + debug_notify("Profile " .. profile_name .. " was applied") end -local PROFILE_CHANGE_ONGOING = false -local PROFILE_CHANGE_RESET_TIMER = nil -local PROFILE_CHANGE_START_TIMER = nil -local POSTPROCESS_TIMER = nil - -local function apply_profile(profile) - if PROFILE_CHANGE_ONGOING then - debug_notify("Monitor profile change is inprogress (debounce)") +local function apply_monitor_profile() + if #apply_monitor_request_queue < 1 then return end - if profile == nil then - debug_notify("No monitor profile available") + table.remove(apply_monitor_request_queue) + + -- try to find all profiles that match current monitors + local matching_profiles = {} + for profile_name, profile in pairs(profiles) do + if all( + profile.monitors, + function(monitor_selector) + local found = + -- if the monitor exists, hyprland should be able to return this monitor + hl.get_monitor(monitor_selector) ~= nil + if not found then + debug_notify("not able to find monitor "..monitor_selector.." for profile "..profile_name) + end + return found + end + ) + then + table.insert(matching_profiles, {name = profile_name, profile = profile}) + end + end + + -- if no profile was found, do nothing + if #matching_profiles < 1 then + local profile = profiles[fallback_profile] or nil + if profile == nil then + debug_notify("No profiles are matching the current monitors and no fallback with name '"..fallback_profile.."' available!") + return + end + debug_notify("No profiles are matching the current monitors, applying fallback") + apply_selected_profile("fallback", profile) return end - debug_notify("Applying monitor profile " .. profile.name) - PROFILE_CHANGE_ONGOING = true - - -- delay application of the profile for some time, as other monitor change events might still be arriving - PROFILE_CHANGE_START_TIMER = hl.timer(function() - - -- after we have started applying our profile, we will generate monitor change events that we do not - -- want to process. Assume 5 seconds of non-interesting monitor events that we do not want to process - -- afterwards, reset the PROFILE_CHANGE_ONGOING flag for the next time we actually want to change - -- monitor profiles - PROFILE_CHANGE_RESET_TIMER = hl.timer(function() - PROFILE_CHANGE_ONGOING = false - debug_notify("Monitor Profile Change Debounce Finished") - PROFILE_CHANGE_RESET_TIMER = nil - end, { timeout = 5000, type = "oneshot" }) - - local monitors = profile.monitors - for _, monitor in ipairs(monitors) do - hl.monitor(monitor) - end - - debug_notify("Monitor Profile " .. profile.name .. " successfully applied") - - -- start any post processing - if profile.postprocess ~= nil then - POSTPROCESS_TIMER = hl.timer(function() - if profile.postprocess ~= nil then - profile.postprocess() - end - - PROFILE_CHANGE_START_TIMER = nil - POSTPROCESS_TIMER = nil - end, { timeout = 200, type = "oneshot" }) - else - PROFILE_CHANGE_START_TIMER = nil - end - end, { timeout = 500, type = "oneshot" }) + -- if multiple profiles are matching, select the correct one by priority + table.sort(matching_profiles, function(a, b) return a.profile.priority > b.profile.priority end) + local matching_profile = matching_profiles[1] + local profile_name, profile = matching_profile.name, matching_profile.profile + debug_notify("Matching monitor profile found: " .. profile_name) + apply_selected_profile(profile_name, profile) end -local function apply_current_profile() - apply_profile(get_matching_profile()) +local monitor_profile_timer = nil +local function request_apply_monitor_profile(data) + debug_notify("requested monitor profile update") + table.insert(apply_monitor_request_queue, data or {}) + if monitor_profile_timer == nil or not monitor_profile_timer:is_enabled() then + monitor_profile_timer = hl.timer(apply_monitor_profile, { timeout = 3000, type = "repeat" }) + debug_notify("monitor profile apply timer has been restarted") + end end -local function force_refresh_profile() - if PROFILE_CHANGE_RESET_TIMER ~= nil then PROFILE_CHANGE_RESET_TIMER:set_enabled(false) end - if POSTPROCESS_TIMER ~= nil then POSTPROCESS_TIMER:set_enabled(false) end - if PROFILE_CHANGE_START_TIMER ~= nil then PROFILE_CHANGE_START_TIMER:set_enabled(false) end +hl.on("hyprland.start", function() + debug_notify("hyprland start :)") + hl.timer(function() + hl.monitor({output = "eDP-1", disabled = false}) + hl.dispatch(function() request_apply_monitor_profile() end) + end, { timeout = 1000, type = "oneshot" }) +end) - PROFILE_CHANGE_RESET_TIMER = nil - POSTPROCESS_TIMER = nil - PROFILE_CHANGE_START_TIMER = nil - PROFILE_CHANGE_ONGOING = false - - debug_notify("Force applying monitor profile") - refresh_monitors() - apply_current_profile() -end - -local function on_lid_close() - debug_notify("Lid was closed") - refresh_monitors() - hl.monitor({ output = "eDP-1", disabled = true }) -end - -local function on_lid_open() - debug_notify("Lid was opened") - refresh_monitors() - apply_current_profile() -end - -local function on_monitor_added(_event) - debug_notify("A monitor was added") - refresh_monitors() - apply_current_profile() -end - -local function on_monitor_removed(_event) - debug_notify("A monitor was removed") - refresh_monitors() - apply_current_profile() -end - -hl.bind("switch:on:Lid Switch", on_lid_close, { locked = true }) -hl.bind("switch:off:Lid Switch", on_lid_open, { locked = true }) -hl.bind("SUPER + P", function() force_refresh_profile() end, { locked = true, description = "Force Refresh Monitor Profile" }) -hl.on("monitor.added", on_monitor_added) -hl.on("monitor.removed", on_monitor_removed) -hl.on("hyprland.start", function() refresh_monitors() end) +hl.on("monitor.layout_changed", request_apply_monitor_profile) +hl.bind("SUPER + P", function() + hl.monitor({output = "eDP-1", disabled = true}) + request_apply_monitor_profile() +end, {locked=true, description="Detect & Apply Monitor Profile"}) +hl.bind("SUPER + SHIFT + P", function() + hl.monitor({output = "eDP-1", disabled = false}) + hl.dispatch(function() request_apply_monitor_profile() end) +end, {locked=true, description="Detect & Apply Monitor Profile"}) diff --git a/user/dot_config/hypr/hyprland-windowrules.lua b/user/dot_config/hypr/hyprland-windowrules.lua index 2f7faa1..ebe4e9e 100644 --- a/user/dot_config/hypr/hyprland-windowrules.lua +++ b/user/dot_config/hypr/hyprland-windowrules.lua @@ -217,6 +217,10 @@ rule( { matches_class("^(org.gnome.seahorse.Application)$") }, { float(), center(), size(800, 600) } ) +rule( + { matches_class("^(hyprland-share-picker)$") }, + { float(), center(), pin() } +) -- Nemo rule( @@ -277,3 +281,9 @@ rule( { float(), size(700, 600), center(), pin() } ) +-- Teams +rule( + { matches_title("^(Teams for Linux - Screen is being shared)$") }, + { float(), size(600, 300), pin() } +) + diff --git a/user/dot_config/mimeapps.list b/user/dot_config/mimeapps.list index 4adb15d..beb4df8 100644 --- a/user/dot_config/mimeapps.list +++ b/user/dot_config/mimeapps.list @@ -35,6 +35,9 @@ x-scheme-handler/snews=userapp-Thunderbird-AH40S3.desktop x-scheme-handler/unknown=librewolf.desktop x-scheme-handler/webcal=userapp-Thunderbird-X7G9S3.desktop x-scheme-handler/webcals=userapp-Thunderbird-X7G9S3.desktop +x-scheme-handler/claude=claude-desktop.desktop +x-scheme-handler/jetbrains=jetbrainsd.desktop +x-scheme-handler/claude-cli=claude-code-url-handler.desktop [Added Associations] application/pdf=librewolf.desktop; diff --git a/user/dot_gitconfig.tmpl b/user/dot_gitconfig.tmpl index 1281ebc..46543cf 100644 --- a/user/dot_gitconfig.tmpl +++ b/user/dot_gitconfig.tmpl @@ -43,7 +43,7 @@ updateRefs = true [branch] - sort = -comitterdate + sort = -committerdate autosetuprebase = remote autosetupmerge = true