Rico
Rico

Reputation: 11

Xlib Window Manager: Closing Focused Window Causes Unexpected Shutdown

i wrote a simple window manager using Xlib. the window manager runs, and launching a terminal with the Super+t shortcut works correctly. however, when i attempted to close the focused window by sending a window close event to the X server, it didn’t work. as an alternative, i used the XDestroyWindow function, but this approach unexpectedly caused the entire window manager to close. What's the problem?

code:

#include <stdio.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/keysym.h>

Display *display;
Window root;
int running = 1;

/* just for debugging */
void wmlog(unsigned long a)
{
    FILE *file;
    file = fopen("/home/reza/.wmlog", "a");
    if (file == NULL)
    {
        printf("error opening file.\n");
    }
    fprintf(file, "%lu \n", a);
    fclose(file);
}

void open_xterm(Display *display, Window root) {
    system("xterm &");
}

void close_focused_window(Display *display) {
    Window focused;
    int revert_to;
    XGetInputFocus(display, &focused, &revert_to);
    wmlog(focused);

    XDestroyWindow(display, focused);
    /*
    XEvent ev;
    ev.xclient.type = ClientMessage;
    ev.xclient.window = focused;
    ev.xclient.message_type = XInternAtom(display, "WM_PROTOCOLS", True);
    ev.xclient.format = 32;
    ev.xclient.data.l[0] = XInternAtom(display, "WM_DELETE_WINDOW", True);
    ev.xclient.data.l[1] = CurrentTime;
    XSendEvent(display, focused, False, NoEventMask, &ev);
    */
    XFlush(display);
}

int main() {
    Display *display = XOpenDisplay(NULL);
    if (!display) {
        fprintf(stderr, "Error: Unable to open display.\n");
        return 1;
    }

    Window root = DefaultRootWindow(display);
    wmlog(root);

    XGrabKey(display, XKeysymToKeycode(display, XK_t), Mod4Mask, root, True, GrabModeAsync, GrabModeAsync);
    XGrabKey(display, XKeysymToKeycode(display, XK_w), Mod4Mask, root, True, GrabModeAsync, GrabModeAsync);
    XGrabKey(display, XKeysymToKeycode(display, XK_q), Mod4Mask, root, True, GrabModeAsync, GrabModeAsync);

    XEvent event;
    while (running) {
        XNextEvent(display, &event);
        if (event.type == KeyPress) {
            if (event.xkey.keycode == XKeysymToKeycode(display, XK_t) && event.xkey.state & Mod4Mask)
                open_xterm(display, root);
            else if (event.xkey.keycode == XKeysymToKeycode(display, XK_w) && event.xkey.state & Mod4Mask)
                close_focused_window(display);
            else if (event.xkey.keycode == XKeysymToKeycode(display, XK_q) && event.xkey.state & Mod4Mask)
                running = 0;
        }
    }

    XCloseDisplay(display);
    return 0;
}

upon examining the XID of both the root window and the focused window, i noticed that they share the same XID(while the focus was on the terminal window and it was receiving inputs correctly), no new MapNotify events occur while opening xterm.

Upvotes: 1

Views: 60

Answers (1)

gsm
gsm

Reputation: 77

You haven't set input focus with XSetInputFocus. So root window still be focused window. And you should close window like that for safe:

void close_win(Window win)
{
    if(!send_wm_protocol_msg(icccm_atoms[WM_DELETE_WINDOW], win))
        XKillClient(display, win);
}
 bool send_wm_protocol_msg(Atom protocol, Window win)
{   
    if(has_spec_wm_protocol(win, protocol))
    {
        XEvent event; 
        event.type=ClientMessage;
        event.xclient.window=win;
        event.xclient.message_type=icccm_atoms[WM_PROTOCOLS];
        event.xclient.format=32;
        event.xclient.data.l[0]=protocol;
        event.xclient.data.l[1]=CurrentTime;
        return XSendEvent(display, win, False, NoEventMask, &event);
    }
    return false;
}

bool has_spec_wm_protocol(Window win, Atom protocol)
{   
    int i, n;
    Atom *protocols=NULL;
    if(XGetWMProtocols(xinfo.display, win, &protocols, &n))
        for(i=0; i<n; i++)
            if(protocols[i] == protocol)
                { XFree(protocols); return true; }
    return false;
}

I am writing WM too, detail: gsmwm.sf.net

Upvotes: 0

Related Questions