5

一个窗口应该位于所有其他窗口的顶部。这对于普通的 x11/xlib 有可能吗?谷歌搜索“始终在顶部”和“x11”/“xlib”没有返回任何有用的信息。

如果可能的话,我会避免使用 GTK+ 之类的工具包。

我正在使用带有 gnome 桌面的 Ubuntu。在窗口菜单中,有一个选项“始终在顶部”。这是由 X 服务器还是窗口管理器提供的?如果是第二种情况,是否有一个可以为几乎任何 wm 调用的通用函数?或者如何以“X11-generic”的方式做到这一点?


编辑:我实现了 fizzer 的答案,现在有以下代码:

XSelectInput(this->display, this->window,
    ButtonPressMask |
    StructureNotifyMask |
    ExposureMask |
    KeyPressMask |
    PropertyChangeMask |
    VisibilityChangeMask ); 
// ...
// In a loop:
if (XPending(this->display) >= 0)
{
    XNextEvent(this->display, &ev);
    switch(ev.type) {
    // ...
    case VisibilityNotify:
        XRaiseWindow(this->display, this->window);
        XFlush(this->display);
    break;
    // ...
    }
}

但是即使我的面具是正确的,事件处理和提升几乎也不会被执行?!

4

4 回答 4

11
#define _NET_WM_STATE_REMOVE        0    // remove/unset property
#define _NET_WM_STATE_ADD           1    // add/set property
#define _NET_WM_STATE_TOGGLE        2    // toggle property

Bool MakeAlwaysOnTop(Display* display, Window root, Window mywin)
{
    Atom wmStateAbove = XInternAtom( display, "_NET_WM_STATE_ABOVE", 1 );
    if( wmStateAbove != None ) {
        printf( "_NET_WM_STATE_ABOVE has atom of %ld\n", (long)wmStateAbove );
    } else {
        printf( "ERROR: cannot find atom for _NET_WM_STATE_ABOVE !\n" );
        return False;
    }
    
    Atom wmNetWmState = XInternAtom( display, "_NET_WM_STATE", 1 );
    if( wmNetWmState != None ) {
        printf( "_NET_WM_STATE has atom of %ld\n", (long)wmNetWmState );
    } else {
        printf( "ERROR: cannot find atom for _NET_WM_STATE !\n" );
        return False;
    }

    // set window always on top hint
    if( wmStateAbove != None )
    {
        XClientMessageEvent xclient;
        memset( &xclient, 0, sizeof (xclient) );
        //
        //window  = the respective client window
        //message_type = _NET_WM_STATE
        //format = 32
        //data.l[0] = the action, as listed below
        //data.l[1] = first property to alter
        //data.l[2] = second property to alter
        //data.l[3] = source indication (0-unk,1-normal app,2-pager)
        //other data.l[] elements = 0
        //
        xclient.type = ClientMessage;
        xclient.window = mywin;              // GDK_WINDOW_XID(window);
        xclient.message_type = wmNetWmState; //gdk_x11_get_xatom_by_name_for_display( display, "_NET_WM_STATE" );
        xclient.format = 32;
        xclient.data.l[0] = _NET_WM_STATE_ADD; // add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
        xclient.data.l[1] = wmStateAbove;      //gdk_x11_atom_to_xatom_for_display (display, state1);
        xclient.data.l[2] = 0;                 //gdk_x11_atom_to_xatom_for_display (display, state2);
        xclient.data.l[3] = 0;
        xclient.data.l[4] = 0;
        //gdk_wmspec_change_state( FALSE, window,
        //  gdk_atom_intern_static_string ("_NET_WM_STATE_BELOW"),
        //  GDK_NONE );
        XSendEvent( display,
          //mywin - wrong, not app window, send to root window!
          root, // <-- DefaultRootWindow( display )
          False,
          SubstructureRedirectMask | SubstructureNotifyMask,
          (XEvent *)&xclient );

        XFlush(display);

        return True;
    }

    return False;
}
于 2013-04-26T12:00:22.537 回答
5

您不想使用 XRaiseWindow() 来保持领先。一些窗口管理器会完全忽略它。对于那些不这样做的人,请考虑如果多个应用程序尝试这样做会发生什么。繁荣!这就是为什么窗口管理器负责堆叠窗口,而不是应用程序。

这样做的方法是使用扩展窗口管理器提示 (EWMH) 中定义的协议,请参阅:http ://www.freedesktop.org/wiki/Specifications/wm-spec

具体来说,您需要 _NET_WM_STATE_ABOVE 这就是“始终位于顶部”菜单项的工作方式。

如果您不使用工具包,您将需要习惯于在工具包源代码中清理以找出如何做事。在这种情况下,您可以查看 GTK+ 的 X11 后端中的函数 gdk_window_set_keep_above()。这将展示如何使用 _NET_WM_STATE_ABOVE 提示。

于 2010-12-03T16:15:47.217 回答
2

很多年前我在 Xlib 中写过类似的东西。这是几行代码。当您的窗口被部分遮挡时,您会收到一个 VisibilityNotify 事件,然后调用 XRaiseWindow。请注意两个“始终位于顶部”的窗口重叠的情况。

于 2010-12-03T11:58:41.470 回答
-7

例如,使用实际标题按钮 (http://www.actualtools.com/titlebuttons/)。它允许将任何窗口始终保持在顶部、卷起、透明等。

于 2010-12-22T07:16:58.790 回答