From f895ffdd413cd02208045e181389a7773cc49994 Mon Sep 17 00:00:00 2001 From: Matthias Kruk Date: Mon, 3 May 2021 09:25:10 +0900 Subject: [PATCH] mwm: Implement monitor detection Monitors connected to the X Server have to be detected in order to provide meaningful window manager functionality. This commit implements dynamic detection of monitors and adds events that a callback can be connected to, so that it will be executed when a monitor has been added. --- Makefile | 6 +- mwm.c | 235 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- mwm.h | 11 +++ 3 files changed, 246 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index af33710..0011f6e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ OUTPUT = mwm -OBJECTS = main.o array.o monitor.o mwm.o +OBJECTS = main.o array.o x.o monitor.o mwm.o ifeq ($(PREFIX), ) PREFIX = /usr/local @@ -9,7 +9,7 @@ ifeq ($(MANPREFIX), ) endif CFLAGS = -std=c99 -pedantic -Wall -Wextra -LDFLAGS = +LDFLAGS = -lX11 -lXinerama PHONY = all clean install uninstall @@ -31,7 +31,7 @@ uninstall: rm -f $(DESTDIR)$(MANPREFIX)/man1/mwm.1 mwm: $(OBJECTS) - $(CC) $(CFLAGS) -o $@ $^ + $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) clean: rm -rf $(OBJECTS) diff --git a/mwm.c b/mwm.c index df16faf..ad5bcb4 100644 --- a/mwm.c +++ b/mwm.c @@ -1,17 +1,174 @@ #include #include #include +#include #include +#include #include "mwm.h" #include "monitor.h" #include "array.h" +#include "x.h" +#include "common.h" + +typedef void (_mwm_xhandler_t)(struct mwm *, XEvent *); struct mwm { Display *display; + int screen; + Window root; + struct geom root_geom; + int running; struct array *monitors; + + _mwm_xhandler_t *xhandler[LASTEvent]; + mwm_handler_t *handler[MWM_EVENT_LAST]; }; +static void _mwm_button_press(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_client_message(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_configure_request(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_configure_notify(struct mwm *mwm, XEvent *event) +{ + XConfigureEvent *cevent; + XineramaScreenInfo *screen_info; + int num_monitors; + int i; + + cevent = &event->xconfigure; + + if(cevent->window != mwm->root) { + return; + } + + if(x_get_geom(mwm->display, mwm->root, &mwm->root_geom) < 0) { + mwm_stop(mwm); + return; + } + + screen_info = XineramaQueryScreens(mwm->display, &num_monitors); + + for(i = 0; i < num_monitors; i++) { + struct monitor *mon; + + printf("Screen Info %d/%d: %d, %d, %d, %d\n", + i, + screen_info[i].screen_number, + screen_info[i].x_org, screen_info[i].y_org, + screen_info[i].width, screen_info[i].height); + + if(array_get(mwm->monitors, screen_info[i].screen_number, (void**)&mon) < 0) { + printf("New monitor\n"); + + if(monitor_new(screen_info[i].screen_number, + screen_info[i].x_org, screen_info[i].y_org, + screen_info[i].width, screen_info[i].height, + &mon) < 0) { + /* TODO: Let the user know */ + return; + } + + if(mwm_attach_monitor(mwm, mon) < 0) { + monitor_free(&mon); + /* TODO: Again, let the user know */ + return; + } + } else { + /* update geometry */ + + printf("Old monitor\n"); + + if(monitor_set_geometry(mon, screen_info[i].x_org, screen_info[i].y_org, + screen_info[i].width, screen_info[i].height) < 0) { + /* TODO: Let the user know */ + } + } + } + + /* TODO: check if monitors have been removed */ + + if(screen_info) { + XFree(screen_info); + } + + return; +} + +static void _mwm_destroy_notify(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_enter_notify(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_expose(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_focus_in(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_key_press(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_mapping_notify(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_map_request(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_motion_notify(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_property_notify(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_unmap_notify(struct mwm *mwm, XEvent *event) +{ + return; +} + +static void _mwm_notify(struct mwm *mwm, mwm_event_t event, void *data) +{ + if(!mwm || event >= MWM_EVENT_LAST) { + return; + } + + if(mwm->handler[event]) { + mwm->handler[event](mwm, event, data); + } + + return; +} + int mwm_new(struct mwm **dst) { struct mwm *mwm; @@ -33,6 +190,21 @@ int mwm_new(struct mwm **dst) return(-ENOMEM); } + mwm->xhandler[ButtonPress] = _mwm_button_press; + mwm->xhandler[ClientMessage] = _mwm_client_message; + mwm->xhandler[ConfigureRequest] = _mwm_configure_request; + mwm->xhandler[ConfigureNotify] = _mwm_configure_notify; + mwm->xhandler[DestroyNotify] = _mwm_destroy_notify; + mwm->xhandler[EnterNotify] = _mwm_enter_notify; + mwm->xhandler[Expose] = _mwm_expose; + mwm->xhandler[FocusIn] = _mwm_focus_in; + mwm->xhandler[KeyPress] = _mwm_key_press; + mwm->xhandler[MappingNotify] = _mwm_mapping_notify; + mwm->xhandler[MapRequest] = _mwm_map_request; + mwm->xhandler[MotionNotify] = _mwm_motion_notify; + mwm->xhandler[PropertyNotify] = _mwm_property_notify; + mwm->xhandler[UnmapNotify] = _mwm_unmap_notify; + *dst = mwm; return(0); @@ -48,6 +220,10 @@ int mwm_free(struct mwm **mwm) return(-EALREADY); } + if((*mwm)->display) { + XCloseDisplay((*mwm)->display); + } + free(*mwm); *mwm = NULL; @@ -56,12 +232,63 @@ int mwm_free(struct mwm **mwm) int mwm_init(struct mwm *mwm) { - return(-ENOSYS); + if(!mwm) { + return(-EINVAL); + } + + mwm->display = XOpenDisplay(NULL); + + if(!mwm->display) { + return(-EIO); + } + + mwm->screen = DefaultScreen(mwm->display); + mwm->root = RootWindow(mwm->display, mwm->screen); + + XSelectInput(mwm->display, mwm->root, + SubstructureRedirectMask | + SubstructureNotifyMask | + ButtonPressMask | + PointerMotionMask | + EnterWindowMask | + LeaveWindowMask | + StructureNotifyMask | + PropertyChangeMask); + + x_configure_notify(mwm->display, mwm->root, NULL, 0); + + return(0); } int mwm_run(struct mwm *mwm) { - return(-ENOSYS); + XEvent event; + + XSync(mwm->display, False); + mwm->running = 1; + + while(mwm->running && !XNextEvent(mwm->display, &event)) { + if(mwm->xhandler[event.type]) { + mwm->xhandler[event.type](mwm, &event); + } + } + + return(0); +} + +int mwm_stop(struct mwm *mwm) +{ + if(!mwm) { + return(-EINVAL); + } + + if(!mwm->running) { + return(-EALREADY); + } + + mwm->running = 0; + + return(0); } int mwm_attach_monitor(struct mwm *mwm, struct monitor *mon) @@ -78,7 +305,9 @@ int mwm_attach_monitor(struct mwm *mwm, struct monitor *mon) return(-ENOMEM); } - /* register monitor */ + _mwm_notify(mwm, MWM_EVENT_MONITOR_ATTACHED, mon); + + printf("Attached monitor %d: %p\n", idx, (void*)mon); return(0); } diff --git a/mwm.h b/mwm.h index 645ec08..067b4c0 100644 --- a/mwm.h +++ b/mwm.h @@ -1,14 +1,25 @@ #ifndef MWM_H #define MWM_H 1 +#include + struct mwm; struct monitor; +typedef enum { + MWM_EVENT_MONITOR_ATTACHED = 0, + MWM_EVENT_MONITOR_DETACHED, + MWM_EVENT_LAST +} mwm_event_t; + +typedef void (mwm_handler_t)(struct mwm *mwm, mwm_event_t, void *); + int mwm_new(struct mwm **mwm); int mwm_free(struct mwm **mwm); int mwm_init(struct mwm *mwm); int mwm_run(struct mwm *mwm); +int mwm_stop(struct mwm *mwm); int mwm_attach_monitor(struct mwm *mwm, struct monitor *mon); int mwm_detach_monitor(struct mwm *mwm, struct monitor *mon); -- 2.47.3