Reputation: 11
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
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