Skip to content

Commit

Permalink
NEW: rework monitor detection
Browse files Browse the repository at this point in the history
  • Loading branch information
ThomasAdam committed Mar 20, 2024
1 parent 12a93f9 commit 03776a2
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 73 deletions.
13 changes: 13 additions & 0 deletions fvwm/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
/* ---------------------------- included header files ---------------------- */

#include "config.h"
#include <X11/extensions/Xrandr.h>

#if HAVE_SYS_BSDTYPES_H
#include <sys/bsdtypes.h>
Expand Down Expand Up @@ -4207,15 +4208,27 @@ void dispatch_event(XEvent *e)
XFlush(dpy);

XRRScreenChangeNotifyEvent *sce;
XRROutputChangeNotifyEvent *oce;

switch (e->type - randr_event) {
case RRScreenChangeNotify: {
sce = (XRRScreenChangeNotifyEvent *)e;
XRRUpdateConfiguration(e);
#if 0
monitor_output_change(sce->display, sce);
monitor_update_ewmh();
monitor_emit_broadcast();
initPanFrames(NULL);
#endif
break;
case RRNotify_OutputChange:
oce = (XRROutputChangeNotifyEvent *)e;
XRRUpdateConfiguration(e);
fprintf(stderr, "THIS HAPPENED: %d\n", oce->connection);
struct monitor *tmbo = monitor_by_output(oce->output);

fprintf(stderr, "%s is: %d\n", tmbo->si->name, oce->connection);

break;
}
}
Expand Down
4 changes: 3 additions & 1 deletion fvwm/fvwm3.c
Original file line number Diff line number Diff line change
Expand Up @@ -2417,8 +2417,10 @@ int main(int argc, char **argv)
LoadWindowStates(state_filename);

is_tracking_shared = false;
RB_FOREACH(m, monitors, &monitor_q)
RB_FOREACH(m, monitors, &monitor_q) {
fvwm_debug(__func__, "SETTING EWMH FOR MONITOR: %s", m->si->name);
EWMH_Init(m);
}

SetRCDefaults();
flush_window_updates();
Expand Down
212 changes: 142 additions & 70 deletions libs/FScreen.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "config.h"

#include <X11/extensions/Xrandr.h>
#include <X11/extensions/randr.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -49,9 +50,15 @@ static bool is_randr_present;
static bool randr_initialised;

static void scan_screens(Display *);
static struct monitor *monitor_new(const char *);
static void monitor_free(struct monitor *);
static void monitor_mark_new(struct monitor *);
static void monitor_mark_old(struct monitor *);
static bool monitor_mark_changed(struct monitor *, XRRMonitorInfo *);
static struct monitor *monitor_by_name(const char *);
static void monitor_set_coords(struct monitor *, XRRMonitorInfo);
static void monitor_assign_number(void);
static void monitor_add(XRRMonitorInfo *);

enum monitor_tracking monitor_mode;
bool is_tracking_shared;
Expand All @@ -77,17 +84,29 @@ static void GetMouseXY(XEvent *eventp, int *x, int *y)
disp, DefaultRootWindow(disp), eventp, x, y);
}

struct monitor *
monitor_new(void)
static struct monitor *
monitor_new(const char *name)
{
struct monitor *m;

m = fxcalloc(1, sizeof *m);
m->flags = m->emit = 0;
m->si = screen_info_new();
m->si->name = fxstrdup(name);

return (m);
}

static void
monitor_free(struct monitor *m)
{
if (m == NULL)
return;

free((char *)m->si->name);
free(m->si);
free(m);
}

static void
monitor_scan_edges(struct monitor *m)
{
Expand Down Expand Up @@ -142,11 +161,8 @@ monitor_refresh_global(void)
* si->name,
* si->{x, y, w, h}
*/
if (monitor_global == NULL) {
monitor_global = monitor_new();
monitor_global->si = screen_info_new();
monitor_global->si->name = fxstrdup(GLOBAL_SCREEN_NAME);
}
if (monitor_global == NULL)
monitor_global = monitor_new(GLOBAL_SCREEN_NAME);

/* At this point, the global screen has been initialised. Refresh the
* coordinate list.
Expand Down Expand Up @@ -455,8 +471,7 @@ monitor_set_coords(struct monitor *m, XRRMonitorInfo rrm)
m->si->y = rrm.y;
m->si->w = rrm.width;
m->si->h = rrm.height;
if (!(m->flags & MONITOR_CHANGED))
m->si->rr_output = *rrm.outputs;
m->si->rr_output = *rrm.outputs;
if (rrm.primary > 0) {
m->flags |= MONITOR_PRIMARY;
m->was_primary = false;
Expand Down Expand Up @@ -491,6 +506,73 @@ monitor_compare(struct monitor *a, struct monitor *b)
(a->si->x - b->si->x) : (a->si->y - b->si->y);
}

static void
monitor_mark_new(struct monitor *m)
{
if (m == NULL)
return;

m->flags |= MONITOR_NEW|MONITOR_ENABLED;

memset(&m->virtual_scr, 0, sizeof(m->virtual_scr));
m->virtual_scr.edge_thickness = 2;
m->virtual_scr.last_edge_thickness = 2;

memset(&m->ewmhc, 0, sizeof(m->ewmhc));
m->Desktops = fxcalloc(1, sizeof *m->Desktops);
m->Desktops->name = NULL;
m->Desktops->next = NULL;
m->Desktops->desk = 0;
m->is_prev = false;
m->was_primary = false;

TAILQ_INSERT_TAIL(&screen_info_q, m->si, entry);

fvwm_debug(__func__, "Added new monitor: %s (%p)", m->si->name, m);
}

static void
monitor_add(XRRMonitorInfo *rrm)
{
struct monitor *m = NULL;
char *name = NULL;

if ((name = XGetAtomName(disp, rrm->name)) == NULL) {
fvwm_debug(__func__, "Tried detecting monitor "
"with output '%d' but it has no name. Skipping.",
(int)*rrm->outputs);
return;
}
m = monitor_new(name);
monitor_mark_new(m);
monitor_set_coords(m, *rrm);

XFree(name);

RB_INSERT(monitors, &monitor_q, m);
}

static bool
monitor_mark_changed(struct monitor *m, XRRMonitorInfo *rrm)
{
if (m == NULL || rrm == NULL)
return (false);

if (m->si->x != rrm->x ||
m->si->y != rrm->y ||
m->si->w != rrm->width ||
m->si->h != rrm->height) {
m->flags |= MONITOR_CHANGED|MONITOR_ENABLED;
m->flags &= ~MONITOR_DISABLED;

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

return (true);
}
return (false);
}

static void
scan_screens(Display *dpy)
{
Expand All @@ -506,70 +588,57 @@ scan_screens(Display *dpy)
exit(101);
}

for (i = 0; i < n; i++) {
if (name != NULL) {
XFree(name);
name = NULL;
}
name = XGetAtomName(dpy, rrm[i].name);

if (name == NULL) {
fprintf(
stderr,
"%s: couldn't detect monitor with empty name\n",
__func__);
exit (101);
/*
* 1. Handle the case where we have no monitors at all. This is going
* to happen at init time. In such cases, we can say that the
* monitor_q is empty.
*
* To handle this case, we create all entries, marking them as new.
*/
if (!randr_initialised && monitor_get_count() == 0) {
fvwm_debug(__func__, "Case 1: Add new monitors");
for (i = 0; i < n; i++) {
monitor_add(&rrm[i]);
}
goto out;
}

/*
* 2. Handle the case where an event has occurred for a monitor. It
* could be that:
* - It's a new monitor.
* - 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.
*/
for (i = 0; i < n; i++) {
if ((name = XGetAtomName(dpy, rrm[i].name)) == NULL)
continue;
if ((m = monitor_by_name(name)) == NULL) {
fvwm_debug(__func__, "NEW: %s\n", name);
m = monitor_new();
m->flags = (MONITOR_NEW|MONITOR_ENABLED);
m->emit |= MONITOR_ENABLED;
m->si = screen_info_new();
m->si->name = strdup(name);

memset(&m->virtual_scr, 0, sizeof(m->virtual_scr));
m->virtual_scr.edge_thickness = 2;
m->virtual_scr.last_edge_thickness = 2;

memset(&m->ewmhc, 0, sizeof(m->ewmhc));
m->Desktops = fxcalloc(1, sizeof *m->Desktops);
m->Desktops->name = NULL;
m->Desktops->next = NULL;
m->Desktops->desk = 0;
m->is_prev = false;
m->was_primary = false;
/* Case 2.1 -- new monitor. */
fvwm_debug(__func__, "Case 2.1");
monitor_add(&rrm[i]);

monitor_set_coords(m, rrm[i]);
TAILQ_INSERT_TAIL(&screen_info_q, m->si, entry);
RB_INSERT(monitors, &monitor_q, m);
} else {
/* We have an existing monitor -- check if it's changed
* at all and flag it for reinsertion.
*/
if (m->si->x != rrm[i].x || m->si->y != rrm[i].y
|| m->si->w != rrm[i].width ||
m->si->h != rrm[i].height) {
m->flags |= MONITOR_CHANGED|MONITOR_ENABLED;
m->flags &= ~MONITOR_DISABLED;
monitor_set_coords(m, rrm[i]);
TAILQ_INSERT_TAIL(&monitorsold_q, m, oentry);

fvwm_debug(__func__, "CHANGED: %s\n", m->si->name);
} else {
if (m->flags & MONITOR_DISABLED) {
m->flags &= ~MONITOR_DISABLED;
m->flags |= MONITOR_ENABLED;

fvwm_debug(__func__, "TOGGLED ENABLED: %s\n", m->si->name);
}
}
}
if (name != NULL) {
XFree(name);
name = NULL;
continue;
}

if (monitor_mark_changed(m, &rrm[i])) {
fvwm_debug(__func__, "Case 2.2");
fvwm_debug(__func__, "I think: %s has changed", m->si->name);
}

/* XXX: Case 2.3 -- toggled. */
#if 0
if (m->flags & MONITOR_DISABLED) {
m->flags &= ~MONITOR_DISABLED;
m->flags |= MONITOR_ENABLED;
fvwm_debug(__func__, "TOGGLED ENABLED: %s\n", m->si->name);
}
#endif
XFree(name);
}

RB_FOREACH_SAFE(m, monitors, &monitor_q, m1) {
Expand All @@ -582,7 +651,7 @@ scan_screens(Display *dpy)
RB_INSERT(monitors, &monitor_q, m);
}
}

out:
/* Now that all monitors have been inserted, assign them a number from
* 0 -> n so that they can be referenced in order.
*/
Expand All @@ -595,6 +664,7 @@ void FScreenInit(Display *dpy)
{
XRRScreenResources *res = NULL;
struct monitor *m;
struct screen_info *si;
int err_base = 0, major, minor;

if (randr_initialised)
Expand All @@ -603,7 +673,6 @@ void FScreenInit(Display *dpy)
disp = dpy;
randr_event = 0;
is_randr_present = false;
struct screen_info *si;
randr_initialised = false;

if (RB_EMPTY(&monitor_q))
Expand Down Expand Up @@ -733,6 +802,9 @@ monitor_get_count(void)
struct monitor *m = NULL;
int c = 0;

if (RB_EMPTY(&monitor_q))
return c;

RB_FOREACH(m, monitors, &monitor_q) {
if (m->flags & MONITOR_DISABLED)
continue;
Expand Down
5 changes: 3 additions & 2 deletions libs/FScreen.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "queue.h"
#include "tree.h"

#include <X11/extensions/Xrandr.h>
#include <stdbool.h>

typedef struct
Expand Down Expand Up @@ -74,7 +75,8 @@ struct screen_info *screen_info_by_name(const char *);
#define MONITOR_ENABLED 0x4
#define MONITOR_PRIMARY 0x8
#define MONITOR_CHANGED 0x10
#define MONITOR_FOUND 0x20
#define MONITOR_OLD 0x20
#define MONITOR_FOUND 0x40
#define MONITOR_ALL (MONITOR_DISABLED|MONITOR_ENABLED|MONITOR_CHANGED)

#define MONITOR_OUTSIDE_EDGE 0
Expand Down Expand Up @@ -172,7 +174,6 @@ void monitor_dump_state(struct monitor *);
void monitor_output_change(Display *, XRRScreenChangeNotifyEvent *);
int monitor_get_all_widths(void);
int monitor_get_all_heights(void);
void monitor_add_new(void);
void monitor_assign_virtual(struct monitor *);
void checkPanFrames(struct monitor *);

Expand Down

0 comments on commit 03776a2

Please sign in to comment.