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