diff --git a/profiles/work/home.nix b/profiles/work/home.nix
index 031cc3c..271e111 100644
--- a/profiles/work/home.nix
+++ b/profiles/work/home.nix
@@ -231,4 +231,6 @@
name = if (config.stylix.polarity == "dark") then "Papirus-Dark" else "Papirus-Light";
};
+ services.pasystray.enable = true;
+
}
diff --git a/user/wm/hyprland/hyprland.nix b/user/wm/hyprland/hyprland.nix
index c7817f1..e896110 100644
--- a/user/wm/hyprland/hyprland.nix
+++ b/user/wm/hyprland/hyprland.nix
@@ -45,6 +45,7 @@ in
env = QT_AUTO_SCREEN_SCALE_FACTOR,1
env = QT_WAYLAND_DISABLE_WINDOWDECORATION,1
env = CLUTTER_BACKEND,wayland
+ env = GDK_PIXBUF_MODULE_FILE,${pkgs.librsvg}/lib/gdk-pixbuf-2.0/2.10.0/loaders.cache
exec-once = hyprprofile Default
@@ -459,7 +460,6 @@ in
hypridle
hyprpaper
fnott
- fuzzel
keepmenu
pinentry-gnome3
wev
@@ -759,6 +759,7 @@ in
sed -i 's/zext_workspace_handle_v1_activate(workspace_handle_);/const std::string command = "hyprctl dispatch focusworkspaceoncurrentmonitor " + std::to_string(id());\n\tsystem(command.c_str());/g' src/modules/wlr/workspace_manager.cpp
sed -i 's/gIPC->getSocket1Reply("dispatch workspace " + std::to_string(id()));/gIPC->getSocket1Reply("dispatch focusworkspaceoncurrentmonitor " + std::to_string(id()));/g' src/modules/hyprland/workspaces.cpp
'';
+ patches = [./patches/waybarpaupdate.patch ./patches/waybarbatupdate.patch];
});
settings = {
mainBar = {
@@ -768,28 +769,70 @@ in
margin = "7 7 3 7";
spacing = 2;
- modules-left = [ "custom/os" "custom/hyprprofile" "battery" "backlight" "keyboard-state" "pulseaudio" "cpu" "memory" ];
- modules-center = [ "hyprland/workspaces" ];
- modules-right = [ "idle_inhibitor" "tray" "clock" ];
+ modules-left = [ "group/power" "group/battery" "group/backlight" "group/cpu" "group/memory" "group/pulseaudio" "keyboard-state" ];
+ modules-center = [ "custom/hyprprofile" "hyprland/workspaces" ];
+ modules-right = [ "group/time" "idle_inhibitor" "tray" ];
"custom/os" = {
"format" = " {} ";
"exec" = ''echo "" '';
"interval" = "once";
"on-click" = "nwggrid-wrapper";
+ "tooltip" = false;
+ };
+ "group/power" = {
+ "orientation" = "horizontal";
+ "drawer" = {
+ "transition-duration" = 500;
+ "children-class" = "not-power";
+ "transition-left-to-right" = true;
+ };
+ "modules" = [
+ "custom/os"
+ "custom/hyprprofileicon"
+ "custom/lock"
+ "custom/quit"
+ "custom/power"
+ "custom/reboot"
+ ];
+ };
+ "custom/quit" = {
+ "format" = "";
+ "tooltip" = false;
+ "on-click" = "hyprctl dispatch exit";
+ };
+ "custom/lock" = {
+ "format" = "";
+ "tooltip" = false;
+ "on-click" = "hyprlock";
+ };
+ "custom/reboot" = {
+ "format" = "";
+ "tooltip" = false;
+ "on-click" = "reboot now";
+ };
+ "custom/power" = {
+ "format" = "";
+ "tooltip" = false;
+ "on-click" = "shutdown now";
+ };
+ "custom/hyprprofileicon" = {
+ "format" = "";
+ "on-click" = "hyprprofile-dmenu";
+ "tooltip" = false;
};
"custom/hyprprofile" = {
- "format" = " {}";
+ "format" = " {}";
"exec" = ''cat ~/.hyprprofile'';
"interval" = 3;
"on-click" = "hyprprofile-dmenu";
};
"keyboard-state" = {
"numlock" = true;
- "format" = " {icon} ";
+ "format" = "{icon}";
"format-icons" = {
- "locked" = "";
- "unlocked" = "";
+ "locked" = " ";
+ "unlocked" = " ";
};
};
"hyprland/workspaces" = {
@@ -813,25 +856,10 @@ in
"on-click" = "activate";
"on-scroll-up" = "hyprctl dispatch workspace e+1";
"on-scroll-down" = "hyprctl dispatch workspace e-1";
- #"all-outputs" = true;
- #"active-only" = true;
+ "all-outputs" = false;
+ "active-only" = false;
"ignore-workspaces" = ["scratch" "-"];
- #"show-special" = false;
- #"persistent-workspaces" = {
- # # this block doesn't seem to work for whatever reason
- # "eDP-1" = [1 2 3 4 5 6 7 8 9];
- # "DP-1" = [1 2 3 4 5 6 7 8 9];
- # "HDMI-A-1" = [1 2 3 4 5 6 7 8 9];
- # "1" = ["eDP-1" "DP-1" "HDMI-A-1"];
- # "2" = ["eDP-1" "DP-1" "HDMI-A-1"];
- # "3" = ["eDP-1" "DP-1" "HDMI-A-1"];
- # "4" = ["eDP-1" "DP-1" "HDMI-A-1"];
- # "5" = ["eDP-1" "DP-1" "HDMI-A-1"];
- # "6" = ["eDP-1" "DP-1" "HDMI-A-1"];
- # "7" = ["eDP-1" "DP-1" "HDMI-A-1"];
- # "8" = ["eDP-1" "DP-1" "HDMI-A-1"];
- # "9" = ["eDP-1" "DP-1" "HDMI-A-1"];
- #};
+ "show-special" = false;
};
"idle_inhibitor" = {
@@ -845,43 +873,106 @@ in
#"icon-size" = 21;
"spacing" = 10;
};
- clock = {
+ "clock#time" = {
"interval" = 1;
- "format" = "{:%a %Y-%m-%d %I:%M:%S %p}";
+ "format" = "{:%I:%M:%S %p}";
"timezone" = "America/Chicago";
"tooltip-format" = ''
{:%Y %B}
{calendar}'';
};
- cpu = {
- "format" = "{usage}% ";
+ "clock#date" = {
+ "interval" = 1;
+ "format" = "{:%a %Y-%m-%d}";
+ "timezone" = "America/Chicago";
+ "tooltip-format" = ''
+ {:%Y %B}
+ {calendar}'';
};
- memory = { "format" = "{}% "; };
+ "group/time" = {
+ "orientation" = "horizontal";
+ "drawer" = {
+ "transition-duration" = 500;
+ "transition-left-to-right" = false;
+ };
+ "modules" = [ "clock#time" "clock#date" ];
+ };
+
+ cpu = { "format" = ""; };
+ "cpu#text" = { "format" = "{usage}%"; };
+ "group/cpu" = {
+ "orientation" = "horizontal";
+ "drawer" = {
+ "transition-duration" = 500;
+ "transition-left-to-right" = true;
+ };
+ "modules" = [ "cpu" "cpu#text" ];
+ };
+
+ memory = { "format" = ""; };
+ "memory#text" = { "format" = "{}%"; };
+ "group/memory" = {
+ "orientation" = "horizontal";
+ "drawer" = {
+ "transition-duration" = 500;
+ "transition-left-to-right" = true;
+ };
+ "modules" = [ "memory" "memory#text" ];
+ };
+
backlight = {
- "format" = "{percent}% {icon}";
+ "format" = "{icon}";
"format-icons" = [ "" "" "" "" "" "" "" "" "" ];
};
+ "backlight#text" = { "format" = "{percent}%"; };
+ "group/backlight" = {
+ "orientation" = "horizontal";
+ "drawer" = {
+ "transition-duration" = 500;
+ "transition-left-to-right" = true;
+ };
+ "modules" = [ "backlight" "backlight#text" ];
+ };
+
battery = {
"states" = {
- "good" = 95;
+ "good" = 75;
"warning" = 30;
"critical" = 15;
};
- "format" = "{capacity}% {icon}";
- "format-charging" = "{capacity}% ";
- "format-plugged" = "{capacity}% ";
- #"format-good" = ""; # An empty format will hide the module
- #"format-full" = "";
- "format-icons" = [ "" "" "" "" "" ];
+ "fullat" = 80;
+ "format" = "{icon}";
+ "format-charging" = "";
+ "format-plugged" = "";
+ "format-full" = "";
+ "format-icons" = [ "" "" "" "" "" "" "" "" "" "" ];
+ "interval" = 10;
+ };
+ "battery#text" = {
+ "states" = {
+ "good" = 75;
+ "warning" = 30;
+ "critical" = 15;
+ };
+ "fullat" = 80;
+ "format" = "{capacity}%";
+ };
+ "group/battery" = {
+ "orientation" = "horizontal";
+ "drawer" = {
+ "transition-duration" = 500;
+ "transition-left-to-right" = true;
+ };
+ "modules" = [ "battery" "battery#text" ];
};
pulseaudio = {
"scroll-step" = 1;
- "format" = "{volume}% {icon} {format_source}";
- "format-bluetooth" = "{volume}% {icon} {format_source}";
- "format-bluetooth-muted" = " {icon} {format_source}";
- "format-muted" = " {format_source}";
- "format-source" = "{volume}% ";
- "format-source-muted" = " ";
+ "format" = "{icon}";
+ "format-bluetooth" = "{icon}";
+ "format-bluetooth-muted" = "";
+ "format-muted" = "";
+ "format-source" = "";
+ "format-source-muted" = "";
"format-icons" = {
"headphone" = "";
"hands-free" = "";
@@ -893,6 +984,24 @@ in
};
"on-click" = "pypr toggle pavucontrol && hyprctl dispatch bringactivetotop";
};
+ "pulseaudio#text" = {
+ "scroll-step" = 1;
+ "format" = "{volume}%";
+ "format-bluetooth" = "{volume}%";
+ "format-bluetooth-muted" = "";
+ "format-muted" = "";
+ "format-source" = "{volume}%";
+ "format-source-muted" = "";
+ "on-click" = "pypr toggle pavucontrol && hyprctl dispatch bringactivetotop";
+ };
+ "group/pulseaudio" = {
+ "orientation" = "horizontal";
+ "drawer" = {
+ "transition-duration" = 500;
+ "transition-left-to-right" = true;
+ };
+ "modules" = [ "pulseaudio" "pulseaudio#text" ];
+ };
};
};
style = ''
@@ -948,7 +1057,7 @@ in
}
#workspaces button {
- padding: 0 7px;
+ padding: 0px 6px;
background-color: transparent;
color: #'' + config.lib.stylix.colors.base04 + '';
}
@@ -973,7 +1082,6 @@ in
color: #'' + config.lib.stylix.colors.base09 + '';
}
- #clock,
#battery,
#cpu,
#memory,
@@ -988,16 +1096,44 @@ in
#mode,
#idle_inhibitor,
#scratchpad,
+ #custom-hyprprofileicon,
+ #custom-quit,
+ #custom-lock,
+ #custom-reboot,
+ #custom-power,
#mpd {
- padding: 0 10px;
+ padding: 0 3px;
color: #'' + config.lib.stylix.colors.base07 + '';
border: none;
border-radius: 8px;
}
+ #custom-hyprprofileicon,
+ #custom-quit,
+ #custom-lock,
+ #custom-reboot,
+ #custom-power,
+ #idle_inhibitor {
+ background-color: transparent;
+ color: #'' + config.lib.stylix.colors.base04 + '';
+ }
+
+ #custom-hyprprofileicon:hover,
+ #custom-quit:hover,
+ #custom-lock:hover,
+ #custom-reboot:hover,
+ #custom-power:hover,
+ #idle_inhibitor:hover {
+ color: #'' + config.lib.stylix.colors.base07 + '';
+ }
+
+ #clock, #tray, #idle_inhibitor {
+ padding: 0 5px;
+ }
+
#window,
#workspaces {
- margin: 0 4px;
+ margin: 0 6px;
}
/* If workspaces is the leftmost module, omit left margin */
@@ -1208,6 +1344,9 @@ in
services.udiskie.enable = true;
services.udiskie.tray = "always";
programs.fuzzel.enable = true;
+ programs.fuzzel.package = pkgs.fuzzel.overrideAttrs (oldAttrs: {
+ patches = ./patches/fuzzelmouseinput.patch;
+ });
programs.fuzzel.settings = {
main = {
font = userSettings.font + ":size=20";
diff --git a/user/wm/hyprland/patches/fuzzelmouseinput.patch b/user/wm/hyprland/patches/fuzzelmouseinput.patch
new file mode 100644
index 0000000..0264ac1
--- /dev/null
+++ b/user/wm/hyprland/patches/fuzzelmouseinput.patch
@@ -0,0 +1,1053 @@
+From 7cc9f3147438fe7dd0062172f46aed415f024464 Mon Sep 17 00:00:00 2001
+From: alz
+Date: Mon, 22 Jul 2024 00:43:56 -0400
+Subject: [PATCH 1/7] implemented left click, right click and scroll wheel
+ listeners
+
+---
+ match.c | 24 ++++++++++++++++++++++++
+ match.h | 1 +
+ render.c | 19 +++++++++++++++++++
+ render.h | 2 ++
+ wayland.c | 38 ++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 84 insertions(+)
+
+diff --git a/match.c b/match.c
+index 5a26000..7d5efaf 100644
+--- a/match.c
++++ b/match.c
+@@ -359,6 +359,30 @@ matches_selected_select(struct matches *matches, const char *_string)
+ return false;
+ }
+
++bool
++matches_selected_select_idx(struct matches *matches, size_t idx)
++{
++ const size_t page_no = matches_get_page(matches);
++ const size_t items_on_page __attribute__((unused)) = matches_get_count(matches);
++
++ LOG_DBG(
++ "page-count: %zu, page-no: %zu, items-on-page: %zu, idx: %zu, max: %zu, "
++ "match-count: %zu",
++ matches->page_count, page_no, items_on_page, idx,
++ matches->max_matches_per_page, matches->match_count);
++
++ if (idx >= items_on_page)
++ return false;
++
++ idx += page_no * matches->max_matches_per_page;
++
++ if (idx >= matches->match_count)
++ return false;
++
++ matches->selected = idx;
++ return true;
++}
++
+ bool
+ matches_selected_first(struct matches *matches)
+ {
+diff --git a/match.h b/match.h
+index 4100881..871635b 100644
+--- a/match.h
++++ b/match.h
+@@ -53,6 +53,7 @@ size_t matches_get_total_count(const struct matches *matches);
+ size_t matches_get_match_index(const struct matches *matches);
+
+ bool matches_selected_select(struct matches *matches, const char *string);
++bool matches_selected_select_idx(struct matches *matches, size_t idx);
+
+ bool matches_selected_first(struct matches *matches);
+ bool matches_selected_last(struct matches *matches);
+diff --git a/render.c b/render.c
+index 403d7c9..3bc507c 100644
+--- a/render.c
++++ b/render.c
+@@ -873,3 +873,22 @@ render_destroy(struct render *render)
+ fcft_destroy(render->font);
+ free(render);
+ }
++
++int render_get_row_num(const struct render *render, int y)
++{
++ const float scale = render->scale;
++ const int y_margin = render->y_margin;
++ const int inner_pad = render->inner_pad;
++ const int border_size = render->border_size;
++ const int row_height = render->row_height;
++ const int first_row = 1 * border_size + y_margin + row_height + inner_pad;
++
++ y = floor(scale * y);
++
++ if (y <= first_row) {
++ return -1;
++ } else {
++ y -= first_row;
++ return y / row_height;
++ }
++}
+diff --git a/render.h b/render.h
+index c097882..1f934f5 100644
+--- a/render.h
++++ b/render.h
+@@ -30,3 +30,5 @@ void render_match_list(
+ const struct prompt *prompt, const struct matches *matches);
+
+ int render_icon_size(const struct render *render);
++
++int render_get_row_num(const struct render *render, int y);
+diff --git a/wayland.c b/wayland.c
+index 15f9e05..c2cf6a6 100644
+--- a/wayland.c
++++ b/wayland.c
+@@ -1062,18 +1062,56 @@ static void
+ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
+ {
++ struct seat *seat = data;
++ struct wayland *wayl = seat->wayl;
++ bool refresh = false;
++
++ refresh = matches_selected_select_idx(wayl->matches,
++ render_get_row_num(wayl->render, wl_fixed_to_int(surface_y)));
++
++ if (refresh) {
++ wayl_refresh(wayl);
++ }
+ }
+
+ static void
+ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
+ uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
+ {
++ struct seat *seat = data;
++ struct wayland *wayl = seat->wayl;
++
++ // Button release
++ if (state == 0) {
++ // Left click
++ if (button == 272) {
++ execute_selected(seat, false, -1);
++ // Right click
++ } else if (button == 273) {
++ wayl->status = EXIT;
++ if (wayl->conf->dmenu.enabled)
++ wayl->exit_code = 2;
++ }
++ }
+ }
+
+ static void
+ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, uint32_t axis, wl_fixed_t value)
+ {
++ struct seat *seat = data;
++ struct wayland *wayl = seat->wayl;
++
++ bool refresh = false;
++ if (value < 0) {
++ refresh = matches_selected_prev_page(wayl->matches);
++ } else if (value > 0) {
++ refresh = matches_selected_next_page(wayl->matches);
++ }
++
++ if (refresh) {
++ wayl_refresh(wayl);
++ }
+ }
+
+ static void
+--
+2.39.2
+
+
+From e023c4f6ceb8bd0fa9b5b1ed2b23af123c2811ed Mon Sep 17 00:00:00 2001
+From: alz
+Date: Mon, 22 Jul 2024 01:07:56 -0400
+Subject: [PATCH 2/7] put the mouse stuff behind a config
+
+---
+ config.c | 4 ++++
+ config.h | 2 ++
+ doc/fuzzel.1.scd | 4 ++++
+ doc/fuzzel.ini.5.scd | 3 +++
+ main.c | 10 ++++++++
+ match.c | 4 ++++
+ wayland.c | 54 +++++++++++++++++++++++++-------------------
+ 7 files changed, 58 insertions(+), 23 deletions(-)
+
+diff --git a/config.c b/config.c
+index e236142..21aab3a 100644
+--- a/config.c
++++ b/config.c
+@@ -778,6 +778,9 @@ parse_section_main(struct context *ctx)
+ else if (strcmp(key, "list-executables-in-path") == 0)
+ return value_to_bool(ctx, &conf->list_executables_in_path);
+
++ else if (strcmp(key, "mouse-listener") == 0)
++ return value_to_bool(ctx, &conf->mouse_listener);
++
+ else if (strcmp(key, "fields") == 0) {
+ _Static_assert(sizeof(conf->match_fields) == sizeof(int),
+ "enum is not 32-bit");
+@@ -1572,6 +1575,7 @@ config_load(struct config *conf, const char *conf_path,
+ .layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP,
+ .exit_on_kb_focus_loss = true,
+ .list_executables_in_path = false,
++ .mouse_listener = false,
+ };
+
+ add_default_key_bindings(conf);
+diff --git a/config.h b/config.h
+index a52976c..99d3a52 100644
+--- a/config.h
++++ b/config.h
+@@ -170,6 +170,8 @@ struct config {
+ bool exit_on_kb_focus_loss;
+
+ bool list_executables_in_path;
++
++ bool mouse_listener;
+ };
+
+ typedef tll(char *) config_override_t;
+diff --git a/doc/fuzzel.1.scd b/doc/fuzzel.1.scd
+index c46d9af..791a5e6 100644
+--- a/doc/fuzzel.1.scd
++++ b/doc/fuzzel.1.scd
+@@ -302,6 +302,10 @@ or command line options:
+ *--log-no-syslog*
+ Disables syslog logging. Logging is only done on stderr.
+
++*--mouse*
++ Allows choosing items with mouse left click, and cancelling fuzzel with
++ right click.
++
+ *-v*,*--version*
+ Show the version number and quit
+
+diff --git a/doc/fuzzel.ini.5.scd b/doc/fuzzel.ini.5.scd
+index e3dfc05..ee6a2c5 100644
+--- a/doc/fuzzel.ini.5.scd
++++ b/doc/fuzzel.ini.5.scd
+@@ -411,6 +411,9 @@ done by setting _action=none_; e.g. *delete-line-forward=none*.
+ *last*
+ Select the last entry, on the last page. Default: _Control+End_.
+
++*mouse-listener*
++ Allows selecting elements with the mouse
++
+ *custom-1*, *custom-2*, ..., *custom-19*
+ Execute the currently selected entry, then exit with a non-zero
+ exit code. *custom-1* exits with exit code 10, *custom-2* with 11,
+diff --git a/match.c b/match.c
+index 7d5efaf..fe3903a 100644
+--- a/match.c
++++ b/match.c
+@@ -362,6 +362,9 @@ matches_selected_select(struct matches *matches, const char *_string)
+ bool
+ matches_selected_select_idx(struct matches *matches, size_t idx)
+ {
++ if (idx < 0)
++ return false;
++
+ const size_t page_no = matches_get_page(matches);
+ const size_t items_on_page __attribute__((unused)) = matches_get_count(matches);
+
+@@ -371,6 +374,7 @@ matches_selected_select_idx(struct matches *matches, size_t idx)
+ matches->page_count, page_no, items_on_page, idx,
+ matches->max_matches_per_page, matches->match_count);
+
++
+ if (idx >= items_on_page)
+ return false;
+
+diff --git a/wayland.c b/wayland.c
+index c2cf6a6..8fff785 100644
+--- a/wayland.c
++++ b/wayland.c
+@@ -1064,13 +1064,16 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
+ {
+ struct seat *seat = data;
+ struct wayland *wayl = seat->wayl;
+- bool refresh = false;
+
+- refresh = matches_selected_select_idx(wayl->matches,
+- render_get_row_num(wayl->render, wl_fixed_to_int(surface_y)));
++ if (wayl->conf->mouse_listener) {
++ bool refresh = false;
+
+- if (refresh) {
+- wayl_refresh(wayl);
++ refresh = matches_selected_select_idx(wayl->matches,
++ render_get_row_num(wayl->render, wl_fixed_to_int(surface_y)));
++
++ if (refresh) {
++ wayl_refresh(wayl);
++ }
+ }
+ }
+
+@@ -1081,16 +1084,18 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
+ struct seat *seat = data;
+ struct wayland *wayl = seat->wayl;
+
+- // Button release
+- if (state == 0) {
+- // Left click
+- if (button == 272) {
+- execute_selected(seat, false, -1);
+- // Right click
+- } else if (button == 273) {
+- wayl->status = EXIT;
+- if (wayl->conf->dmenu.enabled)
+- wayl->exit_code = 2;
++ if (wayl->conf->mouse_listener) {
++ // Button release
++ if (state == 0) {
++ // Left click
++ if (button == 0x110) {
++ execute_selected(seat, false, -1);
++ // Right click
++ } else if (button == 0x111) {
++ wayl->status = EXIT;
++ if (wayl->conf->dmenu.enabled)
++ wayl->exit_code = 2;
++ }
+ }
+ }
+ }
+@@ -1102,15 +1107,18 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
+ struct seat *seat = data;
+ struct wayland *wayl = seat->wayl;
+
+- bool refresh = false;
+- if (value < 0) {
+- refresh = matches_selected_prev_page(wayl->matches);
+- } else if (value > 0) {
+- refresh = matches_selected_next_page(wayl->matches);
+- }
++ if (wayl->conf->mouse_listener) {
++ bool refresh = false;
+
+- if (refresh) {
+- wayl_refresh(wayl);
++ if (value < 0) {
++ refresh = matches_selected_prev_page(wayl->matches);
++ } else if (value > 0) {
++ refresh = matches_selected_next_page(wayl->matches);
++ }
++
++ if (refresh) {
++ wayl_refresh(wayl);
++ }
+ }
+ }
+
+--
+2.39.2
+
+
+From 9e04a13fa2a6b442faaa1451700e04000f24734b Mon Sep 17 00:00:00 2001
+From: alz
+Date: Mon, 22 Jul 2024 12:00:43 -0400
+Subject: [PATCH 3/7] Ignoring left clicks if they're in the prompt row
+
+---
+ wayland.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/wayland.c b/wayland.c
+index 8fff785..e7c0c2c 100644
+--- a/wayland.c
++++ b/wayland.c
+@@ -1068,6 +1068,8 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
+ if (wayl->conf->mouse_listener) {
+ bool refresh = false;
+
++ seat->pointer.y = wl_fixed_to_int(surface_y);
++
+ refresh = matches_selected_select_idx(wayl->matches,
+ render_get_row_num(wayl->render, wl_fixed_to_int(surface_y)));
+
+@@ -1088,7 +1090,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
+ // Button release
+ if (state == 0) {
+ // Left click
+- if (button == 0x110) {
++ if (button == 0x110 && render_get_row_num(wayl->render, seat->pointer.y) >= 0) {
+ execute_selected(seat, false, -1);
+ // Right click
+ } else if (button == 0x111) {
+--
+2.39.2
+
+
+From 607edc371b7ee48ec194ec2ce561d8e10d49923a Mon Sep 17 00:00:00 2001
+From: alz
+Date: Mon, 22 Jul 2024 13:18:43 -0400
+Subject: [PATCH 4/7] Refactored so the data types are correct
+
+---
+ match.c | 36 ++++++++++++------------------------
+ render.c | 14 +++++++++-----
+ render.h | 2 +-
+ wayland.c | 28 +++++++++++++++++-----------
+ 4 files changed, 39 insertions(+), 41 deletions(-)
+
+diff --git a/match.c b/match.c
+index fe3903a..a16f903 100644
+--- a/match.c
++++ b/match.c
+@@ -278,8 +278,8 @@ matches_get_page(const struct matches *matches)
+ : matches->selected;
+ }
+
+-const struct match *
+-matches_get(const struct matches *matches, size_t idx)
++size_t
++match_get_idx(const struct matches *matches, size_t idx)
+ {
+ const size_t page_no = matches_get_page(matches);
+ const size_t items_on_page __attribute__((unused)) = matches_get_count(matches);
+@@ -290,11 +290,17 @@ matches_get(const struct matches *matches, size_t idx)
+ matches->page_count, page_no, items_on_page, idx,
+ matches->max_matches_per_page, matches->match_count);
+
+- assert(idx < items_on_page);
++ assert(idx >= 0 && idx < items_on_page);
+ idx += page_no * matches->max_matches_per_page;
+
+ assert(idx < matches->match_count);
+- return &matches->matches[idx];
++ return idx;
++}
++
++const struct match *
++matches_get(const struct matches *matches, size_t idx)
++{
++ return &matches->matches[match_get_idx(matches, idx)];
+ }
+
+ const struct match *
+@@ -362,28 +368,10 @@ matches_selected_select(struct matches *matches, const char *_string)
+ bool
+ matches_selected_select_idx(struct matches *matches, size_t idx)
+ {
+- if (idx < 0)
++ if (idx == -1)
+ return false;
+
+- const size_t page_no = matches_get_page(matches);
+- const size_t items_on_page __attribute__((unused)) = matches_get_count(matches);
+-
+- LOG_DBG(
+- "page-count: %zu, page-no: %zu, items-on-page: %zu, idx: %zu, max: %zu, "
+- "match-count: %zu",
+- matches->page_count, page_no, items_on_page, idx,
+- matches->max_matches_per_page, matches->match_count);
+-
+-
+- if (idx >= items_on_page)
+- return false;
+-
+- idx += page_no * matches->max_matches_per_page;
+-
+- if (idx >= matches->match_count)
+- return false;
+-
+- matches->selected = idx;
++ matches->selected = match_get_idx(matches, idx);
+ return true;
+ }
+
+diff --git a/render.c b/render.c
+index 3bc507c..1dcefc9 100644
+--- a/render.c
++++ b/render.c
+@@ -874,7 +874,8 @@ render_destroy(struct render *render)
+ free(render);
+ }
+
+-int render_get_row_num(const struct render *render, int y)
++size_t
++render_get_row_num(const struct render *render, int y, size_t match_count)
+ {
+ const float scale = render->scale;
+ const int y_margin = render->y_margin;
+@@ -882,13 +883,16 @@ int render_get_row_num(const struct render *render, int y)
+ const int border_size = render->border_size;
+ const int row_height = render->row_height;
+ const int first_row = 1 * border_size + y_margin + row_height + inner_pad;
++ const int last_row = first_row + match_count*row_height;
+
+ y = floor(scale * y);
+
+- if (y <= first_row) {
+- return -1;
+- } else {
++ size_t row = -1;
++
++ if (y >= first_row && y < last_row) {
+ y -= first_row;
+- return y / row_height;
++ row = y / row_height;
+ }
++
++ return row;
+ }
+diff --git a/render.h b/render.h
+index 1f934f5..c257004 100644
+--- a/render.h
++++ b/render.h
+@@ -31,4 +31,4 @@ void render_match_list(
+
+ int render_icon_size(const struct render *render);
+
+-int render_get_row_num(const struct render *render, int y);
++size_t render_get_row_num(const struct render *render, int y, size_t match_count);
+diff --git a/wayland.c b/wayland.c
+index e7c0c2c..56ff829 100644
+--- a/wayland.c
++++ b/wayland.c
+@@ -1058,6 +1058,19 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
+ seat->pointer.serial = serial;
+ }
+
++static void
++select_hovered_match(struct wayland *wayl, int y)
++{
++ bool refresh = false;
++
++ refresh = matches_selected_select_idx(wayl->matches,
++ render_get_row_num(wayl->render, y, matches_get_count(wayl->matches)));
++
++ if (refresh) {
++ wayl_refresh(wayl);
++ }
++}
++
+ static void
+ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
+@@ -1066,16 +1079,8 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
+ struct wayland *wayl = seat->wayl;
+
+ if (wayl->conf->mouse_listener) {
+- bool refresh = false;
+-
+ seat->pointer.y = wl_fixed_to_int(surface_y);
+-
+- refresh = matches_selected_select_idx(wayl->matches,
+- render_get_row_num(wayl->render, wl_fixed_to_int(surface_y)));
+-
+- if (refresh) {
+- wayl_refresh(wayl);
+- }
++ select_hovered_match(wayl, seat->pointer.y);
+ }
+ }
+
+@@ -1090,7 +1095,8 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
+ // Button release
+ if (state == 0) {
+ // Left click
+- if (button == 0x110 && render_get_row_num(wayl->render, seat->pointer.y) >= 0) {
++ if (button == 0x110 &&
++ render_get_row_num(wayl->render, seat->pointer.y, matches_get_count(wayl->matches)) != -1) {
+ execute_selected(seat, false, -1);
+ // Right click
+ } else if (button == 0x111) {
+@@ -1119,7 +1125,7 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
+ }
+
+ if (refresh) {
+- wayl_refresh(wayl);
++ select_hovered_match(wayl, seat->pointer.y);
+ }
+ }
+ }
+--
+2.39.2
+
+
+From f4d4918ebd6b996deff617c2750000904d1f2d29 Mon Sep 17 00:00:00 2001
+From: alz
+Date: Mon, 22 Jul 2024 13:37:03 -0400
+Subject: [PATCH 5/7] made the hovered row index an attribute of the seat
+ pointer
+
+---
+ wayland.c | 20 +++++++++++---------
+ 1 file changed, 11 insertions(+), 9 deletions(-)
+
+diff --git a/wayland.c b/wayland.c
+index 56ff829..ab88598 100644
+--- a/wayland.c
++++ b/wayland.c
+@@ -148,6 +148,8 @@ struct seat {
+ struct wl_cursor_theme *theme;
+ struct wl_cursor *cursor;
+ float scale;
++
++ size_t hovered_row_idx;
+ } pointer;
+ };
+
+@@ -1059,12 +1061,10 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
+ }
+
+ static void
+-select_hovered_match(struct wayland *wayl, int y)
++select_hovered_match(struct wayland *wayl, size_t idx)
+ {
+ bool refresh = false;
+-
+- refresh = matches_selected_select_idx(wayl->matches,
+- render_get_row_num(wayl->render, y, matches_get_count(wayl->matches)));
++ refresh = matches_selected_select_idx(wayl->matches,idx);
+
+ if (refresh) {
+ wayl_refresh(wayl);
+@@ -1079,8 +1079,11 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
+ struct wayland *wayl = seat->wayl;
+
+ if (wayl->conf->mouse_listener) {
+- seat->pointer.y = wl_fixed_to_int(surface_y);
+- select_hovered_match(wayl, seat->pointer.y);
++ seat->pointer.hovered_row_idx =
++ render_get_row_num(wayl->render,
++ wl_fixed_to_int(surface_y),
++ matches_get_count(wayl->matches));
++ select_hovered_match(wayl, seat->pointer.hovered_row_idx);
+ }
+ }
+
+@@ -1095,8 +1098,7 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
+ // Button release
+ if (state == 0) {
+ // Left click
+- if (button == 0x110 &&
+- render_get_row_num(wayl->render, seat->pointer.y, matches_get_count(wayl->matches)) != -1) {
++ if (button == 0x110 && seat->pointer.hovered_row_idx != -1) {
+ execute_selected(seat, false, -1);
+ // Right click
+ } else if (button == 0x111) {
+@@ -1125,7 +1127,7 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
+ }
+
+ if (refresh) {
+- select_hovered_match(wayl, seat->pointer.y);
++ select_hovered_match(wayl, seat->pointer.hovered_row_idx);
+ }
+ }
+ }
+--
+2.39.2
+
+
+From ef4b0160b3c6e04da7b4bf6a0e6b7d0ac06b54ef Mon Sep 17 00:00:00 2001
+From: alz
+Date: Tue, 23 Jul 2024 16:35:44 -0400
+Subject: [PATCH 6/7] Refreshing display less often
+
+---
+ render.c | 2 +-
+ wayland.c | 7 +++++--
+ 2 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/render.c b/render.c
+index 1dcefc9..505f570 100644
+--- a/render.c
++++ b/render.c
+@@ -839,7 +839,7 @@ render_set_font(struct render *render, struct fcft_font *font,
+ border_size;
+
+ LOG_DBG("x-margin: %d, y-margin: %d, border: %d, row-height: %d, "
+- "icon-height: %d, height: %d, width: %d, scale: %d",
++ "icon-height: %d, height: %d, width: %d, scale: %f",
+ x_margin, y_margin, border_size, row_height, icon_height,
+ height, width, scale);
+
+diff --git a/wayland.c b/wayland.c
+index ab88598..19e902a 100644
+--- a/wayland.c
++++ b/wayland.c
+@@ -1079,11 +1079,14 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
+ struct wayland *wayl = seat->wayl;
+
+ if (wayl->conf->mouse_listener) {
+- seat->pointer.hovered_row_idx =
++ size_t hovered_row =
+ render_get_row_num(wayl->render,
+ wl_fixed_to_int(surface_y),
+ matches_get_count(wayl->matches));
+- select_hovered_match(wayl, seat->pointer.hovered_row_idx);
++ if (hovered_row != seat->pointer.hovered_row_idx) {
++ seat->pointer.hovered_row_idx = hovered_row;
++ select_hovered_match(wayl, seat->pointer.hovered_row_idx);
++ }
+ }
+ }
+
+--
+2.39.2
+
+
+From 761aabf6b7fc55203e23be76a044bbea3e8d99be Mon Sep 17 00:00:00 2001
+From: alz
+Date: Mon, 29 Jul 2024 13:01:12 -0400
+Subject: [PATCH 7/7] Removed config, refactored hovered row selection
+
+---
+ config.c | 4 ---
+ config.h | 2 --
+ doc/fuzzel.1.scd | 4 ---
+ doc/fuzzel.ini.5.scd | 3 --
+ main.c | 10 ------
+ match.c | 12 +++----
+ match.h | 6 ++--
+ render.c | 9 ++---
+ render.h | 4 ++-
+ wayland.c | 78 +++++++++++++++++++++-----------------------
+ 10 files changed, 54 insertions(+), 78 deletions(-)
+
+diff --git a/config.c b/config.c
+index 21aab3a..e236142 100644
+--- a/config.c
++++ b/config.c
+@@ -778,9 +778,6 @@ parse_section_main(struct context *ctx)
+ else if (strcmp(key, "list-executables-in-path") == 0)
+ return value_to_bool(ctx, &conf->list_executables_in_path);
+
+- else if (strcmp(key, "mouse-listener") == 0)
+- return value_to_bool(ctx, &conf->mouse_listener);
+-
+ else if (strcmp(key, "fields") == 0) {
+ _Static_assert(sizeof(conf->match_fields) == sizeof(int),
+ "enum is not 32-bit");
+@@ -1575,7 +1572,6 @@ config_load(struct config *conf, const char *conf_path,
+ .layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP,
+ .exit_on_kb_focus_loss = true,
+ .list_executables_in_path = false,
+- .mouse_listener = false,
+ };
+
+ add_default_key_bindings(conf);
+diff --git a/config.h b/config.h
+index 99d3a52..a52976c 100644
+--- a/config.h
++++ b/config.h
+@@ -170,8 +170,6 @@ struct config {
+ bool exit_on_kb_focus_loss;
+
+ bool list_executables_in_path;
+-
+- bool mouse_listener;
+ };
+
+ typedef tll(char *) config_override_t;
+diff --git a/doc/fuzzel.1.scd b/doc/fuzzel.1.scd
+index 791a5e6..c46d9af 100644
+--- a/doc/fuzzel.1.scd
++++ b/doc/fuzzel.1.scd
+@@ -302,10 +302,6 @@ or command line options:
+ *--log-no-syslog*
+ Disables syslog logging. Logging is only done on stderr.
+
+-*--mouse*
+- Allows choosing items with mouse left click, and cancelling fuzzel with
+- right click.
+-
+ *-v*,*--version*
+ Show the version number and quit
+
+diff --git a/doc/fuzzel.ini.5.scd b/doc/fuzzel.ini.5.scd
+index ee6a2c5..e3dfc05 100644
+--- a/doc/fuzzel.ini.5.scd
++++ b/doc/fuzzel.ini.5.scd
+@@ -411,9 +411,6 @@ done by setting _action=none_; e.g. *delete-line-forward=none*.
+ *last*
+ Select the last entry, on the last page. Default: _Control+End_.
+
+-*mouse-listener*
+- Allows selecting elements with the mouse
+-
+ *custom-1*, *custom-2*, ..., *custom-19*
+ Execute the currently selected entry, then exit with a non-zero
+ exit code. *custom-1* exits with exit code 10, *custom-2* with 11,
+diff --git a/match.c b/match.c
+index a16f903..48c6e4f 100644
+--- a/match.c
++++ b/match.c
+@@ -290,7 +290,7 @@ match_get_idx(const struct matches *matches, size_t idx)
+ matches->page_count, page_no, items_on_page, idx,
+ matches->max_matches_per_page, matches->match_count);
+
+- assert(idx >= 0 && idx < items_on_page);
++ assert(idx < items_on_page);
+ idx += page_no * matches->max_matches_per_page;
+
+ assert(idx < matches->match_count);
+@@ -366,7 +366,7 @@ matches_selected_select(struct matches *matches, const char *_string)
+ }
+
+ bool
+-matches_selected_select_idx(struct matches *matches, size_t idx)
++matches_idx_select(struct matches *matches, size_t idx)
+ {
+ if (idx == -1)
+ return false;
+@@ -427,14 +427,14 @@ matches_selected_next(struct matches *matches, bool wrap)
+ }
+
+ bool
+-matches_selected_prev_page(struct matches *matches)
++matches_selected_prev_page(struct matches *matches, bool scrolling)
+ {
+ const size_t page_no = matches_get_page(matches);
+ if (page_no > 0) {
+ assert(matches->selected >= matches->max_matches_per_page);
+ matches->selected -= matches->max_matches_per_page;
+ return true;
+- } else if (matches->selected > 0) {
++ } else if (!scrolling && matches->selected > 0) {
+ matches->selected = 0;
+ return true;
+ }
+@@ -443,7 +443,7 @@ matches_selected_prev_page(struct matches *matches)
+ }
+
+ bool
+-matches_selected_next_page(struct matches *matches)
++matches_selected_next_page(struct matches *matches, bool scrolling)
+ {
+ const size_t page_no = matches_get_page(matches);
+ if (page_no + 1 < matches->page_count) {
+@@ -451,7 +451,7 @@ matches_selected_next_page(struct matches *matches)
+ matches->selected + matches->max_matches_per_page,
+ matches->match_count - 1);
+ return true;
+- } else if (matches->selected < matches->match_count - 1) {
++ } else if (!scrolling && matches->selected < matches->match_count - 1) {
+ matches->selected = matches->match_count - 1;
+ return true;
+ }
+diff --git a/match.h b/match.h
+index 871635b..35c5d5e 100644
+--- a/match.h
++++ b/match.h
+@@ -53,7 +53,7 @@ size_t matches_get_total_count(const struct matches *matches);
+ size_t matches_get_match_index(const struct matches *matches);
+
+ bool matches_selected_select(struct matches *matches, const char *string);
+-bool matches_selected_select_idx(struct matches *matches, size_t idx);
++bool matches_idx_select(struct matches *matches, size_t idx);
+
+ bool matches_selected_first(struct matches *matches);
+ bool matches_selected_last(struct matches *matches);
+@@ -61,5 +61,5 @@ bool matches_selected_last(struct matches *matches);
+ bool matches_selected_prev(struct matches *matches, bool wrap);
+ bool matches_selected_next(struct matches *matches, bool wrap);
+
+-bool matches_selected_prev_page(struct matches *matches);
+-bool matches_selected_next_page(struct matches *matches);
++bool matches_selected_prev_page(struct matches *matches, bool scrolling);
++bool matches_selected_next_page(struct matches *matches, bool scrolling);
+diff --git a/render.c b/render.c
+index 505f570..ef9aaad 100644
+--- a/render.c
++++ b/render.c
+@@ -875,7 +875,8 @@ render_destroy(struct render *render)
+ }
+
+ size_t
+-render_get_row_num(const struct render *render, int y, size_t match_count)
++render_get_row_num(const struct render *render, int y,
++ const struct matches *matches)
+ {
+ const float scale = render->scale;
+ const int y_margin = render->y_margin;
+@@ -883,15 +884,15 @@ render_get_row_num(const struct render *render, int y, size_t match_count)
+ const int border_size = render->border_size;
+ const int row_height = render->row_height;
+ const int first_row = 1 * border_size + y_margin + row_height + inner_pad;
+- const int last_row = first_row + match_count*row_height;
++ const size_t match_count = matches_get_count(matches);
++ const size_t last_row = first_row + match_count*row_height;
+
+ y = floor(scale * y);
+
+ size_t row = -1;
+
+ if (y >= first_row && y < last_row) {
+- y -= first_row;
+- row = y / row_height;
++ row = (y - first_row) / row_height;
+ }
+
+ return row;
+diff --git a/render.h b/render.h
+index c257004..16887f3 100644
+--- a/render.h
++++ b/render.h
+@@ -31,4 +31,6 @@ void render_match_list(
+
+ int render_icon_size(const struct render *render);
+
+-size_t render_get_row_num(const struct render *render, int y, size_t match_count);
++size_t render_get_row_num(
++ const struct render *render, int y,
++ const struct matches *matches);
+diff --git a/wayland.c b/wayland.c
+index 19e902a..541496d 100644
+--- a/wayland.c
++++ b/wayland.c
+@@ -16,6 +16,7 @@
+ #include
+ #include
+
++#include
+ #include
+ #include
+ #include
+@@ -142,14 +143,13 @@ struct seat {
+
+ int x;
+ int y;
++ size_t hovered_row_idx;
+
+ struct wl_surface *surface;
+ struct wp_viewport *viewport;
+ struct wl_cursor_theme *theme;
+ struct wl_cursor *cursor;
+ float scale;
+-
+- size_t hovered_row_idx;
+ } pointer;
+ };
+
+@@ -706,7 +706,7 @@ execute_binding(struct seat *seat, const struct key_binding *binding, bool *refr
+ return true;
+
+ case BIND_ACTION_MATCHES_PREV_PAGE:
+- *refresh = matches_selected_prev_page(wayl->matches);
++ *refresh = matches_selected_prev_page(wayl->matches, false);
+ return true;
+
+ case BIND_ACTION_MATCHES_NEXT:
+@@ -718,7 +718,7 @@ execute_binding(struct seat *seat, const struct key_binding *binding, bool *refr
+ return true;
+
+ case BIND_ACTION_MATCHES_NEXT_PAGE:
+- *refresh = matches_selected_next_page(wayl->matches);
++ *refresh = matches_selected_next_page(wayl->matches, false);
+ return true;
+
+ case BIND_ACTION_MATCHES_FIRST:
+@@ -1061,12 +1061,22 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
+ }
+
+ static void
+-select_hovered_match(struct wayland *wayl, size_t idx)
++select_hovered_match(struct seat *seat, bool refresh_always)
+ {
++ struct wayland *wayl = seat->wayl;
+ bool refresh = false;
+- refresh = matches_selected_select_idx(wayl->matches,idx);
+
+- if (refresh) {
++ size_t hovered_row =
++ render_get_row_num(wayl->render,
++ seat->pointer.y,
++ wayl->matches);
++
++ if (hovered_row != seat->pointer.hovered_row_idx) {
++ seat->pointer.hovered_row_idx = hovered_row;
++ refresh = matches_idx_select(wayl->matches,hovered_row);
++ }
++
++ if (refresh_always || refresh) {
+ wayl_refresh(wayl);
+ }
+ }
+@@ -1076,18 +1086,11 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
+ uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
+ {
+ struct seat *seat = data;
+- struct wayland *wayl = seat->wayl;
+
+- if (wayl->conf->mouse_listener) {
+- size_t hovered_row =
+- render_get_row_num(wayl->render,
+- wl_fixed_to_int(surface_y),
+- matches_get_count(wayl->matches));
+- if (hovered_row != seat->pointer.hovered_row_idx) {
+- seat->pointer.hovered_row_idx = hovered_row;
+- select_hovered_match(wayl, seat->pointer.hovered_row_idx);
+- }
+- }
++ seat->pointer.x = wl_fixed_to_int(surface_x);
++ seat->pointer.y = wl_fixed_to_int(surface_y);
++
++ select_hovered_match(seat, false);
+ }
+
+ static void
+@@ -1097,18 +1100,14 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
+ struct seat *seat = data;
+ struct wayland *wayl = seat->wayl;
+
+- if (wayl->conf->mouse_listener) {
+- // Button release
+- if (state == 0) {
+- // Left click
+- if (button == 0x110 && seat->pointer.hovered_row_idx != -1) {
+- execute_selected(seat, false, -1);
+- // Right click
+- } else if (button == 0x111) {
+- wayl->status = EXIT;
+- if (wayl->conf->dmenu.enabled)
+- wayl->exit_code = 2;
+- }
++ if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
++ if (button == BTN_LEFT && seat->pointer.hovered_row_idx != -1) {
++ execute_selected(seat, false, -1);
++ } else if (button == BTN_RIGHT) {
++ // Same as pressing ESC
++ wayl->status = EXIT;
++ if (wayl->conf->dmenu.enabled)
++ wayl->exit_code = 2;
+ }
+ }
+ }
+@@ -1119,19 +1118,16 @@ wl_pointer_axis(void *data, struct wl_pointer *wl_pointer,
+ {
+ struct seat *seat = data;
+ struct wayland *wayl = seat->wayl;
++ bool refresh = false;
+
+- if (wayl->conf->mouse_listener) {
+- bool refresh = false;
++ if (value < 0) {
++ refresh = matches_selected_prev_page(wayl->matches, true);
++ } else if (value > 0) {
++ refresh = matches_selected_next_page(wayl->matches, true);
++ }
+
+- if (value < 0) {
+- refresh = matches_selected_prev_page(wayl->matches);
+- } else if (value > 0) {
+- refresh = matches_selected_next_page(wayl->matches);
+- }
+-
+- if (refresh) {
+- select_hovered_match(wayl, seat->pointer.hovered_row_idx);
+- }
++ if (refresh) {
++ select_hovered_match(seat, true);
+ }
+ }
+
+--
+2.39.2
diff --git a/user/wm/hyprland/patches/waybarbatupdate.patch b/user/wm/hyprland/patches/waybarbatupdate.patch
new file mode 100644
index 0000000..364c92e
--- /dev/null
+++ b/user/wm/hyprland/patches/waybarbatupdate.patch
@@ -0,0 +1,192 @@
+From f4608b3e312448b37a8f9d6351154026e67c680a Mon Sep 17 00:00:00 2001
+From: schmop
+Date: Thu, 25 Jul 2024 01:40:49 +0200
+Subject: [PATCH] Fix battery status changes not being detected
+
+Historically we listened to /sys/class/poewr_supply inotify events,
+which does not seem to work anymore.
+We switched now to udev netlink kernel events.
+---
+ include/modules/battery.hpp | 8 +++++--
+ include/util/udev_deleter.hpp | 21 ++++++++++++++++++
+ src/modules/battery.cpp | 40 +++++++++++++++++++---------------
+ src/util/backlight_backend.cpp | 17 +--------------
+ 4 files changed, 51 insertions(+), 35 deletions(-)
+ create mode 100644 include/util/udev_deleter.hpp
+
+diff --git a/include/modules/battery.hpp b/include/modules/battery.hpp
+index 8e1a2ad2b..fc403be05 100644
+--- a/include/modules/battery.hpp
++++ b/include/modules/battery.hpp
+@@ -5,8 +5,11 @@
+ #include
+ #if defined(__linux__)
+ #include
++#include "util/udev_deleter.hpp"
+ #endif
+
++#include
++
+ #include
+ #include
+ #include
+@@ -36,11 +39,12 @@ class Battery : public ALabel {
+ const std::string formatTimeRemaining(float hoursRemaining);
+ void setBarClass(std::string&);
+
+- int global_watch;
+ std::map batteries_;
++ std::unique_ptr udev_;
++ std::array poll_fds_;
++ std::unique_ptr mon_;
+ fs::path adapter_;
+ int battery_watch_fd_;
+- int global_watch_fd_;
+ std::mutex battery_list_mutex_;
+ std::string old_status_;
+ bool warnFirstTime_{true};
+diff --git a/include/util/udev_deleter.hpp b/include/util/udev_deleter.hpp
+new file mode 100644
+index 000000000..b2f1e538b
+--- /dev/null
++++ b/include/util/udev_deleter.hpp
+@@ -0,0 +1,21 @@
++#pragma once
++
++#include
++
++namespace waybar::util {
++struct UdevDeleter {
++ void operator()(udev *ptr) const { udev_unref(ptr); }
++};
++
++struct UdevDeviceDeleter {
++ void operator()(udev_device *ptr) const { udev_device_unref(ptr); }
++};
++
++struct UdevEnumerateDeleter {
++ void operator()(udev_enumerate *ptr) const { udev_enumerate_unref(ptr); }
++};
++
++struct UdevMonitorDeleter {
++ void operator()(udev_monitor *ptr) const { udev_monitor_unref(ptr); }
++};
++} // namespace waybar::util
+\ No newline at end of file
+diff --git a/src/modules/battery.cpp b/src/modules/battery.cpp
+index d87cc6129..bad72e6b0 100644
+--- a/src/modules/battery.cpp
++++ b/src/modules/battery.cpp
+@@ -5,6 +5,9 @@
+ #include
+ #endif
+ #include
++#include
++#include
++#include
+
+ #include
+ waybar::modules::Battery::Battery(const std::string& id, const Bar& bar, const Json::Value& config)
+@@ -14,17 +17,18 @@ waybar::modules::Battery::Battery(const std::string& id, const Bar& bar, const J
+ if (battery_watch_fd_ == -1) {
+ throw std::runtime_error("Unable to listen batteries.");
+ }
+-
+- global_watch_fd_ = inotify_init1(IN_CLOEXEC);
+- if (global_watch_fd_ == -1) {
+- throw std::runtime_error("Unable to listen batteries.");
++ udev_ = std::unique_ptr(udev_new());
++ if (udev_ == nullptr) {
++ throw std::runtime_error("udev_new failed");
+ }
+-
+- // Watch the directory for any added or removed batteries
+- global_watch = inotify_add_watch(global_watch_fd_, data_dir_.c_str(), IN_CREATE | IN_DELETE);
+- if (global_watch < 0) {
+- throw std::runtime_error("Could not watch for battery plug/unplug");
++ mon_ = std::unique_ptr(udev_monitor_new_from_netlink(udev_.get(), "kernel"));
++ if (mon_ == nullptr) {
++ throw std::runtime_error("udev monitor new failed");
+ }
++ if (udev_monitor_filter_add_match_subsystem_devtype(mon_.get(), "power_supply", nullptr) < 0) {
++ throw std::runtime_error("udev failed to add monitor filter");
++ }
++ udev_monitor_enable_receiving(mon_.get());
+ #endif
+ worker();
+ }
+@@ -33,11 +37,6 @@ waybar::modules::Battery::~Battery() {
+ #if defined(__linux__)
+ std::lock_guard guard(battery_list_mutex_);
+
+- if (global_watch >= 0) {
+- inotify_rm_watch(global_watch_fd_, global_watch);
+- }
+- close(global_watch_fd_);
+-
+ for (auto it = batteries_.cbegin(), next_it = it; it != batteries_.cend(); it = next_it) {
+ ++next_it;
+ auto watch_id = (*it).second;
+@@ -74,12 +73,18 @@ void waybar::modules::Battery::worker() {
+ dp.emit();
+ };
+ thread_battery_update_ = [this] {
+- struct inotify_event event = {0};
+- int nbytes = read(global_watch_fd_, &event, sizeof(event));
+- if (nbytes != sizeof(event) || event.mask & IN_IGNORED) {
++ poll_fds_[0].revents = 0;
++ poll_fds_[0].events = POLLIN;
++ poll_fds_[0].fd = udev_monitor_get_fd(mon_.get());
++ int ret = poll(poll_fds_.data(), poll_fds_.size(), -1);
++ if (ret < 0) {
+ thread_.stop();
+ return;
+ }
++ if ((poll_fds_[0].revents & POLLIN) != 0) {
++ signalfd_siginfo signal_info;
++ read(poll_fds_[0].fd, &signal_info, sizeof(signal_info));
++ }
+ refreshBatteries();
+ dp.emit();
+ };
+@@ -668,6 +673,7 @@ auto waybar::modules::Battery::update() -> void {
+ status = getAdapterStatus(capacity);
+ }
+ auto status_pretty = status;
++ puts(status.c_str());
+ // Transform to lowercase and replace space with dash
+ std::transform(status.begin(), status.end(), status.begin(),
+ [](char ch) { return ch == ' ' ? '-' : std::tolower(ch); });
+diff --git a/src/util/backlight_backend.cpp b/src/util/backlight_backend.cpp
+index bb102cd93..df6afd564 100644
+--- a/src/util/backlight_backend.cpp
++++ b/src/util/backlight_backend.cpp
+@@ -1,4 +1,5 @@
+ #include "util/backlight_backend.hpp"
++#include "util/udev_deleter.hpp"
+
+ #include
+ #include
+@@ -29,22 +30,6 @@ class FileDescriptor {
+ int fd_;
+ };
+
+-struct UdevDeleter {
+- void operator()(udev *ptr) { udev_unref(ptr); }
+-};
+-
+-struct UdevDeviceDeleter {
+- void operator()(udev_device *ptr) { udev_device_unref(ptr); }
+-};
+-
+-struct UdevEnumerateDeleter {
+- void operator()(udev_enumerate *ptr) { udev_enumerate_unref(ptr); }
+-};
+-
+-struct UdevMonitorDeleter {
+- void operator()(udev_monitor *ptr) { udev_monitor_unref(ptr); }
+-};
+-
+ void check_eq(int rc, int expected, const char *message = "eq, rc was: ") {
+ if (rc != expected) {
+ throw std::runtime_error(fmt::format(fmt::runtime(message), rc));
diff --git a/user/wm/hyprland/patches/waybarpaupdate.patch b/user/wm/hyprland/patches/waybarpaupdate.patch
new file mode 100644
index 0000000..f1c22cd
--- /dev/null
+++ b/user/wm/hyprland/patches/waybarpaupdate.patch
@@ -0,0 +1,71 @@
+diff --git a/include/util/audio_backend.hpp b/include/util/audio_backend.hpp
+index 2f53103e5..3737ae264 100644
+--- a/include/util/audio_backend.hpp
++++ b/include/util/audio_backend.hpp
+@@ -38,6 +38,8 @@ class AudioBackend {
+ std::string desc_;
+ std::string monitor_;
+ std::string current_sink_name_;
++ std::string default_sink_name;
++ bool default_sink_running_;
+ bool current_sink_running_;
+ // SOURCE
+ uint32_t source_idx_{0};
+diff --git a/src/util/audio_backend.cpp b/src/util/audio_backend.cpp
+index 3d90b6d5a..73aac148b 100644
+--- a/src/util/audio_backend.cpp
++++ b/src/util/audio_backend.cpp
+@@ -1,9 +1,12 @@
+ #include "util/audio_backend.hpp"
+
+ #include
++#include
+ #include
++#include
+ #include
+ #include
++#include
+
+ #include
+ #include
+@@ -139,6 +142,10 @@ void AudioBackend::sinkInfoCb(pa_context * /*context*/, const pa_sink_info *i, i
+ void *data) {
+ if (i == nullptr) return;
+
++ auto running = i->state == PA_SINK_RUNNING;
++ auto idle = i->state == PA_SINK_IDLE;
++ spdlog::trace("Sink name {} Running:[{}] Idle:[{}]", i->name, running, idle);
++
+ auto *backend = static_cast(data);
+
+ if (!backend->ignored_sinks_.empty()) {
+@@ -155,11 +162,19 @@ void AudioBackend::sinkInfoCb(pa_context * /*context*/, const pa_sink_info *i, i
+ }
+ }
+
++ backend->default_sink_running_ = backend->default_sink_name == i->name &&
++ (i->state == PA_SINK_RUNNING || i->state == PA_SINK_IDLE);
++
++ if (i->name != backend->default_sink_name && !backend->default_sink_running_) {
++ return;
++ }
++
+ if (backend->current_sink_name_ == i->name) {
+- backend->current_sink_running_ = i->state == PA_SINK_RUNNING;
++ backend->current_sink_running_ = (i->state == PA_SINK_RUNNING || i->state == PA_SINK_IDLE);
+ }
+
+- if (!backend->current_sink_running_ && i->state == PA_SINK_RUNNING) {
++ if (!backend->current_sink_running_ &&
++ (i->state == PA_SINK_RUNNING || i->state == PA_SINK_IDLE)) {
+ backend->current_sink_name_ = i->name;
+ backend->current_sink_running_ = true;
+ }
+@@ -207,5 +222,6 @@ void AudioBackend::sourceInfoCb(pa_context * /*context*/, const pa_source_info *
+ void AudioBackend::serverInfoCb(pa_context *context, const pa_server_info *i, void *data) {
+ auto *backend = static_cast(data);
+ backend->current_sink_name_ = i->default_sink_name;
++ backend->default_sink_name = i->default_sink_name;
+ backend->default_source_name_ = i->default_source_name;
+
+ pa_context_get_sink_info_list(context, sinkInfoCb, data);