]> Dogcows Code - chaz/openbox/blob - src/Window.cc
remove compiler warnings
[chaz/openbox] / src / Window.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Window.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
4 // Copyright (c) 1997 - 2000, 2002 Brad Hughes <bhughes at trolltech.com>
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef HAVE_CONFIG_H
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
31
32 #ifdef HAVE_STRING_H
33 # include <string.h>
34 #endif // HAVE_STRING_H
35
36 #ifdef DEBUG
37 # ifdef HAVE_STDIO_H
38 # include <stdio.h>
39 # endif // HAVE_STDIO_H
40 #endif // DEBUG
41 }
42
43 #include <cstdlib>
44
45 #include "i18n.hh"
46 #include "blackbox.hh"
47 #include "Font.hh"
48 #include "GCCache.hh"
49 #include "Iconmenu.hh"
50 #include "Image.hh"
51 #include "Screen.hh"
52 #include "Toolbar.hh"
53 #include "Util.hh"
54 #include "Window.hh"
55 #include "Windowmenu.hh"
56 #include "Workspace.hh"
57 #include "Slit.hh"
58
59 using std::string;
60
61 /*
62 * Initializes the class with default values/the window's set initial values.
63 */
64 BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
65 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
66 // sizeof(BlackboxWindow));
67
68 #ifdef DEBUG
69 fprintf(stderr, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w);
70 #endif // DEBUG
71
72 /*
73 set timer to zero... it is initialized properly later, so we check
74 if timer is zero in the destructor, and assume that the window is not
75 fully constructed if timer is zero...
76 */
77 timer = 0;
78 blackbox = b;
79 client.window = w;
80 screen = s;
81 xatom = blackbox->getXAtom();
82
83 if (! validateClient()) {
84 delete this;
85 return;
86 }
87
88 // set the eventmask early in the game so that we make sure we get
89 // all the events we are interested in
90 XSetWindowAttributes attrib_set;
91 attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
92 StructureNotifyMask;
93 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
94 ButtonMotionMask;
95 XChangeWindowAttributes(blackbox->getXDisplay(), client.window,
96 CWEventMask|CWDontPropagate, &attrib_set);
97
98 // fetch client size and placement
99 XWindowAttributes wattrib;
100 if ((! XGetWindowAttributes(blackbox->getXDisplay(),
101 client.window, &wattrib)) ||
102 (! wattrib.screen) || wattrib.override_redirect) {
103 #ifdef DEBUG
104 fprintf(stderr,
105 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
106 #endif // DEBUG
107
108 delete this;
109 return;
110 }
111
112 flags.moving = flags.resizing = flags.shaded = flags.visible =
113 flags.iconic = flags.focused = flags.stuck = flags.modal =
114 flags.send_focus_message = flags.shaped = flags.skip_taskbar =
115 flags.skip_pager = flags.fullscreen = False;
116 flags.maximized = 0;
117
118 blackbox_attrib.workspace = window_number = BSENTINEL;
119
120 blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack
121 = blackbox_attrib.decoration = 0l;
122 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
123 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
124
125 frame.border_w = 1;
126 frame.window = frame.plate = frame.title = frame.handle = None;
127 frame.close_button = frame.iconify_button = frame.maximize_button = None;
128 frame.right_grip = frame.left_grip = None;
129
130 frame.ulabel_pixel = frame.flabel_pixel = frame.utitle_pixel =
131 frame.ftitle_pixel = frame.uhandle_pixel = frame.fhandle_pixel =
132 frame.ubutton_pixel = frame.fbutton_pixel = frame.pbutton_pixel =
133 frame.uborder_pixel = frame.fborder_pixel = frame.ugrip_pixel =
134 frame.fgrip_pixel = 0;
135 frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None;
136 frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None;
137 frame.pbutton = frame.ugrip = frame.fgrip = None;
138
139 decorations = Decor_Titlebar | Decor_Border | Decor_Handle |
140 Decor_Iconify | Decor_Maximize;
141 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
142
143 client.wm_hint_flags = client.normal_hint_flags = 0;
144 client.window_group = None;
145 client.transient_for = 0;
146
147 /*
148 get the initial size and location of client window (relative to the
149 _root window_). This position is the reference point used with the
150 window's gravity to find the window's initial position.
151 */
152 client.rect.setRect(wattrib.x, wattrib.y, wattrib.width, wattrib.height);
153 client.old_bw = wattrib.border_width;
154
155 windowmenu = 0;
156 lastButtonPressTime = 0;
157
158 timer = new BTimer(blackbox, this);
159 timer->setTimeout(blackbox->getAutoRaiseDelay());
160
161 if (! getBlackboxHints()) {
162 getMWMHints();
163 getNetWMHints();
164 }
165
166 // get size, aspect, minimum/maximum size and other hints set by the
167 // client
168 getWMProtocols();
169 getWMHints();
170 getWMNormalHints();
171
172 if (client.initial_state == WithdrawnState) {
173 screen->getSlit()->addClient(client.window);
174 delete this;
175 return;
176 }
177
178 if (isKDESystrayWindow()) {
179 screen->addSystrayWindow(client.window);
180 delete this;
181 return;
182 }
183
184 frame.window = createToplevelWindow();
185 frame.plate = createChildWindow(frame.window);
186 associateClientWindow();
187
188 blackbox->saveWindowSearch(frame.window, this);
189 blackbox->saveWindowSearch(frame.plate, this);
190 blackbox->saveWindowSearch(client.window, this);
191
192 // determine if this is a transient window
193 getTransientInfo();
194
195 // determine the window's type, so we can decide its decorations and
196 // functionality, or if we should not manage it at all
197 getWindowType();
198
199 // adjust the window decorations/behavior based on the window type
200 switch (window_type) {
201 case Type_Desktop:
202 // desktop windows are not managed by us, we just make sure they stay on the
203 // bottom.
204 return;
205
206 case Type_Dock:
207 // docks (such as kicker) cannot be moved, and appear on all workspaces
208 functions &= ~(Func_Move);
209 flags.stuck = True;
210 case Type_Toolbar:
211 case Type_Menu:
212 case Type_Utility:
213 // these windows have minimal decorations, only a titlebar, and cannot
214 // be resized or iconified
215 decorations &= ~(Decor_Maximize | Decor_Handle | Decor_Border |
216 Decor_Iconify);
217 functions &= ~(Func_Resize | Func_Maximize | Func_Iconify);
218 break;
219
220 case Type_Splash:
221 // splash screens have no functionality or decorations, they are left up
222 // to the application which created them
223 decorations = 0;
224 functions = 0;
225 break;
226
227 case Type_Dialog:
228 // dialogs cannot be maximized, and don't display a handle
229 decorations &= ~(Decor_Maximize | Decor_Handle);
230 functions &= ~Func_Maximize;
231 break;
232
233 case Type_Normal:
234 // normal windows retain all of the possible decorations and functionality
235 break;
236 }
237
238 // further adjeust the window's decorations/behavior based on window sizes
239 if ((client.normal_hint_flags & PMinSize) &&
240 (client.normal_hint_flags & PMaxSize) &&
241 client.max_width <= client.min_width &&
242 client.max_height <= client.min_height) {
243 decorations &= ~(Decor_Maximize | Decor_Handle);
244 functions &= ~(Func_Resize | Func_Maximize);
245 }
246 upsize();
247
248 setAllowedActions();
249
250 bool place_window = True;
251 if (blackbox->isStartup() || isTransient() ||
252 client.normal_hint_flags & (PPosition|USPosition)) {
253 applyGravity(frame.rect);
254
255 if (blackbox->isStartup() ||
256 client.rect.intersects(screen->availableArea()))
257 place_window = False;
258 }
259
260 // add the window's strut. note this is done *after* placing the window.
261 screen->addStrut(&client.strut);
262 updateStrut();
263
264 if (decorations & Decor_Titlebar)
265 createTitlebar();
266
267 if (decorations & Decor_Handle)
268 createHandle();
269
270 #ifdef SHAPE
271 if (blackbox->hasShapeExtensions() && flags.shaped) {
272 configureShape();
273 }
274 #endif // SHAPE
275
276 grabButtons();
277
278 windowmenu = new Windowmenu(this);
279
280 if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
281 screen->getCurrentWorkspace()->addWindow(this, place_window);
282 else
283 screen->getWorkspace(blackbox_attrib.workspace)->
284 addWindow(this, place_window);
285
286 if (! place_window) {
287 // don't need to call configure if we are letting the workspace
288 // place the window
289 configure(frame.rect.x(), frame.rect.y(),
290 frame.rect.width(), frame.rect.height());
291 }
292
293 // preserve the window's initial state on first map, and its current state
294 // across a restart
295 if (! getState()) {
296 if (client.wm_hint_flags & StateHint)
297 current_state = client.initial_state;
298 else
299 current_state = NormalState;
300 }
301
302 // get sticky state from our parent window if we've got one
303 if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
304 client.transient_for->isStuck() != flags.stuck)
305 stick();
306
307 if (flags.shaded) {
308 flags.shaded = False;
309 unsigned long orig_state = current_state;
310 shade();
311
312 /*
313 At this point in the life of a window, current_state should only be set
314 to IconicState if the window was an *icon*, not if it was shaded.
315 */
316 if (orig_state != IconicState)
317 current_state = NormalState;
318 }
319
320 if (flags.stuck) {
321 flags.stuck = False;
322 stick();
323 }
324
325 if (flags.maximized && (functions & Func_Maximize)) {
326 remaximize();
327 }
328
329 /*
330 When the window is mapped (and also when its attributes are restored), the
331 current_state that was set here will be used.
332 It is set to Normal if the window is to be mapped or it is set to Iconic
333 if the window is to be iconified.
334 *Note* that for sticky windows, the same rules apply here, they are in
335 fact never set to Iconic since there is no way for us to tell if a sticky
336 window was iconified previously.
337 */
338
339 positionWindows();
340 decorate();
341
342 XMapSubwindows(blackbox->getXDisplay(), frame.window);
343
344 redrawWindowFrame();
345 }
346
347
348 BlackboxWindow::~BlackboxWindow(void) {
349 #ifdef DEBUG
350 fprintf(stderr, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
351 client.window);
352 #endif // DEBUG
353
354 if (! timer) // window not managed...
355 return;
356
357 screen->removeStrut(&client.strut);
358 screen->updateAvailableArea();
359
360 // We don't need to worry about resizing because resizing always grabs the X
361 // server. This should only ever happen if using opaque moving.
362 if (flags.moving)
363 endMove();
364
365 delete timer;
366
367 delete windowmenu;
368
369 if (client.window_group) {
370 BWindowGroup *group = blackbox->searchGroup(client.window_group);
371 if (group) group->removeWindow(this);
372 }
373
374 // remove ourselves from our transient_for
375 if (isTransient()) {
376 if (client.transient_for != (BlackboxWindow *) ~0ul) {
377 client.transient_for->client.transientList.remove(this);
378 }
379 client.transient_for = (BlackboxWindow*) 0;
380 }
381
382 if (client.transientList.size() > 0) {
383 // reset transient_for for all transients
384 BlackboxWindowList::iterator it, end = client.transientList.end();
385 for (it = client.transientList.begin(); it != end; ++it) {
386 (*it)->client.transient_for = (BlackboxWindow*) 0;
387 }
388 }
389
390 if (frame.title)
391 destroyTitlebar();
392
393 if (frame.handle)
394 destroyHandle();
395
396 if (frame.plate) {
397 blackbox->removeWindowSearch(frame.plate);
398 XDestroyWindow(blackbox->getXDisplay(), frame.plate);
399 }
400
401 if (frame.window) {
402 blackbox->removeWindowSearch(frame.window);
403 XDestroyWindow(blackbox->getXDisplay(), frame.window);
404 }
405
406 blackbox->removeWindowSearch(client.window);
407 }
408
409
410 /*
411 * Creates a new top level window, with a given location, size, and border
412 * width.
413 * Returns: the newly created window
414 */
415 Window BlackboxWindow::createToplevelWindow(void) {
416 XSetWindowAttributes attrib_create;
417 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
418 CWOverrideRedirect | CWEventMask;
419
420 attrib_create.background_pixmap = None;
421 attrib_create.colormap = screen->getColormap();
422 attrib_create.override_redirect = True;
423 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
424 ButtonMotionMask | EnterWindowMask;
425
426 return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(),
427 -1, -1, 1, 1, frame.border_w, screen->getDepth(),
428 InputOutput, screen->getVisual(), create_mask,
429 &attrib_create);
430 }
431
432
433 /*
434 * Creates a child window, and optionally associates a given cursor with
435 * the new window.
436 */
437 Window BlackboxWindow::createChildWindow(Window parent, Cursor cursor) {
438 XSetWindowAttributes attrib_create;
439 unsigned long create_mask = CWBackPixmap | CWBorderPixel |
440 CWEventMask;
441
442 attrib_create.background_pixmap = None;
443 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
444 ButtonMotionMask | ExposureMask;
445
446 if (cursor) {
447 create_mask |= CWCursor;
448 attrib_create.cursor = cursor;
449 }
450
451 return XCreateWindow(blackbox->getXDisplay(), parent, 0, 0, 1, 1, 0,
452 screen->getDepth(), InputOutput, screen->getVisual(),
453 create_mask, &attrib_create);
454 }
455
456
457 void BlackboxWindow::associateClientWindow(void) {
458 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0);
459 getWMName();
460 getWMIconName();
461
462 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert);
463
464 XSelectInput(blackbox->getXDisplay(), frame.plate, SubstructureRedirectMask);
465
466 XGrabServer(blackbox->getXDisplay());
467 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
468 XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0);
469 XSelectInput(blackbox->getXDisplay(), client.window,
470 PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
471 XUngrabServer(blackbox->getXDisplay());
472
473 XRaiseWindow(blackbox->getXDisplay(), frame.plate);
474 XMapSubwindows(blackbox->getXDisplay(), frame.plate);
475
476
477 #ifdef SHAPE
478 if (blackbox->hasShapeExtensions()) {
479 XShapeSelectInput(blackbox->getXDisplay(), client.window,
480 ShapeNotifyMask);
481
482 Bool shaped = False;
483 int foo;
484 unsigned int ufoo;
485
486 XShapeQueryExtents(blackbox->getXDisplay(), client.window, &shaped,
487 &foo, &foo, &ufoo, &ufoo, &foo, &foo, &foo,
488 &ufoo, &ufoo);
489 flags.shaped = shaped;
490 }
491 #endif // SHAPE
492 }
493
494
495 void BlackboxWindow::decorate(void) {
496 BTexture* texture;
497
498 texture = &(screen->getWindowStyle()->b_focus);
499 frame.fbutton = texture->render(frame.button_w, frame.button_w,
500 frame.fbutton);
501 if (! frame.fbutton)
502 frame.fbutton_pixel = texture->color().pixel();
503
504 texture = &(screen->getWindowStyle()->b_unfocus);
505 frame.ubutton = texture->render(frame.button_w, frame.button_w,
506 frame.ubutton);
507 if (! frame.ubutton)
508 frame.ubutton_pixel = texture->color().pixel();
509
510 texture = &(screen->getWindowStyle()->b_pressed);
511 frame.pbutton = texture->render(frame.button_w, frame.button_w,
512 frame.pbutton);
513 if (! frame.pbutton)
514 frame.pbutton_pixel = texture->color().pixel();
515
516 if (decorations & Decor_Titlebar) {
517 texture = &(screen->getWindowStyle()->t_focus);
518 frame.ftitle = texture->render(frame.inside_w, frame.title_h,
519 frame.ftitle);
520 if (! frame.ftitle)
521 frame.ftitle_pixel = texture->color().pixel();
522
523 texture = &(screen->getWindowStyle()->t_unfocus);
524 frame.utitle = texture->render(frame.inside_w, frame.title_h,
525 frame.utitle);
526 if (! frame.utitle)
527 frame.utitle_pixel = texture->color().pixel();
528
529 XSetWindowBorder(blackbox->getXDisplay(), frame.title,
530 screen->getBorderColor()->pixel());
531
532 decorateLabel();
533 }
534
535 if (decorations & Decor_Border) {
536 frame.fborder_pixel = screen->getWindowStyle()->f_focus.pixel();
537 frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.pixel();
538 blackbox_attrib.flags |= AttribDecoration;
539 blackbox_attrib.decoration = DecorNormal;
540 } else {
541 blackbox_attrib.flags |= AttribDecoration;
542 blackbox_attrib.decoration = DecorNone;
543 }
544
545 if (decorations & Decor_Handle) {
546 texture = &(screen->getWindowStyle()->h_focus);
547 frame.fhandle = texture->render(frame.inside_w, frame.handle_h,
548 frame.fhandle);
549 if (! frame.fhandle)
550 frame.fhandle_pixel = texture->color().pixel();
551
552 texture = &(screen->getWindowStyle()->h_unfocus);
553 frame.uhandle = texture->render(frame.inside_w, frame.handle_h,
554 frame.uhandle);
555 if (! frame.uhandle)
556 frame.uhandle_pixel = texture->color().pixel();
557
558 texture = &(screen->getWindowStyle()->g_focus);
559 frame.fgrip = texture->render(frame.grip_w, frame.handle_h, frame.fgrip);
560 if (! frame.fgrip)
561 frame.fgrip_pixel = texture->color().pixel();
562
563 texture = &(screen->getWindowStyle()->g_unfocus);
564 frame.ugrip = texture->render(frame.grip_w, frame.handle_h, frame.ugrip);
565 if (! frame.ugrip)
566 frame.ugrip_pixel = texture->color().pixel();
567
568 XSetWindowBorder(blackbox->getXDisplay(), frame.handle,
569 screen->getBorderColor()->pixel());
570 XSetWindowBorder(blackbox->getXDisplay(), frame.left_grip,
571 screen->getBorderColor()->pixel());
572 XSetWindowBorder(blackbox->getXDisplay(), frame.right_grip,
573 screen->getBorderColor()->pixel());
574 }
575
576 XSetWindowBorder(blackbox->getXDisplay(), frame.window,
577 screen->getBorderColor()->pixel());
578 }
579
580
581 void BlackboxWindow::decorateLabel(void) {
582 BTexture *texture;
583
584 texture = &(screen->getWindowStyle()->l_focus);
585 frame.flabel = texture->render(frame.label_w, frame.label_h, frame.flabel);
586 if (! frame.flabel)
587 frame.flabel_pixel = texture->color().pixel();
588
589 texture = &(screen->getWindowStyle()->l_unfocus);
590 frame.ulabel = texture->render(frame.label_w, frame.label_h, frame.ulabel);
591 if (! frame.ulabel)
592 frame.ulabel_pixel = texture->color().pixel();
593 }
594
595
596 void BlackboxWindow::createHandle(void) {
597 frame.handle = createChildWindow(frame.window);
598 blackbox->saveWindowSearch(frame.handle, this);
599
600 frame.left_grip =
601 createChildWindow(frame.handle, blackbox->getLowerLeftAngleCursor());
602 blackbox->saveWindowSearch(frame.left_grip, this);
603
604 frame.right_grip =
605 createChildWindow(frame.handle, blackbox->getLowerRightAngleCursor());
606 blackbox->saveWindowSearch(frame.right_grip, this);
607 }
608
609
610 void BlackboxWindow::destroyHandle(void) {
611 if (frame.fhandle)
612 screen->getImageControl()->removeImage(frame.fhandle);
613
614 if (frame.uhandle)
615 screen->getImageControl()->removeImage(frame.uhandle);
616
617 if (frame.fgrip)
618 screen->getImageControl()->removeImage(frame.fgrip);
619
620 if (frame.ugrip)
621 screen->getImageControl()->removeImage(frame.ugrip);
622
623 blackbox->removeWindowSearch(frame.left_grip);
624 blackbox->removeWindowSearch(frame.right_grip);
625
626 XDestroyWindow(blackbox->getXDisplay(), frame.left_grip);
627 XDestroyWindow(blackbox->getXDisplay(), frame.right_grip);
628 frame.left_grip = frame.right_grip = None;
629
630 blackbox->removeWindowSearch(frame.handle);
631 XDestroyWindow(blackbox->getXDisplay(), frame.handle);
632 frame.handle = None;
633 }
634
635
636 void BlackboxWindow::createTitlebar(void) {
637 frame.title = createChildWindow(frame.window);
638 frame.label = createChildWindow(frame.title);
639 blackbox->saveWindowSearch(frame.title, this);
640 blackbox->saveWindowSearch(frame.label, this);
641
642 if (decorations & Decor_Iconify) createIconifyButton();
643 if (decorations & Decor_Maximize) createMaximizeButton();
644 if (decorations & Decor_Close) createCloseButton();
645 }
646
647
648 void BlackboxWindow::destroyTitlebar(void) {
649 if (frame.close_button)
650 destroyCloseButton();
651
652 if (frame.iconify_button)
653 destroyIconifyButton();
654
655 if (frame.maximize_button)
656 destroyMaximizeButton();
657
658 if (frame.ftitle)
659 screen->getImageControl()->removeImage(frame.ftitle);
660
661 if (frame.utitle)
662 screen->getImageControl()->removeImage(frame.utitle);
663
664 if (frame.flabel)
665 screen->getImageControl()->removeImage(frame.flabel);
666
667 if( frame.ulabel)
668 screen->getImageControl()->removeImage(frame.ulabel);
669
670 if (frame.fbutton)
671 screen->getImageControl()->removeImage(frame.fbutton);
672
673 if (frame.ubutton)
674 screen->getImageControl()->removeImage(frame.ubutton);
675
676 if (frame.pbutton)
677 screen->getImageControl()->removeImage(frame.pbutton);
678
679 blackbox->removeWindowSearch(frame.title);
680 blackbox->removeWindowSearch(frame.label);
681
682 XDestroyWindow(blackbox->getXDisplay(), frame.label);
683 XDestroyWindow(blackbox->getXDisplay(), frame.title);
684 frame.title = frame.label = None;
685 }
686
687
688 void BlackboxWindow::createCloseButton(void) {
689 if (frame.title != None) {
690 frame.close_button = createChildWindow(frame.title);
691 blackbox->saveWindowSearch(frame.close_button, this);
692 }
693 }
694
695
696 void BlackboxWindow::destroyCloseButton(void) {
697 blackbox->removeWindowSearch(frame.close_button);
698 XDestroyWindow(blackbox->getXDisplay(), frame.close_button);
699 frame.close_button = None;
700 }
701
702
703 void BlackboxWindow::createIconifyButton(void) {
704 if (frame.title != None) {
705 frame.iconify_button = createChildWindow(frame.title);
706 blackbox->saveWindowSearch(frame.iconify_button, this);
707 }
708 }
709
710
711 void BlackboxWindow::destroyIconifyButton(void) {
712 blackbox->removeWindowSearch(frame.iconify_button);
713 XDestroyWindow(blackbox->getXDisplay(), frame.iconify_button);
714 frame.iconify_button = None;
715 }
716
717
718 void BlackboxWindow::createMaximizeButton(void) {
719 if (frame.title != None) {
720 frame.maximize_button = createChildWindow(frame.title);
721 blackbox->saveWindowSearch(frame.maximize_button, this);
722 }
723 }
724
725
726 void BlackboxWindow::destroyMaximizeButton(void) {
727 blackbox->removeWindowSearch(frame.maximize_button);
728 XDestroyWindow(blackbox->getXDisplay(), frame.maximize_button);
729 frame.maximize_button = None;
730 }
731
732
733 void BlackboxWindow::positionButtons(bool redecorate_label) {
734 string layout = blackbox->getTitlebarLayout();
735 string parsed;
736
737 bool hasclose, hasiconify, hasmaximize, haslabel;
738 hasclose = hasiconify = hasmaximize = haslabel = false;
739
740 string::const_iterator it, end;
741 for (it = layout.begin(), end = layout.end(); it != end; ++it) {
742 switch(*it) {
743 case 'C':
744 if (! hasclose && (decorations & Decor_Close)) {
745 hasclose = true;
746 parsed += *it;
747 }
748 break;
749 case 'I':
750 if (! hasiconify && (decorations & Decor_Iconify)) {
751 hasiconify = true;
752 parsed += *it;
753 }
754 break;
755 case 'M':
756 if (! hasmaximize && (decorations & Decor_Maximize)) {
757 hasmaximize = true;
758 parsed += *it;
759 }
760 break;
761 case 'L':
762 if (! haslabel) {
763 haslabel = true;
764 parsed += *it;
765 }
766 }
767 }
768 if (! hasclose && frame.close_button)
769 destroyCloseButton();
770 if (! hasiconify && frame.iconify_button)
771 destroyIconifyButton();
772 if (! hasmaximize && frame.maximize_button)
773 destroyMaximizeButton();
774 if (! haslabel)
775 parsed += 'L'; // require that the label be in the layout
776
777 const unsigned int bsep = frame.bevel_w + 1; // separation between elements
778 const unsigned int by = frame.bevel_w + 1;
779 const unsigned int ty = frame.bevel_w;
780
781 frame.label_w = frame.inside_w - bsep * 2 -
782 (frame.button_w + bsep) * (parsed.size() - 1);
783
784 unsigned int x = bsep;
785 for (it = parsed.begin(), end = parsed.end(); it != end; ++it) {
786 switch(*it) {
787 case 'C':
788 if (! frame.close_button) createCloseButton();
789 XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, x, by,
790 frame.button_w, frame.button_w);
791 x += frame.button_w + bsep;
792 break;
793 case 'I':
794 if (! frame.iconify_button) createIconifyButton();
795 XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, x, by,
796 frame.button_w, frame.button_w);
797 x += frame.button_w + bsep;
798 break;
799 case 'M':
800 if (! frame.maximize_button) createMaximizeButton();
801 XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by,
802 frame.button_w, frame.button_w);
803 x += frame.button_w + bsep;
804 break;
805 case 'L':
806 XMoveResizeWindow(blackbox->getXDisplay(), frame.label, x, ty,
807 frame.label_w, frame.label_h);
808 x += frame.label_w + bsep;
809 break;
810 }
811 }
812
813 if (redecorate_label) decorateLabel();
814 redrawLabel();
815 redrawAllButtons();
816 }
817
818
819 void BlackboxWindow::reconfigure(void) {
820 upsize();
821
822 positionWindows();
823 decorate();
824
825 redrawWindowFrame();
826
827 if (windowmenu) {
828 windowmenu->move(windowmenu->getX(), frame.rect.y() + frame.title_h);
829 windowmenu->reconfigure();
830 }
831 }
832
833
834 void BlackboxWindow::grabButtons(void) {
835 if ((! screen->isSloppyFocus()) || screen->doClickRaise())
836 // grab button 1 for changing focus/raising
837 blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
838 GrabModeSync, GrabModeSync, frame.plate, None);
839
840 if (functions & Func_Move)
841 blackbox->grabButton(Button1, Mod1Mask, frame.window, True,
842 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
843 GrabModeAsync, frame.window,
844 blackbox->getMoveCursor());
845 if (functions & Func_Resize)
846 blackbox->grabButton(Button3, Mod1Mask, frame.window, True,
847 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
848 GrabModeAsync, frame.window,
849 blackbox->getLowerRightAngleCursor());
850 }
851
852
853 void BlackboxWindow::ungrabButtons(void) {
854 if ((! screen->isSloppyFocus()) || screen->doClickRaise())
855 blackbox->ungrabButton(Button1, 0, frame.plate);
856
857 blackbox->ungrabButton(Button1, Mod1Mask, frame.window);
858 blackbox->ungrabButton(Button3, Mod1Mask, frame.window);
859 }
860
861
862 void BlackboxWindow::positionWindows(void) {
863 XMoveResizeWindow(blackbox->getXDisplay(), frame.window,
864 frame.rect.x(), frame.rect.y(), frame.inside_w,
865 (flags.shaded) ? frame.title_h : frame.inside_h);
866 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.window,
867 frame.border_w);
868 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.plate,
869 frame.mwm_border_w);
870 XMoveResizeWindow(blackbox->getXDisplay(), frame.plate,
871 frame.margin.left - frame.mwm_border_w - frame.border_w,
872 frame.margin.top - frame.mwm_border_w - frame.border_w,
873 client.rect.width(), client.rect.height());
874 XMoveResizeWindow(blackbox->getXDisplay(), client.window,
875 0, 0, client.rect.width(), client.rect.height());
876 // ensure client.rect contains the real location
877 client.rect.setCoords(frame.rect.left() + frame.margin.left,
878 frame.rect.top() + frame.margin.top,
879 frame.rect.right() - frame.margin.right,
880 frame.rect.bottom() - frame.margin.bottom);
881
882 if (decorations & Decor_Titlebar) {
883 if (frame.title == None) createTitlebar();
884
885 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.title,
886 frame.border_w);
887 XMoveResizeWindow(blackbox->getXDisplay(), frame.title, -frame.border_w,
888 -frame.border_w, frame.inside_w, frame.title_h);
889
890 positionButtons();
891 XMapSubwindows(blackbox->getXDisplay(), frame.title);
892 XMapWindow(blackbox->getXDisplay(), frame.title);
893 } else if (frame.title) {
894 destroyTitlebar();
895 }
896 if (decorations & Decor_Handle) {
897 if (frame.handle == None) createHandle();
898 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.handle,
899 frame.border_w);
900 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.left_grip,
901 frame.border_w);
902 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.right_grip,
903 frame.border_w);
904
905 // use client.rect here so the value is correct even if shaded
906 XMoveResizeWindow(blackbox->getXDisplay(), frame.handle,
907 -frame.border_w,
908 client.rect.height() + frame.margin.top +
909 frame.mwm_border_w - frame.border_w,
910 frame.inside_w, frame.handle_h);
911 XMoveResizeWindow(blackbox->getXDisplay(), frame.left_grip,
912 -frame.border_w, -frame.border_w,
913 frame.grip_w, frame.handle_h);
914 XMoveResizeWindow(blackbox->getXDisplay(), frame.right_grip,
915 frame.inside_w - frame.grip_w - frame.border_w,
916 -frame.border_w, frame.grip_w, frame.handle_h);
917
918 XMapSubwindows(blackbox->getXDisplay(), frame.handle);
919 XMapWindow(blackbox->getXDisplay(), frame.handle);
920 } else if (frame.handle) {
921 destroyHandle();
922 }
923 }
924
925
926 void BlackboxWindow::updateStrut(void) {
927 unsigned long num = 4;
928 unsigned long *data;
929 if (! xatom->getValue(client.window, XAtom::net_wm_strut, XAtom::cardinal,
930 num, &data))
931 return;
932
933 if (num == 4) {
934 client.strut.left = data[0];
935 client.strut.right = data[1];
936 client.strut.top = data[2];
937 client.strut.bottom = data[3];
938
939 screen->updateAvailableArea();
940 }
941
942 delete [] data;
943 }
944
945
946 void BlackboxWindow::getWindowType(void) {
947 unsigned long val;
948 if (xatom->getValue(client.window, XAtom::net_wm_window_type, XAtom::atom,
949 val)) {
950 if (val == xatom->getAtom(XAtom::net_wm_window_type_desktop))
951 window_type = Type_Desktop;
952 else if (val == xatom->getAtom(XAtom::net_wm_window_type_dock))
953 window_type = Type_Dock;
954 else if (val == xatom->getAtom(XAtom::net_wm_window_type_toolbar))
955 window_type = Type_Toolbar;
956 else if (val == xatom->getAtom(XAtom::net_wm_window_type_menu))
957 window_type = Type_Menu;
958 else if (val == xatom->getAtom(XAtom::net_wm_window_type_utility))
959 window_type = Type_Utility;
960 else if (val == xatom->getAtom(XAtom::net_wm_window_type_splash))
961 window_type = Type_Splash;
962 else if (val == xatom->getAtom(XAtom::net_wm_window_type_dialog))
963 window_type = Type_Dialog;
964 else //if (val[0] == xatom->getAtom(XAtom::net_wm_window_type_normal))
965 window_type = Type_Normal;
966 return;
967 }
968
969 /*
970 * the window type hint was not set, which means we either classify ourself
971 * as a normal window or a dialog, depending on if we are a transient.
972 */
973 if (isTransient())
974 window_type = Type_Dialog;
975
976 window_type = Type_Normal;
977 }
978
979
980 void BlackboxWindow::getWMName(void) {
981 if (xatom->getValue(client.window, XAtom::net_wm_name,
982 XAtom::utf8, client.title) &&
983 !client.title.empty()) {
984 xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
985 return;
986 }
987 //fall through to using WM_NAME
988 if (xatom->getValue(client.window, XAtom::wm_name, XAtom::ansi, client.title)
989 && !client.title.empty()) {
990 xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
991 return;
992 }
993 // fall back to an internal default
994 client.title = i18n(WindowSet, WindowUnnamed, "Unnamed");
995 xatom->setValue(client.window, XAtom::net_wm_visible_name, XAtom::utf8,
996 client.title);
997 }
998
999
1000 void BlackboxWindow::getWMIconName(void) {
1001 if (xatom->getValue(client.window, XAtom::net_wm_icon_name,
1002 XAtom::utf8, client.icon_title) &&
1003 !client.icon_title.empty()) {
1004 xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
1005 return;
1006 }
1007 //fall through to using WM_ICON_NAME
1008 if (xatom->getValue(client.window, XAtom::wm_icon_name, XAtom::ansi,
1009 client.icon_title) &&
1010 !client.icon_title.empty()) {
1011 xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
1012 return;
1013 }
1014 // fall back to using the main name
1015 client.icon_title = client.title;
1016 xatom->setValue(client.window, XAtom::net_wm_visible_icon_name, XAtom::utf8,
1017 client.icon_title);
1018 }
1019
1020
1021 /*
1022 * Retrieve which WM Protocols are supported by the client window.
1023 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1024 * window's decorations and allow the close behavior.
1025 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1026 * this.
1027 */
1028 void BlackboxWindow::getWMProtocols(void) {
1029 Atom *proto;
1030 int num_return = 0;
1031
1032 if (XGetWMProtocols(blackbox->getXDisplay(), client.window,
1033 &proto, &num_return)) {
1034 for (int i = 0; i < num_return; ++i) {
1035 if (proto[i] == xatom->getAtom(XAtom::wm_delete_window)) {
1036 decorations |= Decor_Close;
1037 functions |= Func_Close;
1038 } else if (proto[i] == xatom->getAtom(XAtom::wm_take_focus))
1039 flags.send_focus_message = True;
1040 else if (proto[i] == xatom->getAtom(XAtom::blackbox_structure_messages))
1041 screen->addNetizen(new Netizen(screen, client.window));
1042 }
1043
1044 XFree(proto);
1045 }
1046 }
1047
1048
1049 /*
1050 * Gets the value of the WM_HINTS property.
1051 * If the property is not set, then use a set of default values.
1052 */
1053 void BlackboxWindow::getWMHints(void) {
1054 focus_mode = F_Passive;
1055 client.initial_state = NormalState;
1056
1057 // remove from current window group
1058 if (client.window_group) {
1059 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1060 if (group) group->removeWindow(this);
1061 }
1062 client.window_group = None;
1063
1064 XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), client.window);
1065 if (! wmhint) {
1066 return;
1067 }
1068
1069 if (wmhint->flags & InputHint) {
1070 if (wmhint->input == True) {
1071 if (flags.send_focus_message)
1072 focus_mode = F_LocallyActive;
1073 } else {
1074 if (flags.send_focus_message)
1075 focus_mode = F_GloballyActive;
1076 else
1077 focus_mode = F_NoInput;
1078 }
1079 }
1080
1081 if (wmhint->flags & StateHint)
1082 client.initial_state = wmhint->initial_state;
1083
1084 if (wmhint->flags & WindowGroupHint) {
1085 client.window_group = wmhint->window_group;
1086
1087 // add window to the appropriate group
1088 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1089 if (! group) // no group found, create it!
1090 group = new BWindowGroup(blackbox, client.window_group);
1091 group->addWindow(this);
1092 }
1093
1094 client.wm_hint_flags = wmhint->flags;
1095 XFree(wmhint);
1096 }
1097
1098
1099 /*
1100 * Gets the value of the WM_NORMAL_HINTS property.
1101 * If the property is not set, then use a set of default values.
1102 */
1103 void BlackboxWindow::getWMNormalHints(void) {
1104 long icccm_mask;
1105 XSizeHints sizehint;
1106
1107 client.min_width = client.min_height =
1108 client.width_inc = client.height_inc = 1;
1109 client.base_width = client.base_height = 0;
1110
1111 /*
1112 use the full screen, not the strut modified size. otherwise when the
1113 availableArea changes max_width/height will be incorrect and lead to odd
1114 rendering bugs.
1115 */
1116 const Rect& screen_area = screen->getRect();
1117 client.max_width = screen_area.width();
1118
1119 client.max_height = screen_area.height();
1120 client.min_aspect_x = client.min_aspect_y =
1121 client.max_aspect_x = client.max_aspect_y = 1;
1122 client.win_gravity = NorthWestGravity;
1123
1124 if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window,
1125 &sizehint, &icccm_mask))
1126 return;
1127
1128 client.normal_hint_flags = sizehint.flags;
1129
1130 if (sizehint.flags & PMinSize) {
1131 client.min_width = sizehint.min_width;
1132 client.min_height = sizehint.min_height;
1133 }
1134
1135 if (sizehint.flags & PMaxSize) {
1136 client.max_width = sizehint.max_width;
1137 client.max_height = sizehint.max_height;
1138 }
1139
1140 if (sizehint.flags & PResizeInc) {
1141 client.width_inc = sizehint.width_inc;
1142 client.height_inc = sizehint.height_inc;
1143 }
1144
1145 if (sizehint.flags & PAspect) {
1146 client.min_aspect_x = sizehint.min_aspect.x;
1147 client.min_aspect_y = sizehint.min_aspect.y;
1148 client.max_aspect_x = sizehint.max_aspect.x;
1149 client.max_aspect_y = sizehint.max_aspect.y;
1150 }
1151
1152 if (sizehint.flags & PBaseSize) {
1153 client.base_width = sizehint.base_width;
1154 client.base_height = sizehint.base_height;
1155 }
1156
1157 if (sizehint.flags & PWinGravity)
1158 client.win_gravity = sizehint.win_gravity;
1159 }
1160
1161
1162 /*
1163 * Gets the NETWM hints for the class' contained window.
1164 */
1165 void BlackboxWindow::getNetWMHints(void) {
1166 unsigned long workspace;
1167
1168 if (xatom->getValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
1169 workspace)) {
1170 if (workspace == 0xffffffff)
1171 flags.stuck = True;
1172 else
1173 blackbox_attrib.workspace = workspace;
1174 }
1175
1176 unsigned long *state;
1177 unsigned long num = (unsigned) -1;
1178 if (xatom->getValue(client.window, XAtom::net_wm_state, XAtom::atom,
1179 num, &state)) {
1180 bool vert = False,
1181 horz = False;
1182 for (unsigned long i = 0; i < num; ++i) {
1183 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal))
1184 flags.modal = True;
1185 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_shaded))
1186 flags.shaded = True;
1187 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_taskbar))
1188 flags.skip_taskbar = True;
1189 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_pager))
1190 flags.skip_pager = True;
1191 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_fullscreen))
1192 flags.fullscreen = True;
1193 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_hidden))
1194 setState(IconicState);
1195 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_vert))
1196 vert = True;
1197 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_horz))
1198 horz = True;
1199 }
1200 if (vert && horz)
1201 flags.maximized = 1;
1202 else if (vert)
1203 flags.maximized = 2;
1204 else if (horz)
1205 flags.maximized = 3;
1206
1207 delete [] state;
1208 }
1209 }
1210
1211
1212 /*
1213 * Gets the MWM hints for the class' contained window.
1214 * This is used while initializing the window to its first state, and not
1215 * thereafter.
1216 * Returns: true if the MWM hints are successfully retreived and applied;
1217 * false if they are not.
1218 */
1219 void BlackboxWindow::getMWMHints(void) {
1220 unsigned long num;
1221 MwmHints *mwm_hint;
1222
1223 num = PropMwmHintsElements;
1224 if (! xatom->getValue(client.window, XAtom::motif_wm_hints,
1225 XAtom::motif_wm_hints, num,
1226 (unsigned long **)&mwm_hint))
1227 return;
1228 if (num < PropMwmHintsElements) {
1229 delete [] mwm_hint;
1230 return;
1231 }
1232
1233 if (mwm_hint->flags & MwmHintsDecorations) {
1234 if (mwm_hint->decorations & MwmDecorAll) {
1235 decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
1236 Decor_Iconify | Decor_Maximize | Decor_Close;
1237 } else {
1238 decorations = 0;
1239
1240 if (mwm_hint->decorations & MwmDecorBorder)
1241 decorations |= Decor_Border;
1242 if (mwm_hint->decorations & MwmDecorHandle)
1243 decorations |= Decor_Handle;
1244 if (mwm_hint->decorations & MwmDecorTitle)
1245 decorations |= Decor_Titlebar;
1246 if (mwm_hint->decorations & MwmDecorIconify)
1247 decorations |= Decor_Iconify;
1248 if (mwm_hint->decorations & MwmDecorMaximize)
1249 decorations |= Decor_Maximize;
1250 }
1251 }
1252
1253 if (mwm_hint->flags & MwmHintsFunctions) {
1254 if (mwm_hint->functions & MwmFuncAll) {
1255 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize |
1256 Func_Close;
1257 } else {
1258 functions = 0;
1259
1260 if (mwm_hint->functions & MwmFuncResize)
1261 functions |= Func_Resize;
1262 if (mwm_hint->functions & MwmFuncMove)
1263 functions |= Func_Move;
1264 if (mwm_hint->functions & MwmFuncIconify)
1265 functions |= Func_Iconify;
1266 if (mwm_hint->functions & MwmFuncMaximize)
1267 functions |= Func_Maximize;
1268 if (mwm_hint->functions & MwmFuncClose)
1269 functions |= Func_Close;
1270 }
1271 }
1272 delete [] mwm_hint;
1273 }
1274
1275
1276 /*
1277 * Gets the blackbox hints from the class' contained window.
1278 * This is used while initializing the window to its first state, and not
1279 * thereafter.
1280 * Returns: true if the hints are successfully retreived and applied; false if
1281 * they are not.
1282 */
1283 bool BlackboxWindow::getBlackboxHints(void) {
1284 unsigned long num;
1285 BlackboxHints *blackbox_hint;
1286
1287 num = PropBlackboxHintsElements;
1288 if (! xatom->getValue(client.window, XAtom::blackbox_hints,
1289 XAtom::blackbox_hints, num,
1290 (unsigned long **)&blackbox_hint))
1291 return False;
1292 if (num < PropBlackboxHintsElements) {
1293 delete [] blackbox_hint;
1294 return False;
1295 }
1296
1297 if (blackbox_hint->flags & AttribShaded)
1298 flags.shaded = (blackbox_hint->attrib & AttribShaded);
1299
1300 if ((blackbox_hint->flags & AttribMaxHoriz) &&
1301 (blackbox_hint->flags & AttribMaxVert))
1302 flags.maximized = (blackbox_hint->attrib &
1303 (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1304 else if (blackbox_hint->flags & AttribMaxVert)
1305 flags.maximized = (blackbox_hint->attrib & AttribMaxVert) ? 2 : 0;
1306 else if (blackbox_hint->flags & AttribMaxHoriz)
1307 flags.maximized = (blackbox_hint->attrib & AttribMaxHoriz) ? 3 : 0;
1308
1309 if (blackbox_hint->flags & AttribOmnipresent)
1310 flags.stuck = (blackbox_hint->attrib & AttribOmnipresent);
1311
1312 if (blackbox_hint->flags & AttribWorkspace)
1313 blackbox_attrib.workspace = blackbox_hint->workspace;
1314
1315 // if (blackbox_hint->flags & AttribStack)
1316 // don't yet have always on top/bottom for blackbox yet... working
1317 // on that
1318
1319 if (blackbox_hint->flags & AttribDecoration) {
1320 switch (blackbox_hint->decoration) {
1321 case DecorNone:
1322 // clear all decorations except close
1323 decorations &= Decor_Close;
1324 // clear all functions except close
1325 functions &= Func_Close;
1326
1327 break;
1328
1329 case DecorTiny:
1330 decorations |= Decor_Titlebar | Decor_Iconify;
1331 decorations &= ~(Decor_Border | Decor_Handle | Decor_Maximize);
1332 functions |= Func_Move | Func_Iconify;
1333 functions &= ~(Func_Resize | Func_Maximize);
1334
1335 break;
1336
1337 case DecorTool:
1338 decorations |= Decor_Titlebar;
1339 decorations &= ~(Decor_Iconify | Decor_Border | Decor_Handle);
1340 functions |= Func_Move;
1341 functions &= ~(Func_Resize | Func_Maximize | Func_Iconify);
1342
1343 break;
1344
1345 case DecorNormal:
1346 default:
1347 decorations |= Decor_Titlebar | Decor_Border | Decor_Handle |
1348 Decor_Iconify | Decor_Maximize;
1349 functions |= Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
1350
1351 break;
1352 }
1353
1354 reconfigure();
1355 }
1356
1357 delete [] blackbox_hint;
1358
1359 return True;
1360 }
1361
1362
1363 void BlackboxWindow::getTransientInfo(void) {
1364 if (client.transient_for &&
1365 client.transient_for != (BlackboxWindow *) ~0ul) {
1366 // the transient for hint was removed, so we need to tell our
1367 // previous transient_for that we are going away
1368 client.transient_for->client.transientList.remove(this);
1369 }
1370
1371 // we have no transient_for until we find a new one
1372 client.transient_for = 0;
1373
1374 Window trans_for;
1375 if (! XGetTransientForHint(blackbox->getXDisplay(), client.window,
1376 &trans_for)) {
1377 // transient_for hint not set
1378 return;
1379 }
1380
1381 if (trans_for == client.window) {
1382 // wierd client... treat this window as a normal window
1383 return;
1384 }
1385
1386 if (trans_for == None || trans_for == screen->getRootWindow()) {
1387 // this is an undocumented interpretation of the ICCCM. a transient
1388 // associated with None/Root/itself is assumed to be a modal root
1389 // transient. we don't support the concept of a global transient,
1390 // so we just associate this transient with nothing, and perhaps
1391 // we will add support later for global modality.
1392 client.transient_for = (BlackboxWindow *) ~0ul;
1393 flags.modal = True;
1394 return;
1395 }
1396
1397 client.transient_for = blackbox->searchWindow(trans_for);
1398 if (! client.transient_for &&
1399 client.window_group && trans_for == client.window_group) {
1400 // no direct transient_for, perhaps this is a group transient?
1401 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1402 if (group) client.transient_for = group->find(screen);
1403 }
1404
1405 if (! client.transient_for || client.transient_for == this) {
1406 // no transient_for found, or we have a wierd client that wants to be
1407 // a transient for itself, so we treat this window as a normal window
1408 client.transient_for = (BlackboxWindow*) 0;
1409 return;
1410 }
1411
1412 // register ourselves with our new transient_for
1413 client.transient_for->client.transientList.push_back(this);
1414 flags.stuck = client.transient_for->flags.stuck;
1415 }
1416
1417
1418 bool BlackboxWindow::isKDESystrayWindow(void) {
1419 Window systray;
1420 if (xatom->getValue(client.window, XAtom::kde_net_wm_system_tray_window_for,
1421 XAtom::window, systray) && systray)
1422 return True;
1423 return False;
1424 }
1425
1426
1427 BlackboxWindow *BlackboxWindow::getTransientFor(void) const {
1428 if (client.transient_for &&
1429 client.transient_for != (BlackboxWindow*) ~0ul)
1430 return client.transient_for;
1431 return 0;
1432 }
1433
1434
1435 /*
1436 * This function is responsible for updating both the client and the frame
1437 * rectangles.
1438 * According to the ICCCM a client message is not sent for a resize, only a
1439 * move.
1440 */
1441 void BlackboxWindow::configure(int dx, int dy,
1442 unsigned int dw, unsigned int dh) {
1443 bool send_event = (frame.rect.x() != dx || frame.rect.y() != dy);
1444
1445 if (dw != frame.rect.width() || dh != frame.rect.height()) {
1446 frame.rect.setRect(dx, dy, dw, dh);
1447 frame.inside_w = frame.rect.width() - (frame.border_w * 2);
1448 frame.inside_h = frame.rect.height() - (frame.border_w * 2);
1449
1450 if (frame.rect.right() <= 0 || frame.rect.bottom() <= 0)
1451 frame.rect.setPos(0, 0);
1452
1453 client.rect.setCoords(frame.rect.left() + frame.margin.left,
1454 frame.rect.top() + frame.margin.top,
1455 frame.rect.right() - frame.margin.right,
1456 frame.rect.bottom() - frame.margin.bottom);
1457
1458 #ifdef SHAPE
1459 if (blackbox->hasShapeExtensions() && flags.shaped) {
1460 configureShape();
1461 }
1462 #endif // SHAPE
1463
1464 positionWindows();
1465 decorate();
1466 redrawWindowFrame();
1467 } else {
1468 frame.rect.setPos(dx, dy);
1469
1470 XMoveWindow(blackbox->getXDisplay(), frame.window,
1471 frame.rect.x(), frame.rect.y());
1472 }
1473
1474 if (send_event && ! flags.moving) {
1475 // if moving, the update and event will occur when the move finishes
1476 client.rect.setPos(frame.rect.left() + frame.margin.left,
1477 frame.rect.top() + frame.margin.top);
1478
1479 XEvent event;
1480 event.type = ConfigureNotify;
1481
1482 event.xconfigure.display = blackbox->getXDisplay();
1483 event.xconfigure.event = client.window;
1484 event.xconfigure.window = client.window;
1485 event.xconfigure.x = client.rect.x();
1486 event.xconfigure.y = client.rect.y();
1487 event.xconfigure.width = client.rect.width();
1488 event.xconfigure.height = client.rect.height();
1489 event.xconfigure.border_width = client.old_bw;
1490 event.xconfigure.above = frame.window;
1491 event.xconfigure.override_redirect = False;
1492
1493 XSendEvent(blackbox->getXDisplay(), client.window, False,
1494 StructureNotifyMask, &event);
1495 screen->updateNetizenConfigNotify(&event);
1496 }
1497 }
1498
1499
1500 #ifdef SHAPE
1501 void BlackboxWindow::configureShape(void) {
1502 XShapeCombineShape(blackbox->getXDisplay(), frame.window, ShapeBounding,
1503 frame.margin.left - frame.border_w,
1504 frame.margin.top - frame.border_w,
1505 client.window, ShapeBounding, ShapeSet);
1506
1507 int num = 0;
1508 XRectangle xrect[2];
1509
1510 if (decorations & Decor_Titlebar) {
1511 xrect[0].x = xrect[0].y = -frame.border_w;
1512 xrect[0].width = frame.rect.width();
1513 xrect[0].height = frame.title_h + (frame.border_w * 2);
1514 ++num;
1515 }
1516
1517 if (decorations & Decor_Handle) {
1518 xrect[1].x = -frame.border_w;
1519 xrect[1].y = frame.rect.height() - frame.margin.bottom +
1520 frame.mwm_border_w - frame.border_w;
1521 xrect[1].width = frame.rect.width();
1522 xrect[1].height = frame.handle_h + (frame.border_w * 2);
1523 ++num;
1524 }
1525
1526 XShapeCombineRectangles(blackbox->getXDisplay(), frame.window,
1527 ShapeBounding, 0, 0, xrect, num,
1528 ShapeUnion, Unsorted);
1529 }
1530 #endif // SHAPE
1531
1532
1533 bool BlackboxWindow::setInputFocus(void) {
1534 if (flags.focused) return True;
1535
1536 assert(! flags.iconic &&
1537 (flags.stuck || // window must be on the current workspace or sticky
1538 blackbox_attrib.workspace == screen->getCurrentWorkspaceID()));
1539 #if 0
1540 // if the window is not visible, mark the window as wanting focus rather
1541 // than give it focus.
1542 if (! flags.visible) {
1543 Workspace *wkspc = screen->getWorkspace(blackbox_attrib.workspace);
1544 wkspc->setLastFocusedWindow(this);
1545 return True;
1546 }
1547 #endif
1548 if (! frame.rect.intersects(screen->getRect())) {
1549 // client is outside the screen, move it to the center
1550 configure((screen->getWidth() - frame.rect.width()) / 2,
1551 (screen->getHeight() - frame.rect.height()) / 2,
1552 frame.rect.width(), frame.rect.height());
1553 }
1554
1555 if (client.transientList.size() > 0) {
1556 // transfer focus to any modal transients
1557 BlackboxWindowList::iterator it, end = client.transientList.end();
1558 for (it = client.transientList.begin(); it != end; ++it) {
1559 if ((*it)->flags.modal) return (*it)->setInputFocus();
1560 }
1561 }
1562
1563 bool ret = True;
1564 if (focus_mode == F_LocallyActive || focus_mode == F_Passive) {
1565 XSetInputFocus(blackbox->getXDisplay(), client.window,
1566 RevertToPointerRoot, CurrentTime);
1567
1568 blackbox->setFocusedWindow(this);
1569 } else {
1570 /* we could set the focus to none, since the window doesn't accept focus,
1571 * but we shouldn't set focus to nothing since this would surely make
1572 * someone angry
1573 */
1574 ret = False;
1575 }
1576
1577 if (flags.send_focus_message) {
1578 XEvent ce;
1579 ce.xclient.type = ClientMessage;
1580 ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
1581 ce.xclient.display = blackbox->getXDisplay();
1582 ce.xclient.window = client.window;
1583 ce.xclient.format = 32;
1584 ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_take_focus);
1585 ce.xclient.data.l[1] = blackbox->getLastTime();
1586 ce.xclient.data.l[2] = 0l;
1587 ce.xclient.data.l[3] = 0l;
1588 ce.xclient.data.l[4] = 0l;
1589 XSendEvent(blackbox->getXDisplay(), client.window, False,
1590 NoEventMask, &ce);
1591 }
1592
1593 return ret;
1594 }
1595
1596
1597 void BlackboxWindow::iconify(void) {
1598 if (flags.iconic) return;
1599
1600 // We don't need to worry about resizing because resizing always grabs the X
1601 // server. This should only ever happen if using opaque moving.
1602 if (flags.moving)
1603 endMove();
1604
1605 if (windowmenu) windowmenu->hide();
1606
1607 /*
1608 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1609 * we need to clear the event mask on client.window for a split second.
1610 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1611 * split second, leaving us with a ghost window... so, we need to do this
1612 * while the X server is grabbed
1613 */
1614 XGrabServer(blackbox->getXDisplay());
1615 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
1616 XUnmapWindow(blackbox->getXDisplay(), client.window);
1617 XSelectInput(blackbox->getXDisplay(), client.window,
1618 PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
1619 XUngrabServer(blackbox->getXDisplay());
1620
1621 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1622 flags.visible = False;
1623 flags.iconic = True;
1624
1625 setState(IconicState);
1626
1627 screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this);
1628
1629 if (isTransient()) {
1630 if (client.transient_for != (BlackboxWindow *) ~0ul &&
1631 ! client.transient_for->flags.iconic) {
1632 // iconify our transient_for
1633 client.transient_for->iconify();
1634 }
1635 }
1636
1637 screen->addIcon(this);
1638
1639 if (client.transientList.size() > 0) {
1640 // iconify all transients
1641 BlackboxWindowList::iterator it, end = client.transientList.end();
1642 for (it = client.transientList.begin(); it != end; ++it) {
1643 if (! (*it)->flags.iconic) (*it)->iconify();
1644 }
1645 }
1646 }
1647
1648
1649 void BlackboxWindow::show(void) {
1650 flags.visible = True;
1651 flags.iconic = False;
1652
1653 current_state = (flags.shaded) ? IconicState : NormalState;
1654 setState(current_state);
1655
1656 XMapWindow(blackbox->getXDisplay(), client.window);
1657 XMapSubwindows(blackbox->getXDisplay(), frame.window);
1658 XMapWindow(blackbox->getXDisplay(), frame.window);
1659
1660 #ifdef DEBUG
1661 int real_x, real_y;
1662 Window child;
1663 XTranslateCoordinates(blackbox->getXDisplay(), client.window,
1664 screen->getRootWindow(),
1665 0, 0, &real_x, &real_y, &child);
1666 fprintf(stderr, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1667 client.rect.left(), client.rect.top(), real_x, real_y);
1668 assert(client.rect.left() == real_x && client.rect.top() == real_y);
1669 #endif
1670 }
1671
1672
1673 void BlackboxWindow::deiconify(bool reassoc, bool raise) {
1674 if (flags.iconic || reassoc)
1675 screen->reassociateWindow(this, BSENTINEL, False);
1676 else if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID())
1677 return;
1678
1679 show();
1680
1681 // reassociate and deiconify all transients
1682 if (reassoc && client.transientList.size() > 0) {
1683 BlackboxWindowList::iterator it, end = client.transientList.end();
1684 for (it = client.transientList.begin(); it != end; ++it) {
1685 (*it)->deiconify(True, False);
1686 }
1687 }
1688
1689 if (raise)
1690 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1691 }
1692
1693
1694 void BlackboxWindow::close(void) {
1695 XEvent ce;
1696 ce.xclient.type = ClientMessage;
1697 ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
1698 ce.xclient.display = blackbox->getXDisplay();
1699 ce.xclient.window = client.window;
1700 ce.xclient.format = 32;
1701 ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_delete_window);
1702 ce.xclient.data.l[1] = CurrentTime;
1703 ce.xclient.data.l[2] = 0l;
1704 ce.xclient.data.l[3] = 0l;
1705 ce.xclient.data.l[4] = 0l;
1706 XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce);
1707 }
1708
1709
1710 void BlackboxWindow::withdraw(void) {
1711 // We don't need to worry about resizing because resizing always grabs the X
1712 // server. This should only ever happen if using opaque moving.
1713 if (flags.moving)
1714 endMove();
1715
1716 flags.visible = False;
1717 flags.iconic = False;
1718
1719 setState(current_state);
1720
1721 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1722
1723 XGrabServer(blackbox->getXDisplay());
1724
1725 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
1726 XUnmapWindow(blackbox->getXDisplay(), client.window);
1727 XSelectInput(blackbox->getXDisplay(), client.window,
1728 PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
1729
1730 XUngrabServer(blackbox->getXDisplay());
1731
1732 if (windowmenu) windowmenu->hide();
1733 }
1734
1735
1736 void BlackboxWindow::maximize(unsigned int button) {
1737 // We don't need to worry about resizing because resizing always grabs the X
1738 // server. This should only ever happen if using opaque moving.
1739 if (flags.moving)
1740 endMove();
1741
1742 // handle case where menu is open then the max button is used instead
1743 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
1744
1745 if (flags.maximized) {
1746 flags.maximized = 0;
1747
1748 blackbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert);
1749 blackbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert);
1750
1751 /*
1752 when a resize finishes, maximize(0) is called to clear any maximization
1753 flags currently set. Otherwise it still thinks it is maximized.
1754 so we do not need to call configure() because resizing will handle it
1755 */
1756 if (! flags.resizing)
1757 configure(blackbox_attrib.premax_x, blackbox_attrib.premax_y,
1758 blackbox_attrib.premax_w, blackbox_attrib.premax_h);
1759
1760 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
1761 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
1762
1763 redrawAllButtons(); // in case it is not called in configure()
1764 setState(current_state);
1765 return;
1766 }
1767
1768 blackbox_attrib.premax_x = frame.rect.x();
1769 blackbox_attrib.premax_y = frame.rect.y();
1770 blackbox_attrib.premax_w = frame.rect.width();
1771 // use client.rect so that clients can be restored even if shaded
1772 blackbox_attrib.premax_h =
1773 client.rect.height() + frame.margin.top + frame.margin.bottom;
1774
1775 const Rect &screen_area = screen->availableArea();
1776 frame.changing = screen_area;
1777
1778 switch(button) {
1779 case 1:
1780 blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
1781 blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
1782 break;
1783
1784 case 2:
1785 blackbox_attrib.flags |= AttribMaxVert;
1786 blackbox_attrib.attrib |= AttribMaxVert;
1787
1788 frame.changing.setX(frame.rect.x());
1789 frame.changing.setWidth(frame.rect.width());
1790 break;
1791
1792 case 3:
1793 blackbox_attrib.flags |= AttribMaxHoriz;
1794 blackbox_attrib.attrib |= AttribMaxHoriz;
1795
1796 frame.changing.setY(frame.rect.y());
1797 frame.changing.setHeight(frame.rect.height());
1798 break;
1799 }
1800
1801 constrain(TopLeft);
1802
1803 if (flags.shaded) {
1804 blackbox_attrib.flags ^= AttribShaded;
1805 blackbox_attrib.attrib ^= AttribShaded;
1806 flags.shaded = False;
1807 }
1808
1809 flags.maximized = button;
1810
1811 configure(frame.changing.x(), frame.changing.y(),
1812 frame.changing.width(), frame.changing.height());
1813 if (flags.focused)
1814 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1815 redrawAllButtons(); // in case it is not called in configure()
1816 setState(current_state);
1817 }
1818
1819
1820 // re-maximizes the window to take into account availableArea changes
1821 void BlackboxWindow::remaximize(void) {
1822 // save the original dimensions because maximize will wipe them out
1823 int premax_x = blackbox_attrib.premax_x,
1824 premax_y = blackbox_attrib.premax_y,
1825 premax_w = blackbox_attrib.premax_w,
1826 premax_h = blackbox_attrib.premax_h;
1827
1828 unsigned int button = flags.maximized;
1829 flags.maximized = 0; // trick maximize() into working
1830 maximize(button);
1831
1832 // restore saved values
1833 blackbox_attrib.premax_x = premax_x;
1834 blackbox_attrib.premax_y = premax_y;
1835 blackbox_attrib.premax_w = premax_w;
1836 blackbox_attrib.premax_h = premax_h;
1837 }
1838
1839
1840 void BlackboxWindow::setWorkspace(unsigned int n) {
1841 blackbox_attrib.flags |= AttribWorkspace;
1842 blackbox_attrib.workspace = n;
1843 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n);
1844 }
1845
1846
1847 void BlackboxWindow::shade(void) {
1848 if (flags.shaded) {
1849 XResizeWindow(blackbox->getXDisplay(), frame.window,
1850 frame.inside_w, frame.inside_h);
1851 flags.shaded = False;
1852 blackbox_attrib.flags ^= AttribShaded;
1853 blackbox_attrib.attrib ^= AttribShaded;
1854
1855 setState(NormalState);
1856
1857 // set the frame rect to the normal size
1858 frame.rect.setHeight(client.rect.height() + frame.margin.top +
1859 frame.margin.bottom);
1860 } else {
1861 if (! (decorations & Decor_Titlebar))
1862 return; // can't shade it without a titlebar!
1863
1864 XResizeWindow(blackbox->getXDisplay(), frame.window,
1865 frame.inside_w, frame.title_h);
1866 flags.shaded = True;
1867 blackbox_attrib.flags |= AttribShaded;
1868 blackbox_attrib.attrib |= AttribShaded;
1869
1870 setState(IconicState);
1871
1872 // set the frame rect to the shaded size
1873 frame.rect.setHeight(frame.title_h + (frame.border_w * 2));
1874 }
1875 }
1876
1877
1878 /*
1879 * (Un)Sticks a window and its relatives.
1880 */
1881 void BlackboxWindow::stick(void) {
1882 if (flags.stuck) {
1883 blackbox_attrib.flags ^= AttribOmnipresent;
1884 blackbox_attrib.attrib ^= AttribOmnipresent;
1885
1886 flags.stuck = False;
1887
1888 if (! flags.iconic)
1889 screen->reassociateWindow(this, BSENTINEL, True);
1890 else
1891 // temporary fix since sticky windows suck. set the hint to what we
1892 // actually hold in our data.
1893 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
1894 blackbox_attrib.workspace);
1895
1896 setState(current_state);
1897 } else {
1898 flags.stuck = True;
1899
1900 blackbox_attrib.flags |= AttribOmnipresent;
1901 blackbox_attrib.attrib |= AttribOmnipresent;
1902
1903 // temporary fix since sticky windows suck. set the hint to a different
1904 // value than that contained in the class' data.
1905 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
1906 0xffffffff);
1907
1908 setState(current_state);
1909 }
1910 // go up the chain
1911 if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
1912 client.transient_for->isStuck() != flags.stuck)
1913 client.transient_for->stick();
1914 // go down the chain
1915 BlackboxWindowList::iterator it;
1916 const BlackboxWindowList::iterator end = client.transientList.end();
1917 for (it = client.transientList.begin(); it != end; ++it)
1918 if ((*it)->isStuck() != flags.stuck)
1919 (*it)->stick();
1920 }
1921
1922
1923 void BlackboxWindow::redrawWindowFrame(void) const {
1924 if (decorations & Decor_Titlebar) {
1925 if (flags.focused) {
1926 if (frame.ftitle)
1927 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1928 frame.title, frame.ftitle);
1929 else
1930 XSetWindowBackground(blackbox->getXDisplay(),
1931 frame.title, frame.ftitle_pixel);
1932 } else {
1933 if (frame.utitle)
1934 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1935 frame.title, frame.utitle);
1936 else
1937 XSetWindowBackground(blackbox->getXDisplay(),
1938 frame.title, frame.utitle_pixel);
1939 }
1940 XClearWindow(blackbox->getXDisplay(), frame.title);
1941
1942 redrawLabel();
1943 redrawAllButtons();
1944 }
1945
1946 if (decorations & Decor_Handle) {
1947 if (flags.focused) {
1948 if (frame.fhandle)
1949 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1950 frame.handle, frame.fhandle);
1951 else
1952 XSetWindowBackground(blackbox->getXDisplay(),
1953 frame.handle, frame.fhandle_pixel);
1954
1955 if (frame.fgrip) {
1956 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1957 frame.left_grip, frame.fgrip);
1958 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1959 frame.right_grip, frame.fgrip);
1960 } else {
1961 XSetWindowBackground(blackbox->getXDisplay(),
1962 frame.left_grip, frame.fgrip_pixel);
1963 XSetWindowBackground(blackbox->getXDisplay(),
1964 frame.right_grip, frame.fgrip_pixel);
1965 }
1966 } else {
1967 if (frame.uhandle)
1968 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1969 frame.handle, frame.uhandle);
1970 else
1971 XSetWindowBackground(blackbox->getXDisplay(),
1972 frame.handle, frame.uhandle_pixel);
1973
1974 if (frame.ugrip) {
1975 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1976 frame.left_grip, frame.ugrip);
1977 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1978 frame.right_grip, frame.ugrip);
1979 } else {
1980 XSetWindowBackground(blackbox->getXDisplay(),
1981 frame.left_grip, frame.ugrip_pixel);
1982 XSetWindowBackground(blackbox->getXDisplay(),
1983 frame.right_grip, frame.ugrip_pixel);
1984 }
1985 }
1986 XClearWindow(blackbox->getXDisplay(), frame.handle);
1987 XClearWindow(blackbox->getXDisplay(), frame.left_grip);
1988 XClearWindow(blackbox->getXDisplay(), frame.right_grip);
1989 }
1990
1991 if (decorations & Decor_Border) {
1992 if (flags.focused)
1993 XSetWindowBorder(blackbox->getXDisplay(),
1994 frame.plate, frame.fborder_pixel);
1995 else
1996 XSetWindowBorder(blackbox->getXDisplay(),
1997 frame.plate, frame.uborder_pixel);
1998 }
1999 }
2000
2001
2002 void BlackboxWindow::setFocusFlag(bool focus) {
2003 // only focus a window if it is visible
2004 if (focus && !flags.visible)
2005 return;
2006
2007 flags.focused = focus;
2008
2009 redrawWindowFrame();
2010
2011 if (screen->isSloppyFocus() && screen->doAutoRaise()) {
2012 if (isFocused()) timer->start();
2013 else timer->stop();
2014 }
2015
2016 if (isFocused())
2017 blackbox->setFocusedWindow(this);
2018 }
2019
2020
2021 void BlackboxWindow::installColormap(bool install) {
2022 int i = 0, ncmap = 0;
2023 Colormap *cmaps = XListInstalledColormaps(blackbox->getXDisplay(),
2024 client.window, &ncmap);
2025 if (cmaps) {
2026 XWindowAttributes wattrib;
2027 if (XGetWindowAttributes(blackbox->getXDisplay(),
2028 client.window, &wattrib)) {
2029 if (install) {
2030 // install the window's colormap
2031 for (i = 0; i < ncmap; i++) {
2032 if (*(cmaps + i) == wattrib.colormap)
2033 // this window is using an installed color map... do not install
2034 install = False;
2035 }
2036 // otherwise, install the window's colormap
2037 if (install)
2038 XInstallColormap(blackbox->getXDisplay(), wattrib.colormap);
2039 } else {
2040 // uninstall the window's colormap
2041 for (i = 0; i < ncmap; i++) {
2042 if (*(cmaps + i) == wattrib.colormap)
2043 // we found the colormap to uninstall
2044 XUninstallColormap(blackbox->getXDisplay(), wattrib.colormap);
2045 }
2046 }
2047 }
2048
2049 XFree(cmaps);
2050 }
2051 }
2052
2053
2054 void BlackboxWindow::setAllowedActions(void) {
2055 Atom actions[7];
2056 int num = 0;
2057
2058 actions[num++] = xatom->getAtom(XAtom::net_wm_action_shade);
2059 actions[num++] = xatom->getAtom(XAtom::net_wm_action_change_desktop);
2060 actions[num++] = xatom->getAtom(XAtom::net_wm_action_close);
2061
2062 if (functions & Func_Move)
2063 actions[num++] = xatom->getAtom(XAtom::net_wm_action_move);
2064 if (functions & Func_Resize)
2065 actions[num++] = xatom->getAtom(XAtom::net_wm_action_resize);
2066 if (functions & Func_Maximize) {
2067 actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_horz);
2068 actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_vert);
2069 }
2070
2071 xatom->setValue(client.window, XAtom::net_wm_allowed_actions, XAtom::atom,
2072 actions, num);
2073 }
2074
2075
2076 void BlackboxWindow::setState(unsigned long new_state) {
2077 current_state = new_state;
2078
2079 unsigned long state[2];
2080 state[0] = current_state;
2081 state[1] = None;
2082 xatom->setValue(client.window, XAtom::wm_state, XAtom::wm_state, state, 2);
2083
2084 xatom->setValue(client.window, XAtom::blackbox_attributes,
2085 XAtom::blackbox_attributes, (unsigned long *)&blackbox_attrib,
2086 PropBlackboxAttributesElements);
2087
2088 Atom netstate[8];
2089 int num = 0;
2090 if (flags.modal)
2091 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_modal);
2092 if (flags.shaded)
2093 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_shaded);
2094 if (flags.iconic)
2095 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_hidden);
2096 if (flags.skip_taskbar)
2097 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_taskbar);
2098 if (flags.skip_pager)
2099 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_pager);
2100 if (flags.fullscreen)
2101 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_fullscreen);
2102 if (flags.maximized == 1 || flags.maximized == 2)
2103 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_vert);
2104 if (flags.maximized == 1 || flags.maximized == 3)
2105 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_horz);
2106 xatom->setValue(client.window, XAtom::net_wm_state, XAtom::atom,
2107 netstate, num);
2108 }
2109
2110
2111 bool BlackboxWindow::getState(void) {
2112 bool ret = xatom->getValue(client.window, XAtom::wm_state, XAtom::wm_state,
2113 current_state);
2114 if (! ret) current_state = 0;
2115 return ret;
2116 }
2117
2118
2119 void BlackboxWindow::restoreAttributes(void) {
2120 unsigned long num = PropBlackboxAttributesElements;
2121 BlackboxAttributes *net;
2122 if (! xatom->getValue(client.window, XAtom::blackbox_attributes,
2123 XAtom::blackbox_attributes, num,
2124 (unsigned long **)&net))
2125 return;
2126 if (num < PropBlackboxAttributesElements) {
2127 delete [] net;
2128 return;
2129 }
2130
2131 if (net->flags & AttribShaded && net->attrib & AttribShaded) {
2132 flags.shaded = False;
2133 unsigned long orig_state = current_state;
2134 shade();
2135
2136 /*
2137 At this point in the life of a window, current_state should only be set
2138 to IconicState if the window was an *icon*, not if it was shaded.
2139 */
2140 if (orig_state != IconicState)
2141 current_state = WithdrawnState;
2142 }
2143
2144 if (net->workspace != screen->getCurrentWorkspaceID() &&
2145 net->workspace < screen->getWorkspaceCount())
2146 screen->reassociateWindow(this, net->workspace, True);
2147
2148 if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) &&
2149 (blackbox_attrib.workspace < screen->getWorkspaceCount())) {
2150 // set to WithdrawnState so it will be mapped on the new workspace
2151 if (current_state == NormalState) current_state = WithdrawnState;
2152 } else if (current_state == WithdrawnState) {
2153 // the window is on this workspace and is Withdrawn, so it is waiting to
2154 // be mapped
2155 current_state = NormalState;
2156 }
2157
2158 if (net->flags & AttribOmnipresent && net->attrib & AttribOmnipresent) {
2159 flags.stuck = False;
2160 stick();
2161
2162 // if the window was on another workspace, it was going to be hidden. this
2163 // specifies that the window should be mapped since it is sticky.
2164 if (current_state == WithdrawnState) current_state = NormalState;
2165 }
2166
2167 if (net->flags & AttribMaxHoriz || net->flags & AttribMaxVert) {
2168 int x = net->premax_x, y = net->premax_y;
2169 unsigned int w = net->premax_w, h = net->premax_h;
2170 flags.maximized = 0;
2171
2172 unsigned int m = 0;
2173 if ((net->flags & AttribMaxHoriz) &&
2174 (net->flags & AttribMaxVert))
2175 m = (net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
2176 else if (net->flags & AttribMaxVert)
2177 m = (net->attrib & AttribMaxVert) ? 2 : 0;
2178 else if (net->flags & AttribMaxHoriz)
2179 m = (net->attrib & AttribMaxHoriz) ? 3 : 0;
2180
2181 if (m) maximize(m);
2182
2183 blackbox_attrib.premax_x = x;
2184 blackbox_attrib.premax_y = y;
2185 blackbox_attrib.premax_w = w;
2186 blackbox_attrib.premax_h = h;
2187 }
2188
2189 // with the state set it will then be the map event's job to read the
2190 // window's state and behave accordingly
2191
2192 delete [] net;
2193 }
2194
2195
2196 /*
2197 * Positions the Rect r according the the client window position and
2198 * window gravity.
2199 */
2200 void BlackboxWindow::applyGravity(Rect &r) {
2201 // apply horizontal window gravity
2202 switch (client.win_gravity) {
2203 default:
2204 case NorthWestGravity:
2205 case SouthWestGravity:
2206 case WestGravity:
2207 r.setX(client.rect.x());
2208 break;
2209
2210 case NorthGravity:
2211 case SouthGravity:
2212 case CenterGravity:
2213 r.setX(client.rect.x() - (frame.margin.left + frame.margin.right) / 2);
2214 break;
2215
2216 case NorthEastGravity:
2217 case SouthEastGravity:
2218 case EastGravity:
2219 r.setX(client.rect.x() - frame.margin.left - frame.margin.right);
2220 break;
2221
2222 case ForgetGravity:
2223 case StaticGravity:
2224 r.setX(client.rect.x() - frame.margin.left);
2225 break;
2226 }
2227
2228 // apply vertical window gravity
2229 switch (client.win_gravity) {
2230 default:
2231 case NorthWestGravity:
2232 case NorthEastGravity:
2233 case NorthGravity:
2234 r.setY(client.rect.y());
2235 break;
2236
2237 case CenterGravity:
2238 case EastGravity:
2239 case WestGravity:
2240 r.setY(client.rect.y() - (frame.margin.top + frame.margin.bottom) / 2);
2241 break;
2242
2243 case SouthWestGravity:
2244 case SouthEastGravity:
2245 case SouthGravity:
2246 r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom);
2247 break;
2248
2249 case ForgetGravity:
2250 case StaticGravity:
2251 r.setY(client.rect.y() - frame.margin.top);
2252 break;
2253 }
2254 }
2255
2256
2257 /*
2258 * The reverse of the applyGravity function.
2259 *
2260 * Positions the Rect r according to the frame window position and
2261 * window gravity.
2262 */
2263 void BlackboxWindow::restoreGravity(Rect &r) {
2264 // restore horizontal window gravity
2265 switch (client.win_gravity) {
2266 default:
2267 case NorthWestGravity:
2268 case SouthWestGravity:
2269 case WestGravity:
2270 r.setX(frame.rect.x());
2271 break;
2272
2273 case NorthGravity:
2274 case SouthGravity:
2275 case CenterGravity:
2276 r.setX(frame.rect.x() + (frame.margin.left + frame.margin.right) / 2);
2277 break;
2278
2279 case NorthEastGravity:
2280 case SouthEastGravity:
2281 case EastGravity:
2282 r.setX(frame.rect.x() + frame.margin.left + frame.margin.right);
2283 break;
2284
2285 case ForgetGravity:
2286 case StaticGravity:
2287 r.setX(frame.rect.x() + frame.margin.left);
2288 break;
2289 }
2290
2291 // restore vertical window gravity
2292 switch (client.win_gravity) {
2293 default:
2294 case NorthWestGravity:
2295 case NorthEastGravity:
2296 case NorthGravity:
2297 r.setY(frame.rect.y());
2298 break;
2299
2300 case CenterGravity:
2301 case EastGravity:
2302 case WestGravity:
2303 r.setY(frame.rect.y() + (frame.margin.top + frame.margin.bottom) / 2);
2304 break;
2305
2306 case SouthWestGravity:
2307 case SouthEastGravity:
2308 case SouthGravity:
2309 r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom);
2310 break;
2311
2312 case ForgetGravity:
2313 case StaticGravity:
2314 r.setY(frame.rect.y() + frame.margin.top);
2315 break;
2316 }
2317 }
2318
2319
2320 void BlackboxWindow::redrawLabel(void) const {
2321 if (flags.focused) {
2322 if (frame.flabel)
2323 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2324 frame.label, frame.flabel);
2325 else
2326 XSetWindowBackground(blackbox->getXDisplay(),
2327 frame.label, frame.flabel_pixel);
2328 } else {
2329 if (frame.ulabel)
2330 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2331 frame.label, frame.ulabel);
2332 else
2333 XSetWindowBackground(blackbox->getXDisplay(),
2334 frame.label, frame.ulabel_pixel);
2335 }
2336 XClearWindow(blackbox->getXDisplay(), frame.label);
2337
2338 WindowStyle *style = screen->getWindowStyle();
2339
2340 int pos = frame.bevel_w * 2;
2341 style->doJustify(client.title.c_str(), pos, frame.label_w, frame.bevel_w * 4);
2342 style->font->drawString(frame.label, pos, 1,
2343 (flags.focused ? style->l_text_focus :
2344 style->l_text_unfocus),
2345 client.title);
2346 }
2347
2348
2349 void BlackboxWindow::redrawAllButtons(void) const {
2350 if (frame.iconify_button) redrawIconifyButton(False);
2351 if (frame.maximize_button) redrawMaximizeButton(flags.maximized);
2352 if (frame.close_button) redrawCloseButton(False);
2353 }
2354
2355
2356 void BlackboxWindow::redrawIconifyButton(bool pressed) const {
2357 if (! pressed) {
2358 if (flags.focused) {
2359 if (frame.fbutton)
2360 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2361 frame.iconify_button, frame.fbutton);
2362 else
2363 XSetWindowBackground(blackbox->getXDisplay(),
2364 frame.iconify_button, frame.fbutton_pixel);
2365 } else {
2366 if (frame.ubutton)
2367 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2368 frame.iconify_button, frame.ubutton);
2369 else
2370 XSetWindowBackground(blackbox->getXDisplay(), frame.iconify_button,
2371 frame.ubutton_pixel);
2372 }
2373 } else {
2374 if (frame.pbutton)
2375 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2376 frame.iconify_button, frame.pbutton);
2377 else
2378 XSetWindowBackground(blackbox->getXDisplay(),
2379 frame.iconify_button, frame.pbutton_pixel);
2380 }
2381 XClearWindow(blackbox->getXDisplay(), frame.iconify_button);
2382
2383 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2384 screen->getWindowStyle()->b_pic_unfocus);
2385 XDrawRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(),
2386 2, (frame.button_w - 5), (frame.button_w - 5), 2);
2387 }
2388
2389
2390 void BlackboxWindow::redrawMaximizeButton(bool pressed) const {
2391 if (! pressed) {
2392 if (flags.focused) {
2393 if (frame.fbutton)
2394 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2395 frame.maximize_button, frame.fbutton);
2396 else
2397 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2398 frame.fbutton_pixel);
2399 } else {
2400 if (frame.ubutton)
2401 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2402 frame.maximize_button, frame.ubutton);
2403 else
2404 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2405 frame.ubutton_pixel);
2406 }
2407 } else {
2408 if (frame.pbutton)
2409 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2410 frame.maximize_button, frame.pbutton);
2411 else
2412 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2413 frame.pbutton_pixel);
2414 }
2415 XClearWindow(blackbox->getXDisplay(), frame.maximize_button);
2416
2417 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2418 screen->getWindowStyle()->b_pic_unfocus);
2419 XDrawRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2420 2, 2, (frame.button_w - 5), (frame.button_w - 5));
2421 XDrawLine(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2422 2, 3, (frame.button_w - 3), 3);
2423 }
2424
2425
2426 void BlackboxWindow::redrawCloseButton(bool pressed) const {
2427 if (! pressed) {
2428 if (flags.focused) {
2429 if (frame.fbutton)
2430 XSetWindowBackgroundPixmap(blackbox->getXDisplay(), frame.close_button,
2431 frame.fbutton);
2432 else
2433 XSetWindowBackground(blackbox->getXDisplay(), frame.close_button,
2434 frame.fbutton_pixel);
2435 } else {
2436 if (frame.ubutton)
2437 XSetWindowBackgroundPixmap(blackbox->getXDisplay(), frame.close_button,
2438 frame.ubutton);
2439 else
2440 XSetWindowBackground(blackbox->getXDisplay(), frame.close_button,
2441 frame.ubutton_pixel);
2442 }
2443 } else {
2444 if (frame.pbutton)
2445 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2446 frame.close_button, frame.pbutton);
2447 else
2448 XSetWindowBackground(blackbox->getXDisplay(),
2449 frame.close_button, frame.pbutton_pixel);
2450 }
2451 XClearWindow(blackbox->getXDisplay(), frame.close_button);
2452
2453 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2454 screen->getWindowStyle()->b_pic_unfocus);
2455 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2456 2, 2, (frame.button_w - 3), (frame.button_w - 3));
2457 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2458 2, (frame.button_w - 3), (frame.button_w - 3), 2);
2459 }
2460
2461
2462 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) {
2463 if (re->window != client.window)
2464 return;
2465
2466 #ifdef DEBUG
2467 fprintf(stderr, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2468 client.window);
2469 #endif // DEBUG
2470
2471 switch (current_state) {
2472 case IconicState:
2473 iconify();
2474 break;
2475
2476 case WithdrawnState:
2477 withdraw();
2478 break;
2479
2480 case NormalState:
2481 case InactiveState:
2482 case ZoomState:
2483 default:
2484 show();
2485 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2486 if (! blackbox->isStartup() && (isTransient() || screen->doFocusNew())) {
2487 XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped..
2488 setInputFocus();
2489 }
2490 break;
2491 }
2492 }
2493
2494
2495 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent *ue) {
2496 if (ue->window != client.window)
2497 return;
2498
2499 #ifdef DEBUG
2500 fprintf(stderr, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2501 client.window);
2502 #endif // DEBUG
2503
2504 screen->unmanageWindow(this, False);
2505 }
2506
2507
2508 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent *de) {
2509 if (de->window != client.window)
2510 return;
2511
2512 #ifdef DEBUG
2513 fprintf(stderr, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2514 client.window);
2515 #endif // DEBUG
2516
2517 screen->unmanageWindow(this, False);
2518 }
2519
2520
2521 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent *re) {
2522 if (re->window != client.window || re->parent == frame.plate)
2523 return;
2524
2525 #ifdef DEBUG
2526 fprintf(stderr, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2527 "0x%lx.\n", client.window, re->parent);
2528 #endif // DEBUG
2529
2530 XEvent ev;
2531 ev.xreparent = *re;
2532 XPutBackEvent(blackbox->getXDisplay(), &ev);
2533 screen->unmanageWindow(this, True);
2534 }
2535
2536
2537 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) {
2538 if (pe->state == PropertyDelete)
2539 return;
2540
2541 #ifdef DEBUG
2542 fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2543 client.window);
2544 #endif
2545
2546 switch(pe->atom) {
2547 case XA_WM_CLASS:
2548 case XA_WM_CLIENT_MACHINE:
2549 case XA_WM_COMMAND:
2550 break;
2551
2552 case XA_WM_TRANSIENT_FOR: {
2553 // determine if this is a transient window
2554 getTransientInfo();
2555
2556 // adjust the window decorations based on transience
2557 if (isTransient()) {
2558 decorations &= ~(Decor_Maximize | Decor_Handle);
2559 functions &= ~Func_Maximize;
2560 setAllowedActions();
2561 }
2562
2563 reconfigure();
2564 }
2565 break;
2566
2567 case XA_WM_HINTS:
2568 getWMHints();
2569 break;
2570
2571 case XA_WM_ICON_NAME:
2572 getWMIconName();
2573 if (flags.iconic) screen->propagateWindowName(this);
2574 break;
2575
2576 case XAtom::net_wm_name:
2577 case XA_WM_NAME:
2578 getWMName();
2579
2580 if (decorations & Decor_Titlebar)
2581 redrawLabel();
2582
2583 screen->propagateWindowName(this);
2584 break;
2585
2586 case XA_WM_NORMAL_HINTS: {
2587 getWMNormalHints();
2588
2589 if ((client.normal_hint_flags & PMinSize) &&
2590 (client.normal_hint_flags & PMaxSize)) {
2591 // the window now can/can't resize itself, so the buttons need to be
2592 // regrabbed.
2593 ungrabButtons();
2594 if (client.max_width <= client.min_width &&
2595 client.max_height <= client.min_height) {
2596 decorations &= ~(Decor_Maximize | Decor_Handle);
2597 functions &= ~(Func_Resize | Func_Maximize);
2598 } else {
2599 decorations |= Decor_Maximize | Decor_Handle;
2600 functions |= Func_Resize | Func_Maximize;
2601 }
2602 grabButtons();
2603 setAllowedActions();
2604 }
2605
2606 Rect old_rect = frame.rect;
2607
2608 upsize();
2609
2610 if (old_rect != frame.rect)
2611 reconfigure();
2612
2613 break;
2614 }
2615
2616 default:
2617 if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) {
2618 getWMProtocols();
2619
2620 if ((decorations & Decor_Close) && (! frame.close_button)) {
2621 createCloseButton();
2622 if (decorations & Decor_Titlebar) {
2623 positionButtons(True);
2624 XMapSubwindows(blackbox->getXDisplay(), frame.title);
2625 }
2626 if (windowmenu) windowmenu->reconfigure();
2627 }
2628 } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) {
2629 updateStrut();
2630 }
2631
2632 break;
2633 }
2634 }
2635
2636
2637 void BlackboxWindow::exposeEvent(const XExposeEvent *ee) {
2638 #ifdef DEBUG
2639 fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window);
2640 #endif
2641
2642 if (frame.label == ee->window && (decorations & Decor_Titlebar))
2643 redrawLabel();
2644 else if (frame.close_button == ee->window)
2645 redrawCloseButton(False);
2646 else if (frame.maximize_button == ee->window)
2647 redrawMaximizeButton(flags.maximized);
2648 else if (frame.iconify_button == ee->window)
2649 redrawIconifyButton(False);
2650 }
2651
2652
2653 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) {
2654 if (cr->window != client.window || flags.iconic)
2655 return;
2656
2657 if (cr->value_mask & CWBorderWidth)
2658 client.old_bw = cr->border_width;
2659
2660 if (cr->value_mask & (CWX | CWY | CWWidth | CWHeight)) {
2661 Rect req = frame.rect;
2662
2663 if (cr->value_mask & (CWX | CWY)) {
2664 if (cr->value_mask & CWX)
2665 client.rect.setX(cr->x);
2666 if (cr->value_mask & CWY)
2667 client.rect.setY(cr->y);
2668
2669 applyGravity(req);
2670 }
2671
2672 if (cr->value_mask & CWWidth)
2673 req.setWidth(cr->width + frame.margin.left + frame.margin.right);
2674
2675 if (cr->value_mask & CWHeight)
2676 req.setHeight(cr->height + frame.margin.top + frame.margin.bottom);
2677
2678 configure(req.x(), req.y(), req.width(), req.height());
2679 }
2680
2681 if (cr->value_mask & CWStackMode) {
2682 switch (cr->detail) {
2683 case Below:
2684 case BottomIf:
2685 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
2686 break;
2687
2688 case Above:
2689 case TopIf:
2690 default:
2691 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2692 break;
2693 }
2694 }
2695 }
2696
2697
2698 void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) {
2699 #ifdef DEBUG
2700 fprintf(stderr, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2701 client.window);
2702 #endif
2703
2704 if (frame.maximize_button == be->window) {
2705 redrawMaximizeButton(True);
2706 } else if (be->button == 1 || (be->button == 3 && be->state == Mod1Mask)) {
2707 if (! flags.focused)
2708 setInputFocus();
2709
2710 if (frame.iconify_button == be->window) {
2711 redrawIconifyButton(True);
2712 } else if (frame.close_button == be->window) {
2713 redrawCloseButton(True);
2714 } else if (frame.plate == be->window) {
2715 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
2716
2717 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2718
2719 XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time);
2720 } else {
2721 if (frame.title == be->window || frame.label == be->window) {
2722 if (((be->time - lastButtonPressTime) <=
2723 blackbox->getDoubleClickInterval()) ||
2724 (be->state & ControlMask)) {
2725 lastButtonPressTime = 0;
2726 shade();
2727 } else {
2728 lastButtonPressTime = be->time;
2729 }
2730 }
2731
2732 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
2733
2734 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2735 }
2736 } else if (be->button == 2 && (be->window != frame.iconify_button) &&
2737 (be->window != frame.close_button)) {
2738 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
2739 } else if (windowmenu && be->button == 3 &&
2740 (frame.title == be->window || frame.label == be->window ||
2741 frame.handle == be->window || frame.window == be->window)) {
2742 if (windowmenu->isVisible()) {
2743 windowmenu->hide();
2744 } else {
2745 int mx = be->x_root - windowmenu->getWidth() / 2,
2746 my = be->y_root - windowmenu->getHeight() / 2;
2747
2748 // snap the window menu into a corner/side if necessary
2749 int left_edge, right_edge, top_edge, bottom_edge;
2750
2751 /*
2752 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2753 and height of the menu, as the sizes returned by it do not include
2754 the borders.
2755 */
2756 left_edge = frame.rect.x();
2757 right_edge = frame.rect.right() -
2758 (windowmenu->getWidth() + (frame.border_w * 2) - 1);
2759 top_edge = client.rect.top() - (frame.border_w + frame.mwm_border_w);
2760 bottom_edge = client.rect.bottom() -
2761 (windowmenu->getHeight() + (frame.border_w * 2) - 1) +
2762 (frame.border_w + frame.mwm_border_w);
2763
2764 if (mx < left_edge)
2765 mx = left_edge;
2766 if (mx > right_edge)
2767 mx = right_edge;
2768 if (my < top_edge)
2769 my = top_edge;
2770 if (my > bottom_edge)
2771 my = bottom_edge;
2772
2773 windowmenu->move(mx, my);
2774 windowmenu->show();
2775 XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID());
2776 XRaiseWindow(blackbox->getXDisplay(),
2777 windowmenu->getSendToMenu()->getWindowID());
2778 }
2779 // mouse wheel up
2780 } else if (be->button == 4) {
2781 if ((be->window == frame.label ||
2782 be->window == frame.title) &&
2783 ! flags.shaded)
2784 shade();
2785 // mouse wheel down
2786 } else if (be->button == 5) {
2787 if ((be->window == frame.label ||
2788 be->window == frame.title) &&
2789 flags.shaded)
2790 shade();
2791 }
2792 }
2793
2794
2795 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) {
2796 #ifdef DEBUG
2797 fprintf(stderr, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
2798 client.window);
2799 #endif
2800
2801 if (re->window == frame.maximize_button) {
2802 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
2803 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
2804 maximize(re->button);
2805 } else {
2806 redrawMaximizeButton(flags.maximized);
2807 }
2808 } else if (re->window == frame.iconify_button) {
2809 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
2810 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
2811 iconify();
2812 } else {
2813 redrawIconifyButton(False);
2814 }
2815 } else if (re->window == frame.close_button) {
2816 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
2817 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w)))
2818 close();
2819 redrawCloseButton(False);
2820 } else if (flags.moving) {
2821 endMove();
2822 } else if (flags.resizing) {
2823 endResize();
2824 }
2825 }
2826
2827
2828
2829 void BlackboxWindow::beginMove(int x_root, int y_root) {
2830 assert(! (flags.resizing || flags.moving));
2831
2832 /*
2833 Only one window can be moved/resized at a time. If another window is already
2834 being moved or resized, then stop it before whating to work with this one.
2835 */
2836 BlackboxWindow *changing = blackbox->getChangingWindow();
2837 if (changing && changing != this) {
2838 if (changing->flags.moving)
2839 changing->endMove();
2840 else // if (changing->flags.resizing)
2841 changing->endResize();
2842 }
2843
2844 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
2845 PointerMotionMask | ButtonReleaseMask,
2846 GrabModeAsync, GrabModeAsync,
2847 None, blackbox->getMoveCursor(), CurrentTime);
2848
2849 if (windowmenu && windowmenu->isVisible())
2850 windowmenu->hide();
2851
2852 flags.moving = True;
2853 blackbox->setChangingWindow(this);
2854
2855 if (! screen->doOpaqueMove()) {
2856 XGrabServer(blackbox->getXDisplay());
2857
2858 frame.changing = frame.rect;
2859 screen->showPosition(frame.changing.x(), frame.changing.y());
2860
2861 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
2862 screen->getOpGC(),
2863 frame.changing.x(),
2864 frame.changing.y(),
2865 frame.changing.width() - 1,
2866 frame.changing.height() - 1);
2867 }
2868
2869 frame.grab_x = x_root - frame.rect.x() - frame.border_w;
2870 frame.grab_y = y_root - frame.rect.y() - frame.border_w;
2871 }
2872
2873
2874 void BlackboxWindow::doMove(int x_root, int y_root) {
2875 assert(flags.moving);
2876 assert(blackbox->getChangingWindow() == this);
2877
2878 int dx = x_root - frame.grab_x, dy = y_root - frame.grab_y;
2879 dx -= frame.border_w;
2880 dy -= frame.border_w;
2881
2882 const int snap_distance = screen->getEdgeSnapThreshold();
2883
2884 if (snap_distance) {
2885 // window corners
2886 const int wleft = dx,
2887 wright = dx + frame.rect.width() - 1,
2888 wtop = dy,
2889 wbottom = dy + frame.rect.height() - 1;
2890
2891 if (screen->getWindowToWindowSnap()) {
2892 Workspace *w = screen->getWorkspace(getWorkspaceNumber());
2893 assert(w);
2894
2895 // try snap to another window
2896 for (unsigned int i = 0, c = w->getCount(); i < c; ++i) {
2897 BlackboxWindow *snapwin = w->getWindow(i);
2898 if (snapwin == this)
2899 continue; // don't snap to self
2900
2901 bool snapped = False;
2902
2903 const Rect &winrect = snapwin->frameRect();
2904 int dleft = std::abs(wright - winrect.left()),
2905 dright = std::abs(wleft - winrect.right()),
2906 dtop = std::abs(wbottom - winrect.top()),
2907 dbottom = std::abs(wtop - winrect.bottom());
2908
2909 if (wtop >= (signed)(winrect.y() - frame.rect.height() + 1) &&
2910 wtop < (signed)(winrect.y() + winrect.height() - 1)) {
2911
2912 // snap left of other window?
2913 if (dleft < snap_distance && dleft <= dright) {
2914 dx = winrect.left() - frame.rect.width();
2915 snapped = True;
2916 }
2917 // snap right of other window?
2918 else if (dright < snap_distance) {
2919 dx = winrect.right() + 1;
2920 snapped = True;
2921 }
2922
2923 if (snapped) {
2924 if (screen->getWindowCornerSnap()) {
2925 // try corner-snap to its other sides
2926 dtop = std::abs(wtop - winrect.top());
2927 dbottom = std::abs(wbottom - winrect.bottom());
2928 if (dtop < snap_distance && dtop <= dbottom)
2929 dy = winrect.top();
2930 else if (dbottom < snap_distance)
2931 dy = winrect.bottom() - frame.rect.height() + 1;
2932 }
2933
2934 continue;
2935 }
2936 }
2937
2938 if (wleft >= (signed)(winrect.x() - frame.rect.width() + 1) &&
2939 wleft < (signed)(winrect.x() + winrect.width() - 1)) {
2940
2941 // snap top of other window?
2942 if (dtop < snap_distance && dtop <= dbottom) {
2943 dy = winrect.top() - frame.rect.height();
2944 snapped = True;
2945 }
2946 // snap bottom of other window?
2947 else if (dbottom < snap_distance) {
2948 dy = winrect.bottom() + 1;
2949 snapped = True;
2950 }
2951
2952 if (snapped) {
2953 if (screen->getWindowCornerSnap()) {
2954 // try corner-snap to its other sides
2955 dleft = std::abs(wleft - winrect.left());
2956 dright = std::abs(wright - winrect.right());
2957 if (dleft < snap_distance && dleft <= dright)
2958 dx = winrect.left();
2959 else if (dright < snap_distance)
2960 dx = winrect.right() - frame.rect.width() + 1;
2961 }
2962
2963 continue;
2964 }
2965 }
2966 }
2967 }
2968
2969 // try snap to the screen's available area
2970 Rect srect = screen->availableArea();
2971
2972 int dleft = std::abs(wleft - srect.left()),
2973 dright = std::abs(wright - srect.right()),
2974 dtop = std::abs(wtop - srect.top()),
2975 dbottom = std::abs(wbottom - srect.bottom());
2976
2977 // snap left?
2978 if (dleft < snap_distance && dleft <= dright)
2979 dx = srect.left();
2980 // snap right?
2981 else if (dright < snap_distance)
2982 dx = srect.right() - frame.rect.width() + 1;
2983
2984 // snap top?
2985 if (dtop < snap_distance && dtop <= dbottom)
2986 dy = srect.top();
2987 // snap bottom?
2988 else if (dbottom < snap_distance)
2989 dy = srect.bottom() - frame.rect.height() + 1;
2990
2991 srect = screen->getRect(); // now get the full screen
2992
2993 dleft = std::abs(wleft - srect.left()),
2994 dright = std::abs(wright - srect.right()),
2995 dtop = std::abs(wtop - srect.top()),
2996 dbottom = std::abs(wbottom - srect.bottom());
2997
2998 // snap left?
2999 if (dleft < snap_distance && dleft <= dright)
3000 dx = srect.left();
3001 // snap right?
3002 else if (dright < snap_distance)
3003 dx = srect.right() - frame.rect.width() + 1;
3004
3005 // snap top?
3006 if (dtop < snap_distance && dtop <= dbottom)
3007 dy = srect.top();
3008 // snap bottom?
3009 else if (dbottom < snap_distance)
3010 dy = srect.bottom() - frame.rect.height() + 1;
3011 }
3012
3013 if (screen->doOpaqueMove()) {
3014 configure(dx, dy, frame.rect.width(), frame.rect.height());
3015 } else {
3016 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3017 screen->getOpGC(),
3018 frame.changing.x(),
3019 frame.changing.y(),
3020 frame.changing.width() - 1,
3021 frame.changing.height() - 1);
3022
3023 frame.changing.setPos(dx, dy);
3024
3025 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3026 screen->getOpGC(),
3027 frame.changing.x(),
3028 frame.changing.y(),
3029 frame.changing.width() - 1,
3030 frame.changing.height() - 1);
3031 }
3032
3033 screen->showPosition(dx, dy);
3034 }
3035
3036
3037 void BlackboxWindow::endMove(void) {
3038 assert(flags.moving);
3039 assert(blackbox->getChangingWindow() == this);
3040
3041 flags.moving = False;
3042 blackbox->setChangingWindow(0);
3043
3044 if (! screen->doOpaqueMove()) {
3045 /* when drawing the rubber band, we need to make sure we only draw inside
3046 * the frame... frame.changing_* contain the new coords for the window,
3047 * so we need to subtract 1 from changing_w/changing_h every where we
3048 * draw the rubber band (for both moving and resizing)
3049 */
3050 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3051 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3052 frame.changing.width() - 1, frame.changing.height() - 1);
3053 XUngrabServer(blackbox->getXDisplay());
3054
3055 configure(frame.changing.x(), frame.changing.y(),
3056 frame.changing.width(), frame.changing.height());
3057 } else {
3058 configure(frame.rect.x(), frame.rect.y(),
3059 frame.rect.width(), frame.rect.height());
3060 }
3061 screen->hideGeometry();
3062
3063 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3064
3065 // if there are any left over motions from the move, drop them now
3066 XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
3067 XEvent e;
3068 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
3069 MotionNotify, &e));
3070 }
3071
3072
3073 void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) {
3074 assert(! (flags.resizing || flags.moving));
3075
3076 /*
3077 Only one window can be moved/resized at a time. If another window is already
3078 being moved or resized, then stop it before whating to work with this one.
3079 */
3080 BlackboxWindow *changing = blackbox->getChangingWindow();
3081 if (changing && changing != this) {
3082 if (changing->flags.moving)
3083 changing->endMove();
3084 else // if (changing->flags.resizing)
3085 changing->endResize();
3086 }
3087
3088 resize_dir = dir;
3089
3090 Cursor cursor;
3091 Corner anchor;
3092
3093 switch (resize_dir) {
3094 case BottomLeft:
3095 anchor = TopRight;
3096 cursor = blackbox->getLowerLeftAngleCursor();
3097 break;
3098
3099 case BottomRight:
3100 anchor = TopLeft;
3101 cursor = blackbox->getLowerRightAngleCursor();
3102 break;
3103
3104 case TopLeft:
3105 anchor = BottomRight;
3106 cursor = blackbox->getUpperLeftAngleCursor();
3107 break;
3108
3109 case TopRight:
3110 anchor = BottomLeft;
3111 cursor = blackbox->getUpperRightAngleCursor();
3112 break;
3113
3114 default:
3115 assert(false); // unhandled Corner
3116 return; // unreachable, for the compiler
3117 }
3118
3119 XGrabServer(blackbox->getXDisplay());
3120 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3121 PointerMotionMask | ButtonReleaseMask,
3122 GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
3123
3124 flags.resizing = True;
3125 blackbox->setChangingWindow(this);
3126
3127 int gw, gh;
3128 frame.changing = frame.rect;
3129
3130 constrain(anchor, &gw, &gh);
3131
3132 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3133 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3134 frame.changing.width() - 1, frame.changing.height() - 1);
3135
3136 screen->showGeometry(gw, gh);
3137
3138 frame.grab_x = x_root;
3139 frame.grab_y = y_root;
3140 }
3141
3142
3143 void BlackboxWindow::doResize(int x_root, int y_root) {
3144 assert(flags.resizing);
3145 assert(blackbox->getChangingWindow() == this);
3146
3147 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3148 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3149 frame.changing.width() - 1, frame.changing.height() - 1);
3150
3151 int gw, gh;
3152 Corner anchor;
3153
3154 switch (resize_dir) {
3155 case BottomLeft:
3156 anchor = TopRight;
3157 frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
3158 frame.rect.height() + (y_root - frame.grab_y));
3159 break;
3160 case BottomRight:
3161 anchor = TopLeft;
3162 frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
3163 frame.rect.height() + (y_root - frame.grab_y));
3164 break;
3165 case TopLeft:
3166 anchor = BottomRight;
3167 frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
3168 frame.rect.height() - (y_root - frame.grab_y));
3169 break;
3170 case TopRight:
3171 anchor = BottomLeft;
3172 frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
3173 frame.rect.height() - (y_root - frame.grab_y));
3174 break;
3175
3176 default:
3177 assert(false); // unhandled Corner
3178 return; // unreachable, for the compiler
3179 }
3180
3181 constrain(anchor, &gw, &gh);
3182
3183 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3184 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3185 frame.changing.width() - 1, frame.changing.height() - 1);
3186
3187 screen->showGeometry(gw, gh);
3188 }
3189
3190
3191 void BlackboxWindow::endResize(void) {
3192 assert(flags.resizing);
3193 assert(blackbox->getChangingWindow() == this);
3194
3195 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3196 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3197 frame.changing.width() - 1, frame.changing.height() - 1);
3198 XUngrabServer(blackbox->getXDisplay());
3199
3200 // unset maximized state after resized when fully maximized
3201 if (flags.maximized == 1)
3202 maximize(0);
3203
3204 flags.resizing = False;
3205 blackbox->setChangingWindow(0);
3206
3207 configure(frame.changing.x(), frame.changing.y(),
3208 frame.changing.width(), frame.changing.height());
3209 screen->hideGeometry();
3210
3211 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3212
3213 // if there are any left over motions from the resize, drop them now
3214 XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
3215 XEvent e;
3216 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
3217 MotionNotify, &e));
3218 }
3219
3220
3221 void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
3222 #ifdef DEBUG
3223 fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3224 client.window);
3225 #endif
3226
3227 if (flags.moving) {
3228 doMove(me->x_root, me->y_root);
3229 } else if (flags.resizing) {
3230 doResize(me->x_root, me->y_root);
3231 } else {
3232 if (! flags.resizing && (me->state & Button1Mask) &&
3233 (functions & Func_Move) &&
3234 (frame.title == me->window || frame.label == me->window ||
3235 frame.handle == me->window || frame.window == me->window)) {
3236 beginMove(me->x_root, me->y_root);
3237 } else if ((functions & Func_Resize) &&
3238 (((me->state & Button1Mask) &&
3239 (me->window == frame.right_grip ||
3240 me->window == frame.left_grip)) ||
3241 (me->state & (Mod1Mask | Button3Mask) &&
3242 me->window == frame.window))) {
3243 beginResize(me->x_root, me->y_root,
3244 (me->window == frame.left_grip) ? BottomLeft : BottomRight);
3245 }
3246 }
3247 }
3248
3249
3250 #ifdef SHAPE
3251 void BlackboxWindow::shapeEvent(XShapeEvent *) {
3252 if (blackbox->hasShapeExtensions() && flags.shaped) {
3253 configureShape();
3254 }
3255 }
3256 #endif // SHAPE
3257
3258
3259 bool BlackboxWindow::validateClient(void) const {
3260 XSync(blackbox->getXDisplay(), False);
3261
3262 XEvent e;
3263 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3264 DestroyNotify, &e) ||
3265 XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3266 UnmapNotify, &e)) {
3267 XPutBackEvent(blackbox->getXDisplay(), &e);
3268
3269 return False;
3270 }
3271
3272 return True;
3273 }
3274
3275
3276 void BlackboxWindow::restore(bool remap) {
3277 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeDelete);
3278 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
3279 XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask);
3280
3281 // do not leave a shaded window as an icon unless it was an icon
3282 if (flags.shaded && ! flags.iconic) setState(NormalState);
3283
3284 restoreGravity(client.rect);
3285
3286 XUnmapWindow(blackbox->getXDisplay(), frame.window);
3287 XUnmapWindow(blackbox->getXDisplay(), client.window);
3288
3289 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, client.old_bw);
3290
3291 XEvent ev;
3292 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3293 ReparentNotify, &ev)) {
3294 remap = True;
3295 } else {
3296 // according to the ICCCM - if the client doesn't reparent to
3297 // root, then we have to do it for them
3298 XReparentWindow(blackbox->getXDisplay(), client.window,
3299 screen->getRootWindow(),
3300 client.rect.x(), client.rect.y());
3301 }
3302
3303 if (remap) XMapWindow(blackbox->getXDisplay(), client.window);
3304 }
3305
3306
3307 // timer for autoraise
3308 void BlackboxWindow::timeout(void) {
3309 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3310 }
3311
3312
3313 void BlackboxWindow::changeBlackboxHints(BlackboxHints *net) {
3314 if ((net->flags & AttribShaded) &&
3315 ((blackbox_attrib.attrib & AttribShaded) !=
3316 (net->attrib & AttribShaded)))
3317 shade();
3318
3319 if (flags.visible && // watch out for requests when we can not be seen
3320 (net->flags & (AttribMaxVert | AttribMaxHoriz)) &&
3321 ((blackbox_attrib.attrib & (AttribMaxVert | AttribMaxHoriz)) !=
3322 (net->attrib & (AttribMaxVert | AttribMaxHoriz)))) {
3323 if (flags.maximized) {
3324 maximize(0);
3325 } else {
3326 int button = 0;
3327
3328 if ((net->flags & AttribMaxHoriz) && (net->flags & AttribMaxVert))
3329 button = ((net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0);
3330 else if (net->flags & AttribMaxVert)
3331 button = ((net->attrib & AttribMaxVert) ? 2 : 0);
3332 else if (net->flags & AttribMaxHoriz)
3333 button = ((net->attrib & AttribMaxHoriz) ? 3 : 0);
3334
3335 maximize(button);
3336 }
3337 }
3338
3339 if ((net->flags & AttribOmnipresent) &&
3340 ((blackbox_attrib.attrib & AttribOmnipresent) !=
3341 (net->attrib & AttribOmnipresent)))
3342 stick();
3343
3344 if ((net->flags & AttribWorkspace) &&
3345 (blackbox_attrib.workspace != net->workspace)) {
3346 screen->reassociateWindow(this, net->workspace, True);
3347
3348 if (screen->getCurrentWorkspaceID() != net->workspace) {
3349 withdraw();
3350 } else {
3351 show();
3352 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3353 }
3354 }
3355
3356 if (net->flags & AttribDecoration) {
3357 switch (net->decoration) {
3358 case DecorNone:
3359 // clear all decorations except close
3360 decorations &= Decor_Close;
3361
3362 break;
3363
3364 default:
3365 case DecorNormal:
3366 decorations |= Decor_Titlebar | Decor_Border | Decor_Iconify;
3367
3368 decorations = ((functions & Func_Resize) && !isTransient() ?
3369 decorations | Decor_Handle :
3370 decorations &= ~Decor_Handle);
3371 decorations = (functions & Func_Maximize ?
3372 decorations | Decor_Maximize :
3373 decorations &= ~Decor_Maximize);
3374
3375 break;
3376
3377 case DecorTiny:
3378 decorations |= Decor_Titlebar | Decor_Iconify;
3379 decorations &= ~(Decor_Border | Decor_Handle);
3380
3381 decorations = (functions & Func_Maximize ?
3382 decorations | Decor_Maximize :
3383 decorations &= ~Decor_Maximize);
3384
3385 break;
3386
3387 case DecorTool:
3388 decorations |= Decor_Titlebar;
3389 decorations &= ~(Decor_Iconify | Decor_Border);
3390
3391 decorations = ((functions & Func_Resize) && !isTransient() ?
3392 decorations | Decor_Handle :
3393 decorations &= ~Decor_Handle);
3394 decorations = (functions & Func_Maximize ?
3395 decorations | Decor_Maximize :
3396 decorations &= ~Decor_Maximize);
3397
3398 break;
3399 }
3400
3401 // we can not be shaded if we lack a titlebar
3402 if (flags.shaded && ! (decorations & Decor_Titlebar))
3403 shade();
3404
3405 if (flags.visible && frame.window) {
3406 XMapSubwindows(blackbox->getXDisplay(), frame.window);
3407 XMapWindow(blackbox->getXDisplay(), frame.window);
3408 }
3409
3410 reconfigure();
3411 setState(current_state);
3412 }
3413 }
3414
3415
3416 /*
3417 * Set the sizes of all components of the window frame
3418 * (the window decorations).
3419 * These values are based upon the current style settings and the client
3420 * window's dimensions.
3421 */
3422 void BlackboxWindow::upsize(void) {
3423 frame.bevel_w = screen->getBevelWidth();
3424
3425 if (decorations & Decor_Border) {
3426 frame.border_w = screen->getBorderWidth();
3427 if (! isTransient())
3428 frame.mwm_border_w = screen->getFrameWidth();
3429 else
3430 frame.mwm_border_w = 0;
3431 } else {
3432 frame.mwm_border_w = frame.border_w = 0;
3433 }
3434
3435 if (decorations & Decor_Titlebar) {
3436 // the height of the titlebar is based upon the height of the font being
3437 // used to display the window's title
3438 WindowStyle *style = screen->getWindowStyle();
3439 frame.title_h = style->font->height() + (frame.bevel_w * 2) + 2;
3440
3441 frame.label_h = frame.title_h - (frame.bevel_w * 2);
3442 frame.button_w = (frame.label_h - 2);
3443
3444 // set the top frame margin
3445 frame.margin.top = frame.border_w + frame.title_h +
3446 frame.border_w + frame.mwm_border_w;
3447 } else {
3448 frame.title_h = 0;
3449 frame.label_h = 0;
3450 frame.button_w = 0;
3451
3452 // set the top frame margin
3453 frame.margin.top = frame.border_w + frame.mwm_border_w;
3454 }
3455
3456 // set the left/right frame margin
3457 frame.margin.left = frame.margin.right = frame.border_w + frame.mwm_border_w;
3458
3459 if (decorations & Decor_Handle) {
3460 frame.grip_w = frame.button_w * 2;
3461 frame.handle_h = screen->getHandleWidth();
3462
3463 // set the bottom frame margin
3464 frame.margin.bottom = frame.border_w + frame.handle_h +
3465 frame.border_w + frame.mwm_border_w;
3466 } else {
3467 frame.handle_h = 0;
3468 frame.grip_w = 0;
3469
3470 // set the bottom frame margin
3471 frame.margin.bottom = frame.border_w + frame.mwm_border_w;
3472 }
3473
3474 /*
3475 We first get the normal dimensions and use this to define the inside_w/h
3476 then we modify the height if shading is in effect.
3477 If the shade state is not considered then frame.rect gets reset to the
3478 normal window size on a reconfigure() call resulting in improper
3479 dimensions appearing in move/resize and other events.
3480 */
3481 unsigned int
3482 height = client.rect.height() + frame.margin.top + frame.margin.bottom,
3483 width = client.rect.width() + frame.margin.left + frame.margin.right;
3484
3485 frame.inside_w = width - (frame.border_w * 2);
3486 frame.inside_h = height - (frame.border_w * 2);
3487
3488 if (flags.shaded)
3489 height = frame.title_h + (frame.border_w * 2);
3490 frame.rect.setSize(width, height);
3491 }
3492
3493
3494 /*
3495 * Calculate the size of the client window and constrain it to the
3496 * size specified by the size hints of the client window.
3497 *
3498 * The logical width and height are placed into pw and ph, if they
3499 * are non-zero. Logical size refers to the users perception of
3500 * the window size (for example an xterm resizes in cells, not in pixels).
3501 *
3502 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3503 * Physical geometry refers to the geometry of the window in pixels.
3504 */
3505 void BlackboxWindow::constrain(Corner anchor, int *pw, int *ph) {
3506 // frame.changing represents the requested frame size, we need to
3507 // strip the frame margin off and constrain the client size
3508 frame.changing.setCoords(frame.changing.left() + frame.margin.left,
3509 frame.changing.top() + frame.margin.top,
3510 frame.changing.right() - frame.margin.right,
3511 frame.changing.bottom() - frame.margin.bottom);
3512
3513 int dw = frame.changing.width(), dh = frame.changing.height(),
3514 base_width = (client.base_width) ? client.base_width : client.min_width,
3515 base_height = (client.base_height) ? client.base_height :
3516 client.min_height;
3517
3518 // constrain
3519 if (dw < static_cast<signed>(client.min_width)) dw = client.min_width;
3520 if (dh < static_cast<signed>(client.min_height)) dh = client.min_height;
3521 if (dw > static_cast<signed>(client.max_width)) dw = client.max_width;
3522 if (dh > static_cast<signed>(client.max_height)) dh = client.max_height;
3523
3524 dw -= base_width;
3525 dw /= client.width_inc;
3526 dh -= base_height;
3527 dh /= client.height_inc;
3528
3529 if (pw) {
3530 if (client.width_inc == 1)
3531 *pw = dw + base_width;
3532 else
3533 *pw = dw;
3534 }
3535 if (ph) {
3536 if (client.height_inc == 1)
3537 *ph = dh + base_height;
3538 else
3539 *ph = dh;
3540 }
3541
3542 dw *= client.width_inc;
3543 dw += base_width;
3544 dh *= client.height_inc;
3545 dh += base_height;
3546
3547 frame.changing.setSize(dw, dh);
3548
3549 // add the frame margin back onto frame.changing
3550 frame.changing.setCoords(frame.changing.left() - frame.margin.left,
3551 frame.changing.top() - frame.margin.top,
3552 frame.changing.right() + frame.margin.right,
3553 frame.changing.bottom() + frame.margin.bottom);
3554
3555 // move frame.changing to the specified anchor
3556 int dx = 0,
3557 dy = 0;
3558 switch (anchor) {
3559 case TopLeft:
3560 break;
3561
3562 case TopRight:
3563 dx = frame.rect.right() - frame.changing.right();
3564 break;
3565
3566 case BottomLeft:
3567 dy = frame.rect.bottom() - frame.changing.bottom();
3568 break;
3569
3570 case BottomRight:
3571 dx = frame.rect.right() - frame.changing.right();
3572 dy = frame.rect.bottom() - frame.changing.bottom();
3573 break;
3574
3575 default:
3576 assert(false); // unhandled corner
3577 }
3578 frame.changing.setPos(frame.changing.x() + dx, frame.changing.y() + dy);
3579 }
3580
3581
3582 void WindowStyle::doJustify(const std::string &text, int &start_pos,
3583 unsigned int max_length,
3584 unsigned int modifier) const {
3585 size_t text_len = text.size();
3586 unsigned int length;
3587
3588 do {
3589 length = font->measureString(string(text, 0, text_len)) + modifier;
3590 } while (length > max_length && text_len-- > 0);
3591
3592 switch (justify) {
3593 case RightJustify:
3594 start_pos += max_length - length;
3595 break;
3596
3597 case CenterJustify:
3598 start_pos += (max_length - length) / 2;
3599 break;
3600
3601 case LeftJustify:
3602 default:
3603 break;
3604 }
3605 }
3606
3607
3608 BWindowGroup::BWindowGroup(Blackbox *b, Window _group)
3609 : blackbox(b), group(_group) {
3610 XWindowAttributes wattrib;
3611 if (! XGetWindowAttributes(blackbox->getXDisplay(), group, &wattrib)) {
3612 // group window doesn't seem to exist anymore
3613 delete this;
3614 return;
3615 }
3616
3617 /*
3618 watch for destroy notify on the group window (in addition to
3619 any other events we are looking for)
3620
3621 since some managed windows can also be window group controllers,
3622 we need to make sure that we don't clobber the event mask for the
3623 managed window
3624 */
3625 XSelectInput(blackbox->getXDisplay(), group,
3626 wattrib.your_event_mask | StructureNotifyMask);
3627
3628 blackbox->saveGroupSearch(group, this);
3629 }
3630
3631
3632 BWindowGroup::~BWindowGroup(void) {
3633 blackbox->removeGroupSearch(group);
3634 }
3635
3636
3637 BlackboxWindow *
3638 BWindowGroup::find(BScreen *screen, bool allow_transients) const {
3639 BlackboxWindow *ret = blackbox->getFocusedWindow();
3640
3641 // does the focus window match (or any transient_fors)?
3642 while (ret) {
3643 if (ret->getScreen() == screen && ret->getGroupWindow() == group) {
3644 if (ret->isTransient() && allow_transients) break;
3645 else if (! ret->isTransient()) break;
3646 }
3647
3648 ret = ret->getTransientFor();
3649 }
3650
3651 if (ret) return ret;
3652
3653 // the focus window didn't match, look in the group's window list
3654 BlackboxWindowList::const_iterator it, end = windowList.end();
3655 for (it = windowList.begin(); it != end; ++it) {
3656 ret = *it;
3657 if (ret->getScreen() == screen && ret->getGroupWindow() == group) {
3658 if (ret->isTransient() && allow_transients) break;
3659 else if (! ret->isTransient()) break;
3660 }
3661 }
3662
3663 return ret;
3664 }
This page took 0.217759 seconds and 5 git commands to generate.