1 /**
2 * @file hint.c
3 * @author Joe Wingbermuehle
4 * @date 2004-2006
5 *
6 * @brief Functions for reading and writing X properties.
7 *
8 */
9
10 #include "jwm.h"
11 #include "hint.h"
12 #include "client.h"
13 #include "desktop.h"
14 #include "misc.h"
15 #include "font.h"
16 #include "settings.h"
17
18 #include <X11/Xlibint.h>
19
20 /* MWM Defines */
21 #define MWM_HINTS_FUNCTIONS (1L << 0)
22 #define MWM_HINTS_DECORATIONS (1L << 1)
23 #define MWM_HINTS_INPUT_MODE (1L << 2)
24 #define MWM_HINTS_STATUS (1L << 3)
25
26 #define MWM_FUNC_ALL (1L << 0)
27 #define MWM_FUNC_RESIZE (1L << 1)
28 #define MWM_FUNC_MOVE (1L << 2)
29 #define MWM_FUNC_MINIMIZE (1L << 3)
30 #define MWM_FUNC_MAXIMIZE (1L << 4)
31 #define MWM_FUNC_CLOSE (1L << 5)
32
33 #define MWM_DECOR_ALL (1L << 0)
34 #define MWM_DECOR_BORDER (1L << 1)
35 #define MWM_DECOR_RESIZEH (1L << 2)
36 #define MWM_DECOR_TITLE (1L << 3)
37 #define MWM_DECOR_MENU (1L << 4)
38 #define MWM_DECOR_MINIMIZE (1L << 5)
39 #define MWM_DECOR_MAXIMIZE (1L << 6)
40
41 #define MWM_INPUT_MODELESS 0
42 #define MWM_INPUT_PRIMARY_APPLICATION_MODAL 1
43 #define MWM_INPUT_SYSTEM_MODAL 2
44 #define MWM_INPUT_FULL_APPLICATION_MODAL 3
45
46 #define MWM_TEAROFF_WINDOW (1L << 0)
47
48 typedef struct {
49
50 unsigned long flags;
51 unsigned long functions;
52 unsigned long decorations;
53 long inputMode;
54 unsigned long status;
55
56 } PropMwmHints;
57
58 typedef struct {
59 Atom *atom;
60 const char *name;
61 } ProtocolNode;
62
63 typedef struct {
64 Atom *atom;
65 const char *name;
66 } AtomNode;
67
68 Atom atoms[ATOM_COUNT];
69
70 const char jwmRestart[] = "_JWM_RESTART";
71 const char jwmExit[] = "_JWM_EXIT";
72 const char jwmReload[] = "_JWM_RELOAD";
73 const char managerProperty[] = "MANAGER";
74
75 static const AtomNode atomList[] = {
76
77 { &atoms[ATOM_COMPOUND_TEXT], "COMPOUND_TEXT" },
78 { &atoms[ATOM_UTF8_STRING], "UTF8_STRING" },
79 { &atoms[ATOM_XROOTPMAP_ID], "_XROOTPMAP_ID" },
80 { &atoms[ATOM_MANAGER], &managerProperty[0] },
81
82 { &atoms[ATOM_WM_STATE], "WM_STATE" },
83 { &atoms[ATOM_WM_PROTOCOLS], "WM_PROTOCOLS" },
84 { &atoms[ATOM_WM_DELETE_WINDOW], "WM_DELETE_WINDOW" },
85 { &atoms[ATOM_WM_TAKE_FOCUS], "WM_TAKE_FOCUS" },
86 { &atoms[ATOM_WM_CHANGE_STATE], "WM_CHANGE_STATE" },
87 { &atoms[ATOM_WM_COLORMAP_WINDOWS], "WM_COLORMAP_WINDOWS" },
88
89 { &atoms[ATOM_NET_SUPPORTED], "_NET_SUPPORTED" },
90 { &atoms[ATOM_NET_NUMBER_OF_DESKTOPS], "_NET_NUMBER_OF_DESKTOPS" },
91 { &atoms[ATOM_NET_DESKTOP_NAMES], "_NET_DESKTOP_NAMES" },
92 { &atoms[ATOM_NET_DESKTOP_GEOMETRY], "_NET_DESKTOP_GEOMETRY" },
93 { &atoms[ATOM_NET_DESKTOP_VIEWPORT], "_NET_DESKTOP_VIEWPORT" },
94 { &atoms[ATOM_NET_CURRENT_DESKTOP], "_NET_CURRENT_DESKTOP" },
95 { &atoms[ATOM_NET_ACTIVE_WINDOW], "_NET_ACTIVE_WINDOW" },
96 { &atoms[ATOM_NET_WORKAREA], "_NET_WORKAREA" },
97 { &atoms[ATOM_NET_SUPPORTING_WM_CHECK], "_NET_SUPPORTING_WM_CHECK" },
98 { &atoms[ATOM_NET_SHOWING_DESKTOP], "_NET_SHOWING_DESKTOP" },
99 { &atoms[ATOM_NET_FRAME_EXTENTS], "_NET_FRAME_EXTENTS" },
100 { &atoms[ATOM_NET_WM_DESKTOP], "_NET_WM_DESKTOP" },
101 { &atoms[ATOM_NET_WM_STATE], "_NET_WM_STATE" },
102 { &atoms[ATOM_NET_WM_STATE_STICKY], "_NET_WM_STATE_STICKY" },
103 { &atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT], "_NET_WM_STATE_MAXIMIZED_VERT"},
104 { &atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ], "_NET_WM_STATE_MAXIMIZED_HORZ"},
105 { &atoms[ATOM_NET_WM_STATE_SHADED], "_NET_WM_STATE_SHADED" },
106 { &atoms[ATOM_NET_WM_STATE_FULLSCREEN], "_NET_WM_STATE_FULLSCREEN" },
107 { &atoms[ATOM_NET_WM_STATE_HIDDEN], "_NET_WM_STATE_HIDDEN" },
108 { &atoms[ATOM_NET_WM_STATE_SKIP_TASKBAR], "_NET_WM_STATE_SKIP_TASKBAR" },
109 { &atoms[ATOM_NET_WM_STATE_SKIP_PAGER], "_NET_WM_STATE_SKIP_PAGER" },
110 { &atoms[ATOM_NET_WM_STATE_BELOW], "_NET_WM_STATE_BELOW" },
111 { &atoms[ATOM_NET_WM_STATE_ABOVE], "_NET_WM_STATE_ABOVE" },
112 { &atoms[ATOM_NET_WM_STATE_DEMANDS_ATTENTION],
113 "_NET_WM_STATE_DEMANDS_ATTENTION"},
114 { &atoms[ATOM_NET_WM_STATE_FOCUSED], "_NET_WM_STATE_FOCUSED" },
115 { &atoms[ATOM_NET_WM_ALLOWED_ACTIONS], "_NET_WM_ALLOWED_ACTIONS" },
116 { &atoms[ATOM_NET_WM_ACTION_MOVE], "_NET_WM_ACTION_MOVE" },
117 { &atoms[ATOM_NET_WM_ACTION_RESIZE], "_NET_WM_ACTION_RESIZE" },
118 { &atoms[ATOM_NET_WM_ACTION_MINIMIZE], "_NET_WM_ACTION_MINIMIZE" },
119 { &atoms[ATOM_NET_WM_ACTION_SHADE], "_NET_WM_ACTION_SHADE" },
120 { &atoms[ATOM_NET_WM_ACTION_STICK], "_NET_WM_ACTION_STICK" },
121 { &atoms[ATOM_NET_WM_ACTION_FULLSCREEN], "_NET_WM_ACTION_FULLSCREEN" },
122 { &atoms[ATOM_NET_WM_ACTION_MAXIMIZE_HORZ], "_NET_WM_ACTION_MAXIMIZE_HORZ"},
123 { &atoms[ATOM_NET_WM_ACTION_MAXIMIZE_VERT], "_NET_WM_ACTION_MAXIMIZE_VERT"},
124 { &atoms[ATOM_NET_WM_ACTION_CHANGE_DESKTOP],
125 "_NET_WM_ACTION_CHANGE_DESKTOP"},
126 { &atoms[ATOM_NET_WM_ACTION_CLOSE], "_NET_WM_ACTION_CLOSE" },
127 { &atoms[ATOM_NET_WM_ACTION_BELOW], "_NET_WM_ACTION_BELOW" },
128 { &atoms[ATOM_NET_WM_ACTION_ABOVE], "_NET_WM_ACTION_ABOVE" },
129 { &atoms[ATOM_NET_CLOSE_WINDOW], "_NET_CLOSE_WINDOW" },
130 { &atoms[ATOM_NET_MOVERESIZE_WINDOW], "_NET_MOVERESIZE_WINDOW" },
131 { &atoms[ATOM_NET_RESTACK_WINDOW], "_NET_RESTACK_WINDOW" },
132 { &atoms[ATOM_NET_REQUEST_FRAME_EXTENTS], "_NET_REQUEST_FRAME_EXTENTS" },
133 { &atoms[ATOM_NET_WM_PID], "_NET_WM_PID" },
134 { &atoms[ATOM_NET_WM_NAME], "_NET_WM_NAME" },
135 { &atoms[ATOM_NET_WM_VISIBLE_NAME], "_NET_WM_VISIBLE_NAME" },
136 { &atoms[ATOM_NET_WM_HANDLED_ICONS], "_NET_WM_HANDLED_ICONS" },
137 { &atoms[ATOM_NET_WM_ICON], "_NET_WM_ICON" },
138 { &atoms[ATOM_NET_WM_ICON_NAME], "_NET_WM_ICON_NAME" },
139 { &atoms[ATOM_NET_WM_USER_TIME], "_NET_WM_USER_TIME" },
140 { &atoms[ATOM_NET_WM_USER_TIME_WINDOW], "_NET_WM_USER_TIME_WINDOW" },
141 { &atoms[ATOM_NET_WM_VISIBLE_ICON_NAME], "_NET_WM_VISIBLE_ICON_NAME" },
142 { &atoms[ATOM_NET_WM_WINDOW_TYPE], "_NET_WM_WINDOW_TYPE" },
143 { &atoms[ATOM_NET_WM_WINDOW_TYPE_DESKTOP],"_NET_WM_WINDOW_TYPE_DESKTOP" },
144 { &atoms[ATOM_NET_WM_WINDOW_TYPE_DOCK], "_NET_WM_WINDOW_TYPE_DOCK" },
145 { &atoms[ATOM_NET_WM_WINDOW_TYPE_SPLASH], "_NET_WM_WINDOW_TYPE_SPLASH" },
146 { &atoms[ATOM_NET_WM_WINDOW_TYPE_DIALOG], "_NET_WM_WINDOW_TYPE_DIALOG" },
147 { &atoms[ATOM_NET_WM_WINDOW_TYPE_NORMAL], "_NET_WM_WINDOW_TYPE_NORMAL" },
148 { &atoms[ATOM_NET_WM_WINDOW_TYPE_MENU], "_NET_WM_WINDOW_TYPE_MENU" },
149 { &atoms[ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION],
150 "_NET_WM_WINDOW_TYPE_NOTIFICATION" },
151 { &atoms[ATOM_NET_WM_WINDOW_TYPE_TOOLBAR], "_NET_WM_WINDOW_TYPE_TOOLBAR"},
152 { &atoms[ATOM_NET_WM_WINDOW_TYPE_UTILITY], "_NET_WM_WINDOW_TYPE_UTILITY"},
153 { &atoms[ATOM_NET_CLIENT_LIST], "_NET_CLIENT_LIST" },
154 { &atoms[ATOM_NET_CLIENT_LIST_STACKING], "_NET_CLIENT_LIST_STACKING" },
155 { &atoms[ATOM_NET_WM_STRUT_PARTIAL], "_NET_WM_STRUT_PARTIAL" },
156 { &atoms[ATOM_NET_WM_STRUT], "_NET_WM_STRUT" },
157 { &atoms[ATOM_NET_WM_WINDOW_OPACITY], "_NET_WM_WINDOW_OPACITY" },
158 { &atoms[ATOM_NET_WM_MOVERESIZE], "_NET_WM_MOVERESIZE" },
159 { &atoms[ATOM_NET_SYSTEM_TRAY_OPCODE], "_NET_SYSTEM_TRAY_OPCODE" },
160 { &atoms[ATOM_NET_SYSTEM_TRAY_ORIENTATION],
161 "_NET_SYSTEM_TRAY_ORIENTATION" },
162
163 { &atoms[ATOM_MOTIF_WM_HINTS], "_MOTIF_WM_HINTS" },
164
165 { &atoms[ATOM_JWM_RESTART], &jwmRestart[0] },
166 { &atoms[ATOM_JWM_EXIT], &jwmExit[0] },
167 { &atoms[ATOM_JWM_RELOAD], &jwmReload[0] },
168 { &atoms[ATOM_JWM_WM_STATE_MAXIMIZED_TOP],
169 "_JWM_WM_STATE_MAXIMIZED_TOP" },
170 { &atoms[ATOM_JWM_WM_STATE_MAXIMIZED_BOTTOM],
171 "_JWM_WM_STATE_MAXIMIZED_BOTTOM" },
172 { &atoms[ATOM_JWM_WM_STATE_MAXIMIZED_LEFT],
173 "_JWM_WM_STATE_MAXIMIZED_LEFT" },
174 { &atoms[ATOM_JWM_WM_STATE_MAXIMIZED_RIGHT],
175 "_JWM_WM_STATE_MAXIMIZED_RIGHT" }
176
177 };
178
179 static char CheckShape(Window win);
180 static void WriteNetAllowed(ClientNode *np);
181 static void ReadWMState(Window win, ClientState *state);
182 static void ReadMotifHints(Window win, ClientState *state);
183
184 /** Set root hints and intern atoms. */
StartupHints(void)185 void StartupHints(void)
186 {
187
188 unsigned long *array;
189 char *data;
190 Atom *supported;
191 Window win;
192 unsigned int x;
193 unsigned int count;
194
195 /* Determine how much space we will need on the stack and allocate it. */
196 count = 0;
197 for(x = 0; x < settings.desktopCount; x++) {
198 count += strlen(GetDesktopName(x)) + 1;
199 }
200 if(count < 2 * sizeof(unsigned long)) {
201 count = 2 * sizeof(unsigned long);
202 }
203 if(count < ATOM_COUNT * sizeof(Atom)) {
204 count = ATOM_COUNT * sizeof(Atom);
205 }
206 data = AllocateStack(count);
207 array = (unsigned long*)data;
208 supported = (Atom*)data;
209
210 /* Intern the atoms */
211 for(x = 0; x < ATOM_COUNT; x++) {
212 *atomList[x].atom = JXInternAtom(display, atomList[x].name, False);
213 }
214
215 /* _NET_SUPPORTED */
216 for(x = FIRST_NET_ATOM; x <= LAST_NET_ATOM; x++) {
217 supported[x - FIRST_NET_ATOM] = atoms[x];
218 }
219 JXChangeProperty(display, rootWindow, atoms[ATOM_NET_SUPPORTED],
220 XA_ATOM, 32, PropModeReplace, (unsigned char*)supported,
221 LAST_NET_ATOM - FIRST_NET_ATOM + 1);
222
223 /* _NET_NUMBER_OF_DESKTOPS */
224 SetCardinalAtom(rootWindow, ATOM_NET_NUMBER_OF_DESKTOPS,
225 settings.desktopCount);
226
227 /* _NET_DESKTOP_NAMES */
228 count = 0;
229 for(x = 0; x < settings.desktopCount; x++) {
230 const char *name = GetDesktopName(x);
231 const unsigned len = strlen(name);
232 memcpy(&data[count], name, len + 1);
233 count += len + 1;
234 }
235 JXChangeProperty(display, rootWindow, atoms[ATOM_NET_DESKTOP_NAMES],
236 atoms[ATOM_UTF8_STRING], 8, PropModeReplace,
237 (unsigned char*)data, count);
238
239 /* _NET_DESKTOP_GEOMETRY */
240 array[0] = rootWidth;
241 array[1] = rootHeight;
242 JXChangeProperty(display, rootWindow, atoms[ATOM_NET_DESKTOP_GEOMETRY],
243 XA_CARDINAL, 32, PropModeReplace,
244 (unsigned char*)array, 2);
245
246 /* _NET_DESKTOP_VIEWPORT */
247 array[0] = 0;
248 array[1] = 0;
249 JXChangeProperty(display, rootWindow, atoms[ATOM_NET_DESKTOP_VIEWPORT],
250 XA_CARDINAL, 32, PropModeReplace,
251 (unsigned char*)array, 2);
252
253 /* _NET_WM_NAME */
254 win = supportingWindow;
255 JXChangeProperty(display, win, atoms[ATOM_NET_WM_NAME],
256 atoms[ATOM_UTF8_STRING], 8, PropModeReplace,
257 (unsigned char*)"JWM", 3);
258
259 /* _NET_WM_PID */
260 array[0] = getpid();
261 JXChangeProperty(display, win, atoms[ATOM_NET_WM_PID],
262 XA_CARDINAL, 32, PropModeReplace,
263 (unsigned char*)array, 1);
264
265 /* _NET_SUPPORTING_WM_CHECK */
266 SetWindowAtom(rootWindow, ATOM_NET_SUPPORTING_WM_CHECK, win);
267 SetWindowAtom(win, ATOM_NET_SUPPORTING_WM_CHECK, win);
268
269 ReleaseStack(data);
270
271 }
272
273 /** Determine the current desktop. */
ReadCurrentDesktop(void)274 void ReadCurrentDesktop(void)
275 {
276 unsigned long temp;
277 currentDesktop = 0;
278 if(GetCardinalAtom(rootWindow, ATOM_NET_CURRENT_DESKTOP, &temp)) {
279 ChangeDesktop(temp);
280 } else {
281 SetCardinalAtom(rootWindow, ATOM_NET_CURRENT_DESKTOP, currentDesktop);
282 }
283 }
284
285 /** Read client hints.
286 * This is called while the client is being added to management.
287 */
ReadClientInfo(ClientNode * np,char alreadyMapped)288 void ReadClientInfo(ClientNode *np, char alreadyMapped)
289 {
290
291 Status status;
292 ClientNode *pp;
293
294 Assert(np);
295
296 ReadWMName(np);
297 ReadWMClass(np);
298 ReadWMNormalHints(np);
299 ReadWMColormaps(np);
300
301 status = JXGetTransientForHint(display, np->window, &np->owner);
302 if(!status) {
303 np->owner = None;
304 }
305
306 /* Read the window state. */
307 np->state = ReadWindowState(np->window, alreadyMapped);
308 if(np->minWidth == np->maxWidth && np->minHeight == np->maxHeight) {
309 np->state.border &= ~BORDER_RESIZE;
310 np->state.border &= ~BORDER_MAX;
311 if(np->minWidth * np->xinc >= rootWidth
312 && np->minHeight * np->yinc >= rootHeight) {
313 np->state.status |= STAT_FULLSCREEN;
314 }
315 }
316
317 /* Make sure this client is on at least as high of a layer
318 * as its owner. */
319 if(np->owner != None) {
320 pp = FindClientByWindow(np->owner);
321 if(pp) {
322 np->state.layer = Max(pp->state.layer, np->state.layer);
323 }
324 }
325
326 }
327
328 /** Write the window state hint for a client. */
WriteState(ClientNode * np)329 void WriteState(ClientNode *np)
330 {
331 unsigned long data[2];
332
333 if(np->state.status & STAT_MAPPED) {
334 data[0] = NormalState;
335 } else if(np->state.status & STAT_MINIMIZED) {
336 data[0] = IconicState;
337 } else if(np->state.status & STAT_SHADED) {
338 data[0] = NormalState;
339 } else {
340 data[0] = WithdrawnState;
341 }
342 data[1] = None;
343
344 if(data[0] == WithdrawnState) {
345 JXDeleteProperty(display, np->window, atoms[ATOM_WM_STATE]);
346 } else {
347 JXChangeProperty(display, np->window, atoms[ATOM_WM_STATE],
348 atoms[ATOM_WM_STATE], 32, PropModeReplace,
349 (unsigned char*)data, 2);
350 }
351
352 WriteNetState(np);
353 WriteFrameExtents(np->window, &np->state);
354 WriteNetAllowed(np);
355 }
356
357 /** Set the opacity of a client. */
SetOpacity(ClientNode * np,unsigned int opacity,char force)358 void SetOpacity(ClientNode *np, unsigned int opacity, char force)
359 {
360 Window w;
361 if(np->state.opacity == opacity && !force) {
362 return;
363 }
364
365 w = np->parent != None ? np->parent : np->window;
366 np->state.opacity = opacity;
367 if(opacity == 0xFFFFFFFF) {
368 JXDeleteProperty(display, w, atoms[ATOM_NET_WM_WINDOW_OPACITY]);
369 } else {
370 SetCardinalAtom(w, ATOM_NET_WM_WINDOW_OPACITY, opacity);
371 }
372 }
373
374 /** Write the net state hint for a client. */
WriteNetState(ClientNode * np)375 void WriteNetState(ClientNode *np)
376 {
377 unsigned long values[16];
378 int index;
379
380 Assert(np);
381
382 /* We remove the _NET_WM_STATE and _NET_WM_DESKTOP for withdrawn windows. */
383 if(!(np->state.status & (STAT_MAPPED | STAT_MINIMIZED | STAT_SHADED))) {
384 JXDeleteProperty(display, np->window, atoms[ATOM_NET_WM_STATE]);
385 JXDeleteProperty(display, np->window, atoms[ATOM_NET_WM_DESKTOP]);
386 return;
387 }
388
389 index = 0;
390 if(np->state.status & STAT_MINIMIZED) {
391 values[index++] = atoms[ATOM_NET_WM_STATE_HIDDEN];
392 }
393
394 if(np->state.maxFlags & MAX_HORIZ) {
395 values[index++] = atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ];
396 }
397 if(np->state.maxFlags & MAX_VERT) {
398 values[index++] = atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT];
399 }
400 if(np->state.maxFlags & MAX_TOP) {
401 values[index++] = atoms[ATOM_JWM_WM_STATE_MAXIMIZED_TOP];
402 }
403 if(np->state.maxFlags & MAX_BOTTOM) {
404 values[index++] = atoms[ATOM_JWM_WM_STATE_MAXIMIZED_BOTTOM];
405 }
406 if(np->state.maxFlags & MAX_LEFT) {
407 values[index++] = atoms[ATOM_JWM_WM_STATE_MAXIMIZED_LEFT];
408 }
409 if(np->state.maxFlags & MAX_RIGHT) {
410 values[index++] = atoms[ATOM_JWM_WM_STATE_MAXIMIZED_RIGHT];
411 }
412
413 if(np->state.status & STAT_SHADED) {
414 values[index++] = atoms[ATOM_NET_WM_STATE_SHADED];
415 }
416
417 if(np->state.status & STAT_STICKY) {
418 values[index++] = atoms[ATOM_NET_WM_STATE_STICKY];
419 }
420
421 if(np->state.status & STAT_FULLSCREEN) {
422 values[index++] = atoms[ATOM_NET_WM_STATE_FULLSCREEN];
423 }
424
425 if(np->state.status & STAT_NOLIST) {
426 values[index++] = atoms[ATOM_NET_WM_STATE_SKIP_TASKBAR];
427 }
428
429 if(np->state.status & STAT_NOPAGER) {
430 values[index++] = atoms[ATOM_NET_WM_STATE_SKIP_PAGER];
431 }
432
433 if(np->state.layer != np->state.defaultLayer) {
434 if(np->state.layer == LAYER_BELOW) {
435 values[index++] = atoms[ATOM_NET_WM_STATE_BELOW];
436 } else if(np->state.layer == LAYER_ABOVE) {
437 values[index++] = atoms[ATOM_NET_WM_STATE_ABOVE];
438 }
439 }
440
441 if(np->state.status & STAT_URGENT) {
442 values[index++] = atoms[ATOM_NET_WM_STATE_DEMANDS_ATTENTION];
443 }
444 if(np->state.status & STAT_ACTIVE) {
445 values[index++] = atoms[ATOM_NET_WM_STATE_FOCUSED];
446 }
447
448 JXChangeProperty(display, np->window, atoms[ATOM_NET_WM_STATE],
449 XA_ATOM, 32, PropModeReplace,
450 (unsigned char*)values, index);
451 }
452
453 /** Set _NET_FRAME_EXTENTS. */
WriteFrameExtents(Window win,const ClientState * state)454 void WriteFrameExtents(Window win, const ClientState *state)
455 {
456 unsigned long values[4];
457 int north, south, east, west;
458
459 GetBorderSize(state, &north, &south, &east, &west);
460
461 /* left, right, top, bottom */
462 values[0] = west;
463 values[1] = east;
464 values[2] = north;
465 values[3] = south;
466
467 JXChangeProperty(display, win, atoms[ATOM_NET_FRAME_EXTENTS],
468 XA_CARDINAL, 32, PropModeReplace,
469 (unsigned char*)values, 4);
470
471 }
472
473 /** Write the allowed action property. */
WriteNetAllowed(ClientNode * np)474 void WriteNetAllowed(ClientNode *np)
475 {
476
477 unsigned long values[12];
478 unsigned int index;
479
480 Assert(np);
481
482 index = 0;
483
484 if(np->state.border & BORDER_SHADE) {
485 values[index++] = atoms[ATOM_NET_WM_ACTION_SHADE];
486 }
487
488 if(np->state.border & BORDER_MIN) {
489 values[index++] = atoms[ATOM_NET_WM_ACTION_MINIMIZE];
490 }
491
492 if(np->state.border & BORDER_MAX) {
493 values[index++] = atoms[ATOM_NET_WM_ACTION_MAXIMIZE_HORZ];
494 values[index++] = atoms[ATOM_NET_WM_ACTION_MAXIMIZE_VERT];
495 values[index++] = atoms[ATOM_NET_WM_ACTION_FULLSCREEN];
496 }
497
498 if(np->state.border & BORDER_CLOSE) {
499 values[index++] = atoms[ATOM_NET_WM_ACTION_CLOSE];
500 }
501
502 if(np->state.border & BORDER_RESIZE) {
503 values[index++] = atoms[ATOM_NET_WM_ACTION_RESIZE];
504 }
505
506 if(np->state.border & BORDER_MOVE) {
507 values[index++] = atoms[ATOM_NET_WM_ACTION_MOVE];
508 }
509
510 if(!(np->state.status & STAT_STICKY)) {
511 values[index++] = atoms[ATOM_NET_WM_ACTION_CHANGE_DESKTOP];
512 }
513
514 values[index++] = atoms[ATOM_NET_WM_ACTION_STICK];
515 values[index++] = atoms[ATOM_NET_WM_ACTION_BELOW];
516 values[index++] = atoms[ATOM_NET_WM_ACTION_ABOVE];
517
518 JXChangeProperty(display, np->window, atoms[ATOM_NET_WM_ALLOWED_ACTIONS],
519 XA_ATOM, 32, PropModeReplace,
520 (unsigned char*)values, index);
521
522 }
523
524 /** Check if a window uses the shape extension. */
CheckShape(Window win)525 char CheckShape(Window win)
526 {
527 #ifdef USE_SHAPE
528 int shaped = 0;
529 int r1;
530 unsigned int r2;
531 if(haveShape) {
532 JXShapeSelectInput(display, win, ShapeNotifyMask);
533 XShapeQueryExtents(display, win, &shaped,
534 &r1, &r1, &r2, &r2,
535 &r1, &r1, &r1, &r2, &r2);
536 return shaped ? 1 : 0;
537 } else {
538 return 0;
539 }
540 #else
541 return 0;
542 #endif
543 }
544
545 /** Read all hints needed to determine the current window state. */
ReadWindowState(Window win,char alreadyMapped)546 ClientState ReadWindowState(Window win, char alreadyMapped)
547 {
548
549 ClientState result;
550 Status status;
551 unsigned long count, x;
552 unsigned long extra;
553 Atom realType;
554 int realFormat;
555 unsigned char *temp;
556 Atom *state;
557 unsigned long card;
558 Window utwin;
559
560 Assert(win != None);
561
562 result.status = STAT_MAPPED;
563 result.maxFlags = MAX_NONE;
564 result.border = BORDER_DEFAULT;
565 result.layer = LAYER_NORMAL;
566 result.defaultLayer = LAYER_NORMAL;
567 result.desktop = currentDesktop;
568 result.opacity = UINT_MAX;
569
570 ReadWMProtocols(win, &result);
571 ReadWMHints(win, &result, alreadyMapped);
572 ReadWMState(win, &result);
573 ReadMotifHints(win, &result);
574 ReadWMOpacity(win, &result.opacity);
575
576 /* _NET_WM_DESKTOP */
577 if(GetCardinalAtom(win, ATOM_NET_WM_DESKTOP, &card)) {
578 if(card == ~0UL) {
579 result.status |= STAT_STICKY;
580 } else if(card < settings.desktopCount) {
581 result.desktop = card;
582 } else {
583 result.desktop = settings.desktopCount - 1;
584 }
585 }
586
587 /* _NET_WM_STATE */
588 status = JXGetWindowProperty(display, win, atoms[ATOM_NET_WM_STATE], 0, 32,
589 False, XA_ATOM, &realType, &realFormat,
590 &count, &extra, &temp);
591 if(status == Success && realFormat != 0) {
592 if(count > 0) {
593 state = (Atom*)temp;
594 for(x = 0; x < count; x++) {
595 if(state[x] == atoms[ATOM_NET_WM_STATE_STICKY]) {
596 result.status |= STAT_STICKY;
597 } else if(state[x] == atoms[ATOM_NET_WM_STATE_SHADED]) {
598 result.status |= STAT_SHADED;
599 } else if(state[x] == atoms[ATOM_NET_WM_STATE_MAXIMIZED_VERT]) {
600 result.maxFlags |= MAX_VERT;
601 } else if(state[x] == atoms[ATOM_NET_WM_STATE_MAXIMIZED_HORZ]) {
602 result.maxFlags |= MAX_HORIZ;
603 } else if(state[x] == atoms[ATOM_JWM_WM_STATE_MAXIMIZED_TOP]) {
604 result.maxFlags |= MAX_TOP;
605 } else if(state[x] == atoms[ATOM_JWM_WM_STATE_MAXIMIZED_BOTTOM]) {
606 result.maxFlags |= MAX_BOTTOM;
607 } else if(state[x] == atoms[ATOM_JWM_WM_STATE_MAXIMIZED_LEFT]) {
608 result.maxFlags |= MAX_LEFT;
609 } else if(state[x] == atoms[ATOM_JWM_WM_STATE_MAXIMIZED_RIGHT]) {
610 result.maxFlags |= MAX_RIGHT;
611 } else if(state[x] == atoms[ATOM_NET_WM_STATE_FULLSCREEN]) {
612 result.status |= STAT_FULLSCREEN;
613 } else if(state[x] == atoms[ATOM_NET_WM_STATE_HIDDEN]) {
614 result.status |= STAT_MINIMIZED;
615 } else if(state[x] == atoms[ATOM_NET_WM_STATE_SKIP_TASKBAR]) {
616 result.status |= STAT_NOLIST;
617 } else if(state[x] == atoms[ATOM_NET_WM_STATE_SKIP_PAGER]) {
618 result.status |= STAT_NOPAGER;
619 } else if(state[x] == atoms[ATOM_NET_WM_STATE_ABOVE]) {
620 result.layer = LAYER_ABOVE;
621 } else if(state[x] == atoms[ATOM_NET_WM_STATE_BELOW]) {
622 result.layer = LAYER_BELOW;
623 } else if(state[x] == atoms[ATOM_NET_WM_STATE_DEMANDS_ATTENTION]) {
624 result.status |= STAT_URGENT;
625 }
626 }
627 }
628 if(temp) {
629 JXFree(temp);
630 }
631 }
632
633 /* _NET_WM_WINDOW_TYPE */
634 status = JXGetWindowProperty(display, win, atoms[ATOM_NET_WM_WINDOW_TYPE],
635 0, 32, False, XA_ATOM, &realType, &realFormat,
636 &count, &extra, &temp);
637 if(status == Success && realFormat != 0) {
638 /* Loop until we hit a window type we recognize. */
639 state = (Atom*)temp;
640 for(x = 0; x < count; x++) {
641 if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_NORMAL]) {
642 break;
643 } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_DESKTOP]) {
644 result.defaultLayer = LAYER_DESKTOP;
645 result.border = BORDER_NONE;
646 result.status |= STAT_STICKY;
647 result.status |= STAT_NOLIST;
648 result.status |= STAT_NOFOCUS;
649 break;
650 } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_DOCK]) {
651 result.border = BORDER_NONE;
652 result.defaultLayer = LAYER_ABOVE;
653 result.status |= STAT_NOFOCUS;
654 break;
655 } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_SPLASH]) {
656 result.border = BORDER_NONE;
657 break;
658 } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_DIALOG]) {
659 result.border &= ~BORDER_MIN;
660 result.border &= ~BORDER_MAX;
661 break;
662 } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_MENU]) {
663 result.border &= ~BORDER_MAX;
664 result.status |= STAT_NOLIST;
665 } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_NOTIFICATION]) {
666 result.border = BORDER_NONE;
667 result.status |= STAT_NOLIST;
668 result.status |= STAT_NOFOCUS;
669 } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_TOOLBAR]) {
670 result.border &= ~BORDER_MAX;
671 result.defaultLayer = LAYER_ABOVE;
672 result.status |= STAT_STICKY;
673 result.status |= STAT_NOLIST;
674 result.status |= STAT_NOFOCUS;
675 } else if( state[x] == atoms[ATOM_NET_WM_WINDOW_TYPE_UTILITY]) {
676 result.border &= ~BORDER_MAX;
677 result.status |= STAT_NOFOCUS;
678 } else {
679 Debug("Unknown _NET_WM_WINDOW_TYPE: %lu", state[x]);
680 }
681 }
682 if(temp) {
683 JXFree(temp);
684 }
685 }
686
687 /* _NET_WM_USER_TIME_WINDOW */
688 if(!GetWindowAtom(win, ATOM_NET_WM_USER_TIME_WINDOW, &utwin)) {
689 utwin = win;
690 }
691
692 /* _NET_WM_USER_TIME */
693 if(GetCardinalAtom(utwin, ATOM_NET_WM_USER_TIME, &card)) {
694 if(card == 0) {
695 result.status |= STAT_NOFOCUS;
696 }
697 }
698
699 /* Use the default layer if the layer wasn't set explicitly. */
700 if(result.layer == LAYER_NORMAL) {
701 result.layer = result.defaultLayer;
702 }
703
704 /* Check if this window uses the shape extension. */
705 if(CheckShape(win)) {
706 result.status |= STAT_SHAPED;
707 }
708
709 return result;
710
711 }
712
713 /** Determine the title to display for a client. */
ReadWMName(ClientNode * np)714 void ReadWMName(ClientNode *np)
715 {
716
717 unsigned long count;
718 int status;
719 unsigned long extra;
720 Atom realType;
721 int realFormat;
722 unsigned char *name;
723
724 if(np->name) {
725 Release(np->name);
726 }
727
728 status = JXGetWindowProperty(display, np->window,
729 atoms[ATOM_NET_WM_NAME], 0, 1024, False,
730 atoms[ATOM_UTF8_STRING], &realType,
731 &realFormat, &count, &extra, &name);
732 if(status != Success || realFormat == 0) {
733 np->name = NULL;
734 } else {
735 np->name = Allocate(count + 1);
736 memcpy(np->name, name, count);
737 np->name[count] = 0;
738 JXFree(name);
739 np->name = ConvertFromUTF8(np->name);
740 }
741
742 #ifdef USE_XUTF8
743 if(!np->name) {
744 status = JXGetWindowProperty(display, np->window,
745 XA_WM_NAME, 0, 1024, False,
746 atoms[ATOM_COMPOUND_TEXT],
747 &realType, &realFormat, &count,
748 &extra, &name);
749 if(status == Success && realFormat != 0) {
750 char **tlist;
751 XTextProperty tprop;
752 int tcount;
753 tprop.value = name;
754 tprop.encoding = atoms[ATOM_COMPOUND_TEXT];
755 tprop.format = realFormat;
756 tprop.nitems = count;
757 if(XmbTextPropertyToTextList(display, &tprop, &tlist, &tcount)
758 == Success && tcount > 0) {
759 const size_t len = strlen(tlist[0]) + 1;
760 np->name = Allocate(len);
761 memcpy(np->name, tlist[0], len);
762 XFreeStringList(tlist);
763 }
764 JXFree(name);
765 }
766 }
767 #endif
768
769 if(!np->name) {
770 char *temp = NULL;
771 if(JXFetchName(display, np->window, &temp)) {
772 const size_t len = strlen(temp) + 1;
773 np->name = Allocate(len);
774 memcpy(np->name, temp, len);
775 JXFree(temp);
776 }
777 }
778
779 }
780
781 /** Read the window class for a client. */
ReadWMClass(ClientNode * np)782 void ReadWMClass(ClientNode *np)
783 {
784 XClassHint hint;
785 Assert(np);
786 if(JXGetClassHint(display, np->window, &hint)) {
787 np->instanceName = hint.res_name;
788 np->className = hint.res_class;
789 }
790 }
791
792 /** Read the protocols hint for a window. */
ReadWMProtocols(Window w,ClientState * state)793 void ReadWMProtocols(Window w, ClientState *state)
794 {
795
796 unsigned long count, x;
797 int status;
798 unsigned long extra;
799 Atom realType;
800 int realFormat;
801 unsigned char *temp;
802 Atom *p;
803
804 Assert(w != None);
805
806 state->status &= ~STAT_TAKEFOCUS;
807 state->status &= ~STAT_DELETE;
808 status = JXGetWindowProperty(display, w, atoms[ATOM_WM_PROTOCOLS],
809 0, 32, False, XA_ATOM, &realType, &realFormat,
810 &count, &extra, &temp);
811 p = (Atom*)temp;
812 if(status != Success || realFormat == 0 || !p) {
813 return;
814 }
815
816 for(x = 0; x < count; x++) {
817 if(p[x] == atoms[ATOM_WM_DELETE_WINDOW]) {
818 state->status |= STAT_DELETE;
819 } else if(p[x] == atoms[ATOM_WM_TAKE_FOCUS]) {
820 state->status |= STAT_TAKEFOCUS;
821 }
822 }
823
824 JXFree(p);
825
826 }
827
828 /** Read the "normal hints" for a client. */
ReadWMNormalHints(ClientNode * np)829 void ReadWMNormalHints(ClientNode *np)
830 {
831
832 XSizeHints hints;
833 long temp;
834
835 Assert(np);
836
837 if(!JXGetWMNormalHints(display, np->window, &hints, &temp)) {
838 np->sizeFlags = 0;
839 } else {
840 np->sizeFlags = hints.flags;
841 }
842
843 if(np->sizeFlags & PResizeInc) {
844 np->xinc = Max(1, hints.width_inc);
845 np->yinc = Max(1, hints.height_inc);
846 } else {
847 np->xinc = 1;
848 np->yinc = 1;
849 }
850
851 if(np->sizeFlags & PMinSize) {
852 np->minWidth = Max(0, hints.min_width);
853 np->minHeight = Max(0, hints.min_height);
854 } else {
855 np->minWidth = 1;
856 np->minHeight = 1;
857 }
858
859 if(np->sizeFlags & PMaxSize) {
860 np->maxWidth = hints.max_width;
861 np->maxHeight = hints.max_height;
862 if(np->maxWidth <= 0) {
863 np->maxWidth = rootWidth;
864 }
865 if(np->maxHeight <= 0) {
866 np->maxHeight = rootHeight;
867 }
868 } else {
869 np->maxWidth = MAX_WINDOW_WIDTH;
870 np->maxHeight = MAX_WINDOW_HEIGHT;
871 }
872
873 if(np->sizeFlags & PBaseSize) {
874 np->baseWidth = hints.base_width;
875 np->baseHeight = hints.base_height;
876 } else if(np->sizeFlags & PMinSize) {
877 np->baseWidth = np->minWidth;
878 np->baseHeight = np->minHeight;
879 } else {
880 np->baseWidth = 0;
881 np->baseHeight = 0;
882 }
883
884 if(np->sizeFlags & PAspect) {
885 np->aspect.minx = hints.min_aspect.x;
886 np->aspect.miny = hints.min_aspect.y;
887 np->aspect.maxx = hints.max_aspect.x;
888 np->aspect.maxy = hints.max_aspect.y;
889 }
890
891 if(np->sizeFlags & PWinGravity) {
892 np->gravity = hints.win_gravity;
893 } else {
894 np->gravity = 1;
895 }
896
897 }
898
899 /** Read colormap information for a client. */
ReadWMColormaps(ClientNode * np)900 void ReadWMColormaps(ClientNode *np)
901 {
902
903 Window *windows;
904 ColormapNode *cp;
905 int count;
906
907 Assert(np);
908
909 if(JXGetWMColormapWindows(display, np->window, &windows, &count)) {
910 if(count > 0) {
911 int x;
912
913 /* Free old colormaps. */
914 while(np->colormaps) {
915 cp = np->colormaps->next;
916 Release(np->colormaps);
917 np->colormaps = cp;
918 }
919
920 /* Put the maps in the list in order so they will come out in
921 * reverse order. This way they will be installed with the
922 * most important last.
923 * Keep track of at most colormapCount colormaps for each
924 * window to avoid doing extra work. */
925 count = Min(colormapCount, count);
926 for(x = 0; x < count; x++) {
927 cp = Allocate(sizeof(ColormapNode));
928 cp->window = windows[x];
929 cp->next = np->colormaps;
930 np->colormaps = cp;
931 }
932
933 JXFree(windows);
934
935 }
936 }
937
938 }
939
940 /** Read the WM state for a window. */
ReadWMState(Window win,ClientState * state)941 void ReadWMState(Window win, ClientState *state)
942 {
943
944 Status status;
945 unsigned long count;
946 unsigned long extra;
947 Atom realType;
948 int realFormat;
949 unsigned long *temp;
950
951 count = 0;
952 status = JXGetWindowProperty(display, win, atoms[ATOM_WM_STATE], 0, 2,
953 False, atoms[ATOM_WM_STATE],
954 &realType, &realFormat,
955 &count, &extra, (unsigned char**)&temp);
956 if(JLIKELY(status == Success && realFormat != 0)) {
957 if(JLIKELY(count == 2)) {
958 switch(temp[0]) {
959 case IconicState:
960 state->status |= STAT_MINIMIZED;
961 break;
962 case WithdrawnState:
963 state->status &= ~STAT_MAPPED;
964 break;
965 default:
966 break;
967 }
968 }
969 JXFree(temp);
970 }
971
972 }
973
974 /** Read the WM hints for a window. */
ReadWMHints(Window win,ClientState * state,char alreadyMapped)975 void ReadWMHints(Window win, ClientState *state, char alreadyMapped)
976 {
977
978 XWMHints *wmhints;
979
980 Assert(win != None);
981 Assert(state);
982
983 state->status |= STAT_CANFOCUS;
984 wmhints = JXGetWMHints(display, win);
985 if(wmhints) {
986 if(!alreadyMapped && (wmhints->flags & StateHint)) {
987 switch(wmhints->initial_state) {
988 case IconicState:
989 state->status |= STAT_MINIMIZED;
990 break;
991 default:
992 break;
993 }
994 }
995 if((wmhints->flags & InputHint) && wmhints->input == False) {
996 state->status &= ~STAT_CANFOCUS;
997 }
998 if(wmhints->flags & XUrgencyHint) {
999 state->status |= STAT_URGENT;
1000 } else {
1001 state->status &= ~(STAT_URGENT | STAT_FLASH);
1002 }
1003 JXFree(wmhints);
1004 }
1005
1006 }
1007
1008 /** Read _NET_WM_WINDOW_OPACITY. */
ReadWMOpacity(Window win,unsigned * opacity)1009 void ReadWMOpacity(Window win, unsigned *opacity)
1010 {
1011 unsigned long card;
1012 if(GetCardinalAtom(win, ATOM_NET_WM_WINDOW_OPACITY, &card)) {
1013 *opacity = card;
1014 } else {
1015 *opacity = UINT_MAX;
1016 }
1017 }
1018
1019 /** Read _MOTIF_WM_HINTS */
ReadMotifHints(Window win,ClientState * state)1020 void ReadMotifHints(Window win, ClientState *state)
1021 {
1022
1023 PropMwmHints *mhints;
1024 Atom type;
1025 unsigned long itemCount, bytesLeft;
1026 unsigned char *data;
1027 int format;
1028 int status;
1029
1030 Assert(win != None);
1031 Assert(state);
1032
1033 status = JXGetWindowProperty(display, win, atoms[ATOM_MOTIF_WM_HINTS],
1034 0L, 20L, False, atoms[ATOM_MOTIF_WM_HINTS],
1035 &type, &format, &itemCount, &bytesLeft, &data);
1036 if(status != Success || type == 0) {
1037 return;
1038 }
1039
1040 mhints = (PropMwmHints*)data;
1041 if(JLIKELY(mhints)) {
1042
1043 if((mhints->flags & MWM_HINTS_FUNCTIONS)
1044 && !(mhints->functions & MWM_FUNC_ALL)) {
1045
1046 if(!(mhints->functions & MWM_FUNC_RESIZE)) {
1047 state->border &= ~BORDER_RESIZE;
1048 }
1049 if(!(mhints->functions & MWM_FUNC_MOVE)) {
1050 state->border &= ~BORDER_MOVE;
1051 }
1052 if(!(mhints->functions & MWM_FUNC_MINIMIZE)) {
1053 state->border &= ~BORDER_MIN;
1054 }
1055 if(!(mhints->functions & MWM_FUNC_MAXIMIZE)) {
1056 state->border &= ~BORDER_MAX;
1057 }
1058 if(!(mhints->functions & MWM_FUNC_CLOSE)) {
1059 state->border &= ~BORDER_CLOSE;
1060 }
1061 }
1062
1063 if((mhints->flags & MWM_HINTS_DECORATIONS)
1064 && !(mhints->decorations & MWM_DECOR_ALL)) {
1065
1066 if(!(mhints->decorations & MWM_DECOR_BORDER)) {
1067 state->border &= ~BORDER_OUTLINE;
1068 }
1069 if(!(mhints->decorations & MWM_DECOR_TITLE)) {
1070 state->border &= ~BORDER_TITLE;
1071 }
1072 }
1073
1074 JXFree(mhints);
1075 }
1076 }
1077
1078 /** Read a cardinal atom. */
GetCardinalAtom(Window window,AtomType atom,unsigned long * value)1079 char GetCardinalAtom(Window window, AtomType atom, unsigned long *value)
1080 {
1081
1082 unsigned long count;
1083 int status;
1084 unsigned long extra;
1085 Atom realType;
1086 int realFormat;
1087 unsigned char *data;
1088 char ret;
1089
1090 Assert(window != None);
1091 Assert(value);
1092
1093 count = 0;
1094 status = JXGetWindowProperty(display, window, atoms[atom], 0, 1, False,
1095 XA_CARDINAL, &realType, &realFormat,
1096 &count, &extra, &data);
1097 ret = 0;
1098 if(status == Success && realFormat != 0 && data) {
1099 if(JLIKELY(count == 1)) {
1100 *value = *(unsigned long*)data;
1101 ret = 1;
1102 }
1103 JXFree(data);
1104 }
1105
1106 return ret;
1107
1108 }
1109
1110 /** Set a cardinal atom. */
SetCardinalAtom(Window window,AtomType atom,unsigned long value)1111 void SetCardinalAtom(Window window, AtomType atom, unsigned long value)
1112 {
1113 Assert(window != None);
1114 JXChangeProperty(display, window, atoms[atom], XA_CARDINAL, 32,
1115 PropModeReplace, (unsigned char*)&value, 1);
1116 }
1117
1118 /** Read a window atom. */
GetWindowAtom(Window window,AtomType atom,Window * value)1119 char GetWindowAtom(Window window, AtomType atom, Window *value)
1120 {
1121
1122 unsigned long count;
1123 int status;
1124 unsigned long extra;
1125 Atom realType;
1126 int realFormat;
1127 unsigned char *data;
1128 char ret;
1129
1130 Assert(window != None);
1131 Assert(value);
1132
1133 count = 0;
1134 status = JXGetWindowProperty(display, window, atoms[atom], 0, 1, False,
1135 XA_WINDOW, &realType, &realFormat,
1136 &count, &extra, &data);
1137 ret = 0;
1138 if(status == Success && realFormat != 0 && data) {
1139 if(JLIKELY(count == 1)) {
1140 *value = *(Window*)data;
1141 ret = 1;
1142 }
1143 JXFree(data);
1144 }
1145
1146 return ret;
1147
1148 }
1149
1150 /** Set a window atom. */
SetWindowAtom(Window window,AtomType atom,unsigned long value)1151 void SetWindowAtom(Window window, AtomType atom, unsigned long value)
1152 {
1153 Assert(window != None);
1154 JXChangeProperty(display, window, atoms[atom], XA_WINDOW, 32,
1155 PropModeReplace, (unsigned char*)&value, 1);
1156 }
1157
1158 /** Set a pixmap atom. */
SetPixmapAtom(Window window,AtomType atom,Pixmap value)1159 void SetPixmapAtom(Window window, AtomType atom, Pixmap value)
1160 {
1161 Assert(window != None);
1162 JXChangeProperty(display, window, atoms[atom], XA_PIXMAP, 32,
1163 PropModeReplace, (unsigned char*)&value, 1);
1164 }
1165
1166 /** Set an atom atom. */
SetAtomAtom(Window window,AtomType atom,AtomType value)1167 void SetAtomAtom(Window window, AtomType atom, AtomType value)
1168 {
1169 Assert(window != None);
1170 JXChangeProperty(display, window, atoms[atom], XA_ATOM, 32,
1171 PropModeReplace, (unsigned char*)&atoms[value], 1);
1172 }
1173