]> Dogcows Code - chaz/openbox/blob - src/Window.cc
fix bug where destroying the wrong windows in BlackboxWindow::positionButtons.
[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 "GCCache.hh"
48 #include "Iconmenu.hh"
49 #include "Image.hh"
50 #include "Screen.hh"
51 #include "Toolbar.hh"
52 #include "Util.hh"
53 #include "Window.hh"
54 #include "Windowmenu.hh"
55 #include "Workspace.hh"
56 #include "Slit.hh"
57
58 using std::string;
59
60 /*
61 * Initializes the class with default values/the window's set initial values.
62 */
63 BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
64 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
65 // sizeof(BlackboxWindow));
66
67 #ifdef DEBUG
68 fprintf(stderr, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w);
69 #endif // DEBUG
70
71 // set timer to zero... it is initialized properly later, so we check
72 // if timer is zero in the destructor, and assume that the window is not
73 // fully constructed if timer is zero...
74 timer = 0;
75 blackbox = b;
76 client.window = w;
77 screen = s;
78
79 if (! validateClient()) {
80 delete this;
81 return;
82 }
83
84 // set the eventmask early in the game so that we make sure we get
85 // all the events we are interested in
86 XSetWindowAttributes attrib_set;
87 attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
88 StructureNotifyMask;
89 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
90 ButtonMotionMask;
91 XChangeWindowAttributes(blackbox->getXDisplay(), client.window,
92 CWEventMask|CWDontPropagate, &attrib_set);
93
94 // fetch client size and placement
95 XWindowAttributes wattrib;
96 if ((! XGetWindowAttributes(blackbox->getXDisplay(),
97 client.window, &wattrib)) ||
98 (! wattrib.screen) || wattrib.override_redirect) {
99 #ifdef DEBUG
100 fprintf(stderr,
101 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
102 #endif // DEBUG
103
104 delete this;
105 return;
106 }
107
108 flags.moving = flags.resizing = flags.shaded = flags.visible =
109 flags.iconic = flags.focused = flags.stuck = flags.modal =
110 flags.send_focus_message = flags.shaped = False;
111 flags.maximized = 0;
112
113 blackbox_attrib.workspace = window_number = BSENTINEL;
114
115 blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack
116 = blackbox_attrib.decoration = 0l;
117 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
118 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
119
120 frame.border_w = 1;
121 frame.window = frame.plate = frame.title = frame.handle = None;
122 frame.close_button = frame.iconify_button = frame.maximize_button = None;
123 frame.right_grip = frame.left_grip = None;
124
125 frame.ulabel_pixel = frame.flabel_pixel = frame.utitle_pixel =
126 frame.ftitle_pixel = frame.uhandle_pixel = frame.fhandle_pixel =
127 frame.ubutton_pixel = frame.fbutton_pixel = frame.pbutton_pixel =
128 frame.uborder_pixel = frame.fborder_pixel = frame.ugrip_pixel =
129 frame.fgrip_pixel = 0;
130 frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None;
131 frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None;
132 frame.pbutton = frame.ugrip = frame.fgrip = decorations;
133
134 decorations = Decor_Titlebar | Decor_Border | Decor_Handle |
135 Decor_Iconify | Decor_Maximize;
136 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
137
138 client.wm_hint_flags = client.normal_hint_flags = 0;
139 client.transient_for = 0;
140
141 // get the initial size and location of client window (relative to the
142 // _root window_). This position is the reference point used with the
143 // window's gravity to find the window's initial position.
144 client.rect.setRect(wattrib.x, wattrib.y, wattrib.width, wattrib.height);
145 client.old_bw = wattrib.border_width;
146
147 windowmenu = 0;
148 lastButtonPressTime = 0;
149
150 timer = new BTimer(blackbox, this);
151 timer->setTimeout(blackbox->getAutoRaiseDelay());
152
153 if (! getBlackboxHints())
154 getMWMHints();
155
156 // get size, aspect, minimum/maximum size and other hints set by the
157 // client
158 getWMProtocols();
159 getWMHints();
160 getWMNormalHints();
161
162 if (client.initial_state == WithdrawnState) {
163 screen->getSlit()->addClient(client.window);
164 delete this;
165 return;
166 }
167
168 frame.window = createToplevelWindow();
169 frame.plate = createChildWindow(frame.window);
170 associateClientWindow();
171
172 blackbox->saveWindowSearch(frame.window, this);
173 blackbox->saveWindowSearch(frame.plate, this);
174 blackbox->saveWindowSearch(client.window, this);
175
176 // determine if this is a transient window
177 getTransientInfo();
178
179 // adjust the window decorations based on transience and window sizes
180 if (isTransient()) {
181 decorations &= ~(Decor_Maximize | Decor_Handle);
182 functions &= ~Func_Maximize;
183 }
184
185 if ((client.normal_hint_flags & PMinSize) &&
186 (client.normal_hint_flags & PMaxSize) &&
187 client.max_width <= client.min_width &&
188 client.max_height <= client.min_height) {
189 decorations &= ~(Decor_Maximize | Decor_Handle);
190 functions &= ~(Func_Resize | Func_Maximize);
191 }
192 upsize();
193
194 bool place_window = True;
195 if (blackbox->isStartup() || isTransient() ||
196 client.normal_hint_flags & (PPosition|USPosition)) {
197 setGravityOffsets();
198
199
200 if (blackbox->isStartup() ||
201 client.rect.intersects(screen->availableArea()))
202 place_window = False;
203 }
204
205 if (decorations & Decor_Titlebar)
206 createTitlebar();
207
208 if (decorations & Decor_Handle)
209 createHandle();
210
211 #ifdef SHAPE
212 if (blackbox->hasShapeExtensions() && flags.shaped) {
213 configureShape();
214 }
215 #endif // SHAPE
216
217 if ((! screen->isSloppyFocus()) || screen->doClickRaise()) {
218 // grab button 1 for changing focus/raising
219 blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
220 GrabModeSync, GrabModeSync, frame.plate, None);
221 }
222
223 blackbox->grabButton(Button1, Mod1Mask, frame.window, True,
224 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
225 GrabModeAsync, frame.window, blackbox->getMoveCursor());
226 blackbox->grabButton(Button2, Mod1Mask, frame.window, True,
227 ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
228 frame.window, None);
229 blackbox->grabButton(Button3, Mod1Mask, frame.window, True,
230 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
231 GrabModeAsync, frame.window,
232 blackbox->getLowerRightAngleCursor());
233
234 positionWindows();
235 decorate();
236
237 if (decorations & Decor_Titlebar)
238 XMapSubwindows(blackbox->getXDisplay(), frame.title);
239 XMapSubwindows(blackbox->getXDisplay(), frame.window);
240
241 windowmenu = new Windowmenu(this);
242
243 if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
244 screen->getCurrentWorkspace()->addWindow(this, place_window);
245 else
246 screen->getWorkspace(blackbox_attrib.workspace)->
247 addWindow(this, place_window);
248
249 if (! place_window) {
250 // don't need to call configure if we are letting the workspace
251 // place the window
252 configure(frame.rect.x(), frame.rect.y(),
253 frame.rect.width(), frame.rect.height());
254 }
255
256 if (flags.shaded) {
257 flags.shaded = False;
258 shade();
259 }
260
261 if (flags.maximized && (functions & Func_Maximize)) {
262 remaximize();
263 }
264
265 setFocusFlag(False);
266 }
267
268
269 BlackboxWindow::~BlackboxWindow(void) {
270
271 #ifdef DEBUG
272 fprintf(stderr, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
273 client.window);
274 #endif // DEBUG
275
276 if (! timer) // window not managed...
277 return;
278
279 if (flags.moving || flags.resizing) {
280 screen->hideGeometry();
281 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
282 }
283
284 delete timer;
285
286 delete windowmenu;
287
288 if (client.window_group) {
289 BWindowGroup *group = blackbox->searchGroup(client.window_group);
290 if (group) group->removeWindow(this);
291 }
292
293 // remove ourselves from our transient_for
294 if (isTransient()) {
295 if (client.transient_for != (BlackboxWindow *) ~0ul) {
296 client.transient_for->client.transientList.remove(this);
297 }
298 client.transient_for = (BlackboxWindow*) 0;
299 }
300
301 if (client.transientList.size() > 0) {
302 // reset transient_for for all transients
303 BlackboxWindowList::iterator it, end = client.transientList.end();
304 for (it = client.transientList.begin(); it != end; ++it) {
305 (*it)->client.transient_for = (BlackboxWindow*) 0;
306 }
307 }
308
309 if (frame.title)
310 destroyTitlebar();
311
312 if (frame.handle)
313 destroyHandle();
314
315 if (frame.plate) {
316 blackbox->removeWindowSearch(frame.plate);
317 XDestroyWindow(blackbox->getXDisplay(), frame.plate);
318 }
319
320 if (frame.window) {
321 blackbox->removeWindowSearch(frame.window);
322 XDestroyWindow(blackbox->getXDisplay(), frame.window);
323 }
324
325 blackbox->removeWindowSearch(client.window);
326 }
327
328
329 /*
330 * Creates a new top level window, with a given location, size, and border
331 * width.
332 * Returns: the newly created window
333 */
334 Window BlackboxWindow::createToplevelWindow(void) {
335 XSetWindowAttributes attrib_create;
336 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
337 CWOverrideRedirect | CWEventMask;
338
339 attrib_create.background_pixmap = None;
340 attrib_create.colormap = screen->getColormap();
341 attrib_create.override_redirect = True;
342 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
343 ButtonMotionMask | EnterWindowMask;
344
345 return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(),
346 -1, -1, 1, 1, frame.border_w, screen->getDepth(),
347 InputOutput, screen->getVisual(), create_mask,
348 &attrib_create);
349 }
350
351
352 /*
353 * Creates a child window, and optionally associates a given cursor with
354 * the new window.
355 */
356 Window BlackboxWindow::createChildWindow(Window parent, Cursor cursor) {
357 XSetWindowAttributes attrib_create;
358 unsigned long create_mask = CWBackPixmap | CWBorderPixel |
359 CWEventMask;
360
361 attrib_create.background_pixmap = None;
362 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
363 ButtonMotionMask | ExposureMask;
364
365 if (cursor) {
366 create_mask |= CWCursor;
367 attrib_create.cursor = cursor;
368 }
369
370 return XCreateWindow(blackbox->getXDisplay(), parent, 0, 0, 1, 1, 0,
371 screen->getDepth(), InputOutput, screen->getVisual(),
372 create_mask, &attrib_create);
373 }
374
375
376 void BlackboxWindow::associateClientWindow(void) {
377 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0);
378 getWMName();
379 getWMIconName();
380
381 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert);
382
383 XSelectInput(blackbox->getXDisplay(), frame.plate, SubstructureRedirectMask);
384
385 XGrabServer(blackbox->getXDisplay());
386 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
387 XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0);
388 XSelectInput(blackbox->getXDisplay(), client.window,
389 PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
390 XUngrabServer(blackbox->getXDisplay());
391
392 XRaiseWindow(blackbox->getXDisplay(), frame.plate);
393 XMapSubwindows(blackbox->getXDisplay(), frame.plate);
394
395
396 #ifdef SHAPE
397 if (blackbox->hasShapeExtensions()) {
398 XShapeSelectInput(blackbox->getXDisplay(), client.window,
399 ShapeNotifyMask);
400
401 Bool shaped = False;
402 int foo;
403 unsigned int ufoo;
404
405 XShapeQueryExtents(blackbox->getXDisplay(), client.window, &shaped,
406 &foo, &foo, &ufoo, &ufoo, &foo, &foo, &foo,
407 &ufoo, &ufoo);
408 flags.shaped = shaped;
409 }
410 #endif // SHAPE
411 }
412
413
414 void BlackboxWindow::decorate(void) {
415 BTexture* texture;
416
417 texture = &(screen->getWindowStyle()->b_focus);
418 frame.fbutton = texture->render(frame.button_w, frame.button_w,
419 frame.fbutton);
420 if (! frame.fbutton)
421 frame.fbutton_pixel = texture->color().pixel();
422
423 texture = &(screen->getWindowStyle()->b_unfocus);
424 frame.ubutton = texture->render(frame.button_w, frame.button_w,
425 frame.ubutton);
426 if (! frame.ubutton)
427 frame.ubutton_pixel = texture->color().pixel();
428
429 texture = &(screen->getWindowStyle()->b_pressed);
430 frame.pbutton = texture->render(frame.button_w, frame.button_w,
431 frame.pbutton);
432 if (! frame.pbutton)
433 frame.pbutton_pixel = texture->color().pixel();
434
435 if (decorations & Decor_Titlebar) {
436 texture = &(screen->getWindowStyle()->t_focus);
437 frame.ftitle = texture->render(frame.inside_w, frame.title_h,
438 frame.ftitle);
439 if (! frame.ftitle)
440 frame.ftitle_pixel = texture->color().pixel();
441
442 texture = &(screen->getWindowStyle()->t_unfocus);
443 frame.utitle = texture->render(frame.inside_w, frame.title_h,
444 frame.utitle);
445 if (! frame.utitle)
446 frame.utitle_pixel = texture->color().pixel();
447
448 XSetWindowBorder(blackbox->getXDisplay(), frame.title,
449 screen->getBorderColor()->pixel());
450
451 decorateLabel();
452 }
453
454 if (decorations & Decor_Border) {
455 frame.fborder_pixel = screen->getWindowStyle()->f_focus.pixel();
456 frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.pixel();
457 blackbox_attrib.flags |= AttribDecoration;
458 blackbox_attrib.decoration = DecorNormal;
459 } else {
460 blackbox_attrib.flags |= AttribDecoration;
461 blackbox_attrib.decoration = DecorNone;
462 }
463
464 if (decorations & Decor_Handle) {
465 texture = &(screen->getWindowStyle()->h_focus);
466 frame.fhandle = texture->render(frame.inside_w, frame.handle_h,
467 frame.fhandle);
468 if (! frame.fhandle)
469 frame.fhandle_pixel = texture->color().pixel();
470
471 texture = &(screen->getWindowStyle()->h_unfocus);
472 frame.uhandle = texture->render(frame.inside_w, frame.handle_h,
473 frame.uhandle);
474 if (! frame.uhandle)
475 frame.uhandle_pixel = texture->color().pixel();
476
477 texture = &(screen->getWindowStyle()->g_focus);
478 frame.fgrip = texture->render(frame.grip_w, frame.handle_h, frame.fgrip);
479 if (! frame.fgrip)
480 frame.fgrip_pixel = texture->color().pixel();
481
482 texture = &(screen->getWindowStyle()->g_unfocus);
483 frame.ugrip = texture->render(frame.grip_w, frame.handle_h, frame.ugrip);
484 if (! frame.ugrip)
485 frame.ugrip_pixel = texture->color().pixel();
486
487 XSetWindowBorder(blackbox->getXDisplay(), frame.handle,
488 screen->getBorderColor()->pixel());
489 XSetWindowBorder(blackbox->getXDisplay(), frame.left_grip,
490 screen->getBorderColor()->pixel());
491 XSetWindowBorder(blackbox->getXDisplay(), frame.right_grip,
492 screen->getBorderColor()->pixel());
493 }
494
495 XSetWindowBorder(blackbox->getXDisplay(), frame.window,
496 screen->getBorderColor()->pixel());
497 }
498
499
500 void BlackboxWindow::decorateLabel(void) {
501 BTexture *texture;
502
503 texture = &(screen->getWindowStyle()->l_focus);
504 frame.flabel = texture->render(frame.label_w, frame.label_h, frame.flabel);
505 if (! frame.flabel)
506 frame.flabel_pixel = texture->color().pixel();
507
508 texture = &(screen->getWindowStyle()->l_unfocus);
509 frame.ulabel = texture->render(frame.label_w, frame.label_h, frame.ulabel);
510 if (! frame.ulabel)
511 frame.ulabel_pixel = texture->color().pixel();
512 }
513
514
515 void BlackboxWindow::createHandle(void) {
516 frame.handle = createChildWindow(frame.window);
517 blackbox->saveWindowSearch(frame.handle, this);
518
519 frame.left_grip =
520 createChildWindow(frame.handle, blackbox->getLowerLeftAngleCursor());
521 blackbox->saveWindowSearch(frame.left_grip, this);
522
523 frame.right_grip =
524 createChildWindow(frame.handle, blackbox->getLowerRightAngleCursor());
525 blackbox->saveWindowSearch(frame.right_grip, this);
526 }
527
528
529 void BlackboxWindow::destroyHandle(void) {
530 if (frame.fhandle)
531 screen->getImageControl()->removeImage(frame.fhandle);
532
533 if (frame.uhandle)
534 screen->getImageControl()->removeImage(frame.uhandle);
535
536 if (frame.fgrip)
537 screen->getImageControl()->removeImage(frame.fgrip);
538
539 if (frame.ugrip)
540 screen->getImageControl()->removeImage(frame.ugrip);
541
542 blackbox->removeWindowSearch(frame.left_grip);
543 blackbox->removeWindowSearch(frame.right_grip);
544
545 XDestroyWindow(blackbox->getXDisplay(), frame.left_grip);
546 XDestroyWindow(blackbox->getXDisplay(), frame.right_grip);
547 frame.left_grip = frame.right_grip = None;
548
549 blackbox->removeWindowSearch(frame.handle);
550 XDestroyWindow(blackbox->getXDisplay(), frame.handle);
551 frame.handle = None;
552 }
553
554
555 void BlackboxWindow::createTitlebar(void) {
556 frame.title = createChildWindow(frame.window);
557 frame.label = createChildWindow(frame.title);
558 blackbox->saveWindowSearch(frame.title, this);
559 blackbox->saveWindowSearch(frame.label, this);
560
561 if (decorations & Decor_Iconify) createIconifyButton();
562 if (decorations & Decor_Maximize) createMaximizeButton();
563 if (decorations & Decor_Close) createCloseButton();
564 }
565
566
567 void BlackboxWindow::destroyTitlebar(void) {
568 if (frame.close_button)
569 destroyCloseButton();
570
571 if (frame.iconify_button)
572 destroyIconifyButton();
573
574 if (frame.maximize_button)
575 destroyMaximizeButton();
576
577 if (frame.ftitle)
578 screen->getImageControl()->removeImage(frame.ftitle);
579
580 if (frame.utitle)
581 screen->getImageControl()->removeImage(frame.utitle);
582
583 if (frame.flabel)
584 screen->getImageControl()->removeImage(frame.flabel);
585
586 if( frame.ulabel)
587 screen->getImageControl()->removeImage(frame.ulabel);
588
589 if (frame.fbutton)
590 screen->getImageControl()->removeImage(frame.fbutton);
591
592 if (frame.ubutton)
593 screen->getImageControl()->removeImage(frame.ubutton);
594
595 if (frame.pbutton)
596 screen->getImageControl()->removeImage(frame.pbutton);
597
598 blackbox->removeWindowSearch(frame.title);
599 blackbox->removeWindowSearch(frame.label);
600
601 XDestroyWindow(blackbox->getXDisplay(), frame.label);
602 XDestroyWindow(blackbox->getXDisplay(), frame.title);
603 frame.title = frame.label = None;
604 }
605
606
607 void BlackboxWindow::createCloseButton(void) {
608 if (frame.title != None) {
609 frame.close_button = createChildWindow(frame.title);
610 blackbox->saveWindowSearch(frame.close_button, this);
611 }
612 }
613
614
615 void BlackboxWindow::destroyCloseButton(void) {
616 blackbox->removeWindowSearch(frame.close_button);
617 XDestroyWindow(blackbox->getXDisplay(), frame.close_button);
618 frame.close_button = None;
619 }
620
621
622 void BlackboxWindow::createIconifyButton(void) {
623 if (frame.title != None) {
624 frame.iconify_button = createChildWindow(frame.title);
625 blackbox->saveWindowSearch(frame.iconify_button, this);
626 }
627 }
628
629
630 void BlackboxWindow::destroyIconifyButton(void) {
631 blackbox->removeWindowSearch(frame.iconify_button);
632 XDestroyWindow(blackbox->getXDisplay(), frame.iconify_button);
633 frame.iconify_button = None;
634 }
635
636
637 void BlackboxWindow::createMaximizeButton(void) {
638 if (frame.title != None) {
639 frame.maximize_button = createChildWindow(frame.title);
640 blackbox->saveWindowSearch(frame.maximize_button, this);
641 }
642 }
643
644
645 void BlackboxWindow::destroyMaximizeButton(void) {
646 blackbox->removeWindowSearch(frame.maximize_button);
647 XDestroyWindow(blackbox->getXDisplay(), frame.maximize_button);
648 frame.maximize_button = None;
649 }
650
651
652 void BlackboxWindow::positionButtons(bool redecorate_label) {
653 string layout = blackbox->getTitlebarLayout();
654 string parsed;
655
656 bool hasclose, hasiconify, hasmaximize, haslabel;
657 hasclose = hasiconify = hasmaximize = haslabel = false;
658
659 string::const_iterator it, end;
660 for (it = layout.begin(), end = layout.end(); it != end; ++it) {
661 switch(*it) {
662 case 'C':
663 if (! hasclose && (decorations & Decor_Close)) {
664 hasclose = true;
665 parsed += *it;
666 }
667 break;
668 case 'I':
669 if (! hasiconify && (decorations & Decor_Iconify)) {
670 hasiconify = true;
671 parsed += *it;
672 }
673 break;
674 case 'M':
675 if (! hasmaximize && (decorations & Decor_Maximize)) {
676 hasmaximize = true;
677 parsed += *it;
678 }
679 break;
680 case 'L':
681 if (! haslabel) {
682 haslabel = true;
683 parsed += *it;
684 }
685 }
686 }
687 if (! hasclose && frame.close_button)
688 destroyCloseButton();
689 if (! hasiconify && frame.iconify_button)
690 destroyIconifyButton();
691 if (! hasmaximize && frame.maximize_button)
692 destroyMaximizeButton();
693 if (! haslabel)
694 parsed += 'L'; // require that the label be in the layout
695
696 const unsigned int bsep = frame.bevel_w + 1; // separation between elements
697 const unsigned int by = frame.bevel_w + 1;
698 const unsigned int ty = frame.bevel_w;
699
700 frame.label_w = frame.inside_w - bsep * 2 -
701 (frame.button_w + bsep) * (parsed.size() - 1);
702
703 unsigned int x = bsep;
704 for (it = parsed.begin(), end = parsed.end(); it != end; ++it) {
705 switch(*it) {
706 case 'C':
707 if (!frame.close_button) createCloseButton();
708 XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, x, by,
709 frame.button_w, frame.button_w);
710 x += frame.button_w + bsep;
711 break;
712 case 'I':
713 if (!frame.iconify_button) createIconifyButton();
714 XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, x, by,
715 frame.button_w, frame.button_w);
716 x += frame.button_w + bsep;
717 break;
718 case 'M':
719 if (!frame.maximize_button) createMaximizeButton();
720 XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by,
721 frame.button_w, frame.button_w);
722 x += frame.button_w + bsep;
723 break;
724 case 'L':
725 XMoveResizeWindow(blackbox->getXDisplay(), frame.label, x, ty,
726 frame.label_w, frame.label_h);
727 x += frame.label_w + bsep;
728 break;
729 }
730 }
731
732 if (redecorate_label) decorateLabel();
733 redrawLabel();
734 redrawAllButtons();
735 }
736
737
738 void BlackboxWindow::reconfigure(void) {
739 upsize();
740
741 client.rect.setPos(frame.rect.left() + frame.margin.left,
742 frame.rect.top() + frame.margin.top);
743
744 positionWindows();
745 decorate();
746
747 XClearWindow(blackbox->getXDisplay(), frame.window);
748 setFocusFlag(flags.focused);
749
750 configure(frame.rect.x(), frame.rect.y(),
751 frame.rect.width(), frame.rect.height());
752
753 if (windowmenu) {
754 windowmenu->move(windowmenu->getX(), frame.rect.y() + frame.title_h);
755 windowmenu->reconfigure();
756 }
757 }
758
759
760 void BlackboxWindow::updateFocusModel(void) {
761 if ((! screen->isSloppyFocus()) || screen->doClickRaise()) {
762 // grab button 1 for changing focus/raising
763 blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
764 GrabModeSync, GrabModeSync, None, None);
765 } else {
766 blackbox->ungrabButton(Button1, 0, frame.plate);
767 }
768 }
769
770
771 void BlackboxWindow::positionWindows(void) {
772 XMoveResizeWindow(blackbox->getXDisplay(), frame.window,
773 frame.rect.x(), frame.rect.y(), frame.inside_w,
774 (flags.shaded) ? frame.title_h : frame.inside_h);
775 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.window, frame.border_w);
776 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.plate,
777 frame.mwm_border_w);
778 XMoveResizeWindow(blackbox->getXDisplay(), frame.plate,
779 frame.margin.left - frame.mwm_border_w - frame.border_w,
780 frame.margin.top - frame.mwm_border_w - frame.border_w,
781 client.rect.width(), client.rect.height());
782 XMoveResizeWindow(blackbox->getXDisplay(), client.window,
783 0, 0, client.rect.width(), client.rect.height());
784
785 if (decorations & Decor_Titlebar) {
786 if (frame.title == None) createTitlebar();
787
788 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.title,
789 frame.border_w);
790 XMoveResizeWindow(blackbox->getXDisplay(), frame.title, -frame.border_w,
791 -frame.border_w, frame.inside_w, frame.title_h);
792
793 positionButtons();
794 XMapSubwindows(blackbox->getXDisplay(), frame.title);
795 XMapWindow(blackbox->getXDisplay(), frame.title);
796 } else if (frame.title) {
797 destroyTitlebar();
798 }
799 if (decorations & Decor_Handle) {
800 if (frame.handle == None) createHandle();
801 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.handle,
802 frame.border_w);
803 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.left_grip,
804 frame.border_w);
805 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.right_grip,
806 frame.border_w);
807
808 XMoveResizeWindow(blackbox->getXDisplay(), frame.handle,
809 -frame.border_w,
810 frame.rect.height() - frame.margin.bottom +
811 frame.mwm_border_w - frame.border_w,
812 frame.inside_w, frame.handle_h);
813 XMoveResizeWindow(blackbox->getXDisplay(), frame.left_grip,
814 -frame.border_w, -frame.border_w,
815 frame.grip_w, frame.handle_h);
816 XMoveResizeWindow(blackbox->getXDisplay(), frame.right_grip,
817 frame.inside_w - frame.grip_w - frame.border_w,
818 -frame.border_w, frame.grip_w, frame.handle_h);
819 XMapSubwindows(blackbox->getXDisplay(), frame.handle);
820 XMapWindow(blackbox->getXDisplay(), frame.handle);
821 } else if (frame.handle) {
822 destroyHandle();
823 }
824 }
825
826
827 void BlackboxWindow::getWMName(void) {
828 XTextProperty text_prop;
829
830 if (XGetWMName(blackbox->getXDisplay(), client.window, &text_prop)) {
831 client.title = textPropertyToString(blackbox->getXDisplay(), text_prop);
832 if (client.title.empty())
833 client.title = i18n(WindowSet, WindowUnnamed, "Unnamed");
834 XFree((char *) text_prop.value);
835 } else {
836 client.title = i18n(WindowSet, WindowUnnamed, "Unnamed");
837 }
838 }
839
840
841 void BlackboxWindow::getWMIconName(void) {
842 XTextProperty text_prop;
843
844 if (XGetWMIconName(blackbox->getXDisplay(), client.window, &text_prop)) {
845 client.icon_title =
846 textPropertyToString(blackbox->getXDisplay(), text_prop);
847 if (client.icon_title.empty())
848 client.icon_title = client.title;
849 XFree((char *) text_prop.value);
850 } else {
851 client.icon_title = client.title;
852 }
853 }
854
855
856 /*
857 * Retrieve which WM Protocols are supported by the client window.
858 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
859 * window's decorations and allow the close behavior.
860 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
861 * this.
862 */
863 void BlackboxWindow::getWMProtocols(void) {
864 Atom *proto;
865 int num_return = 0;
866
867 if (XGetWMProtocols(blackbox->getXDisplay(), client.window,
868 &proto, &num_return)) {
869 for (int i = 0; i < num_return; ++i) {
870 if (proto[i] == blackbox->getWMDeleteAtom()) {
871 decorations |= Decor_Close;
872 functions |= Func_Close;
873 } else if (proto[i] == blackbox->getWMTakeFocusAtom())
874 flags.send_focus_message = True;
875 else if (proto[i] == blackbox->getBlackboxStructureMessagesAtom())
876 screen->addNetizen(new Netizen(screen, client.window));
877 }
878
879 XFree(proto);
880 }
881 }
882
883
884 /*
885 * Gets the value of the WM_HINTS property.
886 * If the property is not set, then use a set of default values.
887 */
888 void BlackboxWindow::getWMHints(void) {
889 focus_mode = F_Passive;
890 client.initial_state = NormalState;
891
892 // remove from current window group
893 if (client.window_group) {
894 BWindowGroup *group = blackbox->searchGroup(client.window_group);
895 if (group) group->removeWindow(this);
896 }
897 client.window_group = None;
898
899 XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), client.window);
900 if (! wmhint) {
901 return;
902 }
903
904 if (wmhint->flags & InputHint) {
905 if (wmhint->input == True) {
906 if (flags.send_focus_message)
907 focus_mode = F_LocallyActive;
908 } else {
909 if (flags.send_focus_message)
910 focus_mode = F_GloballyActive;
911 else
912 focus_mode = F_NoInput;
913 }
914 }
915
916 if (wmhint->flags & StateHint)
917 client.initial_state = wmhint->initial_state;
918
919 if (wmhint->flags & WindowGroupHint) {
920 client.window_group = wmhint->window_group;
921
922 // add window to the appropriate group
923 BWindowGroup *group = blackbox->searchGroup(client.window_group);
924 if (! group) // no group found, create it!
925 group = new BWindowGroup(blackbox, client.window_group);
926 group->addWindow(this);
927 }
928
929 client.wm_hint_flags = wmhint->flags;
930 XFree(wmhint);
931 }
932
933
934 /*
935 * Gets the value of the WM_NORMAL_HINTS property.
936 * If the property is not set, then use a set of default values.
937 */
938 void BlackboxWindow::getWMNormalHints(void) {
939 long icccm_mask;
940 XSizeHints sizehint;
941
942 client.min_width = client.min_height =
943 client.width_inc = client.height_inc = 1;
944 client.base_width = client.base_height = 0;
945
946 /*
947 use the full screen, not the strut modified size. otherwise when the
948 availableArea changes max_width/height will be incorrect and lead to odd
949 rendering bugs.
950 */
951 const Rect& screen_area = screen->getRect();
952 client.max_width = screen_area.width();
953
954 client.max_height = screen_area.height();
955 client.min_aspect_x = client.min_aspect_y =
956 client.max_aspect_x = client.max_aspect_y = 1;
957 client.win_gravity = NorthWestGravity;
958
959 if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window,
960 &sizehint, &icccm_mask))
961 return;
962
963 client.normal_hint_flags = sizehint.flags;
964
965 if (sizehint.flags & PMinSize) {
966 client.min_width = sizehint.min_width;
967 client.min_height = sizehint.min_height;
968 }
969
970 if (sizehint.flags & PMaxSize) {
971 client.max_width = sizehint.max_width;
972 client.max_height = sizehint.max_height;
973 }
974
975 if (sizehint.flags & PResizeInc) {
976 client.width_inc = sizehint.width_inc;
977 client.height_inc = sizehint.height_inc;
978 }
979
980 if (sizehint.flags & PAspect) {
981 client.min_aspect_x = sizehint.min_aspect.x;
982 client.min_aspect_y = sizehint.min_aspect.y;
983 client.max_aspect_x = sizehint.max_aspect.x;
984 client.max_aspect_y = sizehint.max_aspect.y;
985 }
986
987 if (sizehint.flags & PBaseSize) {
988 client.base_width = sizehint.base_width;
989 client.base_height = sizehint.base_height;
990 }
991
992 if (sizehint.flags & PWinGravity)
993 client.win_gravity = sizehint.win_gravity;
994 }
995
996
997 /*
998 * Gets the MWM hints for the class' contained window.
999 * This is used while initializing the window to its first state, and not
1000 * thereafter.
1001 * Returns: true if the MWM hints are successfully retreived and applied;
1002 * false if they are not.
1003 */
1004 void BlackboxWindow::getMWMHints(void) {
1005 int format;
1006 Atom atom_return;
1007 unsigned long num, len;
1008 MwmHints *mwm_hint = 0;
1009
1010 int ret = XGetWindowProperty(blackbox->getXDisplay(), client.window,
1011 blackbox->getMotifWMHintsAtom(), 0,
1012 PropMwmHintsElements, False,
1013 blackbox->getMotifWMHintsAtom(), &atom_return,
1014 &format, &num, &len,
1015 (unsigned char **) &mwm_hint);
1016
1017 if (ret != Success || ! mwm_hint || num != PropMwmHintsElements)
1018 return;
1019
1020 if (mwm_hint->flags & MwmHintsDecorations) {
1021 if (mwm_hint->decorations & MwmDecorAll) {
1022 decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
1023 Decor_Iconify | Decor_Maximize | Decor_Close;
1024 } else {
1025 decorations = 0;
1026
1027 if (mwm_hint->decorations & MwmDecorBorder)
1028 decorations |= Decor_Border;
1029 if (mwm_hint->decorations & MwmDecorHandle)
1030 decorations |= Decor_Handle;
1031 if (mwm_hint->decorations & MwmDecorTitle)
1032 decorations |= Decor_Titlebar;
1033 if (mwm_hint->decorations & MwmDecorIconify)
1034 decorations |= Decor_Iconify;
1035 if (mwm_hint->decorations & MwmDecorMaximize)
1036 decorations |= Decor_Maximize;
1037 }
1038 }
1039
1040 if (mwm_hint->flags & MwmHintsFunctions) {
1041 if (mwm_hint->functions & MwmFuncAll) {
1042 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize |
1043 Func_Close;
1044 } else {
1045 functions = 0;
1046
1047 if (mwm_hint->functions & MwmFuncResize)
1048 functions |= Func_Resize;
1049 if (mwm_hint->functions & MwmFuncMove)
1050 functions |= Func_Move;
1051 if (mwm_hint->functions & MwmFuncIconify)
1052 functions |= Func_Iconify;
1053 if (mwm_hint->functions & MwmFuncMaximize)
1054 functions |= Func_Maximize;
1055 if (mwm_hint->functions & MwmFuncClose)
1056 functions |= Func_Close;
1057 }
1058 }
1059 XFree(mwm_hint);
1060 }
1061
1062
1063 /*
1064 * Gets the blackbox hints from the class' contained window.
1065 * This is used while initializing the window to its first state, and not
1066 * thereafter.
1067 * Returns: true if the hints are successfully retreived and applied; false if
1068 * they are not.
1069 */
1070 bool BlackboxWindow::getBlackboxHints(void) {
1071 int format;
1072 Atom atom_return;
1073 unsigned long num, len;
1074 BlackboxHints *blackbox_hint = 0;
1075
1076 int ret = XGetWindowProperty(blackbox->getXDisplay(), client.window,
1077 blackbox->getBlackboxHintsAtom(), 0,
1078 PropBlackboxHintsElements, False,
1079 blackbox->getBlackboxHintsAtom(), &atom_return,
1080 &format, &num, &len,
1081 (unsigned char **) &blackbox_hint);
1082 if (ret != Success || ! blackbox_hint || num != PropBlackboxHintsElements)
1083 return False;
1084
1085 if (blackbox_hint->flags & AttribShaded)
1086 flags.shaded = (blackbox_hint->attrib & AttribShaded);
1087
1088 if ((blackbox_hint->flags & AttribMaxHoriz) &&
1089 (blackbox_hint->flags & AttribMaxVert))
1090 flags.maximized = (blackbox_hint->attrib &
1091 (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1092 else if (blackbox_hint->flags & AttribMaxVert)
1093 flags.maximized = (blackbox_hint->attrib & AttribMaxVert) ? 2 : 0;
1094 else if (blackbox_hint->flags & AttribMaxHoriz)
1095 flags.maximized = (blackbox_hint->attrib & AttribMaxHoriz) ? 3 : 0;
1096
1097 if (blackbox_hint->flags & AttribOmnipresent)
1098 flags.stuck = (blackbox_hint->attrib & AttribOmnipresent);
1099
1100 if (blackbox_hint->flags & AttribWorkspace)
1101 blackbox_attrib.workspace = blackbox_hint->workspace;
1102
1103 // if (blackbox_hint->flags & AttribStack)
1104 // don't yet have always on top/bottom for blackbox yet... working
1105 // on that
1106
1107 if (blackbox_hint->flags & AttribDecoration) {
1108 switch (blackbox_hint->decoration) {
1109 case DecorNone:
1110 // clear all decorations except close
1111 decorations &= Decor_Close;
1112 // clear all functions except close
1113 functions &= Func_Close;
1114
1115 break;
1116
1117 case DecorTiny:
1118 decorations |= Decor_Titlebar | Decor_Iconify;
1119 decorations &= ~(Decor_Border | Decor_Handle | Decor_Maximize);
1120 functions |= Func_Move | Func_Iconify;
1121 functions &= ~(Func_Resize | Func_Maximize);
1122
1123 break;
1124
1125 case DecorTool:
1126 decorations |= Decor_Titlebar;
1127 decorations &= ~(Decor_Iconify | Decor_Border | Decor_Handle);
1128 functions |= Func_Move;
1129 functions &= ~(Func_Resize | Func_Maximize | Func_Iconify);
1130
1131 break;
1132
1133 case DecorNormal:
1134 default:
1135 decorations |= Decor_Titlebar | Decor_Border | Decor_Handle |
1136 Decor_Iconify | Decor_Maximize;
1137 functions |= Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
1138
1139 break;
1140 }
1141
1142 reconfigure();
1143 }
1144 XFree(blackbox_hint);
1145 return True;
1146 }
1147
1148
1149 void BlackboxWindow::getTransientInfo(void) {
1150 if (client.transient_for &&
1151 client.transient_for != (BlackboxWindow *) ~0ul) {
1152 // the transient for hint was removed, so we need to tell our
1153 // previous transient_for that we are going away
1154 client.transient_for->client.transientList.remove(this);
1155 }
1156
1157 // we have no transient_for until we find a new one
1158 client.transient_for = 0;
1159
1160 Window trans_for;
1161 if (! XGetTransientForHint(blackbox->getXDisplay(), client.window,
1162 &trans_for)) {
1163 // transient_for hint not set
1164 return;
1165 }
1166
1167 if (trans_for == client.window) {
1168 // wierd client... treat this window as a normal window
1169 return;
1170 }
1171
1172 if (trans_for == None || trans_for == screen->getRootWindow()) {
1173 // this is an undocumented interpretation of the ICCCM. a transient
1174 // associated with None/Root/itself is assumed to be a modal root
1175 // transient. we don't support the concept of a global transient,
1176 // so we just associate this transient with nothing, and perhaps
1177 // we will add support later for global modality.
1178 client.transient_for = (BlackboxWindow *) ~0ul;
1179 flags.modal = True;
1180 return;
1181 }
1182
1183 client.transient_for = blackbox->searchWindow(trans_for);
1184 if (! client.transient_for &&
1185 client.window_group && trans_for == client.window_group) {
1186 // no direct transient_for, perhaps this is a group transient?
1187 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1188 if (group) client.transient_for = group->find(screen);
1189 }
1190
1191 if (! client.transient_for || client.transient_for == this) {
1192 // no transient_for found, or we have a wierd client that wants to be
1193 // a transient for itself, so we treat this window as a normal window
1194 client.transient_for = (BlackboxWindow*) 0;
1195 return;
1196 }
1197
1198 // register ourselves with our new transient_for
1199 client.transient_for->client.transientList.push_back(this);
1200 flags.stuck = client.transient_for->flags.stuck;
1201 }
1202
1203
1204 BlackboxWindow *BlackboxWindow::getTransientFor(void) const {
1205 if (client.transient_for &&
1206 client.transient_for != (BlackboxWindow*) ~0ul)
1207 return client.transient_for;
1208 return 0;
1209 }
1210
1211
1212 void BlackboxWindow::configure(int dx, int dy,
1213 unsigned int dw, unsigned int dh) {
1214 bool send_event = (frame.rect.x() != dx || frame.rect.y() != dy);
1215
1216 if ((dw != frame.rect.width()) || (dh != frame.rect.height())) {
1217 frame.rect.setRect(dx, dy, dw, dh);
1218 frame.inside_w = frame.rect.width() - (frame.border_w * 2);
1219 frame.inside_h = frame.rect.height() - (frame.border_w * 2);
1220
1221 if (frame.rect.right() <= 0 || frame.rect.bottom() <= 0)
1222 frame.rect.setPos(0, 0);
1223
1224 client.rect.setCoords(frame.rect.left() + frame.margin.left,
1225 frame.rect.top() + frame.margin.top,
1226 frame.rect.right() - frame.margin.right,
1227 frame.rect.bottom() - frame.margin.bottom);
1228
1229 #ifdef SHAPE
1230 if (blackbox->hasShapeExtensions() && flags.shaped) {
1231 configureShape();
1232 }
1233 #endif // SHAPE
1234
1235 positionWindows();
1236 decorate();
1237 setFocusFlag(flags.focused);
1238 redrawAllButtons();
1239 } else {
1240 frame.rect.setPos(dx, dy);
1241
1242 XMoveWindow(blackbox->getXDisplay(), frame.window,
1243 frame.rect.x(), frame.rect.y());
1244
1245 if (! flags.moving) send_event = True;
1246 }
1247
1248 if (send_event && ! flags.moving) {
1249 client.rect.setPos(frame.rect.left() + frame.margin.left,
1250 frame.rect.top() + frame.margin.top);
1251
1252 XEvent event;
1253 event.type = ConfigureNotify;
1254
1255 event.xconfigure.display = blackbox->getXDisplay();
1256 event.xconfigure.event = client.window;
1257 event.xconfigure.window = client.window;
1258 event.xconfigure.x = client.rect.x();
1259 event.xconfigure.y = client.rect.y();
1260 event.xconfigure.width = client.rect.width();
1261 event.xconfigure.height = client.rect.height();
1262 event.xconfigure.border_width = client.old_bw;
1263 event.xconfigure.above = frame.window;
1264 event.xconfigure.override_redirect = False;
1265
1266 XSendEvent(blackbox->getXDisplay(), client.window, True,
1267 NoEventMask, &event);
1268
1269 screen->updateNetizenConfigNotify(&event);
1270 }
1271 }
1272
1273
1274 #ifdef SHAPE
1275 void BlackboxWindow::configureShape(void) {
1276 XShapeCombineShape(blackbox->getXDisplay(), frame.window, ShapeBounding,
1277 frame.margin.left - frame.border_w,
1278 frame.margin.top - frame.border_w,
1279 client.window, ShapeBounding, ShapeSet);
1280
1281 int num = 0;
1282 XRectangle xrect[2];
1283
1284 if (decorations & Decor_Titlebar) {
1285 xrect[0].x = xrect[0].y = -frame.border_w;
1286 xrect[0].width = frame.rect.width();
1287 xrect[0].height = frame.title_h + (frame.border_w * 2);
1288 ++num;
1289 }
1290
1291 if (decorations & Decor_Handle) {
1292 xrect[1].x = -frame.border_w;
1293 xrect[1].y = frame.rect.height() - frame.margin.bottom +
1294 frame.mwm_border_w - frame.border_w;
1295 xrect[1].width = frame.rect.width();
1296 xrect[1].height = frame.handle_h + (frame.border_w * 2);
1297 ++num;
1298 }
1299
1300 XShapeCombineRectangles(blackbox->getXDisplay(), frame.window,
1301 ShapeBounding, 0, 0, xrect, num,
1302 ShapeUnion, Unsorted);
1303 }
1304 #endif // SHAPE
1305
1306
1307 bool BlackboxWindow::setInputFocus(void) {
1308 if (flags.focused) return True;
1309
1310 if (! client.rect.intersects(screen->getRect())) {
1311 // client is outside the screen, move it to the center
1312 configure((screen->getWidth() - frame.rect.width()) / 2,
1313 (screen->getHeight() - frame.rect.height()) / 2,
1314 frame.rect.width(), frame.rect.height());
1315 }
1316
1317 if (client.transientList.size() > 0) {
1318 // transfer focus to any modal transients
1319 BlackboxWindowList::iterator it, end = client.transientList.end();
1320 for (it = client.transientList.begin(); it != end; ++it) {
1321 if ((*it)->flags.modal) return (*it)->setInputFocus();
1322 }
1323 }
1324
1325 bool ret = True;
1326 if (focus_mode == F_LocallyActive || focus_mode == F_Passive) {
1327 XSetInputFocus(blackbox->getXDisplay(), client.window,
1328 RevertToPointerRoot, CurrentTime);
1329
1330 blackbox->setFocusedWindow(this);
1331 } else {
1332 /* we could set the focus to none, since the window doesn't accept focus,
1333 * but we shouldn't set focus to nothing since this would surely make
1334 * someone angry
1335 */
1336 ret = False;
1337 }
1338
1339 if (flags.send_focus_message) {
1340 XEvent ce;
1341 ce.xclient.type = ClientMessage;
1342 ce.xclient.message_type = blackbox->getWMProtocolsAtom();
1343 ce.xclient.display = blackbox->getXDisplay();
1344 ce.xclient.window = client.window;
1345 ce.xclient.format = 32;
1346 ce.xclient.data.l[0] = blackbox->getWMTakeFocusAtom();
1347 ce.xclient.data.l[1] = blackbox->getLastTime();
1348 ce.xclient.data.l[2] = 0l;
1349 ce.xclient.data.l[3] = 0l;
1350 ce.xclient.data.l[4] = 0l;
1351 XSendEvent(blackbox->getXDisplay(), client.window, False,
1352 NoEventMask, &ce);
1353 }
1354
1355 return ret;
1356 }
1357
1358
1359 void BlackboxWindow::iconify(void) {
1360 if (flags.iconic) return;
1361
1362 if (windowmenu) windowmenu->hide();
1363
1364 setState(IconicState);
1365
1366 /*
1367 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1368 * we need to clear the event mask on client.window for a split second.
1369 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1370 * split second, leaving us with a ghost window... so, we need to do this
1371 * while the X server is grabbed
1372 */
1373 XGrabServer(blackbox->getXDisplay());
1374 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
1375 XUnmapWindow(blackbox->getXDisplay(), client.window);
1376 XSelectInput(blackbox->getXDisplay(), client.window,
1377 PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
1378 XUngrabServer(blackbox->getXDisplay());
1379
1380 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1381 flags.visible = False;
1382 flags.iconic = True;
1383
1384 screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this);
1385
1386 if (isTransient()) {
1387 if (client.transient_for != (BlackboxWindow *) ~0ul &&
1388 ! client.transient_for->flags.iconic) {
1389 // iconify our transient_for
1390 client.transient_for->iconify();
1391 }
1392 }
1393
1394 screen->addIcon(this);
1395
1396 if (client.transientList.size() > 0) {
1397 // iconify all transients
1398 BlackboxWindowList::iterator it, end = client.transientList.end();
1399 for (it = client.transientList.begin(); it != end; ++it) {
1400 if (! (*it)->flags.iconic) (*it)->iconify();
1401 }
1402 }
1403 }
1404
1405
1406 void BlackboxWindow::show(void) {
1407 setState(NormalState);
1408
1409 XMapWindow(blackbox->getXDisplay(), client.window);
1410 XMapSubwindows(blackbox->getXDisplay(), frame.window);
1411 XMapWindow(blackbox->getXDisplay(), frame.window);
1412
1413 flags.visible = True;
1414 flags.iconic = False;
1415 }
1416
1417
1418 void BlackboxWindow::deiconify(bool reassoc, bool raise) {
1419 if (flags.iconic || reassoc)
1420 screen->reassociateWindow(this, BSENTINEL, False);
1421 else if (blackbox_attrib.workspace != screen->getCurrentWorkspace()->getID())
1422 return;
1423
1424 show();
1425
1426 // reassociate and deiconify all transients
1427 if (reassoc && client.transientList.size() > 0) {
1428 BlackboxWindowList::iterator it, end = client.transientList.end();
1429 for (it = client.transientList.begin(); it != end; ++it) {
1430 (*it)->deiconify(True, False);
1431 }
1432 }
1433
1434 if (raise)
1435 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1436 }
1437
1438
1439 void BlackboxWindow::close(void) {
1440 XEvent ce;
1441 ce.xclient.type = ClientMessage;
1442 ce.xclient.message_type = blackbox->getWMProtocolsAtom();
1443 ce.xclient.display = blackbox->getXDisplay();
1444 ce.xclient.window = client.window;
1445 ce.xclient.format = 32;
1446 ce.xclient.data.l[0] = blackbox->getWMDeleteAtom();
1447 ce.xclient.data.l[1] = CurrentTime;
1448 ce.xclient.data.l[2] = 0l;
1449 ce.xclient.data.l[3] = 0l;
1450 ce.xclient.data.l[4] = 0l;
1451 XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce);
1452 }
1453
1454
1455 void BlackboxWindow::withdraw(void) {
1456 setState(current_state);
1457
1458 flags.visible = False;
1459 flags.iconic = False;
1460
1461 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1462
1463 XGrabServer(blackbox->getXDisplay());
1464 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
1465 XUnmapWindow(blackbox->getXDisplay(), client.window);
1466 XSelectInput(blackbox->getXDisplay(), client.window,
1467 PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
1468 XUngrabServer(blackbox->getXDisplay());
1469
1470 if (windowmenu) windowmenu->hide();
1471 }
1472
1473
1474 void BlackboxWindow::maximize(unsigned int button) {
1475 // handle case where menu is open then the max button is used instead
1476 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
1477
1478 if (flags.maximized) {
1479 flags.maximized = 0;
1480
1481 blackbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert);
1482 blackbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert);
1483
1484 /*
1485 when a resize is begun, maximize(0) is called to clear any maximization
1486 flags currently set. Otherwise it still thinks it is maximized.
1487 so we do not need to call configure() because resizing will handle it
1488 */
1489 if (! flags.resizing)
1490 configure(blackbox_attrib.premax_x, blackbox_attrib.premax_y,
1491 blackbox_attrib.premax_w, blackbox_attrib.premax_h);
1492
1493 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
1494 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
1495
1496 redrawAllButtons();
1497 setState(current_state);
1498 return;
1499 }
1500
1501 blackbox_attrib.premax_x = frame.rect.x();
1502 blackbox_attrib.premax_y = frame.rect.y();
1503 blackbox_attrib.premax_w = frame.rect.width();
1504 blackbox_attrib.premax_h = frame.rect.height();
1505
1506 const Rect &screen_area = screen->availableArea();
1507 frame.changing = screen_area;
1508 constrain(TopLeft);
1509
1510 switch(button) {
1511 case 1:
1512 blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
1513 blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
1514 break;
1515
1516 case 2:
1517 blackbox_attrib.flags |= AttribMaxVert;
1518 blackbox_attrib.attrib |= AttribMaxVert;
1519
1520 frame.changing.setX(frame.rect.x());
1521 frame.changing.setWidth(frame.rect.width());
1522 break;
1523
1524 case 3:
1525 blackbox_attrib.flags |= AttribMaxHoriz;
1526 blackbox_attrib.attrib |= AttribMaxHoriz;
1527
1528 frame.changing.setY(frame.rect.y());
1529 frame.changing.setHeight(frame.rect.height());
1530 break;
1531 }
1532
1533 if (flags.shaded) {
1534 blackbox_attrib.flags ^= AttribShaded;
1535 blackbox_attrib.attrib ^= AttribShaded;
1536 flags.shaded = False;
1537 }
1538
1539 flags.maximized = button;
1540
1541 configure(frame.changing.x(), frame.changing.y(),
1542 frame.changing.width(), frame.changing.height());
1543 if (flags.focused)
1544 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1545 redrawAllButtons();
1546 setState(current_state);
1547 }
1548
1549
1550 // re-maximizes the window to take into account availableArea changes
1551 void BlackboxWindow::remaximize(void) {
1552 // save the original dimensions because maximize will wipe them out
1553 int premax_x = blackbox_attrib.premax_x,
1554 premax_y = blackbox_attrib.premax_y,
1555 premax_w = blackbox_attrib.premax_w,
1556 premax_h = blackbox_attrib.premax_h;
1557
1558 unsigned int button = flags.maximized;
1559 flags.maximized = 0; // trick maximize() into working
1560 maximize(button);
1561
1562 // restore saved values
1563 blackbox_attrib.premax_x = premax_x;
1564 blackbox_attrib.premax_y = premax_y;
1565 blackbox_attrib.premax_w = premax_w;
1566 blackbox_attrib.premax_h = premax_h;
1567 }
1568
1569
1570 void BlackboxWindow::setWorkspace(unsigned int n) {
1571 blackbox_attrib.flags |= AttribWorkspace;
1572 blackbox_attrib.workspace = n;
1573 }
1574
1575
1576 void BlackboxWindow::shade(void) {
1577 if (flags.shaded) {
1578 XResizeWindow(blackbox->getXDisplay(), frame.window,
1579 frame.inside_w, frame.inside_h);
1580 flags.shaded = False;
1581 blackbox_attrib.flags ^= AttribShaded;
1582 blackbox_attrib.attrib ^= AttribShaded;
1583
1584 setState(NormalState);
1585
1586 // set the frame rect to the normal size
1587 frame.rect.setHeight(client.rect.height() + frame.margin.top +
1588 frame.margin.bottom);
1589 } else {
1590 if (! (decorations & Decor_Titlebar))
1591 return;
1592
1593 XResizeWindow(blackbox->getXDisplay(), frame.window,
1594 frame.inside_w, frame.title_h);
1595 flags.shaded = True;
1596 blackbox_attrib.flags |= AttribShaded;
1597 blackbox_attrib.attrib |= AttribShaded;
1598
1599 setState(IconicState);
1600
1601 // set the frame rect to the shaded size
1602 frame.rect.setHeight(frame.title_h + (frame.border_w * 2));
1603 }
1604 }
1605
1606
1607 void BlackboxWindow::stick(void) {
1608 if (flags.stuck) {
1609 blackbox_attrib.flags ^= AttribOmnipresent;
1610 blackbox_attrib.attrib ^= AttribOmnipresent;
1611
1612 flags.stuck = False;
1613
1614 if (! flags.iconic)
1615 screen->reassociateWindow(this, BSENTINEL, True);
1616
1617 setState(current_state);
1618 } else {
1619 flags.stuck = True;
1620
1621 blackbox_attrib.flags |= AttribOmnipresent;
1622 blackbox_attrib.attrib |= AttribOmnipresent;
1623
1624 setState(current_state);
1625 }
1626 }
1627
1628
1629 void BlackboxWindow::setFocusFlag(bool focus) {
1630 flags.focused = focus;
1631
1632 if (decorations & Decor_Titlebar) {
1633 if (flags.focused) {
1634 if (frame.ftitle)
1635 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1636 frame.title, frame.ftitle);
1637 else
1638 XSetWindowBackground(blackbox->getXDisplay(),
1639 frame.title, frame.ftitle_pixel);
1640 } else {
1641 if (frame.utitle)
1642 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1643 frame.title, frame.utitle);
1644 else
1645 XSetWindowBackground(blackbox->getXDisplay(),
1646 frame.title, frame.utitle_pixel);
1647 }
1648 XClearWindow(blackbox->getXDisplay(), frame.title);
1649
1650 redrawLabel();
1651 redrawAllButtons();
1652 }
1653
1654 if (decorations & Decor_Handle) {
1655 if (flags.focused) {
1656 if (frame.fhandle)
1657 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1658 frame.handle, frame.fhandle);
1659 else
1660 XSetWindowBackground(blackbox->getXDisplay(),
1661 frame.handle, frame.fhandle_pixel);
1662
1663 if (frame.fgrip) {
1664 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1665 frame.left_grip, frame.fgrip);
1666 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1667 frame.right_grip, frame.fgrip);
1668 } else {
1669 XSetWindowBackground(blackbox->getXDisplay(),
1670 frame.left_grip, frame.fgrip_pixel);
1671 XSetWindowBackground(blackbox->getXDisplay(),
1672 frame.right_grip, frame.fgrip_pixel);
1673 }
1674 } else {
1675 if (frame.uhandle)
1676 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1677 frame.handle, frame.uhandle);
1678 else
1679 XSetWindowBackground(blackbox->getXDisplay(),
1680 frame.handle, frame.uhandle_pixel);
1681
1682 if (frame.ugrip) {
1683 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1684 frame.left_grip, frame.ugrip);
1685 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1686 frame.right_grip, frame.ugrip);
1687 } else {
1688 XSetWindowBackground(blackbox->getXDisplay(),
1689 frame.left_grip, frame.ugrip_pixel);
1690 XSetWindowBackground(blackbox->getXDisplay(),
1691 frame.right_grip, frame.ugrip_pixel);
1692 }
1693 }
1694 XClearWindow(blackbox->getXDisplay(), frame.handle);
1695 XClearWindow(blackbox->getXDisplay(), frame.left_grip);
1696 XClearWindow(blackbox->getXDisplay(), frame.right_grip);
1697 }
1698
1699 if (decorations & Decor_Border) {
1700 if (flags.focused)
1701 XSetWindowBorder(blackbox->getXDisplay(),
1702 frame.plate, frame.fborder_pixel);
1703 else
1704 XSetWindowBorder(blackbox->getXDisplay(),
1705 frame.plate, frame.uborder_pixel);
1706 }
1707
1708 if (screen->isSloppyFocus() && screen->doAutoRaise()) {
1709 if (isFocused()) timer->start();
1710 else timer->stop();
1711 }
1712
1713 if (isFocused())
1714 blackbox->setFocusedWindow(this);
1715 }
1716
1717
1718 void BlackboxWindow::installColormap(bool install) {
1719 int i = 0, ncmap = 0;
1720 Colormap *cmaps = XListInstalledColormaps(blackbox->getXDisplay(),
1721 client.window, &ncmap);
1722 XWindowAttributes wattrib;
1723 if (cmaps) {
1724 if (XGetWindowAttributes(blackbox->getXDisplay(),
1725 client.window, &wattrib)) {
1726 if (install) {
1727 // install the window's colormap
1728 for (i = 0; i < ncmap; i++) {
1729 if (*(cmaps + i) == wattrib.colormap)
1730 // this window is using an installed color map... do not install
1731 install = False;
1732 }
1733 // otherwise, install the window's colormap
1734 if (install)
1735 XInstallColormap(blackbox->getXDisplay(), wattrib.colormap);
1736 } else {
1737 // uninstall the window's colormap
1738 for (i = 0; i < ncmap; i++) {
1739 if (*(cmaps + i) == wattrib.colormap)
1740 // we found the colormap to uninstall
1741 XUninstallColormap(blackbox->getXDisplay(), wattrib.colormap);
1742 }
1743 }
1744 }
1745
1746 XFree(cmaps);
1747 }
1748 }
1749
1750
1751 void BlackboxWindow::setState(unsigned long new_state) {
1752 current_state = new_state;
1753
1754 unsigned long state[2];
1755 state[0] = current_state;
1756 state[1] = None;
1757 XChangeProperty(blackbox->getXDisplay(), client.window,
1758 blackbox->getWMStateAtom(), blackbox->getWMStateAtom(), 32,
1759 PropModeReplace, (unsigned char *) state, 2);
1760
1761 XChangeProperty(blackbox->getXDisplay(), client.window,
1762 blackbox->getBlackboxAttributesAtom(),
1763 blackbox->getBlackboxAttributesAtom(), 32, PropModeReplace,
1764 (unsigned char *) &blackbox_attrib,
1765 PropBlackboxAttributesElements);
1766 }
1767
1768
1769 bool BlackboxWindow::getState(void) {
1770 current_state = 0;
1771
1772 Atom atom_return;
1773 bool ret = False;
1774 int foo;
1775 unsigned long *state, ulfoo, nitems;
1776
1777 if ((XGetWindowProperty(blackbox->getXDisplay(), client.window,
1778 blackbox->getWMStateAtom(),
1779 0l, 2l, False, blackbox->getWMStateAtom(),
1780 &atom_return, &foo, &nitems, &ulfoo,
1781 (unsigned char **) &state) != Success) ||
1782 (! state)) {
1783 return False;
1784 }
1785
1786 if (nitems >= 1) {
1787 current_state = static_cast<unsigned long>(state[0]);
1788
1789 ret = True;
1790 }
1791
1792 XFree((void *) state);
1793
1794 return ret;
1795 }
1796
1797
1798 void BlackboxWindow::restoreAttributes(void) {
1799 if (! getState()) current_state = NormalState;
1800
1801 Atom atom_return;
1802 int foo;
1803 unsigned long ulfoo, nitems;
1804
1805 BlackboxAttributes *net;
1806 int ret = XGetWindowProperty(blackbox->getXDisplay(), client.window,
1807 blackbox->getBlackboxAttributesAtom(), 0l,
1808 PropBlackboxAttributesElements, False,
1809 blackbox->getBlackboxAttributesAtom(),
1810 &atom_return, &foo, &nitems, &ulfoo,
1811 (unsigned char **) &net);
1812 if (ret != Success || ! net || nitems != PropBlackboxAttributesElements)
1813 return;
1814
1815 if (net->flags & AttribShaded &&
1816 net->attrib & AttribShaded) {
1817 int save_state =
1818 ((current_state == IconicState) ? NormalState : current_state);
1819
1820 flags.shaded = False;
1821 shade();
1822
1823 current_state = save_state;
1824 }
1825
1826 if ((net->workspace != screen->getCurrentWorkspaceID()) &&
1827 (net->workspace < screen->getWorkspaceCount())) {
1828 screen->reassociateWindow(this, net->workspace, True);
1829
1830 if (current_state == NormalState) current_state = WithdrawnState;
1831 } else if (current_state == WithdrawnState) {
1832 current_state = NormalState;
1833 }
1834
1835 if (net->flags & AttribOmnipresent &&
1836 net->attrib & AttribOmnipresent) {
1837 flags.stuck = False;
1838 stick();
1839
1840 current_state = NormalState;
1841 }
1842
1843 if ((net->flags & AttribMaxHoriz) ||
1844 (net->flags & AttribMaxVert)) {
1845 int x = net->premax_x, y = net->premax_y;
1846 unsigned int w = net->premax_w, h = net->premax_h;
1847 flags.maximized = 0;
1848
1849 unsigned int m = 0;
1850 if ((net->flags & AttribMaxHoriz) &&
1851 (net->flags & AttribMaxVert))
1852 m = (net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1853 else if (net->flags & AttribMaxVert)
1854 m = (net->attrib & AttribMaxVert) ? 2 : 0;
1855 else if (net->flags & AttribMaxHoriz)
1856 m = (net->attrib & AttribMaxHoriz) ? 3 : 0;
1857
1858 if (m) maximize(m);
1859
1860 blackbox_attrib.premax_x = x;
1861 blackbox_attrib.premax_y = y;
1862 blackbox_attrib.premax_w = w;
1863 blackbox_attrib.premax_h = h;
1864 }
1865
1866 setState(current_state);
1867
1868 XFree((void *) net);
1869 }
1870
1871
1872 /*
1873 * Positions the frame according the the client window position and window
1874 * gravity.
1875 */
1876 void BlackboxWindow::setGravityOffsets(void) {
1877 // x coordinates for each gravity type
1878 const int x_west = client.rect.x();
1879 const int x_east = client.rect.right() - frame.inside_w + 1;
1880 const int x_center = client.rect.right() - (frame.rect.width()/2) + 1;
1881 // y coordinates for each gravity type
1882 const int y_north = client.rect.y();
1883 const int y_south = client.rect.bottom() - frame.inside_h + 1;
1884 const int y_center = client.rect.bottom() - (frame.rect.height()/2) + 1;
1885
1886 switch (client.win_gravity) {
1887 default:
1888 case NorthWestGravity: frame.rect.setPos(x_west, y_north); break;
1889 case NorthGravity: frame.rect.setPos(x_center, y_north); break;
1890 case NorthEastGravity: frame.rect.setPos(x_east, y_north); break;
1891 case SouthWestGravity: frame.rect.setPos(x_west, y_south); break;
1892 case SouthGravity: frame.rect.setPos(x_center, y_south); break;
1893 case SouthEastGravity: frame.rect.setPos(x_east, y_south); break;
1894 case WestGravity: frame.rect.setPos(x_west, y_center); break;
1895 case CenterGravity: frame.rect.setPos(x_center, y_center); break;
1896 case EastGravity: frame.rect.setPos(x_east, y_center); break;
1897
1898 case ForgetGravity:
1899 case StaticGravity:
1900 frame.rect.setPos(client.rect.x() - frame.margin.left,
1901 client.rect.y() - frame.margin.top);
1902 break;
1903 }
1904 }
1905
1906
1907 /*
1908 * The reverse of the setGravityOffsets function. Uses the frame window's
1909 * position to find the window's reference point.
1910 */
1911 void BlackboxWindow::restoreGravity(void) {
1912 // x coordinates for each gravity type
1913 const int x_west = frame.rect.x();
1914 const int x_east = frame.rect.x() + frame.inside_w - client.rect.width();
1915 const int x_center = frame.rect.x() + (frame.rect.width()/2) -
1916 client.rect.width();
1917 // y coordinates for each gravity type
1918 const int y_north = frame.rect.y();
1919 const int y_south = frame.rect.y() + frame.inside_h - client.rect.height();
1920 const int y_center = frame.rect.y() + (frame.rect.height()/2) -
1921 client.rect.height();
1922
1923 switch(client.win_gravity) {
1924 default:
1925 case NorthWestGravity: client.rect.setPos(x_west, y_north); break;
1926 case NorthGravity: client.rect.setPos(x_center, y_north); break;
1927 case NorthEastGravity: client.rect.setPos(x_east, y_north); break;
1928 case SouthWestGravity: client.rect.setPos(x_west, y_south); break;
1929 case SouthGravity: client.rect.setPos(x_center, y_south); break;
1930 case SouthEastGravity: client.rect.setPos(x_east, y_south); break;
1931 case WestGravity: client.rect.setPos(x_west, y_center); break;
1932 case CenterGravity: client.rect.setPos(x_center, y_center); break;
1933 case EastGravity: client.rect.setPos(x_east, y_center); break;
1934
1935 case ForgetGravity:
1936 case StaticGravity:
1937 client.rect.setPos(frame.rect.left() + frame.margin.left,
1938 frame.rect.top() + frame.margin.top);
1939 break;
1940 }
1941 }
1942
1943
1944 void BlackboxWindow::redrawLabel(void) {
1945 if (flags.focused) {
1946 if (frame.flabel)
1947 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1948 frame.label, frame.flabel);
1949 else
1950 XSetWindowBackground(blackbox->getXDisplay(),
1951 frame.label, frame.flabel_pixel);
1952 } else {
1953 if (frame.ulabel)
1954 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1955 frame.label, frame.ulabel);
1956 else
1957 XSetWindowBackground(blackbox->getXDisplay(),
1958 frame.label, frame.ulabel_pixel);
1959 }
1960 XClearWindow(blackbox->getXDisplay(), frame.label);
1961
1962 WindowStyle *style = screen->getWindowStyle();
1963
1964 int pos = frame.bevel_w * 2,
1965 dlen = style->doJustify(client.title.c_str(), pos, frame.label_w,
1966 frame.bevel_w * 4, i18n.multibyte());
1967
1968 BPen pen((flags.focused) ? style->l_text_focus : style->l_text_unfocus,
1969 style->font);
1970 if (i18n.multibyte())
1971 XmbDrawString(blackbox->getXDisplay(), frame.label, style->fontset,
1972 pen.gc(), pos,
1973 (1 - style->fontset_extents->max_ink_extent.y),
1974 client.title.c_str(), dlen);
1975 else
1976 XDrawString(blackbox->getXDisplay(), frame.label, pen.gc(), pos,
1977 (style->font->ascent + 1), client.title.c_str(), dlen);
1978 }
1979
1980
1981 void BlackboxWindow::redrawAllButtons(void) {
1982 if (frame.iconify_button) redrawIconifyButton(False);
1983 if (frame.maximize_button) redrawMaximizeButton(flags.maximized);
1984 if (frame.close_button) redrawCloseButton(False);
1985 }
1986
1987
1988 void BlackboxWindow::redrawIconifyButton(bool pressed) {
1989 if (! pressed) {
1990 if (flags.focused) {
1991 if (frame.fbutton)
1992 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
1993 frame.iconify_button, frame.fbutton);
1994 else
1995 XSetWindowBackground(blackbox->getXDisplay(),
1996 frame.iconify_button, frame.fbutton_pixel);
1997 } else {
1998 if (frame.ubutton)
1999 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2000 frame.iconify_button, frame.ubutton);
2001 else
2002 XSetWindowBackground(blackbox->getXDisplay(), frame.iconify_button,
2003 frame.ubutton_pixel);
2004 }
2005 } else {
2006 if (frame.pbutton)
2007 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2008 frame.iconify_button, frame.pbutton);
2009 else
2010 XSetWindowBackground(blackbox->getXDisplay(),
2011 frame.iconify_button, frame.pbutton_pixel);
2012 }
2013 XClearWindow(blackbox->getXDisplay(), frame.iconify_button);
2014
2015 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2016 screen->getWindowStyle()->b_pic_unfocus);
2017 XDrawRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(),
2018 2, (frame.button_w - 5), (frame.button_w - 5), 2);
2019 }
2020
2021
2022 void BlackboxWindow::redrawMaximizeButton(bool pressed) {
2023 if (! pressed) {
2024 if (flags.focused) {
2025 if (frame.fbutton)
2026 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2027 frame.maximize_button, frame.fbutton);
2028 else
2029 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2030 frame.fbutton_pixel);
2031 } else {
2032 if (frame.ubutton)
2033 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2034 frame.maximize_button, frame.ubutton);
2035 else
2036 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2037 frame.ubutton_pixel);
2038 }
2039 } else {
2040 if (frame.pbutton)
2041 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2042 frame.maximize_button, frame.pbutton);
2043 else
2044 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2045 frame.pbutton_pixel);
2046 }
2047 XClearWindow(blackbox->getXDisplay(), frame.maximize_button);
2048
2049 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2050 screen->getWindowStyle()->b_pic_unfocus);
2051 XDrawRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2052 2, 2, (frame.button_w - 5), (frame.button_w - 5));
2053 XDrawLine(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2054 2, 3, (frame.button_w - 3), 3);
2055 }
2056
2057
2058 void BlackboxWindow::redrawCloseButton(bool pressed) {
2059 if (! pressed) {
2060 if (flags.focused) {
2061 if (frame.fbutton)
2062 XSetWindowBackgroundPixmap(blackbox->getXDisplay(), frame.close_button,
2063 frame.fbutton);
2064 else
2065 XSetWindowBackground(blackbox->getXDisplay(), frame.close_button,
2066 frame.fbutton_pixel);
2067 } else {
2068 if (frame.ubutton)
2069 XSetWindowBackgroundPixmap(blackbox->getXDisplay(), frame.close_button,
2070 frame.ubutton);
2071 else
2072 XSetWindowBackground(blackbox->getXDisplay(), frame.close_button,
2073 frame.ubutton_pixel);
2074 }
2075 } else {
2076 if (frame.pbutton)
2077 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2078 frame.close_button, frame.pbutton);
2079 else
2080 XSetWindowBackground(blackbox->getXDisplay(),
2081 frame.close_button, frame.pbutton_pixel);
2082 }
2083 XClearWindow(blackbox->getXDisplay(), frame.close_button);
2084
2085 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2086 screen->getWindowStyle()->b_pic_unfocus);
2087 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2088 2, 2, (frame.button_w - 3), (frame.button_w - 3));
2089 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2090 2, (frame.button_w - 3), (frame.button_w - 3), 2);
2091 }
2092
2093
2094 void BlackboxWindow::mapRequestEvent(XMapRequestEvent *re) {
2095 if (re->window != client.window)
2096 return;
2097
2098 #ifdef DEBUG
2099 fprintf(stderr, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2100 client.window);
2101 #endif // DEBUG
2102
2103 bool get_state_ret = getState();
2104 if (! (get_state_ret && blackbox->isStartup())) {
2105 if ((client.wm_hint_flags & StateHint) &&
2106 (! (current_state == NormalState || current_state == IconicState)))
2107 current_state = client.initial_state;
2108 else
2109 current_state = NormalState;
2110 } else if (flags.iconic) {
2111 current_state = NormalState;
2112 }
2113
2114 switch (current_state) {
2115 case IconicState:
2116 iconify();
2117 break;
2118
2119 case WithdrawnState:
2120 withdraw();
2121 break;
2122
2123 case NormalState:
2124 case InactiveState:
2125 case ZoomState:
2126 default:
2127 show();
2128 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2129 if (! blackbox->isStartup() && (isTransient() || screen->doFocusNew())) {
2130 XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped..
2131 setInputFocus();
2132 }
2133 break;
2134 }
2135 }
2136
2137
2138 void BlackboxWindow::unmapNotifyEvent(XUnmapEvent *ue) {
2139 if (ue->window != client.window)
2140 return;
2141
2142 #ifdef DEBUG
2143 fprintf(stderr, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2144 client.window);
2145 #endif // DEBUG
2146
2147 screen->unmanageWindow(this, False);
2148 }
2149
2150
2151 void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent *de) {
2152 if (de->window != client.window)
2153 return;
2154
2155 #ifdef DEBUG
2156 fprintf(stderr, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2157 client.window);
2158 #endif // DEBUG
2159
2160 screen->unmanageWindow(this, False);
2161 }
2162
2163
2164 void BlackboxWindow::reparentNotifyEvent(XReparentEvent *re) {
2165 if (re->window != client.window || re->parent == frame.plate)
2166 return;
2167
2168 #ifdef DEBUG
2169 fprintf(stderr, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2170 "0x%lx.\n", client.window, re->parent);
2171 #endif // DEBUG
2172
2173 XEvent ev;
2174 ev.xreparent = *re;
2175 XPutBackEvent(blackbox->getXDisplay(), &ev);
2176 screen->unmanageWindow(this, True);
2177 }
2178
2179
2180 void BlackboxWindow::propertyNotifyEvent(Atom atom) {
2181 switch(atom) {
2182 case XA_WM_CLASS:
2183 case XA_WM_CLIENT_MACHINE:
2184 case XA_WM_COMMAND:
2185 break;
2186
2187 case XA_WM_TRANSIENT_FOR: {
2188 // determine if this is a transient window
2189 getTransientInfo();
2190
2191 // adjust the window decorations based on transience
2192 if (isTransient()) {
2193 decorations &= ~(Decor_Maximize | Decor_Handle);
2194 functions &= ~Func_Maximize;
2195 }
2196
2197 reconfigure();
2198 }
2199 break;
2200
2201 case XA_WM_HINTS:
2202 getWMHints();
2203 break;
2204
2205 case XA_WM_ICON_NAME:
2206 getWMIconName();
2207 if (flags.iconic) screen->propagateWindowName(this);
2208 break;
2209
2210 case XA_WM_NAME:
2211 getWMName();
2212
2213 if (decorations & Decor_Titlebar)
2214 redrawLabel();
2215
2216 screen->propagateWindowName(this);
2217 break;
2218
2219 case XA_WM_NORMAL_HINTS: {
2220 getWMNormalHints();
2221
2222 if ((client.normal_hint_flags & PMinSize) &&
2223 (client.normal_hint_flags & PMaxSize)) {
2224 if (client.max_width <= client.min_width &&
2225 client.max_height <= client.min_height) {
2226 decorations &= ~(Decor_Maximize | Decor_Handle);
2227 functions &= ~(Func_Resize | Func_Maximize);
2228 } else {
2229 decorations |= Decor_Maximize | Decor_Handle;
2230 functions |= Func_Resize | Func_Maximize;
2231 }
2232 }
2233
2234 Rect old_rect = frame.rect;
2235
2236 upsize();
2237
2238 if (old_rect != frame.rect)
2239 reconfigure();
2240
2241 break;
2242 }
2243
2244 default:
2245 if (atom == blackbox->getWMProtocolsAtom()) {
2246 getWMProtocols();
2247
2248 if ((decorations & Decor_Close) && (! frame.close_button)) {
2249 createCloseButton();
2250 if (decorations & Decor_Titlebar) {
2251 positionButtons(True);
2252 XMapSubwindows(blackbox->getXDisplay(), frame.title);
2253 }
2254 if (windowmenu) windowmenu->reconfigure();
2255 }
2256 }
2257
2258 break;
2259 }
2260 }
2261
2262
2263 void BlackboxWindow::exposeEvent(XExposeEvent *ee) {
2264 if (frame.label == ee->window && (decorations & Decor_Titlebar))
2265 redrawLabel();
2266 else if (frame.close_button == ee->window)
2267 redrawCloseButton(False);
2268 else if (frame.maximize_button == ee->window)
2269 redrawMaximizeButton(flags.maximized);
2270 else if (frame.iconify_button == ee->window)
2271 redrawIconifyButton(False);
2272 }
2273
2274
2275 void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent *cr) {
2276 if (cr->window != client.window || flags.iconic)
2277 return;
2278
2279 int cx = frame.rect.x(), cy = frame.rect.y();
2280 unsigned int cw = frame.rect.width(), ch = frame.rect.height();
2281
2282 if (cr->value_mask & CWBorderWidth)
2283 client.old_bw = cr->border_width;
2284
2285 if (cr->value_mask & CWX)
2286 cx = cr->x - frame.margin.left;
2287
2288 if (cr->value_mask & CWY)
2289 cy = cr->y - frame.margin.top;
2290
2291 if (cr->value_mask & CWWidth)
2292 cw = cr->width + frame.margin.left + frame.margin.right;
2293
2294 if (cr->value_mask & CWHeight)
2295 ch = cr->height + frame.margin.top + frame.margin.bottom;
2296
2297 if (frame.rect != Rect(cx, cy, cw, ch))
2298 configure(cx, cy, cw, ch);
2299
2300 if (cr->value_mask & CWStackMode) {
2301 switch (cr->detail) {
2302 case Below:
2303 case BottomIf:
2304 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
2305 break;
2306
2307 case Above:
2308 case TopIf:
2309 default:
2310 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2311 break;
2312 }
2313 }
2314 }
2315
2316
2317 void BlackboxWindow::buttonPressEvent(XButtonEvent *be) {
2318 if (frame.maximize_button == be->window) {
2319 redrawMaximizeButton(True);
2320 } else if (be->button == 1 || (be->button == 3 && be->state == Mod1Mask)) {
2321 if (! flags.focused)
2322 setInputFocus();
2323
2324 if (frame.iconify_button == be->window) {
2325 redrawIconifyButton(True);
2326 } else if (frame.close_button == be->window) {
2327 redrawCloseButton(True);
2328 } else if (frame.plate == be->window) {
2329 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
2330
2331 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2332
2333 XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time);
2334 } else {
2335 if (frame.title == be->window || frame.label == be->window) {
2336 if (((be->time - lastButtonPressTime) <=
2337 blackbox->getDoubleClickInterval()) ||
2338 (be->state & ControlMask)) {
2339 lastButtonPressTime = 0;
2340 shade();
2341 } else {
2342 lastButtonPressTime = be->time;
2343 }
2344 }
2345
2346 frame.grab_x = be->x_root - frame.rect.x() - frame.border_w;
2347 frame.grab_y = be->y_root - frame.rect.y() - frame.border_w;
2348
2349 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
2350
2351 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2352 }
2353 } else if (be->button == 2 && (be->window != frame.iconify_button) &&
2354 (be->window != frame.close_button)) {
2355 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
2356 } else if (windowmenu && be->button == 3 &&
2357 (frame.title == be->window || frame.label == be->window ||
2358 frame.handle == be->window || frame.window == be->window)) {
2359 int mx = 0, my = 0;
2360
2361 if (frame.title == be->window || frame.label == be->window) {
2362 mx = be->x_root - (windowmenu->getWidth() / 2);
2363 my = frame.rect.y() + frame.title_h + frame.border_w;
2364 } else if (frame.handle == be->window) {
2365 mx = be->x_root - (windowmenu->getWidth() / 2);
2366 my = frame.rect.bottom() - frame.handle_h - (frame.border_w * 3) -
2367 windowmenu->getHeight();
2368 } else {
2369 mx = be->x_root - (windowmenu->getWidth() / 2);
2370
2371 if (be->y <= static_cast<signed>(frame.bevel_w))
2372 my = frame.rect.y() + frame.title_h;
2373 else
2374 my = be->y_root - (windowmenu->getHeight() / 2);
2375 }
2376
2377 // snap the window menu into a corner if necessary - we check the
2378 // position of the menu with the coordinates of the client to
2379 // make the comparisions easier.
2380 // ### this needs some work!
2381 if (mx > client.rect.right() -
2382 static_cast<signed>(windowmenu->getWidth()))
2383 mx = frame.rect.right() - windowmenu->getWidth() - frame.border_w + 1;
2384 if (mx < client.rect.left())
2385 mx = frame.rect.x();
2386
2387 if (my > client.rect.bottom() -
2388 static_cast<signed>(windowmenu->getHeight()))
2389 my = frame.rect.bottom() - windowmenu->getHeight() - frame.border_w + 1;
2390 if (my < client.rect.top())
2391 my = frame.rect.y() + ((decorations & Decor_Titlebar) ?
2392 frame.title_h : 0);
2393
2394 if (windowmenu) {
2395 if (! windowmenu->isVisible()) {
2396 windowmenu->move(mx, my);
2397 windowmenu->show();
2398 XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID());
2399 XRaiseWindow(blackbox->getXDisplay(),
2400 windowmenu->getSendToMenu()->getWindowID());
2401 } else {
2402 windowmenu->hide();
2403 }
2404 }
2405 // mouse wheel up
2406 } else if (be->button == 4) {
2407 if ((be->window == frame.label ||
2408 be->window == frame.title) &&
2409 ! flags.shaded)
2410 shade();
2411 // mouse wheel down
2412 } else if (be->button == 5) {
2413 if ((be->window == frame.label ||
2414 be->window == frame.title) &&
2415 flags.shaded)
2416 shade();
2417 }
2418 }
2419
2420
2421 void BlackboxWindow::buttonReleaseEvent(XButtonEvent *re) {
2422 if (re->window == frame.maximize_button) {
2423 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
2424 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
2425 maximize(re->button);
2426 } else {
2427 redrawMaximizeButton(flags.maximized);
2428 }
2429 } else if (re->window == frame.iconify_button) {
2430 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
2431 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
2432 iconify();
2433 } else {
2434 redrawIconifyButton(False);
2435 }
2436 } else if (re->window == frame.close_button) {
2437 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
2438 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w)))
2439 close();
2440 redrawCloseButton(False);
2441 } else if (flags.moving) {
2442 flags.moving = False;
2443
2444 if (! screen->doOpaqueMove()) {
2445 /* when drawing the rubber band, we need to make sure we only draw inside
2446 * the frame... frame.changing_* contain the new coords for the window,
2447 * so we need to subtract 1 from changing_w/changing_h every where we
2448 * draw the rubber band (for both moving and resizing)
2449 */
2450 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
2451 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
2452 frame.changing.width() - 1, frame.changing.height() - 1);
2453 XUngrabServer(blackbox->getXDisplay());
2454
2455 configure(frame.changing.x(), frame.changing.y(),
2456 frame.changing.width(), frame.changing.height());
2457 } else {
2458 configure(frame.rect.x(), frame.rect.y(),
2459 frame.rect.width(), frame.rect.height());
2460 }
2461 screen->hideGeometry();
2462 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
2463 } else if (flags.resizing) {
2464 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
2465 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
2466 frame.changing.width() - 1, frame.changing.height() - 1);
2467 XUngrabServer(blackbox->getXDisplay());
2468
2469 screen->hideGeometry();
2470
2471 constrain((re->window == frame.left_grip) ? TopRight : TopLeft);
2472
2473 // unset maximized state when resized after fully maximized
2474 if (flags.maximized == 1)
2475 maximize(0);
2476 flags.resizing = False;
2477 configure(frame.changing.x(), frame.changing.y(),
2478 frame.changing.width(), frame.changing.height());
2479
2480 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
2481 } else if (re->window == frame.window) {
2482 if (re->button == 2 && re->state == Mod1Mask)
2483 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
2484 }
2485 }
2486
2487
2488 void BlackboxWindow::motionNotifyEvent(XMotionEvent *me) {
2489 if (! flags.resizing && (me->state & Button1Mask) &&
2490 (functions & Func_Move) &&
2491 (frame.title == me->window || frame.label == me->window ||
2492 frame.handle == me->window || frame.window == me->window)) {
2493 if (! flags.moving) {
2494 XGrabPointer(blackbox->getXDisplay(), me->window, False,
2495 Button1MotionMask | ButtonReleaseMask,
2496 GrabModeAsync, GrabModeAsync,
2497 None, blackbox->getMoveCursor(), CurrentTime);
2498
2499 if (windowmenu && windowmenu->isVisible())
2500 windowmenu->hide();
2501
2502 flags.moving = True;
2503
2504 if (! screen->doOpaqueMove()) {
2505 XGrabServer(blackbox->getXDisplay());
2506
2507 frame.changing = frame.rect;
2508 screen->showPosition(frame.changing.x(), frame.changing.y());
2509
2510 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
2511 screen->getOpGC(),
2512 frame.changing.x(),
2513 frame.changing.y(),
2514 frame.changing.width() - 1,
2515 frame.changing.height() - 1);
2516 }
2517 } else {
2518 int dx = me->x_root - frame.grab_x, dy = me->y_root - frame.grab_y;
2519 dx -= frame.border_w;
2520 dy -= frame.border_w;
2521
2522 const int snap_distance = screen->getEdgeSnapThreshold();
2523
2524 if (snap_distance) {
2525 Rect srect = screen->availableArea();
2526 // window corners
2527 const int wleft = dx,
2528 wright = dx + frame.rect.width() - 1,
2529 wtop = dy,
2530 wbottom = dy + frame.rect.height() - 1;
2531
2532 int dleft = std::abs(wleft - srect.left()),
2533 dright = std::abs(wright - srect.right()),
2534 dtop = std::abs(wtop - srect.top()),
2535 dbottom = std::abs(wbottom - srect.bottom());
2536
2537 // snap left?
2538 if (dleft < snap_distance && dleft < dright)
2539 dx = srect.left();
2540 // snap right?
2541 else if (dright < snap_distance && dright < dleft)
2542 dx = srect.right() - frame.rect.width() + 1;
2543
2544 // snap top?
2545 if (dtop < snap_distance && dtop < dbottom)
2546 dy = srect.top();
2547 // snap bottom?
2548 else if (dbottom < snap_distance && dbottom < dtop)
2549 dy = srect.bottom() - frame.rect.height() + 1;
2550
2551 srect = screen->getRect(); // now get the full screen
2552
2553 dleft = std::abs(wleft - srect.left()),
2554 dright = std::abs(wright - srect.right()),
2555 dtop = std::abs(wtop - srect.top()),
2556 dbottom = std::abs(wbottom - srect.bottom());
2557
2558 // snap left?
2559 if (dleft < snap_distance && dleft < dright)
2560 dx = srect.left();
2561 // snap right?
2562 else if (dright < snap_distance && dright < dleft)
2563 dx = srect.right() - frame.rect.width() + 1;
2564
2565 // snap top?
2566 if (dtop < snap_distance && dtop < dbottom)
2567 dy = srect.top();
2568 // snap bottom?
2569 else if (dbottom < snap_distance && dbottom < dtop)
2570 dy = srect.bottom() - frame.rect.height() + 1;
2571 }
2572
2573 if (screen->doOpaqueMove()) {
2574 configure(dx, dy, frame.rect.width(), frame.rect.height());
2575 } else {
2576 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
2577 screen->getOpGC(),
2578 frame.changing.x(),
2579 frame.changing.y(),
2580 frame.changing.width() - 1,
2581 frame.changing.height() - 1);
2582
2583 frame.changing.setPos(dx, dy);
2584
2585 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
2586 screen->getOpGC(),
2587 frame.changing.x(),
2588 frame.changing.y(),
2589 frame.changing.width() - 1,
2590 frame.changing.height() - 1);
2591 }
2592
2593 screen->showPosition(dx, dy);
2594 }
2595 } else if ((functions & Func_Resize) &&
2596 (((me->state & Button1Mask) &&
2597 (me->window == frame.right_grip ||
2598 me->window == frame.left_grip)) ||
2599 (me->state & (Mod1Mask | Button3Mask) &&
2600 me->window == frame.window))) {
2601 bool left = (me->window == frame.left_grip);
2602
2603 if (! flags.resizing) {
2604 XGrabServer(blackbox->getXDisplay());
2605 XGrabPointer(blackbox->getXDisplay(), me->window, False,
2606 ButtonMotionMask | ButtonReleaseMask,
2607 GrabModeAsync, GrabModeAsync, None,
2608 ((left) ? blackbox->getLowerLeftAngleCursor() :
2609 blackbox->getLowerRightAngleCursor()),
2610 CurrentTime);
2611
2612 flags.resizing = True;
2613
2614 int gw, gh;
2615 frame.grab_x = me->x;
2616 frame.grab_y = me->y;
2617 frame.changing = frame.rect;
2618
2619 constrain((left) ? TopRight : TopLeft, &gw, &gh);
2620
2621 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
2622 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
2623 frame.changing.width() - 1, frame.changing.height() - 1);
2624
2625 screen->showGeometry(gw, gh);
2626 } else {
2627 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
2628 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
2629 frame.changing.width() - 1, frame.changing.height() - 1);
2630
2631 int gw, gh;
2632
2633 Corner anchor;
2634
2635 if (left) {
2636 anchor = TopRight;
2637 frame.changing.setCoords(me->x_root - frame.grab_x, frame.rect.top(),
2638 frame.rect.right(), frame.rect.bottom());
2639 frame.changing.setHeight(frame.rect.height() + (me->y - frame.grab_y));
2640 } else {
2641 anchor = TopLeft;
2642 frame.changing.setSize(frame.rect.width() + (me->x - frame.grab_x),
2643 frame.rect.height() + (me->y - frame.grab_y));
2644 }
2645
2646 constrain(anchor, &gw, &gh);
2647
2648 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
2649 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
2650 frame.changing.width() - 1, frame.changing.height() - 1);
2651
2652 screen->showGeometry(gw, gh);
2653 }
2654 }
2655 }
2656
2657
2658 #ifdef SHAPE
2659 void BlackboxWindow::shapeEvent(XShapeEvent *) {
2660 if (blackbox->hasShapeExtensions() && flags.shaped) {
2661 configureShape();
2662 }
2663 }
2664 #endif // SHAPE
2665
2666
2667 bool BlackboxWindow::validateClient(void) {
2668 XSync(blackbox->getXDisplay(), False);
2669
2670 XEvent e;
2671 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
2672 DestroyNotify, &e) ||
2673 XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
2674 UnmapNotify, &e)) {
2675 XPutBackEvent(blackbox->getXDisplay(), &e);
2676
2677 return False;
2678 }
2679
2680 return True;
2681 }
2682
2683
2684 void BlackboxWindow::restore(bool remap) {
2685 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeDelete);
2686 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
2687 XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask);
2688
2689 restoreGravity();
2690
2691 XUnmapWindow(blackbox->getXDisplay(), frame.window);
2692 XUnmapWindow(blackbox->getXDisplay(), client.window);
2693
2694 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, client.old_bw);
2695
2696 XEvent ev;
2697 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
2698 ReparentNotify, &ev)) {
2699 remap = True;
2700 } else {
2701 // according to the ICCCM - if the client doesn't reparent to
2702 // root, then we have to do it for them
2703 XReparentWindow(blackbox->getXDisplay(), client.window,
2704 screen->getRootWindow(),
2705 client.rect.x(), client.rect.y());
2706 }
2707
2708 if (remap) XMapWindow(blackbox->getXDisplay(), client.window);
2709 }
2710
2711
2712 // timer for autoraise
2713 void BlackboxWindow::timeout(void) {
2714 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2715 }
2716
2717
2718 void BlackboxWindow::changeBlackboxHints(BlackboxHints *net) {
2719 if ((net->flags & AttribShaded) &&
2720 ((blackbox_attrib.attrib & AttribShaded) !=
2721 (net->attrib & AttribShaded)))
2722 shade();
2723
2724 if (flags.visible && // watch out for requests when we can not be seen
2725 (net->flags & (AttribMaxVert | AttribMaxHoriz)) &&
2726 ((blackbox_attrib.attrib & (AttribMaxVert | AttribMaxHoriz)) !=
2727 (net->attrib & (AttribMaxVert | AttribMaxHoriz)))) {
2728 if (flags.maximized) {
2729 maximize(0);
2730 } else {
2731 int button = 0;
2732
2733 if ((net->flags & AttribMaxHoriz) && (net->flags & AttribMaxVert))
2734 button = ((net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0);
2735 else if (net->flags & AttribMaxVert)
2736 button = ((net->attrib & AttribMaxVert) ? 2 : 0);
2737 else if (net->flags & AttribMaxHoriz)
2738 button = ((net->attrib & AttribMaxHoriz) ? 3 : 0);
2739
2740 maximize(button);
2741 }
2742 }
2743
2744 if ((net->flags & AttribOmnipresent) &&
2745 ((blackbox_attrib.attrib & AttribOmnipresent) !=
2746 (net->attrib & AttribOmnipresent)))
2747 stick();
2748
2749 if ((net->flags & AttribWorkspace) &&
2750 (blackbox_attrib.workspace != net->workspace)) {
2751 screen->reassociateWindow(this, net->workspace, True);
2752
2753 if (screen->getCurrentWorkspaceID() != net->workspace) {
2754 withdraw();
2755 } else {
2756 show();
2757 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2758 }
2759 }
2760
2761 if (net->flags & AttribDecoration) {
2762 switch (net->decoration) {
2763 case DecorNone:
2764 // clear all decorations except close
2765 decorations &= Decor_Close;
2766
2767 break;
2768
2769 default:
2770 case DecorNormal:
2771 decorations |= Decor_Titlebar | Decor_Handle | Decor_Border |
2772 Decor_Iconify | Decor_Maximize;
2773
2774 break;
2775
2776 case DecorTiny:
2777 decorations |= Decor_Titlebar | Decor_Iconify;
2778 decorations &= ~(Decor_Border | Decor_Handle | Decor_Maximize);
2779
2780 break;
2781
2782 case DecorTool:
2783 decorations |= Decor_Titlebar;
2784 decorations &= ~(Decor_Iconify | Decor_Border | Decor_Handle);
2785 functions |= Func_Move;
2786
2787 break;
2788 }
2789
2790 // we can not be shaded if we lack a titlebar
2791 if (flags.shaded && ! (decorations & Decor_Titlebar))
2792 shade();
2793
2794 if (frame.window) {
2795 XMapSubwindows(blackbox->getXDisplay(), frame.window);
2796 XMapWindow(blackbox->getXDisplay(), frame.window);
2797 }
2798
2799 reconfigure();
2800 setState(current_state);
2801 }
2802 }
2803
2804
2805 /*
2806 * Set the sizes of all components of the window frame
2807 * (the window decorations).
2808 * These values are based upon the current style settings and the client
2809 * window's dimensions.
2810 */
2811 void BlackboxWindow::upsize(void) {
2812 frame.bevel_w = screen->getBevelWidth();
2813
2814 if (decorations & Decor_Border) {
2815 frame.border_w = screen->getBorderWidth();
2816 if (! isTransient())
2817 frame.mwm_border_w = screen->getFrameWidth();
2818 else
2819 frame.mwm_border_w = 0;
2820 } else {
2821 frame.mwm_border_w = frame.border_w = 0;
2822 }
2823
2824 if (decorations & Decor_Titlebar) {
2825 // the height of the titlebar is based upon the height of the font being
2826 // used to display the window's title
2827 WindowStyle *style = screen->getWindowStyle();
2828 if (i18n.multibyte())
2829 frame.title_h = (style->fontset_extents->max_ink_extent.height +
2830 (frame.bevel_w * 2) + 2);
2831 else
2832 frame.title_h = (style->font->ascent + style->font->descent +
2833 (frame.bevel_w * 2) + 2);
2834
2835 frame.label_h = frame.title_h - (frame.bevel_w * 2);
2836 frame.button_w = (frame.label_h - 2);
2837
2838 // set the top frame margin
2839 frame.margin.top = frame.border_w + frame.title_h +
2840 frame.border_w + frame.mwm_border_w;
2841 } else {
2842 frame.title_h = 0;
2843 frame.label_h = 0;
2844 frame.button_w = 0;
2845
2846 // set the top frame margin
2847 frame.margin.top = frame.border_w + frame.mwm_border_w;
2848 }
2849
2850 // set the left/right frame margin
2851 frame.margin.left = frame.margin.right = frame.border_w + frame.mwm_border_w;
2852
2853 if (decorations & Decor_Handle) {
2854 frame.grip_w = frame.button_w * 2;
2855 frame.handle_h = screen->getHandleWidth();
2856
2857 // set the bottom frame margin
2858 frame.margin.bottom = frame.border_w + frame.handle_h +
2859 frame.border_w + frame.mwm_border_w;
2860 } else {
2861 frame.handle_h = 0;
2862 frame.grip_w = 0;
2863
2864 // set the bottom frame margin
2865 frame.margin.bottom = frame.border_w + frame.mwm_border_w;
2866 }
2867
2868 // set the frame rect
2869 frame.rect.setSize(client.rect.width() + frame.margin.left +
2870 frame.margin.right,
2871 client.rect.height() + frame.margin.top +
2872 frame.margin.bottom);
2873 frame.inside_w = frame.rect.width() - (frame.border_w * 2);
2874 frame.inside_h = frame.rect.height() - (frame.border_w * 2);
2875 }
2876
2877
2878 /*
2879 * Calculate the size of the client window and constrain it to the
2880 * size specified by the size hints of the client window.
2881 *
2882 * The logical width and height are placed into pw and ph, if they
2883 * are non-zero. Logical size refers to the users perception of
2884 * the window size (for example an xterm has resizes in cells, not in
2885 * pixels).
2886 *
2887 * The physical geometry is placed into frame.changing_{x,y,width,height}.
2888 * Physical geometry refers to the geometry of the window in pixels.
2889 */
2890 void BlackboxWindow::constrain(Corner anchor, int *pw, int *ph) {
2891 // frame.changing represents the requested frame size, we need to
2892 // strip the frame margin off and constrain the client size
2893 frame.changing.setCoords(frame.changing.left() + frame.margin.left,
2894 frame.changing.top() + frame.margin.top,
2895 frame.changing.right() - frame.margin.right,
2896 frame.changing.bottom() - frame.margin.bottom);
2897
2898 int dw = frame.changing.width(), dh = frame.changing.height(),
2899 base_width = (client.base_width) ? client.base_width : client.min_width,
2900 base_height = (client.base_height) ? client.base_height :
2901 client.min_height;
2902
2903 // constrain
2904 if (dw < static_cast<signed>(client.min_width)) dw = client.min_width;
2905 if (dh < static_cast<signed>(client.min_height)) dh = client.min_height;
2906 if (dw > static_cast<signed>(client.max_width)) dw = client.max_width;
2907 if (dh > static_cast<signed>(client.max_height)) dh = client.max_height;
2908
2909 dw -= base_width;
2910 dw /= client.width_inc;
2911 dh -= base_height;
2912 dh /= client.height_inc;
2913
2914 if (pw) *pw = dw;
2915 if (ph) *ph = dh;
2916
2917 dw *= client.width_inc;
2918 dw += base_width;
2919 dh *= client.height_inc;
2920 dh += base_height;
2921
2922 frame.changing.setSize(dw, dh);
2923
2924 // add the frame margin back onto frame.changing
2925 frame.changing.setCoords(frame.changing.left() - frame.margin.left,
2926 frame.changing.top() - frame.margin.top,
2927 frame.changing.right() + frame.margin.right,
2928 frame.changing.bottom() + frame.margin.bottom);
2929
2930 // move frame.changing to the specified anchor
2931 switch (anchor) {
2932 case TopLeft:
2933 // nothing to do
2934 break;
2935
2936 case TopRight:
2937 int dx = frame.rect.right() - frame.changing.right();
2938 frame.changing.setPos(frame.changing.x() + dx, frame.changing.y());
2939 break;
2940 }
2941 }
2942
2943
2944 int WindowStyle::doJustify(const char *text, int &start_pos,
2945 unsigned int max_length, unsigned int modifier,
2946 bool multibyte) const {
2947 size_t text_len = strlen(text);
2948 unsigned int length;
2949
2950 do {
2951 if (multibyte) {
2952 XRectangle ink, logical;
2953 XmbTextExtents(fontset, text, text_len, &ink, &logical);
2954 length = logical.width;
2955 } else {
2956 length = XTextWidth(font, text, text_len);
2957 }
2958 length += modifier;
2959 } while (length > max_length && text_len-- > 0);
2960
2961 switch (justify) {
2962 case RightJustify:
2963 start_pos += max_length - length;
2964 break;
2965
2966 case CenterJustify:
2967 start_pos += (max_length - length) / 2;
2968 break;
2969
2970 case LeftJustify:
2971 default:
2972 break;
2973 }
2974
2975 return text_len;
2976 }
2977
2978
2979 BWindowGroup::BWindowGroup(Blackbox *b, Window _group)
2980 : blackbox(b), group(_group) {
2981 // watch for destroy notify on the group window
2982 XSelectInput(blackbox->getXDisplay(), group, StructureNotifyMask);
2983 blackbox->saveGroupSearch(group, this);
2984 }
2985
2986
2987 BWindowGroup::~BWindowGroup(void) {
2988 blackbox->removeGroupSearch(group);
2989 }
2990
2991
2992 BlackboxWindow *
2993 BWindowGroup::find(BScreen *screen, bool allow_transients) const {
2994 BlackboxWindow *ret = blackbox->getFocusedWindow();
2995
2996 // does the focus window match (or any transient_fors)?
2997 while (ret) {
2998 if (ret->getScreen() == screen && ret->getGroupWindow() == group) {
2999 if (ret->isTransient() && allow_transients) break;
3000 else if (! ret->isTransient()) break;
3001 }
3002
3003 ret = ret->getTransientFor();
3004 }
3005
3006 if (ret) return ret;
3007
3008 // the focus window didn't match, look in the group's window list
3009 BlackboxWindowList::const_iterator it, end = windowList.end();
3010 for (it = windowList.begin(); it != end; ++it) {
3011 ret = *it;
3012 if (ret->getScreen() == screen && ret->getGroupWindow() == group) {
3013 if (ret->isTransient() && allow_transients) break;
3014 else if (! ret->isTransient()) break;
3015 }
3016 }
3017
3018 return ret;
3019 }
This page took 0.180197 seconds and 4 git commands to generate.