Python/X11:找出用户是否切换虚拟桌面

发布于 2024-08-28 13:07:37 字数 375 浏览 5 评论 0原文

我正在寻找一种方法来确定用户是否在 X11 下切换虚拟桌面。

我正在使用带有 X11 库和 PyGTK 的 Python。我找到了一些 C 语言的工作示例,但我缺乏将它们翻译成 Python 的专业知识,并且我阅读了几个 X11 寻呼机应用程序(fbpanel、pypanel)的源代码,但我似乎找不到我要找的东西。

我必须注册信号吗?使用 X11 还是 GTK? 我必须忙着等待吗?

我对 X11 和 GTK 都是全新的,因此任何提示/帮助将不胜感激。

问候, Philip

PS:我目前的努力可以在此处找到。

I'm looking for a way to determine if the user switches virtual desktops under X11.

I'm using Python with X11 libraries and PyGTK. I found some working examples in C, but I lack the expertise to translate them into Python, and I read the source code of several X11 pager applications (fbpanel, pypanel), but I can't seem to find what I'm looking for.

Do I have to register for a signal? Using X11 or GTK?
Do I have to busy-wait?

I'm completely new to both X11 and GTK, so any hints/help would be greatly appreciated.

Greets,
Philip

PS: My current efforts can be found here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

焚却相思 2024-09-04 13:07:37

这是一个基于 GTK 的解决方案:

screen = gtk.gdk.screen_get_default()
root = screen.get_root_window()
root.set_events(gtk.gdk.SUBSTRUCTURE_MASK)
root.add_filter(event_filter)

def event_filter(event, user_data):
        # process event
        return gtk.gdk.FILTER_CONTINUE

显然,SUBSTRUCTURE_MASK 包含通常与工作区切换相关的事件。然而,这个解决方案感觉有点尴尬。有什么想法吗?

问候,
菲利普

Here is a GTK based solution:

screen = gtk.gdk.screen_get_default()
root = screen.get_root_window()
root.set_events(gtk.gdk.SUBSTRUCTURE_MASK)
root.add_filter(event_filter)

def event_filter(event, user_data):
        # process event
        return gtk.gdk.FILTER_CONTINUE

Apparently, the SUBSTRUCTURE_MASK contains events which are typically associated with workspace switches. Nevertheless, this solution feels a bit awkward. Any ideas?

Greets,
Philip

深海夜未眠 2024-09-04 13:07:37

您可能想查看 libwnck,或者可能是它的 Python 绑定。

You may want to take a look at libwnck, or possibly its Python bindings.

素罗衫 2024-09-04 13:07:37

通常,桌面更改是通过根窗口上的属性更改向客户端宣布的,
所以监听 PROPERTY_CHANGE_MASK 而不是 SUBSTRUCTURE_MASK;
这会给你带来更少的噪音。

至于哪个属性发生变化,我怀疑不同
不同的窗口管理器/桌面/其他;我正在运行 ubuntu/unity 并且
当我在桌面切换之前和之后执行“xprop -root”并比较结​​果时,
我发现更改的属性是_NET_DESKTOP_VIEWPORT。

另外我得到的主要噪音是根窗口的
每次活动窗口更改时,_NET_ACTIVE_WINDOW 属性都会更改。

Typically a desktop change is announced to clients by a property change on the root window,
so listen for PROPERTY_CHANGE_MASK instead of SUBSTRUCTURE_MASK;
that will give you a lot less noise.

As for which property changes, I suspect that differs among
different windowmanagers/desktops/whatever; I'm running ubuntu/unity and
when I do "xprop -root" before and after a desktop switch, and diff the results,
I find that the property that changed is _NET_DESKTOP_VIEWPORT.

The primary noise I get in addition is that the root window's
_NET_ACTIVE_WINDOW property changes each time the active window changes.

想你只要分分秒秒 2024-09-04 13:07:37

另一项改进:如 Don Hatch 所说,使用 GDK_PROPERTY_CHANGE_MASK<,而不是 GDK_SUBSTRUCTURE_MASK /代码>。此外,您感兴趣的确切属性是_NET_CURRENT_DESKTOP。它是一个 32 位属性,其值为从 0 开始的桌面编号。

这是完整的可编译和可运行的示例,它捕获桌面切换的时刻并报告当前桌面的数量。这个例子是用C语言编写的,因为我对Python不太熟悉,希望你能翻译一下。

#include <gtk/gtk.h>
#include <gdk/gdkx.h>

GdkFilterReturn propertyChangeFilter(GdkXEvent* xevent, GdkEvent*e, gpointer data)
{
    const XPropertyEvent*const propEvt=(const XPropertyEvent*)xevent;

    if(propEvt->type!=PropertyNotify)
        return GDK_FILTER_CONTINUE;
    if(propEvt->state!=PropertyNewValue)
        return GDK_FILTER_CONTINUE;
    const Atom NET_CURRENT_DESKTOP=(Atom)data;
    if(propEvt->atom!=NET_CURRENT_DESKTOP)
        return GDK_FILTER_CONTINUE;

    fprintf(stderr, "Desktop change detected\n");
    Atom actualType;
    int actualFormat;
    unsigned long nitems, remainingBytes;
    unsigned char* prop;
    if(XGetWindowProperty(propEvt->display, propEvt->window, propEvt->atom,
                          0, 1, False, AnyPropertyType,
                          &actualType, &actualFormat, &nitems, &remainingBytes,
                          &prop) != Success)
    {
        fprintf(stderr, "Failed to get current desktop number\n");
        return GDK_FILTER_CONTINUE;
    }
    if(nitems!=1 || remainingBytes!=0 || actualFormat!=32)
    {
        XFree(prop);
        fprintf(stderr, "Unexpected number of items (%lu) or remaining bytes (%lu)"
                        " or format (%d)\n", nitems, remainingBytes, actualFormat);
        return GDK_FILTER_CONTINUE;
    }
    guint32 value;
    memcpy(&value, prop, sizeof value);
    XFree(prop);
    fprintf(stderr, "Current desktop: %u\n", value);

    return GDK_FILTER_CONTINUE;
}

int main(int argc, char** argv)
{
    gtk_init(&argc,&argv);

    GdkDisplay*const gdkDisplay=gdk_display_get_default();
    Display*const display=gdk_x11_display_get_xdisplay(gdkDisplay);
    const Atom atom=XInternAtom(display, "_NET_CURRENT_DESKTOP", True);
    GdkWindow*const root=gdk_get_default_root_window();
    gdk_window_set_events(root, GDK_PROPERTY_CHANGE_MASK);
    gdk_window_add_filter(root, propertyChangeFilter, (gpointer)atom);

    gtk_main();
}

One more refinement: instead of GDK_SUBSTRUCTURE_MASK, as Don Hatch says, use GDK_PROPERTY_CHANGE_MASK. Moreover, the exact property that you're interested in is _NET_CURRENT_DESKTOP. It's a 32-bit property, whose value is a 0-based desktop number.

Here's the complete compilable and runnable example that catches the moment of desktop switch and reports the number of current desktop after that. The example is in C since I'm not fluent in Python, I hope you can translate.

#include <gtk/gtk.h>
#include <gdk/gdkx.h>

GdkFilterReturn propertyChangeFilter(GdkXEvent* xevent, GdkEvent*e, gpointer data)
{
    const XPropertyEvent*const propEvt=(const XPropertyEvent*)xevent;

    if(propEvt->type!=PropertyNotify)
        return GDK_FILTER_CONTINUE;
    if(propEvt->state!=PropertyNewValue)
        return GDK_FILTER_CONTINUE;
    const Atom NET_CURRENT_DESKTOP=(Atom)data;
    if(propEvt->atom!=NET_CURRENT_DESKTOP)
        return GDK_FILTER_CONTINUE;

    fprintf(stderr, "Desktop change detected\n");
    Atom actualType;
    int actualFormat;
    unsigned long nitems, remainingBytes;
    unsigned char* prop;
    if(XGetWindowProperty(propEvt->display, propEvt->window, propEvt->atom,
                          0, 1, False, AnyPropertyType,
                          &actualType, &actualFormat, &nitems, &remainingBytes,
                          &prop) != Success)
    {
        fprintf(stderr, "Failed to get current desktop number\n");
        return GDK_FILTER_CONTINUE;
    }
    if(nitems!=1 || remainingBytes!=0 || actualFormat!=32)
    {
        XFree(prop);
        fprintf(stderr, "Unexpected number of items (%lu) or remaining bytes (%lu)"
                        " or format (%d)\n", nitems, remainingBytes, actualFormat);
        return GDK_FILTER_CONTINUE;
    }
    guint32 value;
    memcpy(&value, prop, sizeof value);
    XFree(prop);
    fprintf(stderr, "Current desktop: %u\n", value);

    return GDK_FILTER_CONTINUE;
}

int main(int argc, char** argv)
{
    gtk_init(&argc,&argv);

    GdkDisplay*const gdkDisplay=gdk_display_get_default();
    Display*const display=gdk_x11_display_get_xdisplay(gdkDisplay);
    const Atom atom=XInternAtom(display, "_NET_CURRENT_DESKTOP", True);
    GdkWindow*const root=gdk_get_default_root_window();
    gdk_window_set_events(root, GDK_PROPERTY_CHANGE_MASK);
    gdk_window_add_filter(root, propertyChangeFilter, (gpointer)atom);

    gtk_main();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文