Skip to content

Window states management

yshui edited this page Oct 27, 2020 · 13 revisions

Types of window states in picom

Raw window states

These are window states tracked by the X server. They might or might not be stored directly in struct managed_win.

Name Description Availability in events
Properties Window properties, the ones you can view with xprop PropertyNotify, only tells us if the property is changed or deleted, new property value not included
Attributes Window attributes Unavailable, but we also don't care. Except for the backing_pixmap of the root window, which is available via property, _XROOTPMAP_ID or _XSETROOT_ID
Geometry Window size and position ConfigureNotify, fully available. But this information is only needed when rendering, so we could aggregate updates between renders
Shape Shape of a non-rectangular window ShapeNotify, only tells us if the shape is changed, new shape not included
Viewability Whether a window is mapped, is viewable MapNotify and UnmapNotify, fully available. But all of the other states of a newly mapped window won't be available
Focus Whether a window has input focus FocusIn and FocusOut, fully available. But also affected by the _NET_ACTIVE_WINDOW property, so can't update in the event handler

There are also states concerning relationships between windows

Name Description Availability in events
Stacking order The order of how windows are stacked on top of each other ConfigureNotify and CirculateNotify, fully available
Hierarchy The tree structure formed by X windows. picom only really cares about toplevel windows, but we still need to keep track of hierarchy changes ReparentNotify, fully available. But if a previously non-toplevel window becomes toplevel; or if a previous child of an unviewable window is reparented to a viewable window, all of its other states won't be available

Mirrored raw states

Each of these states almost directly corresponds to a raw window state. They are stored in the struct manage_win.

Name Description Source
name ICCCM/EWMH window name Property, _NET_WM_NAME and WM_NAME
g Window geometry Geometry
stacking_rank Number of windows above current window Stacking order
bounding_shape Shape
bounding_shaped Whether the current window is Shaped Shape
window_type EWMH window types Property, _NET_WM_WINDOW_TYPE
leader ICCCM window group leader Property, WM_CLIENT_LEADER and WM_TRANSIENT_FOR
class_instance,
class_general
ICCCM window classes Property, WM_CLASS
role ICCCM window role Property, WM_WINDOW_ROLE
opacity_prop Desired opacity of window Property, _NET_WM_WINDOW_OPACITY (not in EWMH),
can be set on the WM frame, or on the client window
frame_extents Size of the window manager frame Property, _NET_FRAME_EXTENTS
prop_shadow Whether a shadow is desired for this window Property, _COMPTON_SHADOW
client_win The client window of the window manager frame Hierarchy

Derived window states

These states are derived from raw X states.

Not user controlled

These states aren't influenced by the user directly

Name Description Source
state Mostly correspond to X window states (mapped/unmapped/etc.),
but because of fading, also includes transitional states
Viewability
mode Whether the window is transparent, frame transparent, or completely opaque Property, and window pixel format
in_openclose Whether the window is in open/close state, in other words,
whether the window is mapped for the first time, or just destroyed.
Viewability
opacity Current window opacity state, and fading progress
opacity_target Target window opacity state (??)

DBus states

User can change these states via DBus

  • fade_force
  • shadow_force
  • invert_color_force
  • focused_force

Option based

Options themselves can't change, only change in other factors would cause these states to change.

Name Option
corner_radius (#480)
frame_opacity frame-opacity
shadow_opacity frame-opacity, and shadow-opacity
shadow_dx, shadow_dy,
shadow_width, shadow_height
various shadow options
dim inactive-dim, and current window state, and Focus

Rule based

All rule based states also derive from window Properties.

Name Description Source
opacity_is_set,
opacity_set
user defined opacity value opacity-rule
fade_exclude fade-exclude

Indirectly rule based

These states are influenced by rules, as well as other window states and other options

Name Description Source
invert_color Rule: invert-color-include
Other states: invert_color_force
shadow Rule: shadow-exclude,
Options: wintypes.xxx.shadow, shadow-ignore-shaped
Other states: shadow_force, prop_shadow
widthb, heightb Window size, including the shadow if there is one Geometry, shadow, shadow_{dx,dy,width,height}
blur_background Rule: blur-background-exclude,
Options: wintypes.xxx.blur-background
focused Focus,
Rule: focus-exclude
Options: mark_ewmh_focused, mark-ovredir-focused, wintypes.xxx.focus
Other states: focused_force

Image data

Image data used for rendering, invalidated when some of the other window states change.

Name Description Source
shadow_image backend dependent image data for the shadow Geometry, shadow, ???
image backend dependent image data for the window itself Geometry, ???

Updating these states

Window state changes start from ev_handle, which handles events sent by the X server. ev_handle will update window states from what is available in the event itself, then mark the window for further processing in the X critical section.

Information stored in the X server has to be queried in the X critical section, otherwise we are prone to race conditions with other X clients.

In the X critical section, window states should be updated in this order:

  • Client windows of window manager frames are updated based on hierarchy information. This is done first, because later updates might require accurate client window information.
  • Window size, position and shape are updated, and added to damage.
  • Updated properties are retrieved from the X server. Mirrored states based on the properties will be updated. (XXX: would window size/shape depend on properties?)
  • Rules are re-evaluated
  • All other states are updated accordingly.

There is a special case, where a window receives a bunch of updates, and is then destroyed before the next X critical section. ev_handle will initiate the destroy sequence (fade out, etc.), and that should clear some (or all?) of the updates previously queued by ev_handle, because none of the raw window states will be available from X after the window is destroyed.

Update 1

Above is generally true for visible (or viewable, in Xorg terms) windows, however, if a window is not visible, we don't really need to keep its states up-to-date, as it won't be seen anyway.

Essentially, in ev_handle, all window will be treated the same, visible or not. But updates queued by ev_handle won't be processed if the window is not visible, and will be processed all at once when the window become visible. This way we don't need take special care around these windows in state update functions, and should make things easier to reason about.

But this creates a chicken and egg problem: if we don't process updates, how could we know if a window has become visible? To solve this problem, we have to declare a set of window states to be "visibility related", and will be updated for all windows. If we want to get philosophical about what actually is "visibility related", things will get really complicated. So right now we only treat the state variable as visibility related.

If a window is UNMAPPING, UNMAPPED, or DESTROYING, it should be treated as not visible; otherwise it is visible. Transitional states are a bit tricky, but I think this is correct. An unmapping or destroying window should retain its last appearance. In other words, the window itself is not visible anymore, what the user sees is an illusion presented by the compositor.