c - 如何捕获 XWindows 中的最小化和最大化事件?

标签 c x11 gdm

我想确定我的 XWindow 是最小化还是最大化。我的示例程序是:

/*
 * Study for multiple windows.
 */
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void prtxevtt(int type)

{

    switch (type) {

        case 2:  fprintf(stderr, "KeyPress"); break;
        case 3:  fprintf(stderr, "KeyRelease"); break;
        case 4:  fprintf(stderr, "ButtonPress"); break;
        case 5:  fprintf(stderr, "ButtonRelease"); break;
        case 6:  fprintf(stderr, "MotionNotify"); break;
        case 7:  fprintf(stderr, "EnterNotify"); break;
        case 8:  fprintf(stderr, "LeaveNotify"); break;
        case 9:  fprintf(stderr, "FocusIn"); break;
        case 10: fprintf(stderr, "FocusOut"); break;
        case 11: fprintf(stderr, "KeymapNotify"); break;
        case 12: fprintf(stderr, "Expose"); break;
        case 13: fprintf(stderr, "GraphicsExpose"); break;
        case 14: fprintf(stderr, "NoExpose"); break;
        case 15: fprintf(stderr, "VisibilityNotify"); break;
        case 16: fprintf(stderr, "CreateNotify"); break;
        case 17: fprintf(stderr, "DestroyNotify"); break;
        case 18: fprintf(stderr, "UnmapNotify"); break;
        case 19: fprintf(stderr, "MapNotify"); break;
        case 20: fprintf(stderr, "MapRequest"); break;
        case 21: fprintf(stderr, "ReparentNotify"); break;
        case 22: fprintf(stderr, "ConfigureNotify"); break;
        case 23: fprintf(stderr, "ConfigureRequest"); break;
        case 24: fprintf(stderr, "GravityNotify"); break;
        case 25: fprintf(stderr, "ResizeRequest"); break;
        case 26: fprintf(stderr, "CirculateNotify"); break;
        case 27: fprintf(stderr, "CirculateRequest"); break;
        case 28: fprintf(stderr, "PropertyNotify"); break;
        case 29: fprintf(stderr, "SelectionClear"); break;
        case 30: fprintf(stderr, "SelectionRequest"); break;
        case 31: fprintf(stderr, "SelectionNotify"); break;
        case 32: fprintf(stderr, "ColormapNotify"); break;
        case 33: fprintf(stderr, "ClientMessage"); break;
        case 34: fprintf(stderr, "MappingNotify"); break;
        case 35: fprintf(stderr, "GenericEvent"); break;
        default: fprintf(stderr, "???"); break;

    }

}

int main(void) {

    Window       w;
    GC           gracxt;
    XEvent       e;
    const char*  msg = "Hello, window";
    int          s;
    XFontStruct* font;
    Display*     d;
    int          front = 1;
    Atom         fullscreen;
    int          status;
    Atom         prop;
    Atom         type;
    int          format;
    unsigned long length;
    unsigned long after;
    unsigned char* dp;
 
    d = XOpenDisplay(NULL);
    if (d == NULL) {

        fprintf(stderr, "Cannot open display\n");
        exit(1);

    }
 
    s = DefaultScreen(d);

    w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 1000, 1000, 5,
                            BlackPixel(d, s), WhitePixel(d, s));
    XSelectInput(d, w, ExposureMask|KeyPressMask|PointerMotionMask|
                       StructureNotifyMask|PropertyChangeMask);
    XMapWindow(d, w);
    gracxt = XCreateGC(d, w, 0, NULL);

    font = XLoadQueryFont(d,
        "-bitstream-courier 10 pitch-bold-r-normal--0-0-200-200-m-0-iso8859-1");
    if (!font) {

        fprintf(stderr, "*** No font ***\n");
        exit(1);

    }
    XSetFont(d, gracxt, font->fid);

    fullscreen = XInternAtom(d, "_NET_WM_STATE_FULLSCREEN", 1);
    printf("Fullscreen atom: %ld\n", fullscreen);

    while (1) {

        XNextEvent(d, &e);
    //printf("XWindow event: "); prtxevtt(e.type); printf("\n"); fflush(stdout);
    if (e.type == Expose) XDrawString(d, e.xany.window, gracxt, 10, 50, msg, strlen(msg));
    else if (e.type == ConfigureNotify) {

        printf("ConfigureNotify: x: %d y: %d w: %d h: %d\n",
        e.xconfigure.x, e.xconfigure.y, e.xconfigure.width, e.xconfigure.height);

    } else if (e.type == PropertyNotify) {

        //printf("PropertyNotify: name: %s value: %ld\n", XGetAtomName(d, e.xproperty.atom),
        //       e.xproperty.atom);
        if (!strcmp(XGetAtomName(d, e.xproperty.atom), "_NET_WM_STATE")) {

            status = XGetWindowProperty(d, w, e.xproperty.atom,
                                        0L, 1L, 0,
                                        AnyPropertyType, &type, &format,
                                        &length, &after, &dp);
            if (status == Success && dp && length) {

                prop = ((Atom*)dp)[0];

                printf("Property string: %s value: %ld\n", XGetAtomName(d, prop), prop);

            }

        }

    }

    XCloseDisplay(d);

    return 0;

}

如果我最大化窗口,我会得到:

配置NotifyXWindow事件: 配置通知:x:2 y:76 w:4976 h:2752 ExposeXWindow 事件:

这并没有真正告诉我用户最大化了它,只是它变得更大了。它与屏幕尺寸不匹配,这当然是事实,因为它不包括桌面的标题和菜单栏。

当点击最小化时,我在程序中根本没有得到任何指示。

在文档中:“客户端到窗口管理器的通信”

“4.2.5.图标化和去图标化 未撤消的顶级窗口如果已映射,则将处于“正常”状态;如果未映射,则将处于“图标”状态。即使窗口已重新调整父级,这也是如此;当切换到图标状态时,窗口管理器将取消映射窗口及其父窗口。 客户端可以通过选择顶级窗口上的 StructureNotify 事件来选择接收这些状态更改的通知。当它变为 Iconic 时,它将收到一个 UnmapNotify 事件;当它变为 Normal 时,它将收到一个 MapNotify 事件。”

我没有看到所描述的取消映射/映射通知行为。应使用 StructureNotifyMask 启用此事件。

工作机器是带有GDM3的Ubuntu 20.04。

谢谢

斯科特·佛朗哥 加利福尼亚州圣何塞

通过 PropertyNotify 事件我得到:

PropertyNotifyXWindow event: 
PropertyNotify: WM_STATE
PropertyNotifyXWindow event: 
PropertyNotify: _NET_WM_STATE
PropertyNotifyXWindow event: 
PropertyNotify: _GTK_EDGE_CONSTRAINTS

最小化/图标化。仍在努力获取原子数据。

第二次尝试(使用上面的新代码):

PropertyNotifyXWindow event: 
PropertyNotify: name: _NET_WM_STATE value: 326
Atom Property Value: a
PropertyNotifyXWindow event: 
PropertyNotify: name: _GTK_EDGE_CONSTRAINTS value: 402
Atom Property Value: �
PropertyNotifyXWindow event: 
PropertyNotify: name: _NET_WM_STATE value: 326
Atom Property Value: a

我在其他地方得到了 XGetWindowProperty() 示例。我不知道什么 窗口管理器试图在这里告诉我。数据是另一个原子吗? (一个数字?)。

我从实用程序 xev 中找到了一些进一步的信息:

FocusIn event, serial 37, synthetic NO, window 0x4a00001,
    mode NotifyNormal, detail NotifyNonlinear

KeymapNotify event, serial 37, synthetic NO, window 0x0,
    keys:  70  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   
           0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   

PropertyNotify event, serial 37, synthetic NO, window 0x4a00001,
    atom 0x146 (_NET_WM_STATE), time 4645675, state PropertyNewValue

PropertyNotify event, serial 37, synthetic NO, window 0x4a00001,
    atom 0x192 (_GTK_EDGE_CONSTRAINTS), time 4645675, state PropertyNewValue

PropertyNotify event, serial 37, synthetic NO, window 0x4a00001,
    atom 0x146 (_NET_WM_STATE), time 4645679, state PropertyNewValue
...

在最大化测试窗口时,最小化会给出类似的跟踪。所以它说“state PropertyNewValue”,我正在寻找 _NET_WM_STATE_FULLSCREEN。请问我如何找到新的属性(property)值(value)是多少?

结语:

我按照建议修改了上面的程序。我注释掉了非必要的打印。现在我得到:

属性字符串:_NET_WM_STATE_MAXIMIZED_HORZ 值:333 配置通知:x:2 y:76 w:4976 h:2752 配置通知:x:20 y:90 w:1000 h:1000 属性字符串:_NET_WM_STATE_FOCUSED 值:353 属性字符串:_NET_WM_STATE_HIDDEN 值:330 属性字符串:_NET_WM_STATE_HIDDEN 值:330 属性字符串:_NET_WM_STATE_FOCUSED 值:353

最大化窗口时收到 _NET_WM_STATE_MAXIMIZED_HORZ。当窗口返回到正常状态(从最小化或最大化)时,会收到 _NET_WM_STATE_FOCUSED 状态,并且 _NET_WM_STATE_HIDDEN 是因为被图标化/最小化。

从互联网上的垃圾箱潜水中,我发现:

_NET_WM_STATE_MAXIMIZED_HORZ 或者 _NET_WM_STATE_MAXIMIZED_VERT

均值最大化。

_NET_WM_STATE_HIDDEN

似乎意味着图标化,但描述“表明如果窗口的桌面/视口(viewport)处于事件状态并且其坐标在屏幕范围内,则窗口在屏幕上将不可见”,是的哈。

_NET_WM_STATE_FOCUSED

“指示窗口的装饰是否在事件状态下绘制”

它似乎与“具有键盘焦点”含义相同。由于您单击窗口来最小化/最大化窗口,因此猜测它可能是此窗口的别名。

无论如何,感谢您的所有帮助,我现在有足够的信息。

斯科特·佛朗哥 加利福尼亚州圣何塞

附注。

观察到的一个小问题是,如果最大化窗口,然后最小化它(不恢复正常),然后选择图标,您会得到 每个事件的 _NET_WM_STATE_MAXIMIZED_HORZ,而不是您期望的 _NET_WM_STATE_HIDDEN。不知道这是一个错误还是什么。

S.

最佳答案

所以我有一个最终的学习计划,可以完成我想要的所需的事情,所以我将其发布为答案。后评论。

 /*
 * Study for minimize/maximize/normalize.
 */
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {

    Window         w;
    GC             gracxt;
    XEvent         e;
    const char*    msg = "Hello, window";
    int            s;
    Display*       d;
    Atom           cmaxhorz;
    Atom           cmaxvert;
    Atom           cfocused;
    Atom           chidden;
    int            maxhorz;
    int            maxvert;
    int            focused;
    int            hidden;
    int            status;
    Atom           prop;
    Atom           type;
    int            format;
    unsigned long  length;
    unsigned long  after;
    unsigned char* dp;
    int            winstate = 0; // 0 = normal, 1 = maximized, 2 = minimized
    int            lws;
 
    d = XOpenDisplay(NULL);
    if (d == NULL) {

        fprintf(stderr, "Cannot open display\n");
        exit(1);

    }
 
    s = DefaultScreen(d);

    w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 1000, 1000, 5,
                            BlackPixel(d, s), WhitePixel(d, s));
    XSelectInput(d, w, ExposureMask|KeyPressMask|PointerMotionMask|
                       StructureNotifyMask|PropertyChangeMask);
    XMapWindow(d, w);
    gracxt = XCreateGC(d, w, 0, NULL);

    cfocused = XInternAtom(d, "_NET_WM_STATE_FOCUSED", 1);
    cmaxhorz = XInternAtom(d, "_NET_WM_STATE_MAXIMIZED_HORZ", 1);
    cmaxvert = XInternAtom(d, "_NET_WM_STATE_MAXIMIZED_VERT", 1);
    chidden = XInternAtom(d, "_NET_WM_STATE_HIDDEN", 1);

    while (1) {

        XNextEvent(d, &e);
        if (e.type == Expose) XDrawString(d, e.xany.window, gracxt, 10, 50, msg, strlen(msg));
        else if (e.type == PropertyNotify) {

            if (!strcmp(XGetAtomName(d, e.xproperty.atom), "_NET_WM_STATE")) {

                after = 1L;
                focused = 0;
                maxhorz = 0;
                maxvert = 0;
                hidden = 0;
                do {

                    status = XGetWindowProperty(d, w, e.xproperty.atom,
                                                0L, after, 0,
                                                4/*XA_ATOM*/, &type, &format,
                                                &length, &after, &dp);
                    if (status == Success && type == 4/*XA_ATOM*/ && dp && format == 32 && length) {

                        for (int i = 0; i < length; i++) {

                            prop = ((Atom*)dp)[i];

                            if (prop == cfocused) focused = 1;
                            if (prop == cmaxhorz) maxhorz = 1;
                            if (prop == cmaxvert) maxvert = 1;
                            if (prop == chidden) hidden = 1;

                        }

                    }

                } while (after);
                if (hidden) {

                    lws = winstate;
                    winstate = 2;
                    if (lws != winstate) printf("Minimized\n");

                } else if (maxhorz || maxvert) {

                    lws = winstate;
                    winstate = 1;
                    if (lws != winstate) printf("Maximized\n");

                } else if (focused) {

                    lws = winstate;
                    winstate = 0;
                    if (lws != winstate) printf("Normalized\n");

                }

            }

        }

    }

    XCloseDisplay(d);

    return 0;

}

我无法使用 XGetWindowProperty() 找到任何好的程序。所有的人都忽略了应该迭代直到“after”返回 0 的想法。其他人忽略了第一个调用也可以包含数据的事实,即使后面跟着其他调用。

我仍然对为什么需要多次调用 XGetWindowProperty() 感到困惑。它可以返回一组结果,并且对于它如何将原子分解成组似乎没有任何押韵或理由。

我不知道是否真的需要获取和存储 _NET_WM_STATE 状态的数字等价物,假设它们在不同的实现之间发生变化。我以为他们会这样做。

我使用了 xprop -spy,然后单击窗口来观察属性并验证我的程序应该看到的内容。

程序将事件塑造成我认为重要的窗口状态,即最大化(占据整个屏幕)、最小化(一个图标)或正常窗口。 Xwindows 不这么看,它将水平和垂直最大化分开,一个窗口可以有多个单独的属性。最小化的窗口也可以最大化,您可以通过以下事实看到这一点:选择最小化的窗口时,它会返回到最大化,而不是标准化。我对此表示同意,并且我认为我的窗口的三种状态是一个很好的范例。

聪明的人会意识到最小化/最大化/标准化的东西来自 MS Windows,这确实是我代码的原始实现。

关于c - 如何捕获 XWindows 中的最小化和最大化事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69249370/

相关文章:

ubuntu - xfce4 via VcXsrv Server on wsl2 与 DPI 问题

c - 如何获得安装的内存大小?

c - 每次请求时 mongoose 中的堆栈溢出

c - 意外空字符导致静态变量在 C 中重置

c - 在 C 中提取位

linux - X11:以另一个用户身份运行 gnome 应用程序

linux - Motif Widget Toolkit 的 Perl 绑定(bind)

ubuntu - 如何在 Ubuntu 上获取 XRender 手册页?