Xlib How Does This (Removing Window Decoration) Work?
Asked Answered
P

2

17

How does the following code remove window borders?

//note the struct is declared elsewhere, is here just for clarity.
//code is from [http://tonyobryan.com/index.php?article=9][1]
typedef struct Hints
{
    unsigned long   flags;
    unsigned long   functions;
    unsigned long   decorations;
    long            inputMode;
    unsigned long   status;
} Hints;

//code to remove decoration
Hints hints;
Atom property;
hints.flags = 2;
hints.decorations = 0;
property = XInternAtom(display, "_MOTIF_WM_HINTS", true);
XChangeProperty(display,window,property,property,32,PropModeReplace,(unsigned char *)&hints,5);
XMapWindow(display, window);

So far I have gathered that an Atom is a sort of identifier similar to Window and Display but I can't figure out where the Hints structure or the "_MOTIF_WM_HINTS" came from. Can anyone explain all of this code for me? Thanks in advance, ell.

Producer answered 27/2, 2011 at 16:19 Comment(4)
This is your source, or your destination? tonyobryan.com/index.php?article=9Alright
This is a little snippet of my source. The Hint structure is declared elsewhere but is shown here for clarity. And I have read that article, it does not explain the hints structure ("I think this structure came from Motif, but I'm not certain"...)Producer
Yeah, its not actually my source, good point.Producer
The window manager that you are running is responsible for either honoring this hint or not. If it honors it then the window manager would remove the window decorations from the window if the window has this hint set.Bagehot
U
17

It's hard to come by any sort of "official"-looking standard or such, but the _MOTIF_WM_HINTS property does seem to come from the... Motif toolkit (ok, you guessed that :-) ). See the MotifZone site.

Warning: what follows is incomplete, but should shed some light I hope.

Documentation for the XmNmwmDecorations, XmNmwmFunctions and XmNmwmInputMode functions of the toolkit indicates that that property is a bitmask of various values used to control the appearance, functions (resize, move, ...) and input mode that the window manager should provide/give to the window. See man vendorshell, or Oreilly Motif reference books, Vol6a chapter 16.

Properties are a part of the whole X11 thing. A window can have any number of properties defined on it. Properties have a name, but setting/getting properties is done through an "atom" (identifier of sorts) to avoid sending the whole string on the wire for every get/set call. See Properties and Atoms

The currently window manager (if any) can react to window property changes by setting the appropriate event filter and acting on PropertyNotify events, or simply inspecting the properties the window has when it gets mapped (or moved, or whatever). If the window manager knows of the _MOTIF_WM_HINT property, it'll interpret those and (hopefully) do what you want. (Note: I'm not entierly sure if that privilege is devolved to the window manager, or if other windows can listen to those "PropertyNotify" events. Not sure that's actually relevant to your question.)

So the code you have works just fine as long as your window manager knows about the _MOTIF_WM_HINTS property.

You start by getting the atom (identifier/shortcut) for it with XInternAtom, and setting its value via XChangeProperty() before the window is actually drawn via MapWindow() (not sure if that would work if you do it after the MapWindow(), that could depend on your window manager).

[Edit: setting the .decorations part to zero clears all the decoration bits, so this requests that the window manager leave your borders the hell alone, essentially.]

I can't come up with somewhere "official" with the definition of that struct. It's defined in lib/X11/MwmUtils.h of the openmotif-2.3.3 distribution. Not sure how the .flags entry is used (can't find the code for the life of me :-/ ) but I suspect it's used to indicate which of the {decoration, function, inputMode} "sub-properties" you're acting on. (Don't take my word for that.)

As a side note, using _MOTIF_WM_HINTS might not be your best option right now. Have you looked at the Extended Window Manager hints specification and other information/standards/drafts over at freedesktop? I'll wager most "modern" window managers/desktop environments/kitchen sinks will tend to adhere to that rather than keeping backwards compatibility with Motif. All depends on what you're coding for I guess.

Thanks for reading :-)

Unsuspected answered 3/3, 2011 at 20:40 Comment(2)
Thanks for all these hints, and I'l look into all of the links you'v given me!Producer
I tried using the _NET_WM_WINDOW_TYPE properties referred to. At least on GNOME/GDM3, these not only don't give the same abilities as the Motif hints, but actually have bad side effects, like needing the window unmapped and remapped before they work.Gig
S
2

Have a look at the _MOTIF_WM_HINTS property. I changed your code to a working state:

#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define MAPIT
#undef REPEAT

void waitxevt(Display* d, int type)

{

    XEvent e; /* XEvent holder */

    do { XNextEvent(d, &e); } while (e.type != type);

}

void frame(Display* d, Window w, int e)

{

    Atom window_type;
    Atom motif_hints;
    long value;

#ifdef MAPIT
    XUnmapWindow(d, w);
    waitxevt(d, UnmapNotify);
#endif
    window_type = XInternAtom(d, "_NET_WM_WINDOW_TYPE", False);
    if (e) value = XInternAtom(d, "_NET_WM_WINDOW_TYPE_NORMAL", False);
    else value = XInternAtom(d, "_NET_WM_WINDOW_TYPE_DOCK", False);
    XChangeProperty(d, w, window_type, XA_ATOM, 32, PropModeReplace, (unsigned char *) &value, 1);
    
    long hints[5] = {e ? 0 : 2, 0, 0, 0, 0};
    motif_hints = XInternAtom(d, "_MOTIF_WM_HINTS", False);

    XChangeProperty(d, w, motif_hints, motif_hints, 32, PropModeReplace, (unsigned char *)&hints, 5);
    
#ifdef MAPIT
    XMapWindow(d, w);
    waitxevt(d, MapNotify);
#endif

}

int main(void) {

    Display*     d;
    Window       w;
    XEvent       e;
    const char*  msg = "Hello, World!";
    int          s;
    GC           gracxt;
    int          frmenb = 0;
 
    d = XOpenDisplay(NULL);
    if (d == NULL) {

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

    }
 
    s = DefaultScreen(d);
    gracxt = XDefaultGC(d, s);

    w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 640, 480, 5,
                            BlackPixel(d, s), WhitePixel(d, s));
    XSelectInput(d, w, ExposureMask|KeyPressMask|StructureNotifyMask);
    XMapWindow(d, w);
    waitxevt(d, MapNotify);

    while (1) {

        XNextEvent(d, &e);
        if (e.type == Expose) XDrawString(d, w, gracxt, 10, 50, msg, strlen(msg));
        if (e.type == KeyPress) {

            frame(d, w, frmenb);
            frmenb = frmenb == 0 ? 1 : 0;
#ifdef REPEAT
            frame(d, w, frmenb);
            frmenb = !frmenb;
#endif

        }

    }

    XCloseDisplay(d);

    return 0;

}

The only thing changed is to include the hints.

Sycamine answered 18/8, 2021 at 19:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.