1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 #include "Manager.h"
4 #include "Client.h"
5
6 #include <X11/Xutil.h>
7 #include <X11/keysym.h>
8
9 #if I18N
10 #include <X11/Xmu/Atoms.h>
11 #endif
12
13 // needed this to be able to use CARD32
14 #include <X11/Xmd.h>
15
16 const char *const Client::m_defaultLabel = "incognito";
17
18 implementList(EdgeRectList, EdgeRect);
19
20
Client(WindowManager * const wm,Window w,Boolean shaped)21 Client::Client(WindowManager *const wm, Window w, Boolean shaped) :
22 m_window(w),
23 m_transient(None),
24 m_groupParent(None),
25 m_border(0),
26 m_shaped(shaped),
27 m_revert(0),
28 m_wroot(None),
29 m_screen(0),
30 m_doSomething(False),
31 m_channel(0),
32 m_unmappedForChannel(False),
33 m_sticky(False),
34 m_skipFocus(False),
35 m_focusOnClick(False),
36 m_layer(NORMAL_LAYER),
37 m_type(NormalClient),
38 m_levelRaised(False),
39 m_speculating(False),
40 m_fixedSize(False),
41 m_movable(True),
42 m_minWidth(0),
43 m_minHeight(0),
44 m_state(WithdrawnState),
45 m_protocol(0),
46 m_managed(False),
47 m_reparenting(False),
48 m_stubborn(False),
49 m_lastPopTime(0L),
50 m_isFullHeight(False),
51 m_isFullWidth(False),
52 m_name(NULL),
53 m_iconName(NULL),
54 m_label(NULL),
55 m_colormap(None),
56 m_colormapWinCount(0),
57 m_colormapWindows(NULL),
58 m_windowColormaps(NULL),
59 m_windowManager(wm)
60 {
61 XWindowAttributes attr;
62 XGetWindowAttributes(display(), m_window, &attr);
63
64 m_x = attr.x;
65 m_y = attr.y;
66 m_w = attr.width;
67 m_h = attr.height;
68 m_bw = attr.border_width;
69 m_wroot = attr.root;
70 m_name = m_iconName = 0;
71 m_sizeHints.flags = 0L;
72
73 wm->setScreenFromRoot(m_wroot);
74 m_screen = wm->screen();
75
76 m_label = NewString(m_defaultLabel);
77 m_border = new Border(this, w);
78
79 m_channel = wm->channel();
80 m_unmappedForChannel = False;
81
82 fprintf(stderr, "new client at %d,%d %dx%d, window = %lx, name = \"%s\"\n",
83 m_x, m_y, m_w, m_h, m_window, m_label);
84
85 //#if CONFIG_MAD_FEEDBACK != 0
86 m_speculating = m_levelRaised = False;
87 //#endif
88
89 if (attr.map_state == IsViewable) manage(True);
90 else fprintf(stderr, "not managing this client; it is not viewable\n");
91
92 netwmUpdateChannel();
93
94 if (m_channel != wm->channel()) {
95 fprintf(stderr, "my channel for \"%s\" %d differs from wm channel %d, withdrawing\n", name(), (int)m_channel, (int)wm->channel());
96 if (isNormal()) {
97 if (activeClient() == this) {
98 wm->setActiveClient(0);
99 }
100 m_unmappedForChannel = True;
101 XUnmapWindow(display(), m_window);
102 withdraw(False);
103 }
104 }
105 }
106
107
~Client()108 Client::~Client()
109 {
110 delete m_border;
111 }
112
113
hasWindow(Window w)114 Boolean Client::hasWindow(Window w)
115 {
116 return ((m_window == w) || m_border->hasWindow(w));
117 }
118
119
root()120 Window Client::root()
121 {
122 return m_wroot;
123 }
124
125
screen()126 int Client::screen()
127 {
128 return m_screen;
129 }
130
release()131 void Client::release()
132 {
133 // assume wm called for this, and will remove me from its list itself
134
135 if (m_window == None) {
136 fprintf(stderr,
137 "wmx: invalid parent in Client::release (released twice?)\n");
138 }
139
140 windowManager()->skipInRevert(this, m_revert);
141
142 if (isHidden()) unhide(False);
143 windowManager()->removeFromOrderedList(this);
144
145 if (isActive()) {
146 if (CONFIG_CLICK_TO_FOCUS || isFocusOnClick()) {
147 if (m_revert) {
148 windowManager()->setActiveClient(m_revert);
149 m_revert->activate();
150 } else windowManager()->setActiveClient(0);
151 } else {
152 windowManager()->setActiveClient(0);
153 }
154 }
155
156 m_window = None;
157
158 if (m_colormapWinCount > 0) {
159 XFree((char *)m_colormapWindows);
160 free((char *)m_windowColormaps); // not allocated through X
161 }
162
163 if (m_iconName) XFree(m_iconName);
164 if (m_name) XFree(m_name);
165 if (m_label) free((void *)m_label);
166
167 delete this;
168 }
169
170
unreparent()171 void Client::unreparent()
172 {
173 XWindowChanges wc;
174
175 if (!isWithdrawn()) {
176 gravitate(True);
177 XReparentWindow(display(), m_window, root(), m_x, m_y);
178 }
179
180 wc.border_width = m_bw;
181 XConfigureWindow(display(), m_window, CWBorderWidth, &wc);
182
183 XSync(display(), True);
184 }
185
186
installColormap()187 void Client::installColormap()
188 {
189 Client *cc = 0;
190 int i, found;
191
192 if (m_colormapWinCount != 0) {
193
194 found = 0;
195
196 for (i = m_colormapWinCount - 1; i >= 0; --i) {
197 windowManager()->installColormap(m_windowColormaps[i]);
198 if (m_colormapWindows[i] == m_window) ++found;
199 }
200
201 if (found == 0) {
202 windowManager()->installColormap(m_colormap);
203 }
204
205 } else if (m_transient != None &&
206 (cc = windowManager()->windowToClient(m_transient))) {
207 if (cc)
208 cc->installColormap();
209 } else {
210 windowManager()->installColormap(m_colormap);
211 }
212 }
213
214
manage(Boolean mapped)215 void Client::manage(Boolean mapped)
216 {
217 static int lastX = 0, lastY = 0;
218 Boolean shouldHide, reshape;
219 XWMHints *hints;
220 Display *d = display();
221 long mSize;
222 int state;
223
224 XSelectInput(d, m_window, ColormapChangeMask | EnterWindowMask |
225 PropertyChangeMask | FocusChangeMask | KeyPressMask |
226 KeyReleaseMask); //!!!
227
228
229
230 if (CONFIG_USE_KEYBOARD) {
231
232 int i;
233 int keycode;
234
235 static KeySym keys[] = {
236 CONFIG_FLIP_UP_KEY, CONFIG_FLIP_DOWN_KEY, CONFIG_CIRCULATE_KEY,
237 CONFIG_HIDE_KEY, CONFIG_DESTROY_KEY, CONFIG_RAISE_KEY,
238 CONFIG_LOWER_KEY, CONFIG_FULLHEIGHT_KEY, CONFIG_NORMALHEIGHT_KEY,
239 CONFIG_FULLWIDTH_KEY, CONFIG_NORMALWIDTH_KEY,
240 CONFIG_MAXIMISE_KEY, CONFIG_UNMAXIMISE_KEY,
241 CONFIG_STICKY_KEY, CONFIG_DEBUG_KEY
242
243 #if CONFIG_WANT_KEYBOARD_MENU
244 , CONFIG_CLIENT_MENU_KEY, CONFIG_COMMAND_MENU_KEY
245 #endif
246 };
247
248 XGrabKey(display(), XKeysymToKeycode(display(), CONFIG_ALT_KEY),
249 0, m_window, True, GrabModeAsync, GrabModeAsync);
250
251 // for dragging windows from anywhere with Alt pressed
252 XGrabButton(display(), Button1,
253 m_windowManager->altModMask(), m_window, False, 0,
254 GrabModeAsync, GrabModeSync, None, None);
255
256 for (i = 0; i < (int)(sizeof(keys)/sizeof(keys[0])); ++i) {
257 keycode = XKeysymToKeycode(display(), keys[i]);
258 if (keycode) {
259 XGrabKey(display(), keycode,
260 m_windowManager->altModMask()|LockMask|Mod2Mask,
261 m_window, True,
262 GrabModeAsync, GrabModeAsync);
263 XGrabKey(display(), keycode,
264 m_windowManager->altModMask()|LockMask,
265 m_window, True,
266 GrabModeAsync, GrabModeAsync);
267 XGrabKey(display(), keycode,
268 m_windowManager->altModMask()|Mod2Mask,
269 m_window, True,
270 GrabModeAsync, GrabModeAsync);
271 XGrabKey(display(), keycode,
272 m_windowManager->altModMask(),
273 m_window, True,
274 GrabModeAsync, GrabModeAsync);
275 }
276 }
277
278 #if CONFIG_GROUPS != False
279 static KeySym numbers[] = {
280 XK_0, XK_1, XK_2, XK_3, XK_4, XK_5, XK_5,
281 XK_6, XK_7, XK_8, XK_9 };
282
283 for (i = 0; i < (int)(sizeof(numbers)/sizeof(numbers[0])); ++i) {
284 keycode = XKeysymToKeycode(display(), numbers[i]);
285 if (keycode) {
286 // someone please tell me there is a better way of
287 // doing this....
288
289 // both caps-lock and num-lock
290 XGrabKey(display(), keycode,
291 m_windowManager->altModMask()|CONFIG_GROUP_REMOVE_ALL|
292 LockMask|Mod2Mask,
293 m_window, True,
294 GrabModeAsync, GrabModeAsync);
295 XGrabKey(display(), keycode,
296 m_windowManager->altModMask()|CONFIG_GROUP_ADD|
297 LockMask|Mod2Mask,
298 m_window, True,
299 GrabModeAsync, GrabModeAsync);
300 XGrabKey(display(), keycode,
301 m_windowManager->altModMask()|LockMask|Mod2Mask,
302 m_window, True,
303 GrabModeAsync, GrabModeAsync);
304
305 // only caps-lock
306 XGrabKey(display(), keycode,
307 m_windowManager->altModMask()|CONFIG_GROUP_REMOVE_ALL|
308 LockMask,
309 m_window, True,
310 GrabModeAsync, GrabModeAsync);
311 XGrabKey(display(), keycode,
312 m_windowManager->altModMask()|CONFIG_GROUP_ADD|LockMask,
313 m_window, True,
314 GrabModeAsync, GrabModeAsync);
315 XGrabKey(display(), keycode,
316 m_windowManager->altModMask()|LockMask,
317 m_window, True,
318 GrabModeAsync, GrabModeAsync);
319 // only num-lock
320 XGrabKey(display(), keycode,
321 m_windowManager->altModMask()|CONFIG_GROUP_REMOVE_ALL|
322 Mod2Mask,
323 m_window, True,
324 GrabModeAsync, GrabModeAsync);
325 XGrabKey(display(), keycode,
326 m_windowManager->altModMask()|CONFIG_GROUP_ADD|Mod2Mask,
327 m_window, True,
328 GrabModeAsync, GrabModeAsync);
329 XGrabKey(display(), keycode,
330 m_windowManager->altModMask()|Mod2Mask,
331 m_window, True,
332 GrabModeAsync, GrabModeAsync);
333 // no locks
334 XGrabKey(display(), keycode,
335 m_windowManager->altModMask()|CONFIG_GROUP_REMOVE_ALL,
336 m_window, True,
337 GrabModeAsync, GrabModeAsync);
338 XGrabKey(display(), keycode,
339 m_windowManager->altModMask()|CONFIG_GROUP_ADD,
340 m_window, True,
341 GrabModeAsync, GrabModeAsync);
342 XGrabKey(display(), keycode,
343 m_windowManager->altModMask(),
344 m_window, True,
345 GrabModeAsync, GrabModeAsync);
346
347 }
348 }
349 #endif
350 keycode = XKeysymToKeycode(display(), CONFIG_QUICKRAISE_KEY);
351 if (keycode) {
352 XGrabKey(display(), keycode, AnyModifier, m_window, True,
353 GrabModeAsync, GrabModeAsync);
354 }
355
356 keycode = XKeysymToKeycode(display(), CONFIG_QUICKHIDE_KEY);
357 if (keycode) {
358 XGrabKey(display(), keycode, AnyModifier, m_window, True,
359 GrabModeAsync, GrabModeAsync);
360 }
361
362 keycode = XKeysymToKeycode(display(), CONFIG_QUICKHEIGHT_KEY);
363 if (keycode) {
364 XGrabKey(display(), keycode, AnyModifier, m_window, True,
365 GrabModeAsync, GrabModeAsync);
366 }
367
368 if (CONFIG_USE_CHANNEL_KEYS) {
369 for (i = 0; i < 12; ++i) {
370 keycode = XKeysymToKeycode(display(), XK_F1 + i);
371 if (keycode) {
372 XGrabKey(display(), keycode,
373 m_windowManager->altModMask(), m_window, True,
374 GrabModeAsync, GrabModeAsync);
375 }
376 }
377 }
378 }
379
380 m_iconName = getProperty(XA_WM_ICON_NAME);
381 m_name = getProperty(XA_WM_NAME);
382 setLabel();
383
384 getColormaps();
385 getProtocols();
386 getTransient();
387 getClientType();
388 getChannel();
389
390 fprintf(stderr, "managing client, name = \"%s\"\n", m_name);
391
392 hints = XGetWMHints(d, m_window);
393
394 #if CONFIG_USE_WINDOW_GROUPS != False
395 m_groupParent = hints ? hints->window_group : None;
396 if (m_groupParent == None) m_groupParent = m_window;
397 fprintf(stderr, "Client %p (%s) has window %lx and groupParent %lx\n",
398 this, m_name, m_window, m_groupParent);
399 #endif
400
401 if (!getState(&state)) {
402 state = hints ? hints->initial_state : NormalState;
403 }
404
405 shouldHide = (state == IconicState);
406 if (hints) XFree(hints);
407
408
409 if (XGetWMNormalHints(d, m_window, &m_sizeHints, &mSize) == 0 ||
410 m_sizeHints.flags == 0) {
411 m_sizeHints.flags = PSize;
412 }
413
414 m_fixedSize = False;
415 if ((m_sizeHints.flags & (PMinSize | PMaxSize)) == (PMinSize | PMaxSize) &&
416 (m_sizeHints.min_width == m_sizeHints.max_width &&
417 m_sizeHints.min_height == m_sizeHints.max_height)) m_fixedSize = True;
418
419 reshape = !mapped;
420
421 if (m_fixedSize) {
422 if ((m_sizeHints.flags & USPosition)) reshape = False;
423 if ((m_sizeHints.flags & PPosition) && shouldHide) reshape = False;
424 if ((m_transient != None)) reshape = False;
425 }
426
427 if ((m_sizeHints.flags & PBaseSize)) {
428 m_minWidth = m_sizeHints.base_width;
429 m_minHeight = m_sizeHints.base_height;
430 } else if ((m_sizeHints.flags & PMinSize)) {
431 m_minWidth = m_sizeHints.min_width;
432 m_minHeight = m_sizeHints.min_height;
433 } else if (!isBorderless()) {
434 m_minWidth = m_minHeight = 50;
435 } else {
436 m_minWidth = m_minHeight = 1;
437 }
438
439 // act
440
441 if (!isBorderless()) {
442
443 gravitate(False);
444
445 // zeros are iffy, should be calling some Manager method
446 int dw = DisplayWidth(display(), 0), dh = DisplayHeight(display(), 0);
447
448 if (m_w < m_minWidth) {
449 m_w = m_minWidth; m_fixedSize = False; reshape = True;
450 }
451 if (m_h < m_minHeight) {
452 m_h = m_minHeight; m_fixedSize = False; reshape = True;
453 }
454
455 if (m_w > dw - 8) m_w = dw - 8;
456 if (m_h > dh - 8) m_h = dh - 8;
457
458 if (!mapped && m_transient == None &&
459 !(m_sizeHints.flags & (PPosition | USPosition))) {
460
461 lastX += 60; lastY += 40;
462
463 if (lastX + m_w + m_border->xIndent() > dw) {
464 lastX = 0;
465 }
466 if (lastY + m_h + m_border->yIndent() > dh) {
467 lastY = 0;
468 }
469 m_x = lastX; m_y = lastY;
470 }
471
472 if (m_x > dw - m_border->xIndent()) {
473 m_x = dw - m_border->xIndent();
474 }
475
476 if (m_y > dh - m_border->yIndent()) {
477 m_y = dh - m_border->yIndent();
478 }
479
480 if (m_x < m_border->xIndent()) m_x = m_border->xIndent();
481 if (m_y < m_border->yIndent()) m_y = m_border->yIndent();
482
483 } else {
484 reshape = False;
485 }
486
487 m_border->configure(m_x, m_y, m_w, m_h, 0L, Above);
488
489 if (mapped) m_reparenting = True;
490 if (reshape && !m_fixedSize) XResizeWindow(d, m_window, m_w, m_h);
491 XSetWindowBorderWidth(d, m_window, 0);
492
493 m_border->reparent();
494
495 // (support for shaped windows absent)
496
497 XAddToSaveSet(d, m_window);
498 m_managed = True;
499
500 if (shouldHide) hide();
501 else {
502 XMapWindow(d, m_window);
503 m_border->map();
504 setState(NormalState);
505
506 if ((CONFIG_CLICK_TO_FOCUS || isFocusOnClick() ||
507 (m_transient != None && activeClient() &&
508 activeClient()->m_window == m_transient))) {
509 activate();
510 mapRaised();
511 } else {
512 deactivate();
513 }
514 }
515
516 if (activeClient() && !isActive()) {
517 activeClient()->installColormap();
518 }
519
520 if (CONFIG_AUTO_RAISE) {
521 m_windowManager->stopConsideringFocus();
522 focusIfAppropriate(False);
523 }
524
525 char *property = 0;
526 int length = 0;
527
528 if ((property = getProperty(Atoms::netwm_winState, XA_CARDINAL, length))) {
529 updateFromNetwmProperty(Atoms::netwm_winState, property[0]);
530 XFree(property);
531 }
532
533 if ((property = getProperty(Atoms::netwm_winHints, XA_CARDINAL, length))) {
534 updateFromNetwmProperty(Atoms::netwm_winHints, property[0]);
535 XFree(property);
536 }
537
538 m_windowManager->hoistToTop(this);
539
540 sendConfigureNotify(); // due to Martin Andrews
541 }
542
543
selectOnMotion(Window w,Boolean select)544 void Client::selectOnMotion(Window w, Boolean select)
545 {
546 if (!CONFIG_AUTO_RAISE) return;
547 if (!w || w == root()) return;
548
549 if (w == m_window || m_border->hasWindow(w)) {
550 XSelectInput(display(), m_window, // not "w"
551 ColormapChangeMask | EnterWindowMask |
552 PropertyChangeMask | FocusChangeMask |
553 (select ? PointerMotionMask : 0L));
554 } else {
555 XSelectInput(display(), w, select ? PointerMotionMask : 0L);
556 }
557 }
558
559
gotoClient()560 void Client::gotoClient()
561 {
562 if (isKilled()) {
563 fprintf(stderr, "Client[%p]::gotoClient: client is killed\n", this);
564 return;
565 }
566 if (m_channel != windowManager()->channel()) {
567 fprintf(stderr, "Client[%p]::gotoClient: going to channel %d\n", this, (int)m_channel);
568 windowManager()->gotoChannel(m_channel, 0);
569 }
570 if (isHidden()) {
571 fprintf(stderr, "Client[%p]::gotoClient: unhiding\n", this);
572 unhide(True);
573 } else {
574 fprintf(stderr, "Client[%p]::gotoClient: bringing to front\n", this);
575 if (CONFIG_CLICK_TO_FOCUS || isFocusOnClick()) activate();
576 else mapRaised();
577 ensureVisible();
578 }
579 }
580
decorate(Boolean active)581 void Client::decorate(Boolean active)
582 {
583 m_border->decorate(active, m_w, m_h);
584 }
585
586
activate()587 void Client::activate()
588 {
589 fprintf(stderr, "Client::activate (this = %p, window = %p, parent = %p)\n",
590 this, (void *)m_window, (void *)parent());
591
592 if(isNonFocusable())
593 return;
594
595 if (parent() == root()) {
596 fprintf(stderr, "wmx: warning: bad parent in Client::activate\n");
597 return;
598 }
599
600 if (!m_managed || isHidden() || isWithdrawn() ||
601 (m_channel != windowManager()->channel())) return;
602
603 if (isActive()) {
604 decorate(True);
605 if (CONFIG_AUTO_RAISE || CONFIG_RAISE_ON_FOCUS) mapRaised();
606 return;
607 }
608 /*!!!
609 if (activeClient()) {
610 activeClient()->deactivate();
611 // & some other-screen business
612 }
613 */
614 Client *previouslyActive = windowManager()->activeClient();
615
616 windowManager()->setActiveClient(this); // deactivates any other
617
618 XUngrabButton(display(), AnyButton, AnyModifier, parent());
619
620 XSetInputFocus(display(), m_window, RevertToPointerRoot,
621 windowManager()->timestamp(False));
622
623 if (m_protocol & PtakeFocus) {
624 sendMessage(Atoms::wm_protocols, Atoms::wm_takeFocus);
625 }
626
627 // now set revert of window that reverts to this one so as to
628 // revert to the window this one used to revert to (huh?)
629
630 windowManager()->skipInRevert(this, m_revert);
631
632 if (previouslyActive && previouslyActive != this) {
633 m_revert = previouslyActive;
634 while (m_revert && !m_revert->isNormal()) {
635 m_revert = m_revert->revertTo();
636 }
637 }
638
639 //!!! windowManager()->setActiveClient(this);
640 decorate(True);
641
642 installColormap(); // new!
643 }
644
645
deactivate()646 void Client::deactivate() // called from wm?
647 {
648 if (parent() == root()) {
649 fprintf(stderr, "wmx: warning: bad parent in Client::deactivate\n");
650 return;
651 }
652
653 XGrabButton(display(), AnyButton, AnyModifier, parent(), False,
654 ButtonPressMask | ButtonReleaseMask,
655 GrabModeSync, GrabModeSync, None, None);
656
657 decorate(False);
658 }
659
setSticky(Boolean sticky)660 void Client::setSticky(Boolean sticky)
661 {
662 m_sticky = sticky;
663 setNetwmProperty(Atoms::netwm_winState, WIN_STATE_STICKY, sticky);
664 }
665
setMovable(Boolean movable)666 void Client::setMovable(Boolean movable)
667 {
668 setNetwmProperty(Atoms::netwm_winState, WIN_STATE_FIXED_POSITION, !movable);
669 m_movable = movable;
670 }
671
setSkipFocus(Boolean skipFocus)672 void Client::setSkipFocus(Boolean skipFocus)
673 {
674 setNetwmProperty(Atoms::netwm_winHints, WIN_HINTS_SKIP_FOCUS, skipFocus);
675 m_skipFocus = skipFocus;
676 fprintf(stderr, "Setting \"%s\" to %sskip focus\n", name(), skipFocus?"":"not ");
677 }
678
setFocusOnClick(Boolean focusOnClick)679 void Client::setFocusOnClick(Boolean focusOnClick)
680 {
681 setNetwmProperty(Atoms::netwm_winHints, WIN_HINTS_FOCUS_ON_CLICK, focusOnClick);
682 m_focusOnClick = focusOnClick;
683 }
684
setNetwmProperty(Atom property,unsigned char state,Boolean to)685 void Client::setNetwmProperty(Atom property, unsigned char state, Boolean to) {
686
687
688 fprintf(stderr, "wmx: Client::setNetwmProperty needs rewriting\n");
689
690 /*
691
692 //!!! out of date, + use getProperty
693 Atom returnType;
694 int returnFormat;
695 unsigned long count;
696 unsigned long bytes_remain;
697 unsigned char *prop;
698 if(XGetWindowProperty(display(), window(), property, 0, 1,
699 False, XA_CARDINAL, &returnType, &returnFormat,
700 &count, &bytes_remain, &prop) == Success) {
701 if (returnType == XA_CARDINAL && returnFormat == 32 && count == 1) {
702 unsigned char oldProp = *prop;
703 if(to)
704 *prop |= state;
705 else
706 *prop &= !state;
707
708 if(*prop != oldProp) // Why bother if it's still the same?
709 XChangeProperty(display(), window(), property,
710 XA_CARDINAL, 32, PropModeReplace, prop, count);
711 }
712 if (prop) XFree(prop);
713 }
714 */
715 }
716
setLayer(int newLayer)717 void Client::setLayer(int newLayer)
718 {
719 if (newLayer < 0)
720 newLayer = 0;
721 else if (newLayer > MAX_LAYER)
722 newLayer = MAX_LAYER;
723
724 if (newLayer == m_layer) {
725 return;
726 }
727
728 windowManager()->removeFromOrderedList(this);
729 m_layer = newLayer;
730 windowManager()->hoistToTop(this); // Puts this client at the top of the
731 // list for its layer.
732 windowManager()->updateStackingOrder();
733
734 fprintf(stderr, "wmx: Moving client \"%s\" to layer %d\n", name(), m_layer);
735 }
736
sendMessage(Atom a,long l)737 void Client::sendMessage(Atom a, long l)
738 {
739 XEvent ev;
740 int status;
741 long mask;
742
743 memset(&ev, 0, sizeof(ev));
744 ev.xclient.type = ClientMessage;
745 ev.xclient.window = m_window;
746 ev.xclient.message_type = a;
747 ev.xclient.format = 32;
748 ev.xclient.data.l[0] = l;
749 ev.xclient.data.l[1] = windowManager()->timestamp(False);
750 mask = 0L;
751 status = XSendEvent(display(), m_window, False, mask, &ev);
752
753 if (status == 0) {
754 fprintf(stderr, "wmx: warning: Client::sendMessage failed\n");
755 }
756 }
757
758
getProperty_aux(Display * d,Window w,Atom a,Atom type,long len,unsigned char ** p)759 static int getProperty_aux(Display *d, Window w, Atom a, Atom type, long len,
760 unsigned char **p)
761 {
762 Atom realType;
763 int format;
764 unsigned long n, extra;
765 int status;
766 Boolean retried = False;
767
768 tryagain:
769 status = XGetWindowProperty(d, w, a, 0L, len, False, type, &realType,
770 &format, &n, &extra, p);
771
772 // fprintf(stderr, "XGetWindowProperty: len = %ld, return count = %lu, format = %d, pointer = %p\n",
773 // len, n, format, *p);
774
775 if (status != Success || *p == 0) return -1;
776 if (n == 0) {
777 XFree((void *) *p);
778 *p = 0;
779 return n;
780 }
781 if (type == XA_STRING || type == AnyPropertyType || retried) {
782 if (realType != XA_STRING || format != 8) {
783 fprintf(stderr, "string property for window %lx is not an 8-bit string\n", w);
784 }
785 // XA_STRING is needed by a caller. But XGetWindowProperty()
786 // returns other typed data. So try to convert them.
787 XTextProperty textprop;
788 textprop.value = *p;
789 textprop.encoding = realType;
790 textprop.format = format;
791 textprop.nitems = n;
792
793 char **list;
794 int num, cnt;
795 cnt = XmbTextPropertyToTextList(d, &textprop, &list, &num);
796 if (cnt > Success) {
797 fprintf(stderr, "wmx: WARNING: Failed to convert text property using Xmb method, trying again using Xutf8\n");
798 XFreeStringList(list);
799 cnt = Xutf8TextPropertyToTextList(d, &textprop, &list, &num);
800 }
801 unsigned char *string;
802 if (cnt == Success && num > 0 && *list) {
803 string = (unsigned char*)NewString(*list);
804 XFreeStringList(list);
805 n = num;
806 } else if (cnt > Success) {
807 fprintf(stderr, "Something wrong, cannot convert "
808 "text property\n"
809 " original type %ld, string %s\n"
810 " converted string %s\n"
811 " decide to use original value as STRING\n",
812 textprop.encoding, textprop.value, *list);
813 string = (unsigned char*)NewString(*(char**)p);
814 XFreeStringList(list);
815 n = n;
816 } else if (!retried) {
817 retried = True;
818 type = AnyPropertyType;
819 goto tryagain;
820 } else {
821 string = NULL;
822 n = 0;
823 }
824 if (*p) XFree((void *) *p);
825 *p = string;
826 }
827
828 return n;
829 }
830
831
getProperty(Atom a)832 char *Client::getProperty(Atom a)
833 {
834 unsigned char *p;
835
836 // no -- allow any type, not just string -- SGI has "compound
837 // text", and part-garbage is possibly better than "incognito" --
838 // thanks to Bill Spitzak
839
840 // if (getProperty_aux(display(), m_window, a, XA_STRING, 100L, &p) <= 0) {
841 if (getProperty_aux(display(), m_window, a, AnyPropertyType, 100L, &p) <= 0) {
842 return NULL;
843 }
844 return (char *)p;
845 }
846
getProperty(Atom a,Atom type,int & length)847 char *Client::getProperty(Atom a, Atom type, int &length)
848 {
849 unsigned char *p;
850
851 if ((length = getProperty_aux(display(), m_window, a, type, 100L, &p))
852 <= 0) {
853 return NULL;
854 }
855
856 return (char *)p;
857 }
858
setState(int state)859 void Client::setState(int state)
860 {
861 m_state = state;
862
863 CARD32 data[2];
864 data[0] = (CARD32)state;
865 data[1] = (CARD32)None;
866
867 XChangeProperty(display(), m_window, Atoms::wm_state, Atoms::wm_state,
868 32, PropModeReplace, (unsigned char *)data, 2);
869 }
870
871
getState(int * state)872 Boolean Client::getState(int *state)
873 {
874 CARD32 *p = 0;
875
876 if (getProperty_aux(display(), m_window, Atoms::wm_state, Atoms::wm_state,
877 2L, (unsigned char **)&p) <= 0) {
878 return False;
879 }
880
881 *state = (int) *p;
882 XFree((char *)p);
883 return True;
884 }
885
886
getProtocols()887 void Client::getProtocols()
888 {
889 long n;
890 Atom *p;
891
892 m_protocol = 0;
893 if ((n = getProperty_aux(display(), m_window, Atoms::wm_protocols, XA_ATOM,
894 20L, (unsigned char **)&p)) <= 0) {
895 return;
896 }
897
898 for (int i = 0; i < n; ++i) {
899 if (p[i] == Atoms::wm_delete) {
900 m_protocol |= Pdelete;
901 } else if (p[i] == Atoms::wm_takeFocus) {
902 m_protocol |= PtakeFocus;
903 }
904 }
905
906 XFree((char *) p);
907 }
908
909
gravitate(Boolean invert)910 void Client::gravitate(Boolean invert)
911 {
912 int gravity;
913 int w = 0, h = 0, xdelta, ydelta;
914
915 // possibly shouldn't work if we haven't been managed yet?
916
917 gravity = NorthWestGravity;
918 if (m_sizeHints.flags & PWinGravity) gravity = m_sizeHints.win_gravity;
919
920 xdelta = m_bw - m_border->xIndent();
921 ydelta = m_bw - m_border->yIndent();
922
923 // note that right and bottom borders have indents of 1
924
925 switch (gravity) {
926
927 case NorthWestGravity:
928 break;
929
930 case NorthGravity:
931 w = xdelta;
932 break;
933
934 case NorthEastGravity:
935 w = xdelta + m_bw-1;
936 break;
937
938 case WestGravity:
939 h = ydelta;
940 break;
941
942 case CenterGravity:
943 case StaticGravity:
944 w = xdelta;
945 h = ydelta;
946 break;
947
948 case EastGravity:
949 w = xdelta + m_bw-1;
950 h = ydelta;
951 break;
952
953 case SouthWestGravity:
954 h = ydelta + m_bw-1;
955 break;
956
957 case SouthGravity:
958 w = xdelta;
959 h = ydelta + m_bw-1;
960 break;
961
962 case SouthEastGravity:
963 w = xdelta + m_bw-1;
964 h = ydelta + m_bw-1;
965 break;
966
967 default:
968 fprintf(stderr, "wmx: bad window gravity %d for window 0x%lx\n",
969 gravity, m_window);
970 return;
971 }
972
973 w += m_border->xIndent();
974 h += m_border->yIndent();
975
976 if (invert) { w = -w; h = -h; }
977
978 m_x += w;
979 m_y += h;
980 }
981
982
setLabel(void)983 Boolean Client::setLabel(void)
984 {
985 const char *newLabel;
986
987 if (m_name) newLabel = m_name;
988 else if (m_iconName) newLabel = m_iconName;
989 else newLabel = m_defaultLabel;
990
991 if (!m_label) {
992
993 m_label = NewString(newLabel);
994 return True;
995
996 } else if (strcmp(m_label, newLabel)) {
997
998 free((void *)m_label);
999 m_label = NewString(newLabel);
1000 return True;
1001
1002 } else return True;//False;// dammit!
1003 }
1004
1005
getColormaps(void)1006 void Client::getColormaps(void)
1007 {
1008 int i, n;
1009 Window *cw;
1010 XWindowAttributes attr;
1011
1012 if (!m_managed) {
1013 XGetWindowAttributes(display(), m_window, &attr);
1014 m_colormap = attr.colormap;
1015 }
1016
1017 n = getProperty_aux(display(), m_window, Atoms::wm_colormaps, XA_WINDOW,
1018 100L, (unsigned char **)&cw);
1019
1020 if (m_colormapWinCount != 0) {
1021 XFree((char *)m_colormapWindows);
1022 free((char *)m_windowColormaps);
1023 }
1024
1025 if (n <= 0) {
1026 m_colormapWinCount = 0;
1027 return;
1028 }
1029
1030 m_colormapWinCount = n;
1031 m_colormapWindows = cw;
1032
1033 m_windowColormaps = (Colormap *)malloc(n * sizeof(Colormap));
1034
1035 for (i = 0; i < n; ++i) {
1036 if (cw[i] == m_window) {
1037 m_windowColormaps[i] = m_colormap;
1038 } else {
1039 XSelectInput(display(), cw[i], ColormapChangeMask);
1040 XGetWindowAttributes(display(), cw[i], &attr);
1041 m_windowColormaps[i] = attr.colormap;
1042 }
1043 }
1044 }
1045
1046
getClientType()1047 void Client::getClientType()
1048 {
1049 m_type = NormalClient;
1050
1051 if (m_transient != None) m_type = DialogClient;
1052
1053 // fprintf(stderr, "trying to get client type...\n");
1054
1055 int count = 0;
1056 char *property = getProperty(Atoms::netwm_winType, XA_ATOM, count);
1057
1058 if (property) {
1059
1060 // fprintf(stderr, "got property, count = %d\n", count);
1061
1062 for (int i = 0; i < count; ++i) {
1063
1064 Atom typeAtom = ((Atom *)property)[i];
1065
1066 char *name = XGetAtomName(display(), typeAtom);
1067
1068 fprintf(stderr, "window type property item %d is \"%s\"\n",
1069 i, name);
1070
1071 if (name) XFree(name);
1072
1073 if (typeAtom == Atoms::netwm_winType_desktop) {
1074 m_type = DesktopClient;
1075 m_layer = DESKTOP_LAYER;
1076 setSticky(True);
1077 break;
1078 } else if (typeAtom == Atoms::netwm_winType_dock) {
1079 m_type = DockClient;
1080 m_layer = DOCK_LAYER;
1081 setSticky(True);
1082 break;
1083 } else if (typeAtom == Atoms::netwm_winType_toolbar) {
1084 m_type = ToolbarClient;
1085 m_layer = TOOLBAR_LAYER;
1086 break;
1087 } else if (typeAtom == Atoms::netwm_winType_menu) {
1088 m_type = MenuClient;
1089 m_layer = TOOLBAR_LAYER;
1090 break;
1091 } else if (typeAtom == Atoms::netwm_winType_utility) {
1092 m_type = UtilityClient;
1093 m_layer = UTILITY_LAYER;
1094 break;
1095 } else if (typeAtom == Atoms::netwm_winType_dialog) {
1096 m_type = DialogClient;
1097 m_layer = DIALOG_LAYER;
1098 break;
1099 } else if (typeAtom == Atoms::netwm_winType_notify) {
1100 m_type = NotifyClient;
1101 m_layer = DOCK_LAYER;
1102 break;
1103 } else if (typeAtom == Atoms::netwm_winType_normal) {
1104 m_type = NormalClient;
1105 break;
1106 }
1107 }
1108
1109 XFree(property);
1110 }
1111
1112 fprintf(stderr, "client window type = %d\n", (int)m_type);
1113 }
1114
1115
getChannel()1116 void Client::getChannel()
1117 {
1118 int count = 0;
1119 char *property = getProperty(Atoms::netwm_winDesktop, XA_CARDINAL, count);
1120
1121 if (property && count > 0) {
1122 m_channel = ((CARD32 *)property)[0] + 1; // netwm counts from 0
1123 if (m_channel < 1) m_channel = 1;
1124 m_windowManager->ensureChannelExists(m_channel);
1125 fprintf(stderr, "channel = %d\n", m_channel);
1126 XFree(property);
1127 }
1128 }
1129
1130
getTransient()1131 void Client::getTransient()
1132 {
1133 Window t = None;
1134
1135 if (XGetTransientForHint(display(), m_window, &t) != 0) {
1136
1137 if (windowManager()->windowToClient(t) == this) {
1138 fprintf(stderr,
1139 "wmx: warning: client \"%s\" thinks it's a transient "
1140 "for\nitself -- ignoring WM_TRANSIENT_FOR property...\n",
1141 m_label ? m_label : "(no name)");
1142 m_transient = None;
1143 } else {
1144 m_transient = t;
1145 }
1146 } else {
1147 m_transient = None;
1148 }
1149 }
1150
1151
hide()1152 void Client::hide()
1153 {
1154 if (isHidden()) {
1155 fprintf(stderr, "wmx: Client already hidden in Client::hide\n");
1156 return;
1157 }
1158
1159 m_border->unmap();
1160 XUnmapWindow(display(), m_window);
1161
1162 if (isActive()) windowManager()->clearFocus();
1163
1164 setState(IconicState);
1165 windowManager()->addToHiddenList(this);
1166
1167 #if CONFIG_USE_WINDOW_GROUPS != False
1168 if (isGroupParent()) {
1169 windowManager()->hideGroup(groupParent(), this);
1170 }
1171 #endif
1172 }
1173
1174
unhide(Boolean map)1175 void Client::unhide(Boolean map)
1176 {
1177 if (CONFIG_MAD_FEEDBACK) {
1178 m_speculating = False;
1179 if (!isHidden()) return;
1180 }
1181
1182 if (!isHidden()) {
1183 fprintf(stderr, "wmx: Client not hidden in Client::unhide\n");
1184 return;
1185 }
1186
1187 windowManager()->removeFromHiddenList(this);
1188
1189 if (map) {
1190 setState(NormalState);
1191
1192 if (m_channel == windowManager()->channel()) {
1193 XMapWindow(display(), m_window);
1194 }
1195 mapRaised();
1196
1197 if (CONFIG_AUTO_RAISE) focusIfAppropriate(False);
1198 else if (CONFIG_CLICK_TO_FOCUS || isFocusOnClick()) activate();
1199 }
1200
1201 #if CONFIG_USE_WINDOW_GROUPS != False
1202 if (isGroupParent()) {
1203 windowManager()->unhideGroup(groupParent(), this, map);
1204 }
1205 #endif
1206 }
1207
1208
sendConfigureNotify()1209 void Client::sendConfigureNotify()
1210 {
1211 XConfigureEvent ce;
1212
1213 ce.type = ConfigureNotify;
1214 ce.event = m_window;
1215 ce.window = m_window;
1216
1217 ce.x = m_x;
1218 ce.y = m_y;
1219 ce.width = m_w;
1220 ce.height = m_h;
1221 ce.border_width = m_bw;
1222 ce.above = None;
1223 ce.override_redirect = 0;
1224
1225 XSendEvent(display(), m_window, False, StructureNotifyMask, (XEvent*)&ce);
1226 }
1227
1228
withdraw(Boolean changeState)1229 void Client::withdraw(Boolean changeState)
1230 {
1231 fprintf(stderr, "withdraw: changeState = %d\n", (int)changeState);
1232 m_border->unmap();
1233
1234 gravitate(True);
1235 XReparentWindow(display(), m_window, root(), m_x, m_y);
1236
1237 gravitate(False);
1238
1239 if (changeState) {
1240 XRemoveFromSaveSet(display(), m_window);
1241 setState(WithdrawnState);
1242 }
1243
1244 #if CONFIG_USE_WINDOW_GROUPS != False
1245 if (isGroupParent()) {
1246 windowManager()->withdrawGroup(groupParent(), this, changeState);
1247 }
1248 #endif
1249
1250 ignoreBadWindowErrors = True;
1251 XSync(display(), False);
1252 ignoreBadWindowErrors = False;
1253
1254 // m_reparenting = False;
1255 }
1256
1257
unwithdraw()1258 void Client::unwithdraw()
1259 {
1260 if (!m_managed) {
1261 if (!m_reparenting) {
1262 manage(True);
1263 }
1264 return;
1265 }
1266
1267 fprintf(stderr, "unwithdraw: reparenting\n");
1268
1269 m_reparenting = true;
1270 m_border->reparent();
1271 // XMapWindow(display(), m_window);
1272 m_border->map();
1273 setState(NormalState);
1274 }
1275
rename()1276 void Client::rename()
1277 {
1278 m_border->configure(0, 0, m_w, m_h, CWWidth | CWHeight, Above);
1279 m_border->expose(0);
1280 }
1281
1282
mapRaised()1283 void Client::mapRaised()
1284 {
1285 if (m_channel == windowManager()->channel()) m_border->map/*Raised*/();
1286 windowManager()->hoistToTop(this);
1287 windowManager()->raiseTransients(this);
1288 windowManager()->updateStackingOrder();
1289 }
1290
1291
kill()1292 void Client::kill()
1293 {
1294 if (m_protocol & Pdelete) {
1295 sendMessage(Atoms::wm_protocols, Atoms::wm_delete);
1296 } else {
1297 XKillClient(display(), m_window);
1298 }
1299
1300 #if CONFIG_USE_WINDOW_GROUPS != False
1301 if (isGroupParent()) {
1302 windowManager()->killGroup(groupParent(), this);
1303 }
1304 #endif
1305 }
1306
1307
ensureVisible()1308 void Client::ensureVisible()
1309 {
1310 int mx = DisplayWidth(display(), 0) - 1; // hack
1311 int my = DisplayHeight(display(), 0) - 1;
1312 int px = m_x;
1313 int py = m_y;
1314
1315 if (m_x + m_w > mx) m_x = mx - m_w;
1316 if (m_y + m_h > my) m_y = my - m_h;
1317 if (m_x < 0) m_x = 0;
1318 if (m_y < 0) m_y = 0;
1319
1320 if (m_x != px || m_y != py) {
1321 m_border->moveTo(m_x, m_y);
1322 sendConfigureNotify();
1323 }
1324 }
1325
1326
lower()1327 void Client::lower()
1328 {
1329 //m_border->lower();
1330 windowManager()->hoistToBottom(this);
1331 windowManager()->updateStackingOrder();
1332 }
1333
1334
raiseOrLower()1335 void Client::raiseOrLower()
1336 {
1337 if (windowManager()->isTop(this)) {
1338 lower();
1339 } else {
1340 mapRaised();
1341 //windowManager()->updateStackingOrder();
1342 }
1343 }
1344
1345
maximise(int max)1346 void Client::maximise(int max)
1347 {
1348 enum {Vertical, Maximum, Horizontal};
1349
1350 if (max != Vertical && max != Horizontal && max != Maximum)
1351 return;
1352
1353 if (m_fixedSize || (m_transient != None))
1354 return;
1355
1356 if (CONFIG_SAME_KEY_MAX_UNMAX) {
1357 if (m_isFullHeight && m_isFullWidth) {
1358 unmaximise(max);
1359 return;
1360 } else if (m_isFullHeight && max == Vertical) {
1361 unmaximise(max);
1362 return;
1363 } else if (m_isFullWidth && max == Horizontal) {
1364 unmaximise(max);
1365 return;
1366 }
1367 } else if ((m_isFullHeight && max == Vertical)
1368 || (m_isFullHeight && m_isFullWidth && max == Maximum)
1369 || (m_isFullWidth && max == Horizontal))
1370 return;
1371
1372 int w = (max == Horizontal || (max == Maximum && !m_isFullWidth));
1373 int h = (max == Vertical || (max == Maximum && !m_isFullHeight));
1374
1375 if (h) {
1376 m_normalH = m_h;
1377 m_normalY = m_y;
1378 m_h = DisplayHeight(display(), windowManager()->screen())
1379 - m_border->yIndent() - 1;
1380
1381 }
1382 if (w) {
1383 m_normalW = m_w;
1384 m_normalX = m_x;
1385 m_w = DisplayWidth(display(), windowManager()->screen())
1386 - m_border->xIndent() - 1;
1387 }
1388
1389 int dw, dh;
1390
1391 fixResizeDimensions(m_w, m_h, dw, dh);
1392
1393 if (h) {
1394 if (m_h > m_normalH) {
1395 m_y -= (m_h - m_normalH);
1396 if (m_y < m_border->yIndent()) m_y = m_border->yIndent();
1397 }
1398 m_isFullHeight = True;
1399 }
1400
1401 if (w) {
1402 if (m_w > m_normalW) {
1403 m_x -= (m_w - m_normalW);
1404 if (m_x < m_border->xIndent()) m_x = m_border->xIndent();
1405 }
1406 m_isFullWidth = True;
1407 }
1408
1409 unsigned long mask;
1410
1411 if (h & w)
1412 mask = CWY | CWX | CWHeight | CWWidth;
1413 else if (h)
1414 mask = CWY | CWHeight;
1415 else
1416 mask = CWX | CWWidth;
1417
1418 m_border->configure(m_x, m_y, m_w, m_h, mask, 0, True);
1419
1420 XResizeWindow(display(), m_window, m_w, m_h);
1421 sendConfigureNotify();
1422 if(max==Vertical || max==Maximum)
1423 setNetwmProperty(Atoms::netwm_winState, WIN_STATE_MAXIMIZED_VERT,
1424 m_isFullHeight);
1425 if(max==Horizontal || max==Maximum)
1426 setNetwmProperty(Atoms::netwm_winState,WIN_STATE_MAXIMIZED_HORIZ,
1427 m_isFullWidth);
1428 }
1429
1430
unmaximise(int max)1431 void Client::unmaximise(int max)
1432 {
1433 enum {Vertical, Maximum, Horizontal};
1434
1435 if (max != Vertical && max != Horizontal && max != Maximum)
1436 return;
1437
1438 if ((!m_isFullHeight && max == Vertical)
1439 || (!m_isFullWidth && max == Horizontal)
1440 || (!(m_isFullHeight && m_isFullWidth) && max == Maximum))
1441 return;
1442
1443 int w = (max == Horizontal || (max == Maximum && m_isFullWidth));
1444 int h = (max == Vertical || (max == Maximum && m_isFullHeight));
1445
1446 if (h) {
1447 m_h = m_normalH;
1448 m_y = m_normalY;
1449 m_isFullHeight = False;
1450 }
1451 if (w) {
1452 m_w = m_normalW;
1453 m_x = m_normalX;
1454 m_isFullWidth = False;
1455 }
1456
1457 unsigned long mask;
1458
1459 if (h & w)
1460 mask = CWY | CWX | CWHeight | CWWidth;
1461 else if (h)
1462 mask = CWY | CWHeight;
1463 else
1464 mask = CWX | CWWidth;
1465
1466 m_border->configure(m_x, m_y, m_w, m_h, mask, 0, True);
1467
1468 XResizeWindow(display(), m_window, m_w, m_h);
1469 sendConfigureNotify();
1470 if(max==Vertical || max==Maximum)
1471 setNetwmProperty(Atoms::netwm_winState, WIN_STATE_MAXIMIZED_VERT,
1472 m_isFullHeight);
1473 if(max==Horizontal || max==Maximum)
1474 setNetwmProperty(Atoms::netwm_winState, WIN_STATE_MAXIMIZED_HORIZ,
1475 m_isFullWidth);
1476 }
1477
1478
warpPointer()1479 void Client::warpPointer()
1480 {
1481 XWarpPointer(display(), None, parent(), 0, 0, 0, 0,
1482 m_border->xIndent() / 2, m_border->xIndent() + 8);
1483 }
1484
1485
flipChannel(Boolean leaving,int newChannel)1486 void Client::flipChannel(Boolean leaving, int newChannel)
1487 {
1488 fprintf(stderr, "Client[%p]::flipChannel(leaving = %d, newChannel = %d, my channel = %d)\n", this, (int)leaving, newChannel, m_channel);
1489
1490 if (m_channel != windowManager()->channel()) {
1491
1492 if (CONFIG_MAD_FEEDBACK) {
1493 if (leaving && m_channel == newChannel &&
1494 m_unmappedForChannel) {
1495 showFeedback();
1496 }
1497 }
1498
1499 return;
1500 }
1501
1502 if (leaving) {
1503
1504 if (CONFIG_MAD_FEEDBACK) {
1505 removeFeedback(isNormal()); // mostly it won't be there anyway, but...
1506 }
1507
1508 if (!isNormal()) return;
1509 if (activeClient() == this) {
1510 windowManager()->setActiveClient(0);
1511 }
1512 m_unmappedForChannel = True;
1513 XUnmapWindow(display(), m_window);
1514 withdraw(False);
1515 return;
1516
1517 } else {
1518
1519 if (CONFIG_MAD_FEEDBACK) {
1520 removeFeedback(isNormal()); // likewise
1521 }
1522
1523 if (!m_unmappedForChannel) {
1524 if (isNormal()) mapRaised();
1525 return;
1526 }
1527
1528 m_unmappedForChannel = False;
1529
1530 setState(WithdrawnState);
1531 m_border->reparent();
1532 if (CONFIG_AUTO_RAISE) m_windowManager->stopConsideringFocus();
1533 XAddToSaveSet(display(), m_window);
1534 XMapWindow(display(), m_window);
1535 setState(NormalState);
1536 mapRaised();
1537 if (CONFIG_CLICK_TO_FOCUS || isFocusOnClick()) activate();
1538 }
1539 }
1540
1541
showFeedback()1542 void Client::showFeedback()
1543 {
1544 if (CONFIG_MAD_FEEDBACK) {
1545 if (m_speculating || m_levelRaised) removeFeedback(False);
1546 m_border->showFeedback(m_x, m_y, m_w, m_h);
1547 // XSync(display(), False);
1548 }
1549 }
1550
raiseFeedbackLevel()1551 void Client::raiseFeedbackLevel()
1552 {
1553 if (CONFIG_MAD_FEEDBACK) {
1554
1555 m_border->removeFeedback();
1556 m_levelRaised = True;
1557
1558 if (isNormal()) {
1559 mapRaised();
1560 } else if (isHidden()) {
1561 unhide(True);
1562 m_speculating = True;
1563 // XSync(display(), False);
1564 }
1565 }
1566 }
1567
removeFeedback(Boolean mapped)1568 void Client::removeFeedback(Boolean mapped)
1569 {
1570 if (CONFIG_MAD_FEEDBACK) {
1571
1572 m_border->removeFeedback();
1573
1574 if (m_levelRaised) {
1575 if (m_speculating) {
1576 if (!mapped) hide();
1577 XSync(display(), False);
1578 } else {
1579 // not much we can do
1580 }
1581 }
1582
1583 m_speculating = m_levelRaised = False;
1584 }
1585 }
1586
updateFromNetwmProperty(Atom property,unsigned char state)1587 void Client::updateFromNetwmProperty(Atom property, unsigned char state) {
1588
1589 //!!! out of date
1590
1591 fprintf(stderr, "Client(\"%s\")::updateFromNetwmProperty(\"%s\", %d)\n",
1592 name(),
1593 XGetAtomName(display(), property),
1594 (int)state);
1595
1596 return;//!!!
1597
1598 enum {Vertical, Maximum, Horizontal};
1599
1600 if(property == Atoms::netwm_winState) {
1601
1602 if(state & WIN_STATE_STICKY) {
1603 if (!isSticky())
1604 setSticky(True);
1605 } else {
1606 if (isSticky())
1607 setSticky(False);
1608 }
1609
1610 if(state & WIN_STATE_MAXIMIZED_VERT) {
1611 // Does this mean 'This is my maximum size' or 'maximise me'?
1612 // I'm presuming the latter - from the spec:
1613 // "the bits set mean that state/property is *desired* by the client"
1614 if(!m_isFullHeight)
1615 maximise(Vertical);
1616 } else {
1617 if(m_isFullHeight);
1618 unmaximise(Vertical);
1619 }
1620
1621 if(state & WIN_STATE_MAXIMIZED_HORIZ) {
1622 // Does this mean 'This is my maximum size' or 'maximise me'?
1623 // I'm presuming the latter - see above.
1624 if(!m_isFullWidth)
1625 maximise(Horizontal);
1626 } else {
1627 if(m_isFullWidth)
1628 unmaximise(Horizontal);
1629 }
1630
1631 if(state & WIN_STATE_FIXED_POSITION) {
1632 if(isMovable())
1633 setMovable(False);
1634 } else {
1635 if(!isMovable())
1636 setMovable(True);
1637 }
1638
1639 /* We ignore:
1640 WIN_STATE_MINIMIZED // Reserved - definition is unclear
1641 WIN_STATE_HIDDEN // not on taskbar but window visible
1642 WIN_STATE_SHADED // shaded (MacOS / Afterstep style)
1643 WIN_STATE_HID_WORKSPACE // not on current desktop
1644 WIN_STATE_HID_TRANSIENT // owner of transient is hidden
1645 WIN_STATE_ARRANGE_IGNORE // ignore for auto arranging
1646 */
1647
1648 } else if(property == Atoms::netwm_winHints) {
1649
1650 if(state & WIN_HINTS_SKIP_FOCUS) {
1651 if(!skipsFocus())
1652 setSkipFocus(True);
1653 } else {
1654 if(skipsFocus())
1655 setSkipFocus(False);
1656 }
1657
1658 if(state & WIN_HINTS_FOCUS_ON_CLICK) {
1659 if(!isFocusOnClick())
1660 setFocusOnClick(True);
1661 } else {
1662 if(isFocusOnClick())
1663 setFocusOnClick(False);
1664 }
1665
1666 /* We ignore:
1667 WIN_HINTS_SKIP_WINLIST // do not show in window list
1668 WIN_HINTS_SKIP_TASKBAR // do not show on taskbar
1669 WIN_HINTS_GROUP_TRANSIENT // Reserved - definition is unclear
1670 WIN_HINTS_FOCUS_ON_CLICK // app only accepts focus if clicked
1671 */
1672 } else {
1673 fprintf(stderr, "wmx: Client::updateFromNetwmProperty called with unknown property!");
1674 }
1675 }
1676
netwmUpdateChannel()1677 void Client::netwmUpdateChannel()
1678 {
1679 CARD32 val;
1680
1681 // netwm numbers then 0... not 1...
1682 val = (CARD32)(channel() - 1);
1683
1684 fprintf(stderr, "Client::netwmUpdateChannel: setting desktop property on window %lx for client \"%s\" to %d\n", window(), name(), (int)val);
1685
1686 XChangeProperty(display(), window(), Atoms::netwm_winDesktop,
1687 XA_CARDINAL, 32,
1688 PropModeReplace, (unsigned char *)&val, 1);
1689 }
1690
appendEdges(EdgeRectList & list)1691 void Client::appendEdges(EdgeRectList &list)
1692 {
1693 if (!m_managed || !isNormal() || isTransient() || m_unmappedForChannel) {
1694 return;
1695 }
1696 EdgeRect r;
1697 if (isBorderless()) {
1698 r.left = m_x - 1;
1699 r.top = m_y - 1;
1700 } else {
1701 r.left = m_x - CONFIG_FRAME_THICKNESS;
1702 r.top = m_y - CONFIG_FRAME_THICKNESS;
1703 }
1704 r.right = m_x + m_w;
1705 r.bottom = m_y + m_h;
1706 // fprintf(stderr, "edges: H %d - %d V %d - %d for \"%s\"\n",
1707 // r.left, r.right, r.top, r.bottom, name());
1708 list.append(r);
1709 }
1710
printClientData()1711 void Client::printClientData()
1712 {
1713 printf(" * Window: %lx - Name: \"%s\"\n",
1714 window(), name() ? name() : "");
1715
1716 printf(" * Managed: %s - Reparenting: %s - Type: ", m_managed ? "Y" : "N", m_reparenting ? "Y" : "N");
1717 switch (m_type) {
1718 case NormalClient: printf("Normal "); break;
1719 case DialogClient: printf("Dialog "); break;
1720 case DesktopClient: printf("Desktop"); break;
1721 case DockClient: printf("Dock "); break;
1722 case ToolbarClient: printf("Toolbar"); break;
1723 case MenuClient: printf("Menu "); break;
1724 case UtilityClient: printf("Utility"); break;
1725 case SplashClient: printf("Splash "); break;
1726 default: printf("(unknown)"); break; // shouldn't happen
1727 }
1728
1729 printf(" - State: ");
1730
1731 switch (m_state) {
1732 case WithdrawnState: printf("Withdrawn (unmapped)"); break;
1733 case NormalState: printf("Normal (visible)"); break;
1734 case IconicState: printf("Iconic (hidden)"); break;
1735 default: printf("Unexpected state %d", m_state);
1736 }
1737
1738 printf("\n");
1739
1740 printf(" * Geometry: %dx%d%s%d%s%d - Shaped: %s - Screen: %d - Channel: %d - Layer: %d%s", m_w, m_h,
1741 (m_x >= 0 ? "+" : ""), m_x,
1742 (m_y >= 0 ? "+" : ""), m_y,
1743 m_shaped ? "Y" : "N",
1744 m_screen, m_channel, m_layer,
1745 m_unmappedForChannel ? " [unmapped]" : "");
1746
1747 printf("\n * Transient for: %lx - Group parent: %lx - Revert to: %p (%lx)\n",
1748 m_transient, m_groupParent, m_revert,
1749 m_revert ? m_revert->window() : None);
1750 }
1751
1752