5

A window should stay on top of all other windows. Is this somehow possible with plain x11/xlib? Googling for "Always on top" and "x11" / "xlib" didn't return anything useful.

I'd avoid toolkits like GTK+, if somehow possible.

I'm using Ubuntu with gnome desktop. In the window menu, there's an option "Always On Top". Is this provided by the X server or the window manager? If the second is the case, is there a general function that can be called for nearly any wm? Or how to do this in an "X11-generic" way?


Edit: I implemented fizzer's answer, now having following code:

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;
    // ...
    }
}

But the eventhandling and raising nearly never gets executed even my mask is correct?!

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() を使用してトップに留まろうとはしません。一部のウィンドウ マネージャは、これを完全に無視します。そうでない場合は、複数のアプリがこれを試みた場合にどうなるかを考えてみてください。ブーム!そのため、アプリではなく、ウィンドウ マネージャーがウィンドウのスタックを担当します。

これを行う方法は、Extended Window Manager Hints (EWMH) で定義されているプロトコルを使用することです。次を参照してください: http://www.freedesktop.org/wiki/Specifications/wm-spec

具体的には、「Always on Top」メニュー項目がどのように機能するかである _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 を呼び出します。「常に一番上」のウィンドウが 2 つ重なっている場合に注意してください。

于 2010-12-03T11:58:41.470 に答える
-7

たとえば、実際のタイトル ボタン (http://www.actualtools.com/titlebuttons/) を使用します。ウィンドウを常に上に置いたり、ロールアップしたり、透明にしたりできます。

于 2010-12-22T07:16:58.790 に答える