While, as a programmer, I probably agree with learning from others’ source code; but I also think there is a big gap of information missing from this equation. There are plenty of high-level explanations of the roles of Window Managers and there is source-code. That’s about it.
So just to clarify, here are the roles my Window Manager will be responsible for:
- Listening for events on the root window and all child windows
- Size and placement of windows when they are first created
- Show the difference between the focused/active window and all other windows
- Iconified/Hidden states of windows
- Resizing windows
- Moving floating windows
- Window decoration (If I choose to go down this route?)
- Launching programs
I decided the next phase would be to write the simplest possible Window Manager. This window manager would allow programs to accept the programs preferred location & size and would also draw a white border around the focused/active window.
The code for this example can also be found in ‘simple-wm’ in my GitHub project-sandbox. (Including the MakeFile)
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
static Window focused_win;
int handle_xerror(Display *dpy, XErrorEvent *ee) {
int i=0, alen = sizeof(ee) / sizeof(XErrorEvent);
for (i=0; i<alen; i++) {
fprintf(stderr, “An error occurred: %dn”, ee[i].error_code);
}
return 0;
}
int main()
{
printf(“opening displayn”);
Display *d = XOpenDisplay(NULL);
printf(“grabbing default screenn”);
int screen = DefaultScreen(d);
printf(“default screen = %dn”, screen);
printf(“grabbing root windown”);
Window root = DefaultRootWindow(d);
// tell root window you’ll be capturing it’s events
XSetWindowAttributes a;
a.event_mask = StructureNotifyMask|SubstructureNotifyMask|EnterWindowMask|LeaveWindowMask; // root + child (sub) windows created, window-in, window-out
XSelectInput(d, root, a.event_mask);
// handle errors
XSetErrorHandler(handle_xerror);
// capture those events
XEvent e;
// main event loop
for (;;) {
XNextEvent(d, &e);
if (e.type == CreateNotify) {
printf(“Event: createn”);
XSelectInput(e.xcreatewindow.display, e.xcreatewindow.window, a.event_mask);
XSetWindowBorderWidth(e.xcreatewindow.display, e.xcreatewindow.window, 1); // always set border to 1px
}
else if (e.type == ConfigureNotify) {
printf(“EVENT: configuren”);
}
else if (e.type == EnterNotify) {
printf(“EVENT: focus-inn”);
focused_win = e.xcrossing.window;
a.border_pixel = WhitePixel(e.xcrossing.display, screen);
XChangeWindowAttributes(e.xcrossing.display, focused_win, CWBorderPixel, &a);
}
else if (e.type == LeaveNotify) {
printf(“EVENT: focus-outn”);
a.border_pixel = BlackPixel(e.xcrossing.display, screen);
XChangeWindowAttributes(e.xcrossing.display, e.xcrossing.window, CWBorderPixel, &a);
}
}
return 0;
}
To see this window manager in action you will need to edit your .xinitrc file to launch and wait for an xterm and run the window manager form here. I realise I could launch the window manager from .xinitrc as a background process, but I want to watch the events as they happen from my logging in the host xterm shell.
So I:
- Edited the .xinitrc file for my wmtest user (click here for my .xinitrc file)
- Logged in as that user via SLiM
- Started simple-wm:
- $ /path/to/simple-wm/program&
- Then launched another terminal window on the other side of the screen:
- $ xterm -geometry 50×50+500+500
Notice how I didn’t need to do anything in the code for the xterm window to position correctly at x=500,y=500 and size of 50charsx50chars? If you don’t change the values on the ConfigureNotify event, the client window’s hints are accepted! Now when I hover over the xterm window, I get a white border! Hover out and the border goes black! š
To exit the session just type exit on the xterm shell.