diff --git a/fvwm/events.c b/fvwm/events.c index 7b52d2ff0..a77c0ecb9 100644 --- a/fvwm/events.c +++ b/fvwm/events.c @@ -1775,10 +1775,10 @@ static void _refocus_stolen_focus_win(const evh_args_t *ea) /* ---------------------------- event handlers ----------------------------- */ -void monitor_update_ewmh(void) +static void monitor_update_ewmh(void) { FvwmWindow *t; - struct monitor *m, *mref, *mo, *mo1; + struct monitor *m, *mref; if (Scr.bo.do_debug_randr) { @@ -1789,21 +1789,6 @@ void monitor_update_ewmh(void) RB_FOREACH(m, monitors, &monitor_q) { if (m->flags & MONITOR_CHANGED) { - fvwm_debug(__func__, "Applying EWMH changes to " - "existing %s", m->si->name); - 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); - } - } - m->emit |= MONITOR_CHANGED; - } m->flags &= ~MONITOR_CHANGED; continue; } @@ -1831,17 +1816,10 @@ void monitor_update_ewmh(void) m->virtual_scr.Vy = 0; set_ewmhc_strut_values(m, ewbs); + + m->flags &= ~MONITOR_NEW; } EWMH_Init(m); - - /* Clear the flag now that it's been registered. */ - m->flags &= ~MONITOR_NEW; - } - - 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); } @@ -1852,7 +1830,7 @@ void monitor_update_ewmh(void) } } -void +static void monitor_emit_broadcast(void) { struct monitor *m; @@ -1861,44 +1839,37 @@ monitor_emit_broadcast(void) RB_FOREACH (m, monitors, &monitor_q) { if (m->emit > 0) fvwm_debug(__func__, "%s: emit: %d\n", m->si->name, m->emit); - if (m->emit &= ~MONITOR_CHANGED) { + if (m->emit & MONITOR_CHANGED) { + fvwm_debug(__func__, "%s: emit monitor changed", m->si->name); BroadcastName( MX_MONITOR_CHANGED, -1, -1, -1, m->si->name); - m->emit &= ~MONITOR_CHANGED; - /* Run the RandRFunc in case a user has set it. */ execute_function_override_window( NULL, NULL, randrfunc, NULL, 0, NULL); } - if (m->emit &= ~MONITOR_ENABLED) { + if (m->emit & MONITOR_ENABLED) { + fvwm_debug(__func__, "%s: emit monitor enabled", m->si->name); BroadcastName( MX_MONITOR_ENABLED, -1, -1, -1, m->si->name); - /* Run the RandRFunc in case a user has set it. */ execute_function_override_window( NULL, NULL, randrfunc, NULL, 0, NULL); } - if (m->emit &= ~MONITOR_DISABLED) { - fvwm_debug(__func__, "MONITOR DISABLED: %s", m->si->name); + if (m->emit & MONITOR_DISABLED) { + fvwm_debug(__func__, "%s: emit monitor disabled", m->si->name); BroadcastName( MX_MONITOR_DISABLED, -1, -1, -1, m->si->name); - /* Run the RandRFunc in case a user has set it. */ execute_function_override_window( NULL, NULL, randrfunc, NULL, 0, NULL); } - if (m->flags & MONITOR_PRIMARY) { - struct monitor *pm = m, *mnew; - - if ((mnew = monitor_by_last_primary()) == NULL) - break; + if ((m->flags & MONITOR_PRIMARY) && + (m != monitor_by_last_primary())) { + fvwm_debug(__func__, "%s: emit monitor primary change", m->si->name); - if (pm != mnew) { - fvwm_debug(__func__, "MONITOR PRIMARY"); - execute_function_override_window( - NULL, NULL, randrfunc, NULL, 0, NULL); - } + execute_function_override_window( + NULL, NULL, randrfunc, NULL, 0, NULL); } } } @@ -4152,11 +4123,21 @@ void dispatch_event(XEvent *e) Window w = e->xany.window; FvwmWindow *fw; event_group_t *event_group; + static unsigned long prev_serial = 0; XFlush(dpy); switch (e->type - randr_event) { case RRScreenChangeNotify: + /* Avoid processing identical RandR events twice. */ + if (e->xany.serial == prev_serial) + { + fvwm_debug(__func__, "Ignoring duplicate event %lu\n", + e->xany.serial); + break; + } + prev_serial = e->xany.serial; + XRRUpdateConfiguration(e); monitor_output_change(e->xany.display, NULL); monitor_update_ewmh(); @@ -4807,4 +4788,4 @@ void CMD_XSync(F_CMD_ARGS) XSync(dpy, 0); return; -} +} \ No newline at end of file diff --git a/libs/FScreen.c b/libs/FScreen.c index 9e6d4b4a2..9aa829501 100644 --- a/libs/FScreen.c +++ b/libs/FScreen.c @@ -65,7 +65,6 @@ 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; @@ -348,17 +347,6 @@ 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) { @@ -510,7 +498,6 @@ monitor_mark_changed(struct monitor *m, XRRMonitorInfo *rrm) m->si->w != rrm->width || m->si->h != rrm->height) { m->flags |= MONITOR_CHANGED; - m->emit |= MONITOR_CHANGED; fvwm_debug(__func__, "%s: x: %d, y: %d, w: %d, h: %d " "comp: x: %d, y: %d, w: %d, h: %d\n", @@ -518,7 +505,6 @@ monitor_mark_changed(struct monitor *m, XRRMonitorInfo *rrm) rrm->x, rrm->y, rrm->width, rrm->height); monitor_set_coords(m, *rrm); - TAILQ_INSERT_TAIL(&monitorsold_q, m, oentry); return (true); } @@ -550,6 +536,10 @@ scan_screens(Display *dpy) int i, n = 0; Window root = RootWindow(dpy, DefaultScreen(dpy)); + RB_FOREACH(m, monitors, &monitor_q) { + m->flags &= ~(MONITOR_NEW|MONITOR_CHANGED); + } + rrm = XRRGetMonitors(dpy, root, true, &n); if (n <= 0 && (!randr_initialised && monitor_get_count() == 0)) { fvwm_debug(__func__, "get monitors failed\n"); @@ -578,9 +568,12 @@ scan_screens(Display *dpy) * - It's an existing monitor (position changed) * - It's an existing monitor which has been toggled on or off. * - * In such cases, we must detect if the monitor exists and what - * state it is in. + * In such cases, we must detect if the monitor exists and what state it + * is in. Regardless of how the monitor state has changed, we flag all + * monitors reported by XRRGetMonitors with flag MONITOR_FOUND, which we + * use below to determine its new state. */ + fvwm_debug(__func__, "Case 2: processing %d monitors", n); for (i = 0; i < n; i++) { if ((name = XGetAtomName(dpy, rrm[i].name)) == NULL) continue; @@ -593,32 +586,52 @@ scan_screens(Display *dpy) if (monitor_mark_changed(m, &rrm[i])) { fvwm_debug(__func__, "Case 2.2: %s changed", m->si->name); } + + /* Flag monitor as MONITOR_FOUND. */ monitor_mark_inlist(name); XFree(name); } out: + /* Update monitor order after changes. Do not mix that up with the + * following loop or some monitors might get their flags processed + * twice. + */ RB_FOREACH_SAFE(m, monitors, &monitor_q, m1) { if (m->flags & MONITOR_CHANGED) { - m->flags &= ~MONITOR_DISABLED; - fvwm_debug(__func__, "REINSERTING: %s\n", m->si->name); RB_REMOVE(monitors, &monitor_q, m); RB_INSERT(monitors, &monitor_q, m); } + } + + RB_FOREACH(m, monitors, &monitor_q) { + int flags = m->flags; + bool found = m->flags & MONITOR_FOUND; /* Check for monitor connection status -- whether a monitor is * active or not. Clearing the MONITOR_FOUND flag is * important here so that the monitor is reconsidered again. */ - if (!(m->flags & (MONITOR_FOUND|MONITOR_NEW))) { - m->flags |= MONITOR_DISABLED; - m->emit |= MONITOR_DISABLED; - } else if ((m->flags & (MONITOR_FOUND|MONITOR_DISABLED)) == - (MONITOR_FOUND|MONITOR_DISABLED)) { + if (found && (flags & MONITOR_NEW)) { m->flags &= ~MONITOR_DISABLED; - } else { - m->flags |= MONITOR_ENABLED; + m->emit = MONITOR_ENABLED; + } else if (found && (flags & MONITOR_CHANGED)) { + m->flags &= ~MONITOR_DISABLED; + m->emit = MONITOR_CHANGED; + } else if (found && (flags & MONITOR_DISABLED)) { + m->flags &= ~MONITOR_DISABLED; + m->emit = MONITOR_ENABLED; + } else if (found && (! (flags & MONITOR_DISABLED))) { + m->emit = 0; + } else if (!found && (flags & MONITOR_NEW)) { + /* This case happens if !randr_initialised. */ + m->emit = 0; + } else if (!found && (flags & MONITOR_DISABLED)) { + m->emit = 0; + } else /* (!found && (! (flags & MONITOR_DISABLED))) */ { + m->flags |= MONITOR_DISABLED; + m->emit = MONITOR_DISABLED; } m->flags &= ~MONITOR_FOUND; } @@ -650,9 +663,6 @@ 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"); @@ -1439,4 +1449,4 @@ int FScreenFetchMangledScreenFromUSPosHints(XSizeHints *hints) screen = 0; return screen; -} +} \ No newline at end of file diff --git a/libs/FScreen.h b/libs/FScreen.h index 809f5530e..0134df54b 100644 --- a/libs/FScreen.h +++ b/libs/FScreen.h @@ -149,11 +149,9 @@ struct monitor { 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);