X11 / Xlib:窗口总是在顶部

时间:2010-12-03 11:48:39

标签: user-interface x11 window-managers

窗口应该保持在所有其他窗口的顶部。使用普通的x11 / xlib可以实现这种方式吗?谷歌搜索“永远在顶部”和“x11”/“xlib”没有返回任何有用的东西。

如果可能的话,我会避免像GTK +这样的工具包。

我正在使用Ubuntu和gnome桌面。在窗口菜单中,有一个选项“Always On Top”。这是由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 个答案:

答案 0 :(得分:10)

#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
...
...
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" );
}

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" );
}
// 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 );
  }

答案 1 :(得分:5)

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

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

具体来说,您需要_NET_WM_STATE_ABOVE,这就是“Always on Top”菜单项的工作方式。

如果您没有使用工具包,那么您将需要习惯于在工具包源代码中进行清理,以了解如何执行操作。在这种情况下,您可以在GTK +的X11后端查看函数gdk_window_set_keep_above()。这将显示如何使用_NET_WM_STATE_ABOVE提示。

答案 2 :(得分:2)

多年前我在Xlib中写过类似的东西。这是几行代码。当您的窗口被部分遮挡时,您将获得VisibilityNotify事件,然后调用XRaiseWindow。注意两个“永远在顶部”窗口重叠的情况。

答案 3 :(得分:-6)

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