From f84a75a23273bb92883d04a23c4ed0fc4ef1fb2d Mon Sep 17 00:00:00 2001 From: Thomas Adam Date: Sun, 18 Feb 2024 22:41:23 +0000 Subject: [PATCH 1/3] RandR: handle monitor {dis,}connection better When monitors are connected and disconnected, the monitor is deleted and reinserted into the RB_TREE. This has to happen as the key has changed and a monitor could have changed position. In doing so, ensure the windows which were on the existing monitors are properly updated. This means keeping a separate list of monitors which have been altered, and reassigning windows on the old monitor to the new one. This is done using monitor names, which seems consistent if one undocks a laptop from a docking station and then reattaches, for example. Without this change, windows would lose which desk they were previously on. --- fvwm/builtins.c | 3 +++ fvwm/events.c | 31 ++++++++++++++++++++++++++++++- libs/FScreen.c | 19 ++++++++++++++++++- libs/FScreen.h | 4 ++++ 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/fvwm/builtins.c b/fvwm/builtins.c index 5a588cb42..833f4f8c5 100644 --- a/fvwm/builtins.c +++ b/fvwm/builtins.c @@ -165,6 +165,9 @@ status_send(void) if ((desk_doc[d_count] = cJSON_CreateObject()) == NULL) goto out; + if (m->Desktops == NULL) + goto out; + this_desktop = cJSON_AddObjectToObject(desk_doc[d_count], "desktops"); diff --git a/fvwm/events.c b/fvwm/events.c index 3623d30d1..b5d9eafe5 100644 --- a/fvwm/events.c +++ b/fvwm/events.c @@ -1774,7 +1774,7 @@ static void _refocus_stolen_focus_win(const evh_args_t *ea) void monitor_update_ewmh(void) { FvwmWindow *t; - struct monitor *m, *mref; + struct monitor *m, *mref, *mo, *mo1; fvwm_debug(__func__, "monitor debug...\n"); if (Scr.bo.do_debug_randr) @@ -1785,6 +1785,23 @@ void monitor_update_ewmh(void) mref = RB_MIN(monitors, &monitor_q); RB_FOREACH(m, monitors, &monitor_q) { + if (m->flags & MONITOR_CHANGED) { + if (changed_monitor_count() == 1) + goto out; + TAILQ_FOREACH(mo, &monitorsold_q, oentry) { + if (strcmp(m->si->name, mo->si->name) != 0) + continue; + if (mo->Desktops == NULL) + continue; + for (t = Scr.FvwmRoot.next; t; t = t->next) { + if (t->m == mo) { + t->m = m; + update_fvwm_monitor(t); + } + } + } + continue; + } if (m->flags & MONITOR_NEW) { if (m->Desktops == NULL) { int ewbs[4] = {0, 0, 0, 0}; @@ -1795,6 +1812,9 @@ void monitor_update_ewmh(void) m->Desktops->desk = 0; apply_desktops_monitor(m); + if (m->Desktops->next == mref->Desktops->next) + continue; + calculate_page_sizes(m, mref->dx, mref->dy); fvwm_debug(__func__, @@ -1813,6 +1833,14 @@ void monitor_update_ewmh(void) EWMH_Init(m); } +out: + TAILQ_FOREACH_SAFE(mo, &monitorsold_q, oentry, mo1) { + TAILQ_REMOVE(&monitorsold_q, mo, oentry); + fvwm_debug(__func__, "Removed mo '%s' from processing", + mo->si->name); + } + + BroadcastMonitorList(NULL); for (t = Scr.FvwmRoot.next; t; t = t->next) { @@ -1861,6 +1889,7 @@ monitor_emit_broadcast(void) break; if (pm != mnew) { + fvwm_debug(__func__, "MONITOR PRIMARY"); execute_function_override_window( NULL, NULL, randrfunc, NULL, 0, NULL); } diff --git a/libs/FScreen.c b/libs/FScreen.c index 041c6fd74..1d5a78703 100644 --- a/libs/FScreen.c +++ b/libs/FScreen.c @@ -56,6 +56,7 @@ enum monitor_tracking monitor_mode; bool is_tracking_shared; struct screen_infos screen_info_q, screen_info_q_temp; struct monitors monitor_q; +struct monitorsold monitorsold_q; int randr_event; const char *prev_focused_monitor; static struct monitor *monitor_global = NULL; @@ -338,6 +339,17 @@ monitor_by_last_primary(void) return (m); } +int changed_monitor_count(void) +{ + struct monitor *m; + int c = 0; + + TAILQ_FOREACH(m, &monitorsold_q, oentry) + c++; + + return (c); +} + static void monitor_check_primary(void) { @@ -431,8 +443,10 @@ monitor_output_change(Display *dpy, XRRScreenChangeNotifyEvent *e) if (oinfo->connection == RR_Connected && m->flags & MONITOR_ENABLED) { - if (m->flags & MONITOR_CHANGED) + if (m->flags & MONITOR_CHANGED) { m->emit |= MONITOR_CHANGED; + TAILQ_INSERT_TAIL(&monitorsold_q, m, oentry); + } continue; } @@ -600,6 +614,9 @@ void FScreenInit(Display *dpy) if (TAILQ_EMPTY(&screen_info_q)) TAILQ_INIT(&screen_info_q); + if (TAILQ_EMPTY(&monitorsold_q)) + TAILQ_INIT(&monitorsold_q); + if (!XRRQueryExtension(dpy, &randr_event, &err_base) || !XRRQueryVersion (dpy, &major, &minor)) { fvwm_debug(__func__, "RandR not present"); diff --git a/libs/FScreen.h b/libs/FScreen.h index 6a6084098..59a98a861 100644 --- a/libs/FScreen.h +++ b/libs/FScreen.h @@ -145,14 +145,18 @@ struct monitor { bool pan_frames_mapped; RB_ENTRY(monitor) entry; + TAILQ_ENTRY(monitor) oentry; }; RB_HEAD(monitors, monitor); +TAILQ_HEAD(monitorsold, monitor); extern struct monitors monitors; extern struct monitors monitor_q; +extern struct monitorsold monitorsold_q; int monitor_compare(struct monitor *, struct monitor *); RB_PROTOTYPE(monitors, monitor, entry, monitor_compare); +int changed_monitor_count(void); struct monitor *monitor_resolve_name(const char *); struct monitor *monitor_by_xy(int, int); struct monitor *monitor_by_output(int); From 61fec78b737c93db10503a1da73b8ff692240e26 Mon Sep 17 00:00:00 2001 From: Thomas Adam Date: Wed, 21 Feb 2024 17:55:34 +0000 Subject: [PATCH 2/3] build: bump golang version check Golang 1.22 is out. --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 63a83aa49..9596ad38e 100644 --- a/configure.ac +++ b/configure.ac @@ -86,7 +86,7 @@ if test ! x"$with_golang" = xno; then sed -e 's/ .*$//') AC_MSG_CHECKING([whether go version is >= 1.14.x ($go_version)]) case "$go_version" in - 1.14*|1.15*|1.16*|1.17*|1.18*|1.19*|1.20*|1.21*) + 1.14*|1.15*|1.16*|1.17*|1.18*|1.19*|1.20*|1.21*|1.22*|1.23*) AC_MSG_RESULT([yes - version is: $go_version]) with_golang="yes" GO= From cb8cce5494fc6db76eb544599a551caafc680f7b Mon Sep 17 00:00:00 2001 From: Thomas Adam Date: Wed, 21 Feb 2024 17:59:50 +0000 Subject: [PATCH 3/3] RandR: avoid segfault with one screen When two monitors go to one monitor (undocking a laptop with one external display, for example), don't set the previous monitor if it's the same as the current monitor. Fixes #947 --- fvwm/events.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fvwm/events.c b/fvwm/events.c index b5d9eafe5..1e498a7d8 100644 --- a/fvwm/events.c +++ b/fvwm/events.c @@ -2295,6 +2295,12 @@ void HandleEnterNotify(const evh_args_t *ea) pfm = monitor_resolve_name(prev_focused_monitor); this_m = monitor_get_current(); + /* Don't toggle the previous monitor if there isn't one, or + * the two monitors are the same. + */ + if ((pfm == NULL) || (pfm == this_m)) + return; + /* Send MX_MONITOR_FOCUS event. */ toggle_prev_monitor_state(this_m, pfm, NULL);