I have developed a window manager using Xlib, where I handle ButtonPress events to set the InputFocus on clicked windows. However, when I open an Xterm window within my window manager, I do not receive the ButtonPress event when clicking on the Xterm window. I am unable to set the InputFocus to the Xterm window, actually, I can't receive any event from Xterm window, the only one that is being sent to my event handler is the events from EnterWindowMask.
I suspect that Xterm is intercepting all events that are not propagating to my window manager. But, when running Xterm under the Mutter window manager, Mutter is able to detect the click on the Xterm window and set the input focus to it.
I would like to understand how Mutter achieves this behavior of triggering some event for the Xterm window and successfully setting the input focus to it when I click on that window. What mechanisms does Mutter employ to intercept and handle input events at a higher level, allowing it to manage window focus and handle button presses on application windows? Are there any specific Xlib or X Input Extension functions I should be using in my Xlib window manager to achieve similar functionality?
My code is something similar to this:
#include <X11/Xlib.h>
#include <iostream>
#include <unordered_map>
#include "FrameWindow.h"
Display* display = nullptr;
std::unordered_map<Window, Window> frames;
std::unordered_map<Window, FrameWindow *> framesMap;
void handleButtonPress(const XButtonEvent event)
{
if (frames.count(event.window)) {
XSetInputFocus(display, event.window, RevertToPointerRoot, CurrentTime);
}
}
void addWindowFrame(Window window, Bool isPreExisting)
{
if (isPreExisting) {
XWindowAttributes winAttrs;
XGetWindowAttributes(display, window, &winAttrs);
if (
winAttrs.override_redirect
|| winAttrs.map_state != IsViewable
) {
return;
}
XSetWindowBorderWidth(display, window, 0);
}
FrameWindow *frame = new FrameWindow(display, window);
frames[window] = frame->frameWindow;
framesMap[frame->frameWindow] = frame;
}
void handleMapRequest(const XMapRequestEvent event)
{
addWindowFrame(event.window, false);
XMapWindow(display, event.window);
}
int main() {
display = XOpenDisplay(NULL);
if (!display) {
std::cerr << "Failed to open X display" << std::endl;
return 1;
}
Window rootWindow = DefaultRootWindow(display);
long events = SubstructureRedirectMask
| SubstructureNotifyMask
| StructureNotifyMask
| ButtonPressMask;
XSelectInput(display, rootWindow, events);
XFlush(display);
XEvent evt;
while (true) {
XNextEvent(display, &evt);
switch (evt.type) {
case CreateNotify:
handleCreateNotify(evt.xcreatewindow);
break;
case ConfigureRequest:
handleConfigureRequest(evt.xconfigurerequest);
break;
case ConfigureNotify:
break;
case MapRequest:
handleMapRequest(display, evt.xmaprequest);
break;
case MapNotify:
handleMapNotify(evt.xmap);
break;
case UnmapNotify:
handleUnmapNotify(evt.xunmap);
break;
case ReparentNotify:
handleReparentNotify(evt.xreparent);
break;
case Expose:
handleButtonPress(evt.xexpose);
break;
case ButtonPress:
handleButtonPress(evt.xbutton);
break;
case ButtonRelease:
handleButtonRelease(evt.xbutton);
break;
case MotionNotify:
handleMotionNotify(evt.xmotion);
break;
case DestroyNotify:
handleDestroyNotify(evt.xdestroywindow);
break;
}
}
// Clean up and close the display
XCloseDisplay(display);
return 0;
}