]> git.corax.cc Git - mwm/commitdiff
mwm: Implement monitor detection
authorMatthias Kruk <m@m10k.eu>
Mon, 3 May 2021 00:25:10 +0000 (09:25 +0900)
committerMatthias Kruk <m@m10k.eu>
Mon, 3 May 2021 00:25:10 +0000 (09:25 +0900)
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
mwm.c
mwm.h

index af33710a5afba2913e1e06fadb8a77049fde2bf2..0011f6e6576d2b216f5aed546709348e2ae89a0a 100644 (file)
--- 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 df16fafa56e9f1bc5ba16c905d5d4388226a4e73..ad5bcb453ec643bf92542caa7bb205f033c729a6 100644 (file)
--- a/mwm.c
+++ b/mwm.c
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <stdio.h>
 #include <X11/Xlib.h>
+#include <X11/extensions/Xinerama.h>
 #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 645ec0898fe9f7eaeb986da8d30e595a21e9f27b..067b4c0bb87c2e26c3ead64b4b212e4a74c2dd94 100644 (file)
--- a/mwm.h
+++ b/mwm.h
@@ -1,14 +1,25 @@
 #ifndef MWM_H
 #define MWM_H 1
 
+#include <X11/Xlib.h>
+
 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);