diff --git a/src/aswm/aswm.c b/src/aswm/aswm.c index 0f44bcd..3144d3b 100644 --- a/src/aswm/aswm.c +++ b/src/aswm/aswm.c @@ -7,24 +7,67 @@ #include "event_handlers/unmap.h" #include "event_handlers/reparent.h" #include "event_handlers/destroy.h" -#include "log/log.h" +#include "log/error.h" Aswm _aswm; + void aswm_open() { _aswm.display = XOpenDisplay(NULL); - Window root_window = DefaultRootWindow(_aswm.display); + _aswm.workspaces = malloc(0); + _aswm.workspace_count = 0; - printf("PointerRoot %lu\n", PointerRoot); - printf("None %lu\n", None); - printf("Root window %lu\n", root_window); + XSetErrorHandler(aswm_error_handler); - XSelectInput(_aswm.display, root_window, SubstructureRedirectMask | SubstructureNotifyMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask); + Window x_root_window = DefaultRootWindow(_aswm.display); + XWindowAttributes x_root_attributes; + XGetWindowAttributes(_aswm.display, x_root_window, &x_root_attributes); + + _aswm.root_window = XCreateSimpleWindow( + _aswm.display, x_root_window, + 0, 0, + x_root_attributes.width, + x_root_attributes.height, + 0, 0, 0); + + // User windows are created from the X root window, while ASWM specific + // windows are created on the ASWM root window + XSelectInput(_aswm.display, _aswm.root_window, FocusChangeMask | EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask); + + XSelectInput(_aswm.display, x_root_window, SubstructureRedirectMask | SubstructureNotifyMask | FocusChangeMask | EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask); + + XMapWindow(_aswm.display, _aswm.root_window); XSync(_aswm.display, 0); + printf("PointerRoot %lu\n", PointerRoot); + printf("Useful constants:\n"); + printf("\tNone: %lu\n", None); + printf("\tTrue / False: %i / %i\n", True, False); + printf("X Root window %lu\n", x_root_window); + printf("ASWM Root window %lu\n", _aswm.root_window); + atexit(aswm_close); } +void aswm_create_workspace() { + _aswm.workspaces = realloc(_aswm.workspaces, (_aswm.workspace_count+1) * sizeof(Window)); + + XWindowAttributes root_attributes; + XGetWindowAttributes(_aswm.display, _aswm.root_window, &root_attributes); + + _aswm.workspaces[_aswm.workspace_count] = XCreateSimpleWindow( + _aswm.display, _aswm.root_window, + 0, 0, + root_attributes.width, root_attributes.height, + 0, 0, 0); + + _aswm.current_workspace = _aswm.workspaces[_aswm.workspace_count]; + _aswm.workspace_count++; + XSelectInput(_aswm.display, _aswm.current_workspace, SubstructureNotifyMask); + XMapWindow(_aswm.display, _aswm.current_workspace); + printf("Create workspace %lu\n", _aswm.current_workspace); +} + void aswm_event_loop() { for (;;) { XEvent e; @@ -32,20 +75,19 @@ void aswm_event_loop() { switch(e.type) { case CreateNotify: - OnCreateNotify(&e.xcreatewindow); + // Windows with override_redirect set to True can be safely + // ignored, according to the X server specification. + if(e.xcreatewindow.override_redirect == False) + OnCreateNotify(&_aswm, &e.xcreatewindow); break; case ConfigureRequest: OnConfigureRequest(&e.xconfigurerequest); break; case MapRequest: OnMapRequest(&_aswm, &e.xmaprequest); - printf("Map tree:\n"); - log_tree(_aswm.display, DefaultRootWindow(_aswm.display), 1); break; case UnmapNotify: OnUnmapNotify(&_aswm, &e.xunmap); - printf("Unmap tree:\n"); - log_tree(_aswm.display, DefaultRootWindow(_aswm.display), 1); break; case DestroyNotify: OnDestroyNotify(&e.xdestroywindow); @@ -75,6 +117,19 @@ void aswm_event_loop() { case ButtonRelease: printf("Release %lu\n", e.xbutton.window); break; + case ClientMessage: + // TODO: handle this + printf("Unhandled client message from window %lu:\n", e.xclient.window); + char* atom_name = XGetAtomName(e.xclient.display, e.xclient.message_type); + printf("\t%s\n", atom_name); + XFree(atom_name); + break; + case PropertyNotify: + // TODO: handle this + printf("Unhandled property change for window %lu:\n", e.xclient.window); + char* property_name = XGetAtomName(e.xclient.display, e.xclient.message_type); + printf("\t%s\n", property_name); + XFree(property_name); default: break; /* LOG(WARNING) << "Ignored event"; */ @@ -83,6 +138,7 @@ void aswm_event_loop() { } void aswm_close() { + free(_aswm.workspaces); XCloseDisplay(_aswm.display); } diff --git a/src/aswm/aswm.h b/src/aswm/aswm.h index bd4c9da..98e97d3 100644 --- a/src/aswm/aswm.h +++ b/src/aswm/aswm.h @@ -5,10 +5,14 @@ typedef struct { Display *display; - Window es_de_window; + Window root_window; + Window* workspaces; + unsigned int workspace_count; + Window current_workspace; } Aswm; void aswm_open(); +void aswm_create_workspace(); void aswm_event_loop(); void aswm_close(); diff --git a/src/aswm/event_handlers/configure.c b/src/aswm/event_handlers/configure.c index ec316a4..937211b 100644 --- a/src/aswm/event_handlers/configure.c +++ b/src/aswm/event_handlers/configure.c @@ -2,25 +2,9 @@ #include void OnConfigureRequest(const XConfigureRequestEvent* e) { - printf("XConfigureRequestEvent %lu\n", e->window); + printf("XConfigureRequestEvent %lu (ignored)\n", e->window); printf("\tx = %i\n", e->x); printf("\ty = %i\n", e->y); printf("\tw = %i\n", e->width); printf("\th = %i\n", e->height); - - int screen_number = XDefaultScreen(e->display); - int full_width = XDisplayWidth(e->display, screen_number); - int full_height = XDisplayWidth(e->display, screen_number); - - // Copy fields from e to changes. - XWindowChanges changes; - changes.x = 0; - changes.y = 0; - changes.width = full_width; - changes.height = full_height; - changes.border_width = e->border_width; - changes.sibling = e->above; - changes.stack_mode = e->detail; - // Grant request by calling XConfigureWindow(). - XConfigureWindow(e->display, e->window, e->value_mask, &changes); } diff --git a/src/aswm/event_handlers/create.c b/src/aswm/event_handlers/create.c index 95c3052..5dec25d 100644 --- a/src/aswm/event_handlers/create.c +++ b/src/aswm/event_handlers/create.c @@ -1,6 +1,34 @@ #include "create.h" #include +#include +#include -void OnCreateNotify(const XCreateWindowEvent* e) { - printf("XCreateWindowEvent %lu\n", e->window); +void OnCreateNotify(Aswm* aswm, const XCreateWindowEvent* e) { + printf("XCreateWindowEvent %lu on parent %lu\n", e->window, e->parent); + printf("\tx = %i\n", e->x); + printf("\ty = %i\n", e->y); + printf("\tw = %i\n", e->width); + printf("\th = %i\n", e->height); + printf("\toverride_redirect = %i\n", e->override_redirect); + + // The WM must subscribe to property changes, notably to implement the + // Extended Window Manager Hints (EWMH) propocol + XSelectInput(aswm->display, e->window, PropertyChangeMask); + + { + XTextProperty text_property; + if(XGetWMName(e->display, e->window, &text_property)) { + printf("\tname: %s\n", text_property.value); + } + } + { + XClassHint class; + if(XGetClassHint(e->display, e->window, &class)) { + printf("\tclass: %s, %s\n", class.res_class, class.res_name); + XFree(class.res_class); + XFree(class.res_name); + } + } + if(aswm->workspace_count == 0) + aswm_create_workspace(); } diff --git a/src/aswm/event_handlers/create.h b/src/aswm/event_handlers/create.h index 3fc8812..bc60d72 100644 --- a/src/aswm/event_handlers/create.h +++ b/src/aswm/event_handlers/create.h @@ -1,3 +1,4 @@ #include +#include "aswm/aswm.h" -void OnCreateNotify(const XCreateWindowEvent*); +void OnCreateNotify(Aswm* aswm, const XCreateWindowEvent*); diff --git a/src/aswm/event_handlers/map.c b/src/aswm/event_handlers/map.c index 357c063..954cf2c 100644 --- a/src/aswm/event_handlers/map.c +++ b/src/aswm/event_handlers/map.c @@ -1,29 +1,27 @@ #include "map.h" #include -#include -#include +#include "aswm/log/log.h" +#include "X11/Xutil.h" void OnMapRequest(Aswm* aswm, const XMapRequestEvent* e) { printf("XMapRequestEvent %lu\n", e->window); - { - XTextProperty text_property; - XGetWMName(e->display, e->window, &text_property); - printf("\tname: %s\n", text_property.value); - if(text_property.value != nullptr && strcmp(text_property.value, "ES-DE") == 0) - aswm->es_de_window = e->window; - } - { - XClassHint class; - XGetClassHint(e->display, e->window, &class); - printf("\tclass: %s, %s\n", class.res_class, class.res_name); - } + /* XSizeHints* size = XAllocSizeHints(); */ + /* long supplied; */ + /* if(XGetWMNormalHints(aswm->display, e->window, size, &supplied)) { */ + /* printf("\tWMNormalHints:\n"); */ + /* printf("\t\tMin w:%i\n", size->min_width); */ + /* printf("\t\tMin h:%i\n", size->min_height); */ + /* printf("\t\tMax w:%i\n", size->max_width); */ + /* printf("\t\tMax h:%i\n", size->max_height); */ + /* printf("\t\tBase w:%i\n", size->base_width); */ + /* printf("\t\tBase h:%i\n", size->base_height); */ + /* } */ - int screen_number = XDefaultScreen(e->display); - int full_width = XDisplayWidth(e->display, screen_number); - int full_height = XDisplayWidth(e->display, screen_number); + // Assumes map requests are always received on root and adressed to the + // current workspace + aswm_map_new_window(e->display, aswm->current_workspace, e->window); - aswm_map_new_window(e->display, DefaultRootWindow(e->display), e->window); - - /* XSelectInput(e->display, e->window, FocusChangeMask | EnterWindowMask | LeaveWindowMask | ButtonPressMask | ButtonReleaseMask); */ + printf("Map tree:\n"); + log_tree(aswm->display, DefaultRootWindow(aswm->display), 1); } diff --git a/src/aswm/event_handlers/unmap.c b/src/aswm/event_handlers/unmap.c index a439967..6faa3b3 100644 --- a/src/aswm/event_handlers/unmap.c +++ b/src/aswm/event_handlers/unmap.c @@ -1,12 +1,17 @@ #include "unmap.h" #include +#include "aswm/log/log.h" void OnUnmapNotify(Aswm* aswm, const XUnmapEvent* e) { printf("XUnmapWindow %lu tiled in %lu\n", e->window, e->event); - printf("ES-DE window %lu\n", aswm->es_de_window); - if(aswm->es_de_window != None) - XSetInputFocus(e->display, aswm->es_de_window, RevertToPointerRoot, CurrentTime); + /* printf("ES-DE window %lu\n", aswm->es_de_window); */ + /* if(aswm->es_de_window != None) */ + /* XSetInputFocus(e->display, aswm->es_de_window, RevertToPointerRoot, CurrentTime); */ // Since SubstructureNotify is selected on each frame, e->event corresponds // to the parent of the unmapped window (e->window) - aswm_unmap_window(e->display, e->event); + + // Only handles request that refer to the ASWM window hierarchy + aswm_unmap_window(e->display, e->event, e->window); + printf("Unmap tree:\n"); + log_tree(aswm->display, DefaultRootWindow(aswm->display), 1); } diff --git a/src/aswm/log/error.h b/src/aswm/log/error.h new file mode 100644 index 0000000..d119390 --- /dev/null +++ b/src/aswm/log/error.h @@ -0,0 +1,15 @@ +#ifndef ASWM_ERROR_H +#define ASWM_ERROR_H + +#include +#include + +char message_buffer[1024]; + +int aswm_error_handler( Display *disp, XErrorEvent *xe ) { + XGetErrorText(xe->display, xe->error_code, message_buffer, 1024); + printf("%s", message_buffer); + return 0; +} + +#endif diff --git a/src/aswm/mapper/mapper.c b/src/aswm/mapper/mapper.c index 1d30688..cbf7e90 100644 --- a/src/aswm/mapper/mapper.c +++ b/src/aswm/mapper/mapper.c @@ -53,23 +53,23 @@ void h_split(Display* display, Window current_tile, Window window_to_map) { XMapWindow(display, window_to_map); } -void resize_children_to_tile(Display* display, Window tile) { +void resize_children_to_parent(Display* display, Window parent) { Window _root_window; // unused Window _grand_parent; // unused Window* children; unsigned int children_count; XQueryTree( - display, tile, + display, parent, &_root_window, &_grand_parent, &children, &children_count); - printf("Current siblings of %lu:\n", tile); + printf(" Resize children of %lu:\n", parent); for(auto i = 0; i < children_count; i++) printf("%lu ", children[i]); printf("\n"); // Resize new children of the parent tile XWindowAttributes parent_attributes; - XGetWindowAttributes(display, tile, &parent_attributes); + XGetWindowAttributes(display, parent, &parent_attributes); for(auto i = 0; i < children_count; i++) { // TODO: currently only hsplit supported @@ -82,11 +82,11 @@ void resize_children_to_tile(Display* display, Window tile) { XFree(children); } -void aswm_unmap_window(Display* display, Window tile) { +void aswm_unmap_window(Display* display, Window parent, Window window) { // +-------------------------------+ // | root | // |+-------------+ +-------------+| - // || tile | | || + // || parent | | || // || +--------+ | | || // || | win 1 | | | || // || +--------+ | | || @@ -99,5 +99,26 @@ void aswm_unmap_window(Display* display, Window tile) { // |+-------------+ +-------------+| // +-------------------------------+ - resize_children_to_tile(display, tile); + Window _root_window; // unused + Window _grand_parent; // unused + Window* children; + unsigned int children_count; + XQueryTree( + display, parent, + &_root_window, &_grand_parent, + &children, &children_count); + printf(" Current children of %lu:\n", parent); + for(auto i = 0; i < children_count; i++) + printf("%lu ", children[i]); + printf("\n"); + for(auto i = 0; i < children_count; i++) { + if(children[i] == window) + // If the unmap request does not come from a destroy window, we + // still want to remove the window from the ASWM hierarchy. It is + // the responsability of the client to decide to remap it latter or + // not. + XReparentWindow(display, window, XDefaultRootWindow(display), 0, 0); + } + + resize_children_to_parent(display, parent); } diff --git a/src/aswm/mapper/mapper.h b/src/aswm/mapper/mapper.h index e14b576..ea82ecd 100644 --- a/src/aswm/mapper/mapper.h +++ b/src/aswm/mapper/mapper.h @@ -6,6 +6,6 @@ Window create_aswm_root_tile(Display* display, Window root_window); void aswm_map_new_window(Display* display, Window current_node, Window window_to_map); -void aswm_unmap_window(Display* display, Window window); +void aswm_unmap_window(Display* display, Window parent, Window window); #endif