Skip to content

Commit

Permalink
monitors: improve detection/changes
Browse files Browse the repository at this point in the history
Move the state logic of when to emit events into scan_screens() and
update the event logic accordingly so that RandRFunc is run correctly.
  • Loading branch information
farblos committed Oct 22, 2024
1 parent 72df98b commit b373a30
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 77 deletions.
73 changes: 27 additions & 46 deletions fvwm/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
}


Expand All @@ -1852,7 +1830,7 @@ void monitor_update_ewmh(void)
}
}

void
static void
monitor_emit_broadcast(void)
{
struct monitor *m;
Expand All @@ -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);
}
}
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -4807,4 +4788,4 @@ void CMD_XSync(F_CMD_ARGS)
XSync(dpy, 0);

return;
}
}
68 changes: 39 additions & 29 deletions libs/FScreen.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -510,15 +498,13 @@ 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",
m->si->name, m->si->x, m->si->y, m->si->w, m->si->h,
rrm->x, rrm->y, rrm->width, rrm->height);

monitor_set_coords(m, *rrm);
TAILQ_INSERT_TAIL(&monitorsold_q, m, oentry);

return (true);
}
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -1439,4 +1449,4 @@ int FScreenFetchMangledScreenFromUSPosHints(XSizeHints *hints)
screen = 0;

return screen;
}
}
2 changes: 0 additions & 2 deletions libs/FScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down

0 comments on commit b373a30

Please sign in to comment.