Xlib How Does This (Removing Window Decoration) Work

Xlib How Does This (Removing Window Decoration) Work?

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 :-)

XLIB Decoration questions

Read EWMH spec and you'll find answers to all questions.

  1. Check "override redirect" window flag
  2. You are trying
    to destroy window which is already destroyed. Instead of using
    event.xdestroywindow.event window id just delete your decoration
    window.
  3. Don't forget to add client window to save set if you are
    writing reparenting WM. That way if you kill wm application windows
    are not destroyed but reparented back to root window

XLib: 'Soft-Closing' a window

I found a solution:

XEvent event;
event.xclient.type = ClientMessage;
event.xclient.window = id;
event.xclient.message_type = XInternAtom(d, "WM_PROTOCOLS", TRUE);
event.xclient.format = 32;
event.xclient.data.l[0] = XInternAtom(d, "WM_DELETE_WINDOW", FALSE);
event.xclient.data.l[1] = CurrentTime;
XSendEvent(d, id, False, NoEventMask, &event);

Where d is the display handle and id is the window ID.

CREDIT: https://john.nachtimwald.com/2009/11/08/sending-wm_delete_window-client-messages/

XLib windows auto-alignment performance

Remove the ConfigureNotify event handling and get the current parent size in the expose processing. This ignores the queued Configure Notify events the give a history of the parent size rather that the current parent window size.

So modifying the code you posted in the comments.

if (e.type == Expose) {
if (e.xexpose.count == 0) {
Window r;
int x,y;
unsigned int wd,ht, bw, dep;
XGetGeometry(d,w,&r,&x,&y,&wd,&ht,&bw,&dep);
width = wd - 20;
height = ht - 20;
XMoveResizeWindow (d, ww, 10, 10, width, height);
for (i=0;i<1000;i++) {
XFillRectangle(d, ww, DefaultGC(d, s), 20, 20, 10, 10);
XFillRectangle(d, ww, DefaultGC(d, s), width-30, height-30, 10, 10);
XFillRectangle(d, ww, DefaultGC(d, s), 20, height-30, 10, 10);
XFillRectangle(d, ww, DefaultGC(d, s), width-30, 20, 10, 10);
}
}
}

Update: To fix the lack of expose events, add the following:

if (e.type == ConfigureNotify) {
{
while (XCheckTypedWindowEvent(d, w, ConfigureNotify, &e) == True);
width = e.xconfigure.width - 20;
height = e.xconfigure.height - 20;
XMoveResizeWindow (d, ww, 10, 10, width, height);
}

This will cause some more expose events. The XCheckTypedWindowEvent may not be necessary, it removes any all the ConfigureNotify events from the queue leaving the last one found in e.

Tkinter, Linux: How to view window in windows task bar which has no title bar?

One way is using libX11 directly and telling it not to draw the title bar on a normal tk.Tk() window like this:

# Mostly taken from: https://www.tonyobryan.com//index.php?article=9
# Inspired by: https://github.com/EDCD/EDMarketConnector/blob/main/theme.py
import tkinter as tk
import ctypes

# Defining types
CHAR = ctypes.c_char
UCHAR = ctypes.c_ubyte
BOOL = ctypes.c_bool
INT = ctypes.c_int
UINT = ctypes.c_uint
LONG = ctypes.c_long
PTR = ctypes.c_void_p

CHAR_PTR = ctypes.POINTER(CHAR)
UINT_PTR = ctypes.POINTER(UINT)
ULONG = ctypes.c_ulong

class HINTS(ctypes.Structure):
_fields_ = (("flags", ULONG),
("functions", ULONG),
("decorations", ULONG),
("inputMode", LONG),
("status", ULONG))

DISPLAY = PTR
ATOM = LONG
WINDOW = LONG
WINDOW_PTR = ctypes.POINTER(WINDOW)
HINTS_PTR = ctypes.POINTER(HINTS)

def _errcheck_not_zero(value, func, args):
if value == 0:
args_str = ", ".join(map(str, args))
raise OSError(f"{func.__name__}({args_str}) => {value}")
return args

def string_to_c(data:str) -> CHAR_PTR:
return ctypes.create_string_buffer(data.encode())

libx11 = ctypes.cdll.LoadLibrary("libX11.so.6")

# Constants
PropModeReplace = 0
XA_ATOM = 4

# Defining functions
XInternAtom = libx11.XInternAtom
XInternAtom.argtypes = (PTR, CHAR_PTR, BOOL)
XInternAtom.restype = ATOM
XInternAtom.errcheck = _errcheck_not_zero

XOpenDisplay = libx11.XOpenDisplay
XOpenDisplay.argtypes = (CHAR_PTR, )
XOpenDisplay.restype = DISPLAY
XOpenDisplay.errcheck = _errcheck_not_zero

XChangeProperty = libx11.XChangeProperty
XChangeProperty.argtypes = (DISPLAY, WINDOW, ATOM, ATOM, INT, INT, HINTS_PTR, INT)
XChangeProperty.restype = INT
XChangeProperty.errcheck = _errcheck_not_zero

XQueryTree = libx11.XQueryTree
XQueryTree.argtypes = (DISPLAY, WINDOW, WINDOW_PTR, WINDOW_PTR, WINDOW_PTR, UINT_PTR)
XQueryTree.restype = INT
XQueryTree.errcheck = _errcheck_not_zero

XFlush = libx11.XFlush
XFlush.argtypes = (DISPLAY, )
XFlush.restype = INT
XFlush.errcheck = _errcheck_not_zero

if __name__ == "__main__":
root = tk.Tk()

# This is needed:
root.update_idletasks()
# Get the handle of the window
handle:int = root.winfo_id()

# Get the default display
display = XOpenDisplay(None)

# Get the parent of the window
parent = WINDOW()
XQueryTree(display, handle, ctypes.byref(WINDOW()),
ctypes.byref(parent), ctypes.byref(WINDOW()),
ctypes.byref(UINT()))

# Change the motif hints of the window
motif_hints = XInternAtom(display, string_to_c("_MOTIF_WM_HINTS"), False)
hints = HINTS()
hints.flags = 2 # Specify that we're changing the window decorations.
hints.decorations = False
XChangeProperty(display, parent, motif_hints, XA_ATOM, 32,
PropModeReplace, ctypes.byref(hints), 5)
# Flush the changes
XFlush(display)

# Normal `tkinter` code can follow
root.mainloop()

It uses root.update_idletasks() and XQueryTree(...) to get the handle of the window. Then it modifies the "_MOTIF_WM_HINTS" so that x11 would remove all of the window decorations including the title bar.

Is it possible to toggle fullscreen without recreating the window?

Windows: Yes

X11/GLX: Yes

MacOS-X: It's complicated.


First the easy stuff: In Windows and X11 there are no such things as special fullscreen mode OpenGL windows. They're all just regular toplevel windows and you can add or remove the window decorations (title bar, border) anytime you like. If you remove the window decorations and set the window size to maximized you essentially get a fullscreen OpenGL window; in fact the graphics drivers are smart enough to detect this situation and switch to a fast track then.


Now MacOS X. In MacOS X clear distinction is made between Windowed and Fullscreen (which IMHO is quite annoying).

The good news is, that you can get access to the underlying context object which allows to implement some resource sharing so that you don't have to recreate the data containing OpenGL objects.

Big Fat Disclaimer: I never ventured as deep into MacOS X as I did with other OSs so my practical experience with this certain topic on MacOS X is only theoretical.



Related Topics



Leave a reply



Submit