Xlib窗口管理器未接收到xterm窗口的ButtonPress事件。

huangapple go评论75阅读模式
英文:

Xlib window manager not receiving ButtonPress event for xterm window

问题

我已经开发了一个使用Xlib的窗口管理器,我在其中处理ButtonPress事件来设置点击的窗口的InputFocus。然而,当我在我的窗口管理器内打开一个Xterm窗口时,当单击Xterm窗口时,我不会收到ButtonPress事件。我无法将InputFocus设置到Xterm窗口,实际上,我无法从Xterm窗口接收任何事件,唯一发送到我的事件处理程序的事件来自EnterWindowMask。

我怀疑Xterm正在拦截所有不传播到我的窗口管理器的事件。但是,当在Mutter窗口管理器下运行Xterm时,Mutter能够检测到单击Xterm窗口并将输入焦点设置到该窗口。

我想了解Mutter是如何实现这种触发Xterm窗口的事件并成功设置输入焦点到它的行为的。Mutter使用了什么机制来拦截和处理更高级别的输入事件,使其能够管理窗口焦点并处理对应用程序窗口的按钮按下事件?是否有任何特定的Xlib或X输入扩展函数,我应该在我的Xlib窗口管理器中使用以实现类似的功能?

我的代码与以下代码类似:

#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;
}

希望这能帮助你解决问题。如果你有进一步的问题,请随时提出。

英文:

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 &lt;X11/Xlib.h&gt;
#include &lt;iostream&gt;
#include &lt;unordered_map&gt;
#include &quot;FrameWindow.h&quot;
Display* display = nullptr;
std::unordered_map&lt;Window, Window&gt; frames;
std::unordered_map&lt;Window, FrameWindow *&gt; 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, &amp;winAttrs);
if (
winAttrs.override_redirect
|| winAttrs.map_state != IsViewable
) {
return;
}
XSetWindowBorderWidth(display, window, 0);
}
FrameWindow *frame = new FrameWindow(display, window);
frames[window] = frame-&gt;frameWindow;
framesMap[frame-&gt;frameWindow] = frame;
}
void handleMapRequest(const XMapRequestEvent event)
{
addWindowFrame(event.window, false);
XMapWindow(display, event.window);
}
int main() {
display = XOpenDisplay(NULL);
if (!display) {
std::cerr &lt;&lt; &quot;Failed to open X display&quot; &lt;&lt; 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, &amp;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;
}

答案1

得分: 0

我目前还无法调试Mutter以理解它如何处理这种情况,但为了解决这个问题并确保我的窗口管理器接收到xterm窗口的ButtonPress事件,我使用了XGrabButton在具体的Xterm窗口上带有我的窗口管理器的ButtonPressMask。通过这样做,我可以覆盖Xterm窗口中的事件处理,让我的窗口管理器处理ButtonPress事件。

以下是如何在具有与xterm相同问题的窗口上使用XGrabButton的示例:

void addWindowFrame(Window window, Bool isPreExisting)
{
  // ...
  
  XGrabButton(
    display, Button1, AnyModifier, contentWindow, true,
    ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None
  );
  
  // ...
}
英文:

I could not debug mutter yet in order to understand how it handles this kind of situation, but to work around this issue and ensure that my window manager receives the ButtonPress event for the xterm window, I've used the XGrabButton with the ButtonPressMask on the specific Xterm window that was framed with my window manager. By doing so, I could override the event handling in the Xterm window and my window manager processes the ButtonPress events.

Here's an example of how to use XGrabButton on window that has the same issue that xterm:

void addWindowFrame(Window window, Bool isPreExisting)
{
// ...
XGrabButton(
display, Button1, AnyModifier, contentWindow, true,
ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None
);
// ...
}

huangapple
  • 本文由 发表于 2023年7月17日 09:05:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/76700987.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定