0
# EWMH
1
2
A Python implementation of Extended Window Manager Hints (EWMH) specification for querying and controlling EWMH-compliant window managers on Linux/Unix systems. Built on top of python-xlib, it enables programmatic interaction with modern window managers to retrieve window information, manipulate window properties, manage desktops and workspaces, and perform window management operations.
3
4
## Package Information
5
6
- **Package Name**: ewmh
7
- **Package Type**: pypi
8
- **Language**: Python
9
- **Installation**: `pip install ewmh`
10
- **Dependencies**: python-xlib
11
12
## Core Imports
13
14
```python
15
from ewmh import EWMH
16
```
17
18
Alternative import pattern:
19
```python
20
import ewmh
21
ewmh_instance = ewmh.EWMH()
22
```
23
24
## Basic Usage
25
26
```python
27
from ewmh import EWMH
28
29
# Initialize EWMH connection (uses default display and root window)
30
ewmh = EWMH()
31
32
# Get current active window
33
active_window = ewmh.getActiveWindow()
34
if active_window:
35
print(f"Active window: {ewmh.getWmName(active_window)}")
36
37
# Get list of all managed windows
38
windows = ewmh.getClientList()
39
print(f"Total windows: {len(windows)}")
40
41
# Get desktop information
42
num_desktops = ewmh.getNumberOfDesktops()
43
current_desktop = ewmh.getCurrentDesktop()
44
print(f"Desktop {current_desktop + 1} of {num_desktops}")
45
46
# Set a window as active
47
if windows:
48
ewmh.setActiveWindow(windows[0])
49
ewmh.display.flush() # Important: flush to send the request
50
51
# Clean up
52
ewmh.display.close()
53
```
54
55
## Architecture
56
57
EWMH provides a comprehensive interface to the Extended Window Manager Hints specification through a single EWMH class. The architecture is organized around five main capability areas:
58
59
- **Desktop/Workspace Management**: Query and control virtual desktops, geometry, viewports, and workspace properties
60
- **Window Discovery**: Enumerate managed windows, get stacking order, and find active windows
61
- **Window Properties**: Access window metadata like names, types, states, process IDs, and allowed actions
62
- **Window Control**: Perform window operations including activation, movement, resizing, state changes, and closure
63
- **Generic Access**: Use string-based property names for dynamic access to any EWMH property
64
65
The implementation builds on python-xlib for low-level X11 communication and provides both specific methods (e.g., `getActiveWindow()`) and generic property access (e.g., `getProperty('_NET_ACTIVE_WINDOW')`) for maximum flexibility. All operations require explicit display flushing to ensure commands are sent to the window manager.
66
67
## Capabilities
68
69
### EWMH Class
70
71
Main class providing access to all EWMH window manager functionality through getter and setter methods.
72
73
```python { .api }
74
class EWMH:
75
"""
76
Implementation of Extended Window Manager Hints specification.
77
78
Args:
79
_display: X11 display connection (optional, defaults to Xlib.display.Display())
80
root: Root window object (optional, defaults to display.screen().root)
81
"""
82
def __init__(self, _display=None, root=None): ...
83
```
84
85
### Desktop and Workspace Information
86
87
Methods for querying and controlling desktop/workspace properties.
88
89
```python { .api }
90
def getClientList(self):
91
"""
92
Get list of windows maintained by the window manager.
93
94
Returns:
95
list: List of Window objects
96
"""
97
98
def getClientListStacking(self):
99
"""
100
Get list of windows in bottom-to-top stacking order.
101
102
Returns:
103
list: List of Window objects in stacking order
104
"""
105
106
def getNumberOfDesktops(self):
107
"""
108
Get number of virtual desktops.
109
110
Returns:
111
int: Number of desktops
112
"""
113
114
def getDesktopGeometry(self):
115
"""
116
Get desktop geometry as width and height.
117
118
Returns:
119
list: [width, height] in pixels
120
"""
121
122
def getDesktopViewPort(self):
123
"""
124
Get viewport positions for each desktop.
125
126
Returns:
127
list: List of [x, y] coordinates for each desktop viewport
128
"""
129
130
def getCurrentDesktop(self):
131
"""
132
Get current desktop number (0-indexed).
133
134
Returns:
135
int: Current desktop index
136
"""
137
138
def getActiveWindow(self):
139
"""
140
Get currently active window.
141
142
Returns:
143
Window or None: Active window object or None if no active window
144
"""
145
146
def getWorkArea(self):
147
"""
148
Get work area geometry for each desktop.
149
150
Returns:
151
list: List of [x, y, width, height] for each desktop work area
152
"""
153
154
def getShowingDesktop(self):
155
"""
156
Get desktop showing mode status.
157
158
Returns:
159
int: 1 if showing desktop mode active, 0 otherwise
160
"""
161
```
162
163
### Desktop and Workspace Control
164
165
Methods for controlling desktop/workspace properties and state.
166
167
```python { .api }
168
def setNumberOfDesktops(self, nb):
169
"""
170
Set number of virtual desktops.
171
172
Args:
173
nb (int): Desired number of desktops
174
"""
175
176
def setDesktopGeometry(self, w, h):
177
"""
178
Set desktop geometry.
179
180
Args:
181
w (int): Desktop width in pixels
182
h (int): Desktop height in pixels
183
"""
184
185
def setDesktopViewport(self, w, h):
186
"""
187
Set desktop viewport size.
188
189
Args:
190
w (int): Viewport width in pixels
191
h (int): Viewport height in pixels
192
"""
193
194
def setCurrentDesktop(self, i):
195
"""
196
Switch to specified desktop.
197
198
Args:
199
i (int): Desktop index (0-indexed)
200
"""
201
202
def setActiveWindow(self, win):
203
"""
204
Set specified window as active.
205
206
Args:
207
win (Window): Window object to activate
208
"""
209
210
def setShowingDesktop(self, show):
211
"""
212
Enable or disable desktop showing mode.
213
214
Args:
215
show (int): 1 to show desktop, 0 to hide
216
"""
217
```
218
219
### Window Information
220
221
Methods for querying individual window properties.
222
223
```python { .api }
224
def getWmName(self, win):
225
"""
226
Get window name/title.
227
228
Args:
229
win (Window): Window object
230
231
Returns:
232
str: Window name
233
"""
234
235
def getWmVisibleName(self, win):
236
"""
237
Get window visible name (may differ from WM_NAME).
238
239
Args:
240
win (Window): Window object
241
242
Returns:
243
str: Window visible name
244
"""
245
246
def getWmDesktop(self, win):
247
"""
248
Get desktop number that window belongs to.
249
250
Args:
251
win (Window): Window object
252
253
Returns:
254
int: Desktop index (0-indexed)
255
"""
256
257
def getWmWindowType(self, win, str=False):
258
"""
259
Get window type(s).
260
261
Args:
262
win (Window): Window object
263
str (bool): If True, return string names instead of atom IDs
264
265
Returns:
266
list: List of window type atoms (int) or names (str)
267
"""
268
269
def getWmState(self, win, str=False):
270
"""
271
Get window state(s).
272
273
Args:
274
win (Window): Window object
275
str (bool): If True, return string names instead of atom IDs
276
277
Returns:
278
list: List of window state atoms (int) or names (str)
279
"""
280
281
def getWmAllowedActions(self, win, str=False):
282
"""
283
Get allowed actions for window.
284
285
Args:
286
win (Window): Window object
287
str (bool): If True, return string names instead of atom IDs
288
289
Returns:
290
list: List of allowed action atoms (int) or names (str)
291
"""
292
293
def getWmPid(self, win):
294
"""
295
Get process ID of window's application.
296
297
Args:
298
win (Window): Window object
299
300
Returns:
301
int: Process ID
302
"""
303
```
304
305
### Window Control
306
307
Methods for controlling individual window properties and actions.
308
309
```python { .api }
310
def setCloseWindow(self, win):
311
"""
312
Request window closure.
313
314
Args:
315
win (Window): Window object to close
316
"""
317
318
def setWmName(self, win, name):
319
"""
320
Set window name/title.
321
322
Args:
323
win (Window): Window object
324
name (str): New window name
325
"""
326
327
def setWmVisibleName(self, win, name):
328
"""
329
Set window visible name.
330
331
Args:
332
win (Window): Window object
333
name (str): New visible name
334
"""
335
336
def setWmDesktop(self, win, i):
337
"""
338
Move window to specified desktop.
339
340
Args:
341
win (Window): Window object
342
i (int): Target desktop index (0-indexed)
343
"""
344
345
def setMoveResizeWindow(self, win, gravity=0, x=None, y=None, w=None, h=None):
346
"""
347
Move and/or resize window.
348
349
Args:
350
win (Window): Window object
351
gravity (int): Gravity hint (Xlib.X.*Gravity constant or 0)
352
x (int, optional): New X coordinate
353
y (int, optional): New Y coordinate
354
w (int, optional): New width
355
h (int, optional): New height
356
"""
357
358
def setWmState(self, win, action, state, state2=0):
359
"""
360
Set or unset window state(s).
361
362
Args:
363
win (Window): Window object
364
action (int): 0=remove, 1=add, 2=toggle
365
state (int or str): Window state atom ID or name
366
state2 (int or str, optional): Second state atom ID or name
367
"""
368
```
369
370
### Generic Property Access
371
372
Methods for accessing EWMH properties by name using generic interfaces.
373
374
```python { .api }
375
def getReadableProperties(self):
376
"""
377
Get list of all readable EWMH property names.
378
379
Returns:
380
list: Property names that can be used with getProperty()
381
"""
382
383
def getProperty(self, prop, *args, **kwargs):
384
"""
385
Get EWMH property value by name.
386
387
Args:
388
prop (str): Property name (e.g., '_NET_ACTIVE_WINDOW')
389
*args: Arguments passed to specific getter method
390
**kwargs: Keyword arguments passed to specific getter method
391
392
Returns:
393
Property value (type depends on property)
394
395
Raises:
396
KeyError: If property name is not recognized
397
"""
398
399
def getWritableProperties(self):
400
"""
401
Get list of all writable EWMH property names.
402
403
Returns:
404
list: Property names that can be used with setProperty()
405
"""
406
407
def setProperty(self, prop, *args, **kwargs):
408
"""
409
Set EWMH property value by name.
410
411
Args:
412
prop (str): Property name (e.g., '_NET_ACTIVE_WINDOW')
413
*args: Arguments passed to specific setter method
414
**kwargs: Keyword arguments passed to specific setter method
415
416
Raises:
417
KeyError: If property name is not recognized
418
"""
419
```
420
421
## Constants
422
423
### Window Types
424
425
```python { .api }
426
NET_WM_WINDOW_TYPES = (
427
'_NET_WM_WINDOW_TYPE_DESKTOP',
428
'_NET_WM_WINDOW_TYPE_DOCK',
429
'_NET_WM_WINDOW_TYPE_TOOLBAR',
430
'_NET_WM_WINDOW_TYPE_MENU',
431
'_NET_WM_WINDOW_TYPE_UTILITY',
432
'_NET_WM_WINDOW_TYPE_SPLASH',
433
'_NET_WM_WINDOW_TYPE_DIALOG',
434
'_NET_WM_WINDOW_TYPE_DROPDOWN_MENU',
435
'_NET_WM_WINDOW_TYPE_POPUP_MENU',
436
'_NET_WM_WINDOW_TYPE_NOTIFICATION',
437
'_NET_WM_WINDOW_TYPE_COMBO',
438
'_NET_WM_WINDOW_TYPE_DND',
439
'_NET_WM_WINDOW_TYPE_NORMAL'
440
)
441
```
442
443
### Window Actions
444
445
```python { .api }
446
NET_WM_ACTIONS = (
447
'_NET_WM_ACTION_MOVE',
448
'_NET_WM_ACTION_RESIZE',
449
'_NET_WM_ACTION_MINIMIZE',
450
'_NET_WM_ACTION_SHADE',
451
'_NET_WM_ACTION_STICK',
452
'_NET_WM_ACTION_MAXIMIZE_HORZ',
453
'_NET_WM_ACTION_MAXIMIZE_VERT',
454
'_NET_WM_ACTION_FULLSCREEN',
455
'_NET_WM_ACTION_CHANGE_DESKTOP',
456
'_NET_WM_ACTION_CLOSE',
457
'_NET_WM_ACTION_ABOVE',
458
'_NET_WM_ACTION_BELOW'
459
)
460
```
461
462
### Window States
463
464
```python { .api }
465
NET_WM_STATES = (
466
'_NET_WM_STATE_MODAL',
467
'_NET_WM_STATE_STICKY',
468
'_NET_WM_STATE_MAXIMIZED_VERT',
469
'_NET_WM_STATE_MAXIMIZED_HORZ',
470
'_NET_WM_STATE_SHADED',
471
'_NET_WM_STATE_SKIP_TASKBAR',
472
'_NET_WM_STATE_SKIP_PAGER',
473
'_NET_WM_STATE_HIDDEN',
474
'_NET_WM_STATE_FULLSCREEN',
475
'_NET_WM_STATE_ABOVE',
476
'_NET_WM_STATE_BELOW',
477
'_NET_WM_STATE_DEMANDS_ATTENTION'
478
)
479
```
480
481
## Types
482
483
```python { .api }
484
# Xlib types used by EWMH methods
485
from Xlib.display import Display
486
from Xlib import Window
487
488
Window = Window # X11 window object from python-xlib
489
Display = Display # X11 display connection object from python-xlib
490
```
491
492
## Usage Notes
493
494
### Flushing Changes
495
496
After calling setter methods, you must flush the display connection to ensure changes are sent to the window manager:
497
498
```python
499
ewmh = EWMH()
500
ewmh.setActiveWindow(some_window)
501
ewmh.display.flush() # Required to send the request
502
```
503
504
### Error Handling
505
506
Methods may raise exceptions from the underlying Xlib operations. Common patterns:
507
508
- Window objects may become invalid if windows are closed
509
- Property access may return None for non-existent properties
510
- Generic property methods raise KeyError for unknown property names
511
512
### Display Management
513
514
Remember to close the display connection when done:
515
516
```python
517
ewmh = EWMH()
518
# ... use ewmh methods ...
519
ewmh.display.close()
520
```
521
522
Or use context management patterns for automatic cleanup.