commit cb313699478ad76b6aa178987f60b949805ada7e Author: Paul Breugnot Date: Sat Dec 7 10:13:17 2024 +0100 :tada: Let's go A minimalistic but working X XM POC. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..18a6bbf --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.20) + +project(aswm) + +find_package(X11 REQUIRED) + +add_executable(aswm + src/main.c + src/create.c + src/configure.c + src/reparent.c + src/destroy.c + src/map.c) +target_include_directories(aswm PUBLIC ${X11_INCLUDE_DIR} include) +target_link_libraries(aswm ${X11_LIBRARIES}) diff --git a/include/configure.h b/include/configure.h new file mode 100644 index 0000000..f6a99d7 --- /dev/null +++ b/include/configure.h @@ -0,0 +1,3 @@ +#include + +void OnConfigureRequest(const XConfigureRequestEvent*); diff --git a/include/create.h b/include/create.h new file mode 100644 index 0000000..3fc8812 --- /dev/null +++ b/include/create.h @@ -0,0 +1,3 @@ +#include + +void OnCreateNotify(const XCreateWindowEvent*); diff --git a/include/destroy.h b/include/destroy.h new file mode 100644 index 0000000..c1be020 --- /dev/null +++ b/include/destroy.h @@ -0,0 +1,3 @@ +#include + +void OnDestroyNotify(const XDestroyWindowEvent* e); diff --git a/include/map.h b/include/map.h new file mode 100644 index 0000000..e8638ca --- /dev/null +++ b/include/map.h @@ -0,0 +1,3 @@ +#include + +void OnMapRequest(Window root, const XMapRequestEvent* e); diff --git a/include/reparent.h b/include/reparent.h new file mode 100644 index 0000000..f36ba22 --- /dev/null +++ b/include/reparent.h @@ -0,0 +1,3 @@ +#include + +void OnReparentNotify(const XReparentEvent*); diff --git a/include/unmap.h b/include/unmap.h new file mode 100644 index 0000000..f82fe1c --- /dev/null +++ b/include/unmap.h @@ -0,0 +1,3 @@ +#include + +void OnUnmapRequest(Window root, const XMapRequestEvent* e); diff --git a/src/configure.c b/src/configure.c new file mode 100644 index 0000000..ec158e9 --- /dev/null +++ b/src/configure.c @@ -0,0 +1,21 @@ +#ifndef ASWM_CONFIGURE +#define ASWM_CONFIGURE + +#include "configure.h" +#include + +void OnConfigureRequest(const XConfigureRequestEvent* e) { + XWindowChanges changes; + printf("XConfigureRequestEvent %lu\n", e->window); + // Copy fields from e to changes. + changes.x = e->x; + changes.y = e->y; + changes.width = e->width; + changes.height = e->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); +} +#endif diff --git a/src/create.c b/src/create.c new file mode 100644 index 0000000..3b6fed9 --- /dev/null +++ b/src/create.c @@ -0,0 +1,10 @@ +#ifndef ASWM_CREATE +#define ASWM_CREATE + +#include "create.h" +#include + +void OnCreateNotify(const XCreateWindowEvent* e) { + printf("XCreateWindowEvent %lu\n", e->window); +} +#endif diff --git a/src/destroy.c b/src/destroy.c new file mode 100644 index 0000000..635c844 --- /dev/null +++ b/src/destroy.c @@ -0,0 +1,7 @@ +#include "destroy.h" +#include + +void OnDestroyNotify(const XDestroyWindowEvent* e) { + printf("XDestroyWindowEvent %lu\n", e->window); + // TODO: destroy frame +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..766493e --- /dev/null +++ b/src/main.c @@ -0,0 +1,46 @@ +#include +#include "create.h" +#include "configure.h" +#include "map.h" +#include "reparent.h" +#include "destroy.h" + +Display *display; +Window root; + +int main(int argc, char** argv) { + display = XOpenDisplay(NULL); + + root = DefaultRootWindow(display); + + XSelectInput(display, root, SubstructureRedirectMask | SubstructureNotifyMask); + XSync(display, 0); + + for (;;) { + XEvent e; + XNextEvent(display, &e); + + switch(e.type) { + case CreateNotify: + OnCreateNotify(&e.xcreatewindow); + break; + case ConfigureRequest: + OnConfigureRequest(&e.xconfigurerequest); + break; + case MapRequest: + OnMapRequest(root, &e.xmaprequest); + break; + case DestroyNotify: + OnDestroyNotify(&e.xdestroywindow); + break; + case ReparentNotify: + OnReparentNotify(&e.xreparent); + break; + default: + break; + /* LOG(WARNING) << "Ignored event"; */ + } + } + + XCloseDisplay(display); +} diff --git a/src/map.c b/src/map.c new file mode 100644 index 0000000..643b470 --- /dev/null +++ b/src/map.c @@ -0,0 +1,75 @@ +#ifndef ASWM_MAP +#define ASWM_MAP + +#include "map.h" +#include + +void map_fullscreen_window(Window root, Display* display, Window w); + +void OnMapRequest(Window root, const XMapRequestEvent* e) { + printf("XMapRequestEvent %lu\n", e->window); + map_fullscreen_window(root, e->display, e->window); + XMapWindow(e->display, e->window); +} + +void map_fullscreen_window(Window root, Display* display, Window w) { + // Visual properties of the frame to create. + const unsigned int BORDER_WIDTH = 0; + const unsigned long BORDER_COLOR = 0xff0000; + const unsigned long BG_COLOR = 0x0000ff; + + // 1. Retrieve attributes of window to frame. + XWindowAttributes x_window_attrs; + XGetWindowAttributes(display, w, &x_window_attrs); + + // 2. TODO - see Framing Existing Top-Level Windows section below. + + printf("\tXCreateSimpleWindow:\n"); + printf("\t\tx: %i\n", x_window_attrs.x); + printf("\t\ty: %i\n", x_window_attrs.y); + printf("\t\tw: %i\n", x_window_attrs.width); + printf("\t\th: %i\n", x_window_attrs.height); + + // 3. Create frame. + const Window frame = XCreateSimpleWindow( + display, + root, + x_window_attrs.x, + x_window_attrs.y, + x_window_attrs.width, + x_window_attrs.height, + BORDER_WIDTH, + BORDER_COLOR, + BG_COLOR); + // 3. Select events on frame. + XSelectInput( + display, + frame, + SubstructureRedirectMask | SubstructureNotifyMask); + // 4. Add client to save set, so that it will be restored and kept alive if we + // crash. + XAddToSaveSet(display, w); + // 5. Reparent client window. + XReparentWindow( + display, + w, + frame, + 0, 0); // Offset of client window within frame. + // 6. Map frame. + XMapWindow(display, frame); + // 7. Save frame handle. + /* clients_[w] = frame; */ + // 8. Grab events for window management actions on client window. + // a. Move windows with alt + left button. + /* XGrabButton(...); */ + // b. Resize windows with alt + right button. + /* XGrabButton(...); */ + // c. Kill windows with alt + f4. + /* XGrabKey(...); */ + // d. Switch windows with alt + tab. + /* XGrabKey(...); */ + + printf("\tFramed window %lu [%lu]\n", w, frame); +} + +#endif diff --git a/src/reparent.c b/src/reparent.c new file mode 100644 index 0000000..f2f3842 --- /dev/null +++ b/src/reparent.c @@ -0,0 +1,6 @@ +#include "reparent.h" +#include + +void OnReparentNotify(const XReparentEvent* e) { + printf("XReparentEvent %lu\n", e->window); +} diff --git a/src/unmap.c b/src/unmap.c new file mode 100644 index 0000000..f55ccac --- /dev/null +++ b/src/unmap.c @@ -0,0 +1,29 @@ +#include "unmap.h" +#include + +void OnUnmapRequest(Window root, const XMapRequestEvent* e) { + printf("XUnmapWindow %lu", e->window); +} + +/* + * void unframe(Window root, Display* display, Window w) { + * // We reverse the steps taken in Frame(). + * const Window frame = clients_[w]; + * // 1. Unmap frame. + * XUnmapWindow(display, frame); + * // 2. Reparent client window back to root window. + * XReparentWindow( + * display, + * w, + * root, + * 0, 0); // Offset of client window within root. + * // 3. Remove client window from save set, as it is now unrelated to us. + * XRemoveFromSaveSet(display, w); + * // 4. Destroy frame. + * XDestroyWindow(display, frame); + * // 5. Drop reference to frame handle. + * clients_.erase(w); + * + * LOG(INFO) << "Unframed window " << w << " [" << frame << "]"; + * } + */