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>
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:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
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.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
29 #include <X11/Xatom.h>
30 #include <X11/keysym.h>
34 #endif // HAVE_STRING_H
39 # endif // HAVE_STDIO_H
44 #endif // HAVE_STDLIB_H
47 #include "blackbox.hh"
54 #include "workspace.hh"
60 * Initializes the class with default values/the window's set initial values.
62 BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
63 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
64 // sizeof(BlackboxWindow));
67 fprintf(stderr, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w);
71 set timer to zero... it is initialized properly later, so we check
72 if timer is zero in the destructor, and assume that the window is not
73 fully constructed if timer is zero...
79 xatom = blackbox->getXAtom();
81 if (! validateClient()) {
86 // fetch client size and placement
87 XWindowAttributes wattrib;
88 if (! XGetWindowAttributes(blackbox->getXDisplay(),
89 client.window, &wattrib) ||
90 ! wattrib.screen || wattrib.override_redirect) {
93 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
100 // set the eventmask early in the game so that we make sure we get
101 // all the events we are interested in
102 XSetWindowAttributes attrib_set;
103 attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
105 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
107 XChangeWindowAttributes(blackbox->getXDisplay(), client.window,
108 CWEventMask|CWDontPropagate, &attrib_set);
110 flags.moving = flags.resizing = flags.shaded = flags.visible =
111 flags.iconic = flags.focused = flags.stuck = flags.modal =
112 flags.send_focus_message = flags.shaped = flags.skip_taskbar =
113 flags.skip_pager = flags.fullscreen = False;
116 blackbox_attrib.workspace = window_number = BSENTINEL;
118 blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack = 0l;
119 blackbox_attrib.decoration = DecorNormal;
120 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
121 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
124 frame.window = frame.plate = frame.title = frame.handle = None;
125 frame.close_button = frame.iconify_button = frame.maximize_button =
126 frame.stick_button = None;
127 frame.right_grip = frame.left_grip = None;
129 frame.ulabel_pixel = frame.flabel_pixel = frame.utitle_pixel =
130 frame.ftitle_pixel = frame.uhandle_pixel = frame.fhandle_pixel =
131 frame.ubutton_pixel = frame.fbutton_pixel = frame.uborder_pixel =
132 frame.fborder_pixel = frame.ugrip_pixel = frame.fgrip_pixel = 0;
133 frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None;
134 frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None;
135 frame.ugrip = frame.fgrip = None;
137 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
138 mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
139 Decor_Iconify | Decor_Maximize;
141 client.normal_hint_flags = 0;
142 client.window_group = None;
143 client.transient_for = 0;
145 current_state = NormalState;
148 set the initial size and location of client window (relative to the
149 _root window_). This position is the reference point used with the
150 window's gravity to find the window's initial position.
152 client.rect.setRect(wattrib.x, wattrib.y, wattrib.width, wattrib.height);
153 client.old_bw = wattrib.border_width;
155 lastButtonPressTime = 0;
157 timer = new BTimer(blackbox, this);
158 timer->setTimeout(blackbox->getAutoRaiseDelay());
160 // get size, aspect, minimum/maximum size and other hints set by the
163 if (! getBlackboxHints())
170 frame.window = createToplevelWindow();
172 blackbox->saveWindowSearch(frame.window, this);
174 frame.plate = createChildWindow(frame.window, ExposureMask);
175 blackbox->saveWindowSearch(frame.plate, this);
177 // determine if this is a transient window
180 // determine the window's type, so we can decide its decorations and
181 // functionality, or if we should not manage it at all
182 if (getWindowType()) {
183 // adjust the window decorations/behavior based on the window type
184 switch (window_type) {
188 blackbox_attrib.workspace = 0; // we do need to belong to a workspace
189 flags.stuck = True; // we show up on all workspaces
191 // none of these windows are manipulated by the window manager
197 // these windows get less functionality
198 functions &= ~(Func_Maximize | Func_Resize | Func_Iconify);
202 // dialogs cannot be maximized
203 functions &= ~Func_Maximize;
207 // normal windows retain all of the possible decorations and
215 // further adjeust the window's decorations/behavior based on window sizes
216 if ((client.normal_hint_flags & PMinSize) &&
217 (client.normal_hint_flags & PMaxSize) &&
218 client.max_width <= client.min_width &&
219 client.max_height <= client.min_height) {
220 functions &= ~(Func_Resize | Func_Maximize);
227 if (decorations & Decor_Titlebar)
230 if (decorations & Decor_Handle)
233 // apply the size and gravity hint to the frame
237 bool place_window = True;
238 if (blackbox->isStartup() || isTransient() ||
239 client.normal_hint_flags & (PPosition|USPosition)) {
240 applyGravity(frame.rect);
242 if (blackbox->isStartup() || client.rect.intersects(screen->getRect()))
243 place_window = False;
246 // add the window's strut. note this is done *after* placing the window.
247 screen->addStrut(&client.strut);
251 the server needs to be grabbed here to prevent client's from sending
252 events while we are in the process of configuring their window.
253 We hold the grab until after we are done moving the window around.
256 XGrabServer(blackbox->getXDisplay());
258 associateClientWindow();
260 blackbox->saveWindowSearch(client.window, this);
262 if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
263 screen->getCurrentWorkspace()->addWindow(this, place_window);
265 screen->getWorkspace(blackbox_attrib.workspace)->
266 addWindow(this, place_window);
268 if (! place_window) {
269 // don't need to call configure if we are letting the workspace
271 configure(frame.rect.x(), frame.rect.y(),
272 frame.rect.width(), frame.rect.height());
278 XUngrabServer(blackbox->getXDisplay());
281 if (blackbox->hasShapeExtensions() && flags.shaped)
285 // now that we know where to put the window and what it should look like
286 // we apply the decorations
291 XMapSubwindows(blackbox->getXDisplay(), frame.window);
293 // this ensures the title, buttons, and other decor are properly displayed
296 // preserve the window's initial state on first map, and its current state
298 unsigned long initial_state = current_state;
300 current_state = initial_state;
302 // get sticky state from our parent window if we've got one
303 if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
304 client.transient_for->isStuck() != flags.stuck)
308 flags.shaded = False;
309 initial_state = current_state;
313 At this point in the life of a window, current_state should only be set
314 to IconicState if the window was an *icon*, not if it was shaded.
316 if (initial_state != IconicState)
317 current_state = NormalState;
325 if (flags.maximized && (functions & Func_Maximize))
330 BlackboxWindow::~BlackboxWindow(void) {
332 fprintf(stderr, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
336 if (! timer) // window not managed...
342 screen->removeStrut(&client.strut);
343 screen->updateAvailableArea();
345 // We don't need to worry about resizing because resizing always grabs the X
346 // server. This should only ever happen if using opaque moving.
352 if (client.window_group) {
353 BWindowGroup *group = blackbox->searchGroup(client.window_group);
354 if (group) group->removeWindow(this);
357 // remove ourselves from our transient_for
359 if (client.transient_for != (BlackboxWindow *) ~0ul)
360 client.transient_for->client.transientList.remove(this);
361 client.transient_for = (BlackboxWindow*) 0;
364 if (client.transientList.size() > 0) {
365 // reset transient_for for all transients
366 BlackboxWindowList::iterator it, end = client.transientList.end();
367 for (it = client.transientList.begin(); it != end; ++it)
368 (*it)->client.transient_for = (BlackboxWindow*) 0;
378 blackbox->removeWindowSearch(frame.plate);
379 XDestroyWindow(blackbox->getXDisplay(), frame.plate);
383 blackbox->removeWindowSearch(frame.window);
384 XDestroyWindow(blackbox->getXDisplay(), frame.window);
387 blackbox->removeWindowSearch(client.window);
391 void BlackboxWindow::enableDecor(bool enable) {
392 blackbox_attrib.flags |= AttribDecoration;
393 blackbox_attrib.decoration = enable ? DecorNormal : DecorNone;
396 // we can not be shaded if we lack a titlebar
397 if (! (decorations & Decor_Titlebar) && flags.shaded)
400 if (flags.visible && frame.window) {
401 XMapSubwindows(blackbox->getXDisplay(), frame.window);
402 XMapWindow(blackbox->getXDisplay(), frame.window);
406 setState(current_state);
410 void BlackboxWindow::setupDecor() {
411 if (blackbox_attrib.decoration != DecorNone) {
412 // start with everything on
413 decorations = Decor_Close |
414 (mwm_decorations & Decor_Titlebar ? Decor_Titlebar : 0) |
415 (mwm_decorations & Decor_Border ? Decor_Border : 0) |
416 (mwm_decorations & Decor_Handle ? Decor_Handle : 0) |
417 (mwm_decorations & Decor_Iconify ? Decor_Iconify : 0) |
418 (mwm_decorations & Decor_Maximize ? Decor_Maximize : 0);
420 if (! (functions & Func_Close)) decorations &= ~Decor_Close;
421 if (! (functions & Func_Maximize)) decorations &= ~Decor_Maximize;
422 if (! (functions & Func_Iconify)) decorations &= ~Decor_Iconify;
423 if (! (functions & Func_Resize)) decorations &= ~Decor_Handle;
425 switch (window_type) {
430 // none of these windows are decorated by the window manager at all
436 decorations &= ~(Decor_Border);
440 decorations &= ~Decor_Handle;
452 * Creates a new top level window, with a given location, size, and border
454 * Returns: the newly created window
456 Window BlackboxWindow::createToplevelWindow(void) {
457 XSetWindowAttributes attrib_create;
458 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
459 CWOverrideRedirect | CWEventMask;
461 attrib_create.background_pixmap = None;
462 attrib_create.colormap = screen->getColormap();
463 attrib_create.override_redirect = True;
464 attrib_create.event_mask = EnterWindowMask | LeaveWindowMask |
467 We catch button presses because other wise they get passed down to the
468 root window, which will then cause root menus to show when you click the
472 return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(),
473 0, 0, 1, 1, frame.border_w, screen->getDepth(),
474 InputOutput, screen->getVisual(), create_mask,
480 * Creates a child window, and optionally associates a given cursor with
483 Window BlackboxWindow::createChildWindow(Window parent,
484 unsigned long event_mask,
486 XSetWindowAttributes attrib_create;
487 unsigned long create_mask = CWBackPixmap | CWBorderPixel |
490 attrib_create.background_pixmap = None;
491 attrib_create.event_mask = event_mask;
494 create_mask |= CWCursor;
495 attrib_create.cursor = cursor;
498 return XCreateWindow(blackbox->getXDisplay(), parent, 0, 0, 1, 1, 0,
499 screen->getDepth(), InputOutput, screen->getVisual(),
500 create_mask, &attrib_create);
504 void BlackboxWindow::associateClientWindow(void) {
505 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0);
509 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert);
511 XSelectInput(blackbox->getXDisplay(), frame.plate, SubstructureRedirectMask);
514 note we used to grab around this call to XReparentWindow however the
515 server is now grabbed before this method is called
517 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
519 XSelectInput(blackbox->getXDisplay(), client.window,
520 event_mask & ~StructureNotifyMask);
521 XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0);
522 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
524 XRaiseWindow(blackbox->getXDisplay(), frame.plate);
525 XMapSubwindows(blackbox->getXDisplay(), frame.plate);
528 if (blackbox->hasShapeExtensions()) {
529 XShapeSelectInput(blackbox->getXDisplay(), client.window,
536 XShapeQueryExtents(blackbox->getXDisplay(), client.window, &shaped,
537 &foo, &foo, &ufoo, &ufoo, &foo, &foo, &foo,
539 flags.shaped = shaped;
545 void BlackboxWindow::decorate(void) {
548 texture = &(screen->getWindowStyle()->b_focus);
549 frame.fbutton = texture->render(frame.button_w, frame.button_w,
552 frame.fbutton_pixel = texture->color().pixel();
554 texture = &(screen->getWindowStyle()->b_unfocus);
555 frame.ubutton = texture->render(frame.button_w, frame.button_w,
558 frame.ubutton_pixel = texture->color().pixel();
560 unsigned char needsPressed = 0;
562 texture = &(screen->getWindowStyle()->b_pressed_focus);
564 if (texture->texture() != BTexture::NoTexture) {
565 frame.pfbutton = texture->render(frame.button_w, frame.button_w,
567 if (! frame.pfbutton)
568 frame.pfbutton_pixel = texture->color().pixel();
573 texture = &(screen->getWindowStyle()->b_pressed_unfocus);
575 if (texture->texture() != BTexture::NoTexture) {
576 frame.pubutton = texture->render(frame.button_w, frame.button_w,
578 if (! frame.pubutton)
579 frame.pubutton = texture->color().pixel();
584 // if we either pressed unfocused, or pressed focused were undefined,
585 // make them inherit from the old resource. It's a hack for sure, but
586 // it allows for some backwards and forwards compatibility.
588 texture = &(screen->getWindowStyle()->b_pressed);
590 if (needsPressed & 0x1) {
591 frame.pfbutton = texture->render(frame.button_w, frame.button_w,
593 if (! frame.pfbutton)
594 frame.pfbutton_pixel = texture->color().pixel();
596 if (needsPressed & 0x2) {
597 frame.pubutton = texture->render(frame.button_w, frame.button_w,
599 if (! frame.pubutton)
600 frame.pubutton = texture->color().pixel();
605 if (decorations & Decor_Titlebar) {
606 texture = &(screen->getWindowStyle()->t_focus);
607 frame.ftitle = texture->render(frame.inside_w, frame.title_h,
610 frame.ftitle_pixel = texture->color().pixel();
612 texture = &(screen->getWindowStyle()->t_unfocus);
613 frame.utitle = texture->render(frame.inside_w, frame.title_h,
616 frame.utitle_pixel = texture->color().pixel();
618 XSetWindowBorder(blackbox->getXDisplay(), frame.title,
619 screen->getBorderColor()->pixel());
624 if (decorations & Decor_Border) {
625 frame.fborder_pixel = screen->getWindowStyle()->f_focus.color().pixel();
626 frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.color().pixel();
629 if (decorations & Decor_Handle) {
630 texture = &(screen->getWindowStyle()->h_focus);
631 frame.fhandle = texture->render(frame.inside_w, frame.handle_h,
634 frame.fhandle_pixel = texture->color().pixel();
636 texture = &(screen->getWindowStyle()->h_unfocus);
637 frame.uhandle = texture->render(frame.inside_w, frame.handle_h,
640 frame.uhandle_pixel = texture->color().pixel();
642 texture = &(screen->getWindowStyle()->g_focus);
643 frame.fgrip = texture->render(frame.grip_w, frame.handle_h, frame.fgrip);
645 frame.fgrip_pixel = texture->color().pixel();
647 texture = &(screen->getWindowStyle()->g_unfocus);
648 frame.ugrip = texture->render(frame.grip_w, frame.handle_h, frame.ugrip);
650 frame.ugrip_pixel = texture->color().pixel();
652 XSetWindowBorder(blackbox->getXDisplay(), frame.handle,
653 screen->getBorderColor()->pixel());
654 XSetWindowBorder(blackbox->getXDisplay(), frame.left_grip,
655 screen->getBorderColor()->pixel());
656 XSetWindowBorder(blackbox->getXDisplay(), frame.right_grip,
657 screen->getBorderColor()->pixel());
660 XSetWindowBorder(blackbox->getXDisplay(), frame.window,
661 screen->getBorderColor()->pixel());
665 void BlackboxWindow::decorateLabel(void) {
668 texture = &(screen->getWindowStyle()->l_focus);
669 frame.flabel = texture->render(frame.label_w, frame.label_h, frame.flabel);
671 frame.flabel_pixel = texture->color().pixel();
673 texture = &(screen->getWindowStyle()->l_unfocus);
674 frame.ulabel = texture->render(frame.label_w, frame.label_h, frame.ulabel);
676 frame.ulabel_pixel = texture->color().pixel();
680 void BlackboxWindow::createHandle(void) {
681 frame.handle = createChildWindow(frame.window,
682 ButtonPressMask | ButtonReleaseMask |
683 ButtonMotionMask | ExposureMask);
684 blackbox->saveWindowSearch(frame.handle, this);
687 createChildWindow(frame.handle,
688 ButtonPressMask | ButtonReleaseMask |
689 ButtonMotionMask | ExposureMask,
690 blackbox->getLowerLeftAngleCursor());
691 blackbox->saveWindowSearch(frame.left_grip, this);
694 createChildWindow(frame.handle,
695 ButtonPressMask | ButtonReleaseMask |
696 ButtonMotionMask | ExposureMask,
697 blackbox->getLowerRightAngleCursor());
698 blackbox->saveWindowSearch(frame.right_grip, this);
702 void BlackboxWindow::destroyHandle(void) {
704 screen->getImageControl()->removeImage(frame.fhandle);
707 screen->getImageControl()->removeImage(frame.uhandle);
710 screen->getImageControl()->removeImage(frame.fgrip);
713 screen->getImageControl()->removeImage(frame.ugrip);
715 blackbox->removeWindowSearch(frame.left_grip);
716 blackbox->removeWindowSearch(frame.right_grip);
718 XDestroyWindow(blackbox->getXDisplay(), frame.left_grip);
719 XDestroyWindow(blackbox->getXDisplay(), frame.right_grip);
720 frame.left_grip = frame.right_grip = None;
722 blackbox->removeWindowSearch(frame.handle);
723 XDestroyWindow(blackbox->getXDisplay(), frame.handle);
728 void BlackboxWindow::createTitlebar(void) {
729 frame.title = createChildWindow(frame.window,
730 ButtonPressMask | ButtonReleaseMask |
731 ButtonMotionMask | ExposureMask);
732 frame.label = createChildWindow(frame.title,
733 ButtonPressMask | ButtonReleaseMask |
734 ButtonMotionMask | ExposureMask);
735 blackbox->saveWindowSearch(frame.title, this);
736 blackbox->saveWindowSearch(frame.label, this);
738 if (decorations & Decor_Iconify) createIconifyButton();
739 if (decorations & Decor_Maximize) createMaximizeButton();
740 if (decorations & Decor_Close) createCloseButton();
744 void BlackboxWindow::destroyTitlebar(void) {
745 if (frame.close_button)
746 destroyCloseButton();
748 if (frame.iconify_button)
749 destroyIconifyButton();
751 if (frame.maximize_button)
752 destroyMaximizeButton();
754 if (frame.stick_button)
755 destroyStickyButton();
758 screen->getImageControl()->removeImage(frame.ftitle);
761 screen->getImageControl()->removeImage(frame.utitle);
764 screen->getImageControl()->removeImage(frame.flabel);
767 screen->getImageControl()->removeImage(frame.ulabel);
770 screen->getImageControl()->removeImage(frame.fbutton);
773 screen->getImageControl()->removeImage(frame.ubutton);
775 blackbox->removeWindowSearch(frame.title);
776 blackbox->removeWindowSearch(frame.label);
778 XDestroyWindow(blackbox->getXDisplay(), frame.label);
779 XDestroyWindow(blackbox->getXDisplay(), frame.title);
780 frame.title = frame.label = None;
784 void BlackboxWindow::createCloseButton(void) {
785 if (frame.title != None) {
786 frame.close_button = createChildWindow(frame.title,
789 ButtonMotionMask | ExposureMask);
790 blackbox->saveWindowSearch(frame.close_button, this);
795 void BlackboxWindow::destroyCloseButton(void) {
796 blackbox->removeWindowSearch(frame.close_button);
797 XDestroyWindow(blackbox->getXDisplay(), frame.close_button);
798 frame.close_button = None;
802 void BlackboxWindow::createIconifyButton(void) {
803 if (frame.title != None) {
804 frame.iconify_button = createChildWindow(frame.title,
807 ButtonMotionMask | ExposureMask);
808 blackbox->saveWindowSearch(frame.iconify_button, this);
813 void BlackboxWindow::destroyIconifyButton(void) {
814 blackbox->removeWindowSearch(frame.iconify_button);
815 XDestroyWindow(blackbox->getXDisplay(), frame.iconify_button);
816 frame.iconify_button = None;
820 void BlackboxWindow::createMaximizeButton(void) {
821 if (frame.title != None) {
822 frame.maximize_button = createChildWindow(frame.title,
825 ButtonMotionMask | ExposureMask);
826 blackbox->saveWindowSearch(frame.maximize_button, this);
831 void BlackboxWindow::destroyMaximizeButton(void) {
832 blackbox->removeWindowSearch(frame.maximize_button);
833 XDestroyWindow(blackbox->getXDisplay(), frame.maximize_button);
834 frame.maximize_button = None;
837 void BlackboxWindow::createStickyButton(void) {
838 if (frame.title != None) {
839 frame.stick_button = createChildWindow(frame.title,
842 ButtonMotionMask | ExposureMask);
843 blackbox->saveWindowSearch(frame.stick_button, this);
847 void BlackboxWindow::destroyStickyButton(void) {
848 blackbox->removeWindowSearch(frame.stick_button);
849 XDestroyWindow(blackbox->getXDisplay(), frame.stick_button);
850 frame.stick_button = None;
853 void BlackboxWindow::positionButtons(bool redecorate_label) {
854 string layout = blackbox->getTitlebarLayout();
857 bool hasclose, hasiconify, hasmaximize, haslabel, hasstick;
858 hasclose = hasiconify = hasmaximize = haslabel = hasstick = false;
860 string::const_iterator it, end;
861 for (it = layout.begin(), end = layout.end(); it != end; ++it) {
864 if (! hasclose && (decorations & Decor_Close)) {
870 if (! hasiconify && (decorations & Decor_Iconify)) {
882 if (! hasmaximize && (decorations & Decor_Maximize)) {
896 if (! hasclose && frame.close_button)
897 destroyCloseButton();
898 if (! hasiconify && frame.iconify_button)
899 destroyIconifyButton();
900 if (! hasmaximize && frame.maximize_button)
901 destroyMaximizeButton();
902 if (! hasstick && frame.stick_button)
903 destroyStickyButton();
905 parsed += 'L'; // require that the label be in the layout
907 const unsigned int bsep = frame.bevel_w + 1; // separation between elements
908 const unsigned int by = frame.bevel_w + 1;
909 const unsigned int ty = frame.bevel_w;
911 frame.label_w = frame.inside_w - bsep * 2 -
912 (frame.button_w + bsep) * (parsed.size() - 1);
914 unsigned int x = bsep;
915 for (it = parsed.begin(), end = parsed.end(); it != end; ++it) {
918 if (! frame.close_button) createCloseButton();
919 XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, x, by,
920 frame.button_w, frame.button_w);
921 x += frame.button_w + bsep;
924 if (! frame.iconify_button) createIconifyButton();
925 XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, x, by,
926 frame.button_w, frame.button_w);
927 x += frame.button_w + bsep;
930 if (! frame.stick_button) createStickyButton();
931 XMoveResizeWindow(blackbox->getXDisplay(), frame.stick_button, x, by,
932 frame.button_w, frame.button_w);
933 x += frame.button_w + bsep;
936 if (! frame.maximize_button) createMaximizeButton();
937 XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by,
938 frame.button_w, frame.button_w);
939 x += frame.button_w + bsep;
942 XMoveResizeWindow(blackbox->getXDisplay(), frame.label, x, ty,
943 frame.label_w, frame.label_h);
944 x += frame.label_w + bsep;
949 if (redecorate_label) decorateLabel();
955 void BlackboxWindow::reconfigure(void) {
956 restoreGravity(client.rect);
958 applyGravity(frame.rect);
968 void BlackboxWindow::grabButtons(void) {
969 mod_mask = blackbox->getMouseModMask();
971 if (! screen->isSloppyFocus() || screen->doClickRaise())
972 // grab button 1 for changing focus/raising
973 blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
974 GrabModeSync, GrabModeSync, frame.plate, None,
975 screen->allowScrollLock());
977 if (functions & Func_Move)
978 blackbox->grabButton(Button1, mod_mask, frame.window, True,
979 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
980 GrabModeAsync, frame.window, None,
981 screen->allowScrollLock());
982 if (functions & Func_Resize)
983 blackbox->grabButton(Button3, mod_mask, frame.window, True,
984 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
985 GrabModeAsync, frame.window, None,
986 screen->allowScrollLock());
987 // alt+middle lowers the window
988 blackbox->grabButton(Button2, mod_mask, frame.window, True,
989 ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
990 frame.window, None, screen->allowScrollLock());
994 void BlackboxWindow::ungrabButtons(void) {
995 blackbox->ungrabButton(Button1, 0, frame.plate);
996 blackbox->ungrabButton(Button1, mod_mask, frame.window);
997 blackbox->ungrabButton(Button2, mod_mask, frame.window);
998 blackbox->ungrabButton(Button3, mod_mask, frame.window);
1002 void BlackboxWindow::positionWindows(void) {
1003 XMoveResizeWindow(blackbox->getXDisplay(), frame.window,
1004 frame.rect.x(), frame.rect.y(), frame.inside_w,
1005 (flags.shaded) ? frame.title_h : frame.inside_h);
1006 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.window,
1008 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.plate,
1009 frame.mwm_border_w);
1010 XMoveResizeWindow(blackbox->getXDisplay(), frame.plate,
1011 frame.margin.left - frame.mwm_border_w - frame.border_w,
1012 frame.margin.top - frame.mwm_border_w - frame.border_w,
1013 client.rect.width(), client.rect.height());
1014 XMoveResizeWindow(blackbox->getXDisplay(), client.window,
1015 0, 0, client.rect.width(), client.rect.height());
1016 // ensure client.rect contains the real location
1017 client.rect.setPos(frame.rect.left() + frame.margin.left,
1018 frame.rect.top() + frame.margin.top);
1020 if (decorations & Decor_Titlebar) {
1021 if (frame.title == None) createTitlebar();
1023 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.title,
1025 XMoveResizeWindow(blackbox->getXDisplay(), frame.title, -frame.border_w,
1026 -frame.border_w, frame.inside_w, frame.title_h);
1029 XMapSubwindows(blackbox->getXDisplay(), frame.title);
1030 XMapWindow(blackbox->getXDisplay(), frame.title);
1031 } else if (frame.title) {
1034 if (decorations & Decor_Handle) {
1035 if (frame.handle == None) createHandle();
1036 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.handle,
1038 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.left_grip,
1040 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.right_grip,
1043 // use client.rect here so the value is correct even if shaded
1044 XMoveResizeWindow(blackbox->getXDisplay(), frame.handle,
1046 client.rect.height() + frame.margin.top +
1047 frame.mwm_border_w - frame.border_w,
1048 frame.inside_w, frame.handle_h);
1049 XMoveResizeWindow(blackbox->getXDisplay(), frame.left_grip,
1050 -frame.border_w, -frame.border_w,
1051 frame.grip_w, frame.handle_h);
1052 XMoveResizeWindow(blackbox->getXDisplay(), frame.right_grip,
1053 frame.inside_w - frame.grip_w - frame.border_w,
1054 -frame.border_w, frame.grip_w, frame.handle_h);
1056 XMapSubwindows(blackbox->getXDisplay(), frame.handle);
1057 XMapWindow(blackbox->getXDisplay(), frame.handle);
1058 } else if (frame.handle) {
1061 XSync(blackbox->getXDisplay(), False);
1065 void BlackboxWindow::updateStrut(void) {
1066 unsigned long num = 4;
1067 unsigned long *data;
1068 if (! xatom->getValue(client.window, XAtom::net_wm_strut, XAtom::cardinal,
1073 client.strut.left = data[0];
1074 client.strut.right = data[1];
1075 client.strut.top = data[2];
1076 client.strut.bottom = data[3];
1078 screen->updateAvailableArea();
1085 bool BlackboxWindow::getWindowType(void) {
1086 window_type = (WindowType) -1;
1089 unsigned long num = (unsigned) -1;
1090 if (xatom->getValue(client.window, XAtom::net_wm_window_type, XAtom::atom,
1092 for (unsigned long i = 0; i < num; ++i) {
1093 if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_desktop))
1094 window_type = Type_Desktop;
1095 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dock))
1096 window_type = Type_Dock;
1097 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_toolbar))
1098 window_type = Type_Toolbar;
1099 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_menu))
1100 window_type = Type_Menu;
1101 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_utility))
1102 window_type = Type_Utility;
1103 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_splash))
1104 window_type = Type_Splash;
1105 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dialog))
1106 window_type = Type_Dialog;
1107 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_normal))
1108 window_type = Type_Normal;
1110 xatom->getAtom(XAtom::kde_net_wm_window_type_override))
1111 mwm_decorations = 0; // prevent this window from getting any decor
1116 if (window_type == (WindowType) -1) {
1118 * the window type hint was not set, which means we either classify ourself
1119 * as a normal window or a dialog, depending on if we are a transient.
1122 window_type = Type_Dialog;
1124 window_type = Type_Normal;
1133 void BlackboxWindow::getWMName(void) {
1134 if (xatom->getValue(client.window, XAtom::net_wm_name,
1135 XAtom::utf8, client.title) &&
1136 !client.title.empty()) {
1137 xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
1140 //fall through to using WM_NAME
1141 if (xatom->getValue(client.window, XAtom::wm_name, XAtom::ansi, client.title)
1142 && !client.title.empty()) {
1143 xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
1146 // fall back to an internal default
1147 client.title = "Unnamed";
1148 xatom->setValue(client.window, XAtom::net_wm_visible_name, XAtom::utf8,
1151 #ifdef DEBUG_WITH_ID
1152 // the 16 is the 8 chars of the debug text plus the number
1153 char *tmp = new char[client.title.length() + 16];
1154 sprintf(tmp, "%s; id: 0x%lx", client.title.c_str(), client.window);
1161 void BlackboxWindow::getWMIconName(void) {
1162 if (xatom->getValue(client.window, XAtom::net_wm_icon_name,
1163 XAtom::utf8, client.icon_title) &&
1164 !client.icon_title.empty()) {
1165 xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
1168 //fall through to using WM_ICON_NAME
1169 if (xatom->getValue(client.window, XAtom::wm_icon_name, XAtom::ansi,
1170 client.icon_title) &&
1171 !client.icon_title.empty()) {
1172 xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
1175 // fall back to using the main name
1176 client.icon_title = client.title;
1177 xatom->setValue(client.window, XAtom::net_wm_visible_icon_name, XAtom::utf8,
1183 * Retrieve which WM Protocols are supported by the client window.
1184 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1185 * window's decorations and allow the close behavior.
1186 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1189 void BlackboxWindow::getWMProtocols(void) {
1193 if (XGetWMProtocols(blackbox->getXDisplay(), client.window,
1194 &proto, &num_return)) {
1195 for (int i = 0; i < num_return; ++i) {
1196 if (proto[i] == xatom->getAtom(XAtom::wm_delete_window)) {
1197 decorations |= Decor_Close;
1198 functions |= Func_Close;
1199 } else if (proto[i] == xatom->getAtom(XAtom::wm_take_focus))
1200 flags.send_focus_message = True;
1209 * Gets the value of the WM_HINTS property.
1210 * If the property is not set, then use a set of default values.
1212 void BlackboxWindow::getWMHints(void) {
1213 focus_mode = F_Passive;
1215 // remove from current window group
1216 if (client.window_group) {
1217 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1218 if (group) group->removeWindow(this);
1220 client.window_group = None;
1222 XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), client.window);
1227 if (wmhint->flags & InputHint) {
1228 if (wmhint->input == True) {
1229 if (flags.send_focus_message)
1230 focus_mode = F_LocallyActive;
1232 if (flags.send_focus_message)
1233 focus_mode = F_GloballyActive;
1235 focus_mode = F_NoInput;
1239 if (wmhint->flags & StateHint)
1240 current_state = wmhint->initial_state;
1242 if (wmhint->flags & WindowGroupHint) {
1243 client.window_group = wmhint->window_group;
1245 // add window to the appropriate group
1246 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1247 if (! group) { // no group found, create it!
1248 new BWindowGroup(blackbox, client.window_group);
1249 group = blackbox->searchGroup(client.window_group);
1252 group->addWindow(this);
1260 * Gets the value of the WM_NORMAL_HINTS property.
1261 * If the property is not set, then use a set of default values.
1263 void BlackboxWindow::getWMNormalHints(void) {
1265 XSizeHints sizehint;
1267 client.min_width = client.min_height =
1268 client.width_inc = client.height_inc = 1;
1269 client.base_width = client.base_height = 0;
1270 client.win_gravity = NorthWestGravity;
1272 client.min_aspect_x = client.min_aspect_y =
1273 client.max_aspect_x = client.max_aspect_y = 1;
1276 // don't limit the size of a window, the default max width is the biggest
1278 client.max_width = (unsigned) -1;
1279 client.max_height = (unsigned) -1;
1282 if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window,
1283 &sizehint, &icccm_mask))
1286 client.normal_hint_flags = sizehint.flags;
1288 if (sizehint.flags & PMinSize) {
1289 if (sizehint.min_width >= 0)
1290 client.min_width = sizehint.min_width;
1291 if (sizehint.min_height >= 0)
1292 client.min_height = sizehint.min_height;
1295 if (sizehint.flags & PMaxSize) {
1296 if (sizehint.max_width > static_cast<signed>(client.min_width))
1297 client.max_width = sizehint.max_width;
1299 client.max_width = client.min_width;
1301 if (sizehint.max_height > static_cast<signed>(client.min_height))
1302 client.max_height = sizehint.max_height;
1304 client.max_height = client.min_height;
1307 if (sizehint.flags & PResizeInc) {
1308 client.width_inc = sizehint.width_inc;
1309 client.height_inc = sizehint.height_inc;
1312 #if 0 // we do not support this at the moment
1313 if (sizehint.flags & PAspect) {
1314 client.min_aspect_x = sizehint.min_aspect.x;
1315 client.min_aspect_y = sizehint.min_aspect.y;
1316 client.max_aspect_x = sizehint.max_aspect.x;
1317 client.max_aspect_y = sizehint.max_aspect.y;
1321 if (sizehint.flags & PBaseSize) {
1322 client.base_width = sizehint.base_width;
1323 client.base_height = sizehint.base_height;
1326 if (sizehint.flags & PWinGravity)
1327 client.win_gravity = sizehint.win_gravity;
1332 * Gets the NETWM hints for the class' contained window.
1334 void BlackboxWindow::getNetWMHints(void) {
1335 unsigned long workspace;
1337 if (xatom->getValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
1339 if (workspace == 0xffffffff)
1342 blackbox_attrib.workspace = workspace;
1345 unsigned long *state;
1346 unsigned long num = (unsigned) -1;
1347 if (xatom->getValue(client.window, XAtom::net_wm_state, XAtom::atom,
1351 for (unsigned long i = 0; i < num; ++i) {
1352 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal))
1354 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_shaded))
1355 flags.shaded = True;
1356 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_taskbar))
1357 flags.skip_taskbar = True;
1358 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_pager))
1359 flags.skip_pager = True;
1360 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_fullscreen))
1361 flags.fullscreen = True;
1362 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_hidden))
1363 setState(IconicState);
1364 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_vert))
1366 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_horz))
1370 flags.maximized = 1;
1372 flags.maximized = 2;
1374 flags.maximized = 3;
1382 * Gets the MWM hints for the class' contained window.
1383 * This is used while initializing the window to its first state, and not
1385 * Returns: true if the MWM hints are successfully retreived and applied;
1386 * false if they are not.
1388 void BlackboxWindow::getMWMHints(void) {
1392 num = PropMwmHintsElements;
1393 if (! xatom->getValue(client.window, XAtom::motif_wm_hints,
1394 XAtom::motif_wm_hints, num,
1395 (unsigned long **)&mwm_hint))
1397 if (num < PropMwmHintsElements) {
1402 if (mwm_hint->flags & MwmHintsDecorations) {
1403 if (mwm_hint->decorations & MwmDecorAll) {
1404 mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
1405 Decor_Iconify | Decor_Maximize;
1407 mwm_decorations = 0;
1409 if (mwm_hint->decorations & MwmDecorBorder)
1410 mwm_decorations |= Decor_Border;
1411 if (mwm_hint->decorations & MwmDecorHandle)
1412 mwm_decorations |= Decor_Handle;
1413 if (mwm_hint->decorations & MwmDecorTitle)
1414 mwm_decorations |= Decor_Titlebar;
1415 if (mwm_hint->decorations & MwmDecorIconify)
1416 mwm_decorations |= Decor_Iconify;
1417 if (mwm_hint->decorations & MwmDecorMaximize)
1418 mwm_decorations |= Decor_Maximize;
1422 if (mwm_hint->flags & MwmHintsFunctions) {
1423 if (mwm_hint->functions & MwmFuncAll) {
1424 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize |
1429 if (mwm_hint->functions & MwmFuncResize)
1430 functions |= Func_Resize;
1431 if (mwm_hint->functions & MwmFuncMove)
1432 functions |= Func_Move;
1433 if (mwm_hint->functions & MwmFuncIconify)
1434 functions |= Func_Iconify;
1435 if (mwm_hint->functions & MwmFuncMaximize)
1436 functions |= Func_Maximize;
1437 if (mwm_hint->functions & MwmFuncClose)
1438 functions |= Func_Close;
1446 * Gets the blackbox hints from the class' contained window.
1447 * This is used while initializing the window to its first state, and not
1449 * Returns: true if the hints are successfully retreived and applied; false if
1452 bool BlackboxWindow::getBlackboxHints(void) {
1454 BlackboxHints *blackbox_hint;
1456 num = PropBlackboxHintsElements;
1457 if (! xatom->getValue(client.window, XAtom::blackbox_hints,
1458 XAtom::blackbox_hints, num,
1459 (unsigned long **)&blackbox_hint))
1461 if (num < PropBlackboxHintsElements) {
1462 delete [] blackbox_hint;
1466 if (blackbox_hint->flags & AttribShaded)
1467 flags.shaded = (blackbox_hint->attrib & AttribShaded);
1469 if ((blackbox_hint->flags & AttribMaxHoriz) &&
1470 (blackbox_hint->flags & AttribMaxVert))
1471 flags.maximized = (blackbox_hint->attrib &
1472 (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1473 else if (blackbox_hint->flags & AttribMaxVert)
1474 flags.maximized = (blackbox_hint->attrib & AttribMaxVert) ? 2 : 0;
1475 else if (blackbox_hint->flags & AttribMaxHoriz)
1476 flags.maximized = (blackbox_hint->attrib & AttribMaxHoriz) ? 3 : 0;
1478 if (blackbox_hint->flags & AttribOmnipresent)
1479 flags.stuck = (blackbox_hint->attrib & AttribOmnipresent);
1481 if (blackbox_hint->flags & AttribWorkspace)
1482 blackbox_attrib.workspace = blackbox_hint->workspace;
1484 // if (blackbox_hint->flags & AttribStack)
1485 // don't yet have always on top/bottom for blackbox yet... working
1488 if (blackbox_hint->flags & AttribDecoration) {
1489 switch (blackbox_hint->decoration) {
1491 blackbox_attrib.decoration = DecorNone;
1498 // blackbox_attrib.decoration defaults to DecorNormal
1503 delete [] blackbox_hint;
1509 void BlackboxWindow::getTransientInfo(void) {
1510 if (client.transient_for &&
1511 client.transient_for != (BlackboxWindow *) ~0ul) {
1512 // reset transient_for in preparation of looking for a new owner
1513 client.transient_for->client.transientList.remove(this);
1516 // we have no transient_for until we find a new one
1517 client.transient_for = (BlackboxWindow *) 0;
1520 if (! XGetTransientForHint(blackbox->getXDisplay(), client.window,
1522 // transient_for hint not set
1526 if (trans_for == client.window) {
1527 // wierd client... treat this window as a normal window
1531 if (trans_for == None || trans_for == screen->getRootWindow()) {
1532 // this is an undocumented interpretation of the ICCCM. a transient
1533 // associated with None/Root/itself is assumed to be a modal root
1534 // transient. we don't support the concept of a global transient,
1535 // so we just associate this transient with nothing, and perhaps
1536 // we will add support later for global modality.
1537 client.transient_for = (BlackboxWindow *) ~0ul;
1542 client.transient_for = blackbox->searchWindow(trans_for);
1543 if (! client.transient_for &&
1544 client.window_group && trans_for == client.window_group) {
1545 // no direct transient_for, perhaps this is a group transient?
1546 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1547 if (group) client.transient_for = group->find(screen);
1550 if (! client.transient_for || client.transient_for == this) {
1551 // no transient_for found, or we have a wierd client that wants to be
1552 // a transient for itself, so we treat this window as a normal window
1553 client.transient_for = (BlackboxWindow*) 0;
1557 // Check for a circular transient state: this can lock up Blackbox
1558 // when it tries to find the non-transient window for a transient.
1559 BlackboxWindow *w = this;
1560 while(w->client.transient_for &&
1561 w->client.transient_for != (BlackboxWindow *) ~0ul) {
1562 if(w->client.transient_for == this) {
1563 client.transient_for = (BlackboxWindow*) 0;
1566 w = w->client.transient_for;
1569 if (client.transient_for &&
1570 client.transient_for != (BlackboxWindow *) ~0ul) {
1571 // register ourselves with our new transient_for
1572 client.transient_for->client.transientList.push_back(this);
1573 flags.stuck = client.transient_for->flags.stuck;
1578 BlackboxWindow *BlackboxWindow::getTransientFor(void) const {
1579 if (client.transient_for &&
1580 client.transient_for != (BlackboxWindow*) ~0ul)
1581 return client.transient_for;
1587 * This function is responsible for updating both the client and the frame
1589 * According to the ICCCM a client message is not sent for a resize, only a
1592 void BlackboxWindow::configure(int dx, int dy,
1593 unsigned int dw, unsigned int dh) {
1594 bool send_event = ((frame.rect.x() != dx || frame.rect.y() != dy) &&
1597 if (dw != frame.rect.width() || dh != frame.rect.height()) {
1598 frame.rect.setRect(dx, dy, dw, dh);
1599 frame.inside_w = frame.rect.width() - (frame.border_w * 2);
1600 frame.inside_h = frame.rect.height() - (frame.border_w * 2);
1602 if (frame.rect.right() <= 0 || frame.rect.bottom() <= 0)
1603 frame.rect.setPos(0, 0);
1605 client.rect.setCoords(frame.rect.left() + frame.margin.left,
1606 frame.rect.top() + frame.margin.top,
1607 frame.rect.right() - frame.margin.right,
1608 frame.rect.bottom() - frame.margin.bottom);
1611 if (blackbox->hasShapeExtensions() && flags.shaped) {
1618 redrawWindowFrame();
1620 frame.rect.setPos(dx, dy);
1622 XMoveWindow(blackbox->getXDisplay(), frame.window,
1623 frame.rect.x(), frame.rect.y());
1625 we may have been called just after an opaque window move, so even though
1626 the old coords match the new ones no ConfigureNotify has been sent yet.
1627 There are likely other times when this will be relevant as well.
1629 if (! flags.moving) send_event = True;
1633 // if moving, the update and event will occur when the move finishes
1634 client.rect.setPos(frame.rect.left() + frame.margin.left,
1635 frame.rect.top() + frame.margin.top);
1638 event.type = ConfigureNotify;
1640 event.xconfigure.display = blackbox->getXDisplay();
1641 event.xconfigure.event = client.window;
1642 event.xconfigure.window = client.window;
1643 event.xconfigure.x = client.rect.x();
1644 event.xconfigure.y = client.rect.y();
1645 event.xconfigure.width = client.rect.width();
1646 event.xconfigure.height = client.rect.height();
1647 event.xconfigure.border_width = client.old_bw;
1648 event.xconfigure.above = frame.window;
1649 event.xconfigure.override_redirect = False;
1651 XSendEvent(blackbox->getXDisplay(), client.window, False,
1652 StructureNotifyMask, &event);
1653 XFlush(blackbox->getXDisplay());
1659 void BlackboxWindow::configureShape(void) {
1660 XShapeCombineShape(blackbox->getXDisplay(), frame.window, ShapeBounding,
1661 frame.margin.left - frame.border_w,
1662 frame.margin.top - frame.border_w,
1663 client.window, ShapeBounding, ShapeSet);
1666 XRectangle xrect[2];
1668 if (decorations & Decor_Titlebar) {
1669 xrect[0].x = xrect[0].y = -frame.border_w;
1670 xrect[0].width = frame.rect.width();
1671 xrect[0].height = frame.title_h + (frame.border_w * 2);
1675 if (decorations & Decor_Handle) {
1676 xrect[1].x = -frame.border_w;
1677 xrect[1].y = frame.rect.height() - frame.margin.bottom +
1678 frame.mwm_border_w - frame.border_w;
1679 xrect[1].width = frame.rect.width();
1680 xrect[1].height = frame.handle_h + (frame.border_w * 2);
1684 XShapeCombineRectangles(blackbox->getXDisplay(), frame.window,
1685 ShapeBounding, 0, 0, xrect, num,
1686 ShapeUnion, Unsorted);
1690 void BlackboxWindow::clearShape(void) {
1691 XShapeCombineMask(blackbox->getXDisplay(), frame.window, ShapeBounding,
1692 frame.margin.left - frame.border_w,
1693 frame.margin.top - frame.border_w,
1699 bool BlackboxWindow::setInputFocus(void) {
1700 if (flags.focused) return True;
1702 assert(flags.stuck || // window must be on the current workspace or sticky
1703 blackbox_attrib.workspace == screen->getCurrentWorkspaceID());
1706 We only do this check for normal windows and dialogs because other windows
1707 do this on purpose, such as kde's kicker, and we don't want to go moving
1710 if (window_type == Type_Normal || window_type == Type_Dialog)
1711 if (! frame.rect.intersects(screen->getRect())) {
1712 // client is outside the screen, move it to the center
1713 configure((screen->getWidth() - frame.rect.width()) / 2,
1714 (screen->getHeight() - frame.rect.height()) / 2,
1715 frame.rect.width(), frame.rect.height());
1718 if (client.transientList.size() > 0) {
1719 // transfer focus to any modal transients
1720 BlackboxWindowList::iterator it, end = client.transientList.end();
1721 for (it = client.transientList.begin(); it != end; ++it)
1722 if ((*it)->flags.modal) return (*it)->setInputFocus();
1726 if (focus_mode == F_LocallyActive || focus_mode == F_Passive) {
1727 XSetInputFocus(blackbox->getXDisplay(), client.window,
1728 RevertToPointerRoot, CurrentTime);
1730 /* we could set the focus to none, since the window doesn't accept focus,
1731 * but we shouldn't set focus to nothing since this would surely make
1737 if (flags.send_focus_message) {
1739 ce.xclient.type = ClientMessage;
1740 ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
1741 ce.xclient.display = blackbox->getXDisplay();
1742 ce.xclient.window = client.window;
1743 ce.xclient.format = 32;
1744 ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_take_focus);
1745 ce.xclient.data.l[1] = blackbox->getLastTime();
1746 ce.xclient.data.l[2] = 0l;
1747 ce.xclient.data.l[3] = 0l;
1748 ce.xclient.data.l[4] = 0l;
1749 XSendEvent(blackbox->getXDisplay(), client.window, False,
1751 XFlush(blackbox->getXDisplay());
1758 void BlackboxWindow::iconify(void) {
1759 if (flags.iconic || ! (functions & Func_Iconify)) return;
1761 // We don't need to worry about resizing because resizing always grabs the X
1762 // server. This should only ever happen if using opaque moving.
1767 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1768 * we need to clear the event mask on client.window for a split second.
1769 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1770 * split second, leaving us with a ghost window... so, we need to do this
1771 * while the X server is grabbed
1773 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
1774 StructureNotifyMask;
1775 XGrabServer(blackbox->getXDisplay());
1776 XSelectInput(blackbox->getXDisplay(), client.window,
1777 event_mask & ~StructureNotifyMask);
1778 XUnmapWindow(blackbox->getXDisplay(), client.window);
1779 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
1780 XUngrabServer(blackbox->getXDisplay());
1782 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1783 flags.visible = False;
1784 flags.iconic = True;
1786 setState(IconicState);
1788 screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this);
1790 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
1791 if (i != blackbox_attrib.workspace)
1792 screen->getWorkspace(i)->removeWindow(this, True);
1795 if (isTransient()) {
1796 if (client.transient_for != (BlackboxWindow *) ~0ul &&
1797 ! client.transient_for->flags.iconic) {
1798 // iconify our transient_for
1799 client.transient_for->iconify();
1803 screen->addIcon(this);
1805 if (client.transientList.size() > 0) {
1806 // iconify all transients
1807 BlackboxWindowList::iterator it, end = client.transientList.end();
1808 for (it = client.transientList.begin(); it != end; ++it) {
1809 if (! (*it)->flags.iconic) (*it)->iconify();
1812 screen->updateStackingList();
1816 void BlackboxWindow::show(void) {
1817 flags.visible = True;
1818 flags.iconic = False;
1820 current_state = (flags.shaded) ? IconicState : NormalState;
1821 setState(current_state);
1823 XMapWindow(blackbox->getXDisplay(), client.window);
1824 XMapSubwindows(blackbox->getXDisplay(), frame.window);
1825 XMapWindow(blackbox->getXDisplay(), frame.window);
1830 XTranslateCoordinates(blackbox->getXDisplay(), client.window,
1831 screen->getRootWindow(),
1832 0, 0, &real_x, &real_y, &child);
1833 fprintf(stderr, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1834 client.rect.left(), client.rect.top(), real_x, real_y);
1835 assert(client.rect.left() == real_x && client.rect.top() == real_y);
1840 void BlackboxWindow::deiconify(bool reassoc, bool raise) {
1841 if (flags.iconic || reassoc)
1842 screen->reassociateWindow(this, BSENTINEL, False);
1843 else if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID())
1848 // reassociate and deiconify all transients
1849 if (reassoc && client.transientList.size() > 0) {
1850 BlackboxWindowList::iterator it, end = client.transientList.end();
1851 for (it = client.transientList.begin(); it != end; ++it)
1852 (*it)->deiconify(True, False);
1856 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1860 void BlackboxWindow::close(void) {
1861 if (! (functions & Func_Close)) return;
1864 ce.xclient.type = ClientMessage;
1865 ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
1866 ce.xclient.display = blackbox->getXDisplay();
1867 ce.xclient.window = client.window;
1868 ce.xclient.format = 32;
1869 ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_delete_window);
1870 ce.xclient.data.l[1] = CurrentTime;
1871 ce.xclient.data.l[2] = 0l;
1872 ce.xclient.data.l[3] = 0l;
1873 ce.xclient.data.l[4] = 0l;
1874 XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce);
1875 XFlush(blackbox->getXDisplay());
1879 void BlackboxWindow::withdraw(void) {
1880 // We don't need to worry about resizing because resizing always grabs the X
1881 // server. This should only ever happen if using opaque moving.
1885 flags.visible = False;
1886 flags.iconic = False;
1888 setState(current_state);
1890 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1892 XGrabServer(blackbox->getXDisplay());
1894 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
1895 StructureNotifyMask;
1896 XSelectInput(blackbox->getXDisplay(), client.window,
1897 event_mask & ~StructureNotifyMask);
1898 XUnmapWindow(blackbox->getXDisplay(), client.window);
1899 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
1901 XUngrabServer(blackbox->getXDisplay());
1905 void BlackboxWindow::maximize(unsigned int button) {
1906 if (! (functions & Func_Maximize)) return;
1908 // We don't need to worry about resizing because resizing always grabs the X
1909 // server. This should only ever happen if using opaque moving.
1913 if (flags.maximized) {
1914 flags.maximized = 0;
1916 blackbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert);
1917 blackbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert);
1920 when a resize finishes, maximize(0) is called to clear any maximization
1921 flags currently set. Otherwise it still thinks it is maximized.
1922 so we do not need to call configure() because resizing will handle it
1924 if (! flags.resizing)
1925 configure(blackbox_attrib.premax_x, blackbox_attrib.premax_y,
1926 blackbox_attrib.premax_w, blackbox_attrib.premax_h);
1928 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
1929 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
1931 redrawAllButtons(); // in case it is not called in configure()
1932 setState(current_state);
1936 blackbox_attrib.premax_x = frame.rect.x();
1937 blackbox_attrib.premax_y = frame.rect.y();
1938 blackbox_attrib.premax_w = frame.rect.width();
1939 // use client.rect so that clients can be restored even if shaded
1940 blackbox_attrib.premax_h =
1941 client.rect.height() + frame.margin.top + frame.margin.bottom;
1944 if (screen->isXineramaActive() && blackbox->doXineramaMaximizing()) {
1945 // find the area to use
1946 RectList availableAreas = screen->allAvailableAreas();
1947 RectList::iterator it, end = availableAreas.end();
1949 for (it = availableAreas.begin(); it != end; ++it)
1950 if (it->intersects(frame.rect)) break;
1951 if (it == end) // the window isn't inside an area
1952 it = availableAreas.begin(); // so just default to the first one
1954 frame.changing = *it;
1957 frame.changing = screen->availableArea();
1961 blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
1962 blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
1966 blackbox_attrib.flags |= AttribMaxVert;
1967 blackbox_attrib.attrib |= AttribMaxVert;
1969 frame.changing.setX(frame.rect.x());
1970 frame.changing.setWidth(frame.rect.width());
1974 blackbox_attrib.flags |= AttribMaxHoriz;
1975 blackbox_attrib.attrib |= AttribMaxHoriz;
1977 frame.changing.setY(frame.rect.y());
1978 frame.changing.setHeight(frame.rect.height());
1985 blackbox_attrib.flags ^= AttribShaded;
1986 blackbox_attrib.attrib ^= AttribShaded;
1987 flags.shaded = False;
1990 flags.maximized = button;
1992 configure(frame.changing.x(), frame.changing.y(),
1993 frame.changing.width(), frame.changing.height());
1995 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1996 redrawAllButtons(); // in case it is not called in configure()
1997 setState(current_state);
2001 // re-maximizes the window to take into account availableArea changes
2002 void BlackboxWindow::remaximize(void) {
2004 // we only update the window's attributes otherwise we lose the shade bit
2005 switch(flags.maximized) {
2007 blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
2008 blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
2012 blackbox_attrib.flags |= AttribMaxVert;
2013 blackbox_attrib.attrib |= AttribMaxVert;
2017 blackbox_attrib.flags |= AttribMaxHoriz;
2018 blackbox_attrib.attrib |= AttribMaxHoriz;
2024 // save the original dimensions because maximize will wipe them out
2025 int premax_x = blackbox_attrib.premax_x,
2026 premax_y = blackbox_attrib.premax_y,
2027 premax_w = blackbox_attrib.premax_w,
2028 premax_h = blackbox_attrib.premax_h;
2030 unsigned int button = flags.maximized;
2031 flags.maximized = 0; // trick maximize() into working
2034 // restore saved values
2035 blackbox_attrib.premax_x = premax_x;
2036 blackbox_attrib.premax_y = premax_y;
2037 blackbox_attrib.premax_w = premax_w;
2038 blackbox_attrib.premax_h = premax_h;
2042 void BlackboxWindow::setWorkspace(unsigned int n) {
2043 blackbox_attrib.flags |= AttribWorkspace;
2044 blackbox_attrib.workspace = n;
2045 if (n == BSENTINEL) { // iconified window
2047 we set the workspace to 'all workspaces' so that taskbars will show the
2048 window. otherwise, it made uniconifying a window imposible without the
2049 blackbox workspace menu
2053 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n);
2057 void BlackboxWindow::shade(void) {
2059 XResizeWindow(blackbox->getXDisplay(), frame.window,
2060 frame.inside_w, frame.inside_h);
2061 flags.shaded = False;
2062 blackbox_attrib.flags ^= AttribShaded;
2063 blackbox_attrib.attrib ^= AttribShaded;
2065 setState(NormalState);
2067 // set the frame rect to the normal size
2068 frame.rect.setHeight(client.rect.height() + frame.margin.top +
2069 frame.margin.bottom);
2071 if (! (decorations & Decor_Titlebar))
2072 return; // can't shade it without a titlebar!
2074 XResizeWindow(blackbox->getXDisplay(), frame.window,
2075 frame.inside_w, frame.title_h);
2076 flags.shaded = True;
2077 blackbox_attrib.flags |= AttribShaded;
2078 blackbox_attrib.attrib |= AttribShaded;
2080 setState(IconicState);
2082 // set the frame rect to the shaded size
2083 frame.rect.setHeight(frame.title_h + (frame.border_w * 2));
2089 * (Un)Sticks a window and its relatives.
2091 void BlackboxWindow::stick(void) {
2093 blackbox_attrib.flags ^= AttribOmnipresent;
2094 blackbox_attrib.attrib ^= AttribOmnipresent;
2096 flags.stuck = False;
2098 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
2099 if (i != blackbox_attrib.workspace)
2100 screen->getWorkspace(i)->removeWindow(this, True);
2103 screen->reassociateWindow(this, BSENTINEL, True);
2104 // temporary fix since sticky windows suck. set the hint to what we
2105 // actually hold in our data.
2106 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
2107 blackbox_attrib.workspace);
2109 setState(current_state);
2113 blackbox_attrib.flags |= AttribOmnipresent;
2114 blackbox_attrib.attrib |= AttribOmnipresent;
2116 // temporary fix since sticky windows suck. set the hint to a different
2117 // value than that contained in the class' data.
2118 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
2121 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
2122 if (i != blackbox_attrib.workspace)
2123 screen->getWorkspace(i)->addWindow(this, False, True);
2125 setState(current_state);
2131 if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
2132 client.transient_for->isStuck() != flags.stuck)
2133 client.transient_for->stick();
2134 // go down the chain
2135 BlackboxWindowList::iterator it;
2136 const BlackboxWindowList::iterator end = client.transientList.end();
2137 for (it = client.transientList.begin(); it != end; ++it)
2138 if ((*it)->isStuck() != flags.stuck)
2143 void BlackboxWindow::redrawWindowFrame(void) const {
2144 if (decorations & Decor_Titlebar) {
2145 if (flags.focused) {
2147 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2148 frame.title, frame.ftitle);
2150 XSetWindowBackground(blackbox->getXDisplay(),
2151 frame.title, frame.ftitle_pixel);
2154 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2155 frame.title, frame.utitle);
2157 XSetWindowBackground(blackbox->getXDisplay(),
2158 frame.title, frame.utitle_pixel);
2160 XClearWindow(blackbox->getXDisplay(), frame.title);
2166 if (decorations & Decor_Handle) {
2167 if (flags.focused) {
2169 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2170 frame.handle, frame.fhandle);
2172 XSetWindowBackground(blackbox->getXDisplay(),
2173 frame.handle, frame.fhandle_pixel);
2176 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2177 frame.left_grip, frame.fgrip);
2178 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2179 frame.right_grip, frame.fgrip);
2181 XSetWindowBackground(blackbox->getXDisplay(),
2182 frame.left_grip, frame.fgrip_pixel);
2183 XSetWindowBackground(blackbox->getXDisplay(),
2184 frame.right_grip, frame.fgrip_pixel);
2188 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2189 frame.handle, frame.uhandle);
2191 XSetWindowBackground(blackbox->getXDisplay(),
2192 frame.handle, frame.uhandle_pixel);
2195 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2196 frame.left_grip, frame.ugrip);
2197 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2198 frame.right_grip, frame.ugrip);
2200 XSetWindowBackground(blackbox->getXDisplay(),
2201 frame.left_grip, frame.ugrip_pixel);
2202 XSetWindowBackground(blackbox->getXDisplay(),
2203 frame.right_grip, frame.ugrip_pixel);
2206 XClearWindow(blackbox->getXDisplay(), frame.handle);
2207 XClearWindow(blackbox->getXDisplay(), frame.left_grip);
2208 XClearWindow(blackbox->getXDisplay(), frame.right_grip);
2211 if (decorations & Decor_Border) {
2213 XSetWindowBorder(blackbox->getXDisplay(),
2214 frame.plate, frame.fborder_pixel);
2216 XSetWindowBorder(blackbox->getXDisplay(),
2217 frame.plate, frame.uborder_pixel);
2222 void BlackboxWindow::setFocusFlag(bool focus) {
2223 // only focus a window if it is visible
2224 if (focus && ! flags.visible)
2227 flags.focused = focus;
2229 redrawWindowFrame();
2232 blackbox->setFocusedWindow(this);
2236 void BlackboxWindow::installColormap(bool install) {
2237 int i = 0, ncmap = 0;
2238 Colormap *cmaps = XListInstalledColormaps(blackbox->getXDisplay(),
2239 client.window, &ncmap);
2241 XWindowAttributes wattrib;
2242 if (XGetWindowAttributes(blackbox->getXDisplay(),
2243 client.window, &wattrib)) {
2245 // install the window's colormap
2246 for (i = 0; i < ncmap; i++) {
2247 if (*(cmaps + i) == wattrib.colormap)
2248 // this window is using an installed color map... do not install
2251 // otherwise, install the window's colormap
2253 XInstallColormap(blackbox->getXDisplay(), wattrib.colormap);
2255 // uninstall the window's colormap
2256 for (i = 0; i < ncmap; i++) {
2257 if (*(cmaps + i) == wattrib.colormap)
2258 // we found the colormap to uninstall
2259 XUninstallColormap(blackbox->getXDisplay(), wattrib.colormap);
2269 void BlackboxWindow::setAllowedActions(void) {
2273 actions[num++] = xatom->getAtom(XAtom::net_wm_action_shade);
2274 actions[num++] = xatom->getAtom(XAtom::net_wm_action_change_desktop);
2275 actions[num++] = xatom->getAtom(XAtom::net_wm_action_close);
2277 if (functions & Func_Move)
2278 actions[num++] = xatom->getAtom(XAtom::net_wm_action_move);
2279 if (functions & Func_Resize)
2280 actions[num++] = xatom->getAtom(XAtom::net_wm_action_resize);
2281 if (functions & Func_Maximize) {
2282 actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_horz);
2283 actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_vert);
2286 xatom->setValue(client.window, XAtom::net_wm_allowed_actions, XAtom::atom,
2291 void BlackboxWindow::setState(unsigned long new_state) {
2292 current_state = new_state;
2294 unsigned long state[2];
2295 state[0] = current_state;
2297 xatom->setValue(client.window, XAtom::wm_state, XAtom::wm_state, state, 2);
2299 xatom->setValue(client.window, XAtom::blackbox_attributes,
2300 XAtom::blackbox_attributes, (unsigned long *)&blackbox_attrib,
2301 PropBlackboxAttributesElements);
2306 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_modal);
2308 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_shaded);
2310 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_hidden);
2311 if (flags.skip_taskbar)
2312 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_taskbar);
2313 if (flags.skip_pager)
2314 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_pager);
2315 if (flags.fullscreen)
2316 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_fullscreen);
2317 if (flags.maximized == 1 || flags.maximized == 2)
2318 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_vert);
2319 if (flags.maximized == 1 || flags.maximized == 3)
2320 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_horz);
2321 xatom->setValue(client.window, XAtom::net_wm_state, XAtom::atom,
2326 bool BlackboxWindow::getState(void) {
2327 bool ret = xatom->getValue(client.window, XAtom::wm_state, XAtom::wm_state,
2329 if (! ret) current_state = 0;
2334 void BlackboxWindow::restoreAttributes(void) {
2335 unsigned long num = PropBlackboxAttributesElements;
2336 BlackboxAttributes *net;
2337 if (! xatom->getValue(client.window, XAtom::blackbox_attributes,
2338 XAtom::blackbox_attributes, num,
2339 (unsigned long **)&net))
2341 if (num < PropBlackboxAttributesElements) {
2346 if (net->flags & AttribShaded && net->attrib & AttribShaded) {
2347 flags.shaded = False;
2348 unsigned long orig_state = current_state;
2352 At this point in the life of a window, current_state should only be set
2353 to IconicState if the window was an *icon*, not if it was shaded.
2355 if (orig_state != IconicState)
2356 current_state = WithdrawnState;
2359 if (net->workspace != screen->getCurrentWorkspaceID() &&
2360 net->workspace < screen->getWorkspaceCount())
2361 screen->reassociateWindow(this, net->workspace, True);
2363 if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) &&
2364 (blackbox_attrib.workspace < screen->getWorkspaceCount())) {
2365 // set to WithdrawnState so it will be mapped on the new workspace
2366 if (current_state == NormalState) current_state = WithdrawnState;
2367 } else if (current_state == WithdrawnState) {
2368 // the window is on this workspace and is Withdrawn, so it is waiting to
2370 current_state = NormalState;
2373 if (net->flags & AttribOmnipresent && net->attrib & AttribOmnipresent &&
2377 // if the window was on another workspace, it was going to be hidden. this
2378 // specifies that the window should be mapped since it is sticky.
2379 if (current_state == WithdrawnState) current_state = NormalState;
2382 if (net->flags & AttribMaxHoriz || net->flags & AttribMaxVert) {
2383 int x = net->premax_x, y = net->premax_y;
2384 unsigned int w = net->premax_w, h = net->premax_h;
2385 flags.maximized = 0;
2388 if ((net->flags & AttribMaxHoriz) &&
2389 (net->flags & AttribMaxVert))
2390 m = (net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
2391 else if (net->flags & AttribMaxVert)
2392 m = (net->attrib & AttribMaxVert) ? 2 : 0;
2393 else if (net->flags & AttribMaxHoriz)
2394 m = (net->attrib & AttribMaxHoriz) ? 3 : 0;
2398 blackbox_attrib.premax_x = x;
2399 blackbox_attrib.premax_y = y;
2400 blackbox_attrib.premax_w = w;
2401 blackbox_attrib.premax_h = h;
2404 if (net->flags & AttribDecoration) {
2405 switch (net->decoration) {
2410 /* since tools only let you toggle this anyways, we'll just make that all
2411 it supports for now.
2422 // with the state set it will then be the map event's job to read the
2423 // window's state and behave accordingly
2430 * Positions the Rect r according the the client window position and
2433 void BlackboxWindow::applyGravity(Rect &r) {
2434 // apply horizontal window gravity
2435 switch (client.win_gravity) {
2437 case NorthWestGravity:
2438 case SouthWestGravity:
2440 r.setX(client.rect.x());
2446 r.setX(client.rect.x() - (frame.margin.left + frame.margin.right) / 2);
2449 case NorthEastGravity:
2450 case SouthEastGravity:
2452 r.setX(client.rect.x() - frame.margin.left - frame.margin.right + 2);
2457 r.setX(client.rect.x() - frame.margin.left);
2461 // apply vertical window gravity
2462 switch (client.win_gravity) {
2464 case NorthWestGravity:
2465 case NorthEastGravity:
2467 r.setY(client.rect.y());
2473 r.setY(client.rect.y() - (frame.margin.top + frame.margin.bottom) / 2);
2476 case SouthWestGravity:
2477 case SouthEastGravity:
2479 r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom + 2);
2484 r.setY(client.rect.y() - frame.margin.top);
2491 * The reverse of the applyGravity function.
2493 * Positions the Rect r according to the frame window position and
2496 void BlackboxWindow::restoreGravity(Rect &r) {
2497 // restore horizontal window gravity
2498 switch (client.win_gravity) {
2500 case NorthWestGravity:
2501 case SouthWestGravity:
2503 r.setX(frame.rect.x());
2509 r.setX(frame.rect.x() + (frame.margin.left + frame.margin.right) / 2);
2512 case NorthEastGravity:
2513 case SouthEastGravity:
2515 r.setX(frame.rect.x() + frame.margin.left + frame.margin.right - 2);
2520 r.setX(frame.rect.x() + frame.margin.left);
2524 // restore vertical window gravity
2525 switch (client.win_gravity) {
2527 case NorthWestGravity:
2528 case NorthEastGravity:
2530 r.setY(frame.rect.y());
2536 r.setY(frame.rect.y() + (frame.margin.top + frame.margin.bottom) / 2);
2539 case SouthWestGravity:
2540 case SouthEastGravity:
2542 r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom - 2);
2547 r.setY(frame.rect.y() + frame.margin.top);
2553 void BlackboxWindow::redrawLabel(void) const {
2554 if (flags.focused) {
2556 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2557 frame.label, frame.flabel);
2559 XSetWindowBackground(blackbox->getXDisplay(),
2560 frame.label, frame.flabel_pixel);
2563 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2564 frame.label, frame.ulabel);
2566 XSetWindowBackground(blackbox->getXDisplay(),
2567 frame.label, frame.ulabel_pixel);
2569 XClearWindow(blackbox->getXDisplay(), frame.label);
2571 WindowStyle *style = screen->getWindowStyle();
2573 int pos = frame.bevel_w * 2;
2574 style->doJustify(client.title.c_str(), pos, frame.label_w, frame.bevel_w * 4);
2575 style->font->drawString(frame.label, pos, 1,
2576 (flags.focused ? style->l_text_focus :
2577 style->l_text_unfocus),
2582 void BlackboxWindow::redrawAllButtons(void) const {
2583 if (frame.iconify_button) redrawIconifyButton(False);
2584 if (frame.maximize_button) redrawMaximizeButton(flags.maximized);
2585 if (frame.close_button) redrawCloseButton(False);
2586 if (frame.stick_button) redrawStickyButton(flags.stuck);
2590 void BlackboxWindow::redrawButton(bool pressed, Window win,
2591 Pixmap fppix, unsigned long fppixel,
2592 Pixmap uppix, unsigned long uppixel,
2593 Pixmap fpix, unsigned long fpixel,
2594 Pixmap upix, unsigned long upixel) const {
2599 if (flags.focused) {
2607 if (flags.focused) {
2617 XSetWindowBackgroundPixmap(blackbox->getXDisplay(), win, p);
2619 XSetWindowBackground(blackbox->getXDisplay(), win, pix);
2623 void BlackboxWindow::redrawIconifyButton(bool pressed) const {
2624 redrawButton(pressed, frame.iconify_button,
2625 frame.pfbutton, frame.pfbutton_pixel,
2626 frame.pubutton, frame.pubutton_pixel,
2627 frame.fbutton, frame.fbutton_pixel,
2628 frame.ubutton, frame.ubutton_pixel);
2630 XClearWindow(blackbox->getXDisplay(), frame.iconify_button);
2631 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2632 screen->getWindowStyle()->b_pic_unfocus);
2634 #ifdef BITMAPBUTTONS
2635 PixmapMask pm = screen->getWindowStyle()->icon_button;
2637 if (screen->getWindowStyle()->icon_button.mask != None) {
2638 XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask);
2639 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(),
2640 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2);
2642 XFillRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(),
2643 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2,
2644 (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2);
2646 XSetClipMask(blackbox->getXDisplay(), pen.gc(), None);
2647 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0);
2649 #endif // BITMAPBUTTONS
2650 XDrawRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(),
2651 2, (frame.button_w - 5), (frame.button_w - 5), 2);
2652 #ifdef BITMAPBUTTONS
2654 #endif // BITMAPBUTTONS
2658 void BlackboxWindow::redrawMaximizeButton(bool pressed) const {
2659 redrawButton(pressed, frame.maximize_button,
2660 frame.pfbutton, frame.pfbutton_pixel,
2661 frame.pubutton, frame.pubutton_pixel,
2662 frame.fbutton, frame.fbutton_pixel,
2663 frame.ubutton, frame.ubutton_pixel);
2665 XClearWindow(blackbox->getXDisplay(), frame.maximize_button);
2667 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2668 screen->getWindowStyle()->b_pic_unfocus);
2670 #ifdef BITMAPBUTTONS
2671 PixmapMask pm = screen->getWindowStyle()->max_button;
2673 if (pm.mask != None) {
2674 XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask);
2675 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(),
2676 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2);
2678 XFillRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2679 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2,
2680 (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2);
2682 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 );
2683 XSetClipMask( blackbox->getXDisplay(), pen.gc(), None );
2685 #endif // BITMAPBUTTONS
2686 XDrawRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2687 2, 2, (frame.button_w - 5), (frame.button_w - 5));
2688 XDrawLine(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2689 2, 3, (frame.button_w - 3), 3);
2690 #ifdef BITMAPBUTTONS
2692 #endif // BITMAPBUTTONS
2696 void BlackboxWindow::redrawCloseButton(bool pressed) const {
2697 redrawButton(pressed, frame.close_button,
2698 frame.pfbutton, frame.pfbutton_pixel,
2699 frame.pubutton, frame.pubutton_pixel,
2700 frame.fbutton, frame.fbutton_pixel,
2701 frame.ubutton, frame.ubutton_pixel);
2703 XClearWindow(blackbox->getXDisplay(), frame.close_button);
2705 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2706 screen->getWindowStyle()->b_pic_unfocus);
2708 #ifdef BITMAPBUTTONS
2709 PixmapMask pm = screen->getWindowStyle()->close_button;
2711 if (pm.mask != None) {
2712 XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask);
2713 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(),
2714 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2);
2716 XFillRectangle(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2717 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2,
2718 (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2);
2721 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 );
2722 XSetClipMask( blackbox->getXDisplay(), pen.gc(), None );
2724 #endif // BITMAPBUTTONS
2725 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2726 2, 2, (frame.button_w - 3), (frame.button_w - 3));
2727 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2728 2, (frame.button_w - 3), (frame.button_w - 3), 2);
2729 #ifdef BITMAPBUTTONS
2731 #endif // BITMAPBUTTONS
2734 void BlackboxWindow::redrawStickyButton(bool pressed) const {
2735 redrawButton(pressed, frame.stick_button,
2736 frame.pfbutton, frame.pfbutton_pixel,
2737 frame.pubutton, frame.pubutton_pixel,
2738 frame.fbutton, frame.fbutton_pixel,
2739 frame.ubutton, frame.ubutton_pixel);
2741 XClearWindow(blackbox->getXDisplay(), frame.stick_button);
2743 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2744 screen->getWindowStyle()->b_pic_unfocus);
2746 #ifdef BITMAPBUTTONS
2747 PixmapMask pm = screen->getWindowStyle()->stick_button;
2749 if (pm.mask != None) {
2750 XSetClipMask(blackbox->getXDisplay(), pen.gc(), pm.mask);
2751 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(),
2752 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2);
2754 XFillRectangle(blackbox->getXDisplay(), frame.stick_button, pen.gc(),
2755 (frame.button_w - pm.w)/2, (frame.button_w - pm.h)/2,
2756 (frame.button_w + pm.w)/2, (frame.button_w + pm.h)/2);
2759 XSetClipOrigin(blackbox->getXDisplay(), pen.gc(), 0, 0 );
2760 XSetClipMask( blackbox->getXDisplay(), pen.gc(), None );
2762 #endif // BITMAPBUTTONS
2763 XFillRectangle(blackbox->getXDisplay(), frame.stick_button, pen.gc(),
2764 frame.button_w/2 - 1, frame.button_w/2 -1, 2, 2 );
2765 #ifdef BITMAPBUTTONS
2770 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) {
2771 if (re->window != client.window)
2775 fprintf(stderr, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2780 Even though the window wants to be shown, if it is not on the current
2781 workspace, then it isn't going to be shown right now.
2783 if (! flags.stuck &&
2784 blackbox_attrib.workspace != screen->getCurrentWorkspaceID() &&
2785 blackbox_attrib.workspace < screen->getWorkspaceCount())
2786 if (current_state == NormalState) current_state = WithdrawnState;
2788 switch (current_state) {
2793 case WithdrawnState:
2802 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2804 if (! blackbox->isStartup()) {
2805 XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped
2806 if (screen->doFocusNew() || (isTransient() && getTransientFor() &&
2807 getTransientFor()->isFocused())) {
2810 if (screen->getPlacementPolicy() == BScreen::ClickMousePlacement) {
2814 XQueryPointer(blackbox->getXDisplay(), screen->getRootWindow(),
2815 &r, &c, &rx, &ry, &x, &y, &m);
2825 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent *ue) {
2826 if (ue->window != client.window)
2830 fprintf(stderr, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2834 screen->unmanageWindow(this, False);
2838 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent *de) {
2839 if (de->window != client.window)
2843 fprintf(stderr, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2847 screen->unmanageWindow(this, False);
2851 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent *re) {
2852 if (re->window != client.window || re->parent == frame.plate)
2856 fprintf(stderr, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2857 "0x%lx.\n", client.window, re->parent);
2862 XPutBackEvent(blackbox->getXDisplay(), &ev);
2863 screen->unmanageWindow(this, True);
2867 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) {
2868 if (pe->state == PropertyDelete || ! validateClient())
2872 fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2878 case XA_WM_CLIENT_MACHINE:
2882 case XA_WM_TRANSIENT_FOR: {
2883 bool s = flags.stuck;
2885 // determine if this is a transient window
2888 if (flags.stuck != s) stick();
2890 // adjust the window decorations based on transience
2891 if (isTransient()) {
2892 functions &= ~Func_Maximize;
2893 setAllowedActions();
2905 case XA_WM_ICON_NAME:
2907 if (flags.iconic) screen->propagateWindowName(this);
2910 case XAtom::net_wm_name:
2914 if (decorations & Decor_Titlebar)
2917 screen->propagateWindowName(this);
2920 case XA_WM_NORMAL_HINTS: {
2923 if ((client.normal_hint_flags & PMinSize) &&
2924 (client.normal_hint_flags & PMaxSize)) {
2925 // the window now can/can't resize itself, so the buttons need to be
2928 if (client.max_width <= client.min_width &&
2929 client.max_height <= client.min_height) {
2930 functions &= ~(Func_Resize | Func_Maximize);
2932 if (! isTransient())
2933 functions |= Func_Maximize;
2934 functions |= Func_Resize;
2937 setAllowedActions();
2941 Rect old_rect = frame.rect;
2945 if (old_rect != frame.rect)
2952 if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) {
2955 if ((decorations & Decor_Close) && (! frame.close_button)) {
2956 createCloseButton();
2957 if (decorations & Decor_Titlebar) {
2958 positionButtons(True);
2959 XMapSubwindows(blackbox->getXDisplay(), frame.title);
2962 } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) {
2971 void BlackboxWindow::exposeEvent(const XExposeEvent *ee) {
2973 fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window);
2976 if (frame.label == ee->window && (decorations & Decor_Titlebar))
2978 else if (frame.close_button == ee->window)
2979 redrawCloseButton(False);
2980 else if (frame.maximize_button == ee->window)
2981 redrawMaximizeButton(flags.maximized);
2982 else if (frame.iconify_button == ee->window)
2983 redrawIconifyButton(False);
2984 else if (frame.stick_button == ee->window)
2985 redrawStickyButton(flags.stuck);
2989 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) {
2990 if (cr->window != client.window || flags.iconic)
2993 if (cr->value_mask & CWBorderWidth)
2994 client.old_bw = cr->border_width;
2996 if (cr->value_mask & (CWX | CWY | CWWidth | CWHeight)) {
2997 frame.changing = frame.rect;
2999 if (cr->value_mask & (CWX | CWY)) {
3000 if (cr->value_mask & CWX)
3001 client.rect.setX(cr->x);
3002 if (cr->value_mask & CWY)
3003 client.rect.setY(cr->y);
3005 applyGravity(frame.changing);
3008 if (cr->value_mask & (CWWidth | CWHeight)) {
3009 if (cr->value_mask & CWWidth)
3010 frame.changing.setWidth(cr->width +
3011 frame.margin.left + frame.margin.right);
3013 if (cr->value_mask & CWHeight)
3014 frame.changing.setHeight(cr->height +
3015 frame.margin.top + frame.margin.bottom);
3018 if a position change has been specified, then that position will be
3019 used instead of determining a position based on the window's gravity.
3021 if (! (cr->value_mask & (CWX | CWY))) {
3023 switch (client.win_gravity) {
3024 case NorthEastGravity:
3028 case SouthWestGravity:
3030 corner = BottomLeft;
3032 case SouthEastGravity:
3033 corner = BottomRight;
3035 default: // NorthWest, Static, etc
3042 configure(frame.changing.x(), frame.changing.y(),
3043 frame.changing.width(), frame.changing.height());
3046 if (cr->value_mask & CWStackMode && !isDesktop()) {
3047 switch (cr->detail) {
3050 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
3056 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3063 void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) {
3065 fprintf(stderr, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3069 if (frame.maximize_button == be->window && be->button <= 3) {
3070 redrawMaximizeButton(True);
3071 } else if (be->button == 1 || (be->button == 3 && be->state == mod_mask)) {
3072 if (! flags.focused)
3075 if (frame.iconify_button == be->window) {
3076 redrawIconifyButton(True);
3077 } else if (frame.close_button == be->window) {
3078 redrawCloseButton(True);
3079 } else if (frame.stick_button == be->window) {
3080 redrawStickyButton(True);
3081 } else if (frame.plate == be->window) {
3082 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3084 XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time);
3086 if (frame.title == be->window || frame.label == be->window) {
3087 if (((be->time - lastButtonPressTime) <=
3088 blackbox->getDoubleClickInterval()) ||
3089 (be->state == ControlMask)) {
3090 lastButtonPressTime = 0;
3093 lastButtonPressTime = be->time;
3097 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3099 } else if (be->button == 2 && (be->window != frame.iconify_button) &&
3100 (be->window != frame.close_button) &&
3101 (be->window != frame.stick_button)) {
3102 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
3104 } else if (be->button == 4) {
3105 if ((be->window == frame.label ||
3106 be->window == frame.title ||
3107 be->window == frame.maximize_button ||
3108 be->window == frame.iconify_button ||
3109 be->window == frame.close_button ||
3110 be->window == frame.stick_button) &&
3114 } else if (be->button == 5) {
3115 if ((be->window == frame.label ||
3116 be->window == frame.title ||
3117 be->window == frame.maximize_button ||
3118 be->window == frame.iconify_button ||
3119 be->window == frame.close_button ||
3120 be->window == frame.stick_button) &&
3127 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) {
3129 fprintf(stderr, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3133 if (re->window == frame.maximize_button &&
3134 re->button >= 1 && re->button <= 3) {
3135 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3136 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
3137 maximize(re->button);
3139 redrawMaximizeButton(flags.maximized);
3141 } else if (re->window == frame.iconify_button && re->button == 1) {
3142 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3143 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
3146 redrawIconifyButton(False);
3148 } else if (re->window == frame.stick_button && re->button == 1) {
3149 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3150 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
3153 redrawStickyButton(False);
3155 } else if (re->window == frame.close_button & re->button == 1) {
3156 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3157 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w)))
3159 redrawCloseButton(False);
3160 } else if (flags.moving) {
3162 } else if (flags.resizing) {
3164 } else if (re->window == frame.window) {
3165 if (re->button == 2 && re->state == mod_mask)
3166 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3172 void BlackboxWindow::beginMove(int x_root, int y_root) {
3173 if (! (functions & Func_Move)) return;
3175 assert(! (flags.resizing || flags.moving));
3178 Only one window can be moved/resized at a time. If another window is already
3179 being moved or resized, then stop it before whating to work with this one.
3181 BlackboxWindow *changing = blackbox->getChangingWindow();
3182 if (changing && changing != this) {
3183 if (changing->flags.moving)
3184 changing->endMove();
3185 else // if (changing->flags.resizing)
3186 changing->endResize();
3189 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3190 PointerMotionMask | ButtonReleaseMask,
3191 GrabModeAsync, GrabModeAsync,
3192 None, blackbox->getMoveCursor(), CurrentTime);
3194 flags.moving = True;
3195 blackbox->setChangingWindow(this);
3197 if (! screen->doOpaqueMove()) {
3198 XGrabServer(blackbox->getXDisplay());
3200 frame.changing = frame.rect;
3201 screen->showPosition(frame.changing.x(), frame.changing.y());
3203 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3207 frame.changing.width() - 1,
3208 frame.changing.height() - 1);
3211 frame.grab_x = x_root - frame.rect.x() - frame.border_w;
3212 frame.grab_y = y_root - frame.rect.y() - frame.border_w;
3216 void BlackboxWindow::doMove(int x_root, int y_root) {
3217 assert(flags.moving);
3218 assert(blackbox->getChangingWindow() == this);
3220 int dx = x_root - frame.grab_x, dy = y_root - frame.grab_y;
3221 dx -= frame.border_w;
3222 dy -= frame.border_w;
3224 doWindowSnapping(dx, dy);
3226 if (screen->doOpaqueMove()) {
3227 if (screen->doWorkspaceWarping())
3228 doWorkspaceWarping(x_root, y_root, dx);
3230 configure(dx, dy, frame.rect.width(), frame.rect.height());
3232 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3236 frame.changing.width() - 1,
3237 frame.changing.height() - 1);
3239 if (screen->doWorkspaceWarping())
3240 doWorkspaceWarping(x_root, y_root, dx);
3242 frame.changing.setPos(dx, dy);
3244 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3248 frame.changing.width() - 1,
3249 frame.changing.height() - 1);
3252 screen->showPosition(dx, dy);
3256 void BlackboxWindow::doWorkspaceWarping(int x_root, int y_root, int &dx) {
3257 // workspace warping
3259 unsigned int dest = screen->getCurrentWorkspaceID();
3263 if (dest > 0) dest--;
3264 else dest = screen->getNumberOfWorkspaces() - 1;
3266 } else if (x_root >= screen->getRect().right()) {
3269 if (dest < screen->getNumberOfWorkspaces() - 1) dest++;
3275 bool focus = flags.focused; // had focus while moving?
3277 int dest_x = x_root;
3279 dest_x += screen->getRect().width() - 1;
3280 dx += screen->getRect().width() - 1;
3282 dest_x -= screen->getRect().width() - 1;
3283 dx -= screen->getRect().width() - 1;
3287 screen->reassociateWindow(this, dest, False);
3288 screen->changeWorkspaceID(dest);
3290 if (screen->doOpaqueMove())
3291 XGrabServer(blackbox->getXDisplay());
3293 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3294 XWarpPointer(blackbox->getXDisplay(), None,
3295 screen->getRootWindow(), 0, 0, 0, 0,
3297 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3298 PointerMotionMask | ButtonReleaseMask,
3299 GrabModeAsync, GrabModeAsync,
3300 None, blackbox->getMoveCursor(), CurrentTime);
3302 if (screen->doOpaqueMove())
3303 XUngrabServer(blackbox->getXDisplay());
3311 void BlackboxWindow::doWindowSnapping(int &dx, int &dy) {
3312 // how much resistance to edges to provide
3313 const int resistance_size = screen->getResistanceSize();
3315 // how far away to snap
3316 const int snap_distance = screen->getSnapThreshold();
3318 // how to snap windows
3319 const int snap_to_windows = screen->getWindowToWindowSnap();
3320 const int snap_to_edges = screen->getWindowToEdgeSnap();
3321 // the amount of space away from the edge to provide resistance/snap
3322 const int snap_offset = screen->getSnapOffset();
3324 // find the geomeetery where the moving window currently is
3325 const Rect &moving = screen->doOpaqueMove() ? frame.rect : frame.changing;
3328 const int wleft = dx,
3329 wright = dx + frame.rect.width() - 1,
3331 wbottom = dy + frame.rect.height() - 1;
3333 if (snap_to_windows) {
3336 Workspace *w = screen->getWorkspace(getWorkspaceNumber());
3339 // add windows on the workspace to the rect list
3340 const BlackboxWindowList& stack_list = w->getStackingList();
3341 BlackboxWindowList::const_iterator st_it, st_end = stack_list.end();
3342 for (st_it = stack_list.begin(); st_it != st_end; ++st_it)
3343 if (*st_it != this) // don't snap to ourself
3344 rectlist.push_back( (*st_it)->frameRect() );
3346 RectList::const_iterator it, end = rectlist.end();
3347 for (it = rectlist.begin(); it != end; ++it) {
3348 bool snapped = False;
3349 const Rect &winrect = *it;
3351 offsetrect.setCoords(winrect.left() - snap_offset,
3352 winrect.top() - snap_offset,
3353 winrect.right() + snap_offset,
3354 winrect.bottom() + snap_offset);
3356 if (snap_to_windows == BScreen::WindowResistance)
3357 // if the window is already over top of this snap target, then
3358 // resistance is futile, so just ignore it
3359 if (winrect.intersects(moving))
3362 int dleft, dright, dtop, dbottom;
3364 // if the windows are in the same plane vertically
3365 if (wtop >= (signed)(winrect.y() - frame.rect.height() + 1) &&
3366 wtop < (signed)(winrect.y() + winrect.height() - 1)) {
3368 if (snap_to_windows == BScreen::WindowResistance) {
3369 dleft = wright - offsetrect.left();
3370 dright = offsetrect.right() - wleft;
3372 // snap left of other window?
3373 if (dleft >= 0 && dleft < resistance_size &&
3374 dleft < (wright - wleft)) {
3375 dx = offsetrect.left() - frame.rect.width();
3378 // snap right of other window?
3379 else if (dright >= 0 && dright < resistance_size &&
3380 dright < (wright - wleft)) {
3381 dx = offsetrect.right() + 1;
3384 } else { // BScreen::WindowSnap
3385 dleft = abs(wright - offsetrect.left());
3386 dright = abs(wleft - offsetrect.right());
3388 // snap left of other window?
3389 if (dleft < snap_distance && dleft <= dright) {
3390 dx = offsetrect.left() - frame.rect.width();
3393 // snap right of other window?
3394 else if (dright < snap_distance) {
3395 dx = offsetrect.right() + 1;
3401 if (screen->getWindowCornerSnap()) {
3402 // try corner-snap to its other sides
3403 if (snap_to_windows == BScreen::WindowResistance) {
3404 dtop = winrect.top() - wtop;
3405 dbottom = wbottom - winrect.bottom();
3406 if (dtop > 0 && dtop < resistance_size) {
3407 // if we're already past the top edge, then don't provide
3409 if (moving.top() >= winrect.top())
3411 } else if (dbottom > 0 && dbottom < resistance_size) {
3412 // if we're already past the bottom edge, then don't provide
3414 if (moving.bottom() <= winrect.bottom())
3415 dy = winrect.bottom() - frame.rect.height() + 1;
3417 } else { // BScreen::WindowSnap
3418 dtop = abs(wtop - winrect.top());
3419 dbottom = abs(wbottom - winrect.bottom());
3420 if (dtop < snap_distance && dtop <= dbottom)
3422 else if (dbottom < snap_distance)
3423 dy = winrect.bottom() - frame.rect.height() + 1;
3431 // if the windows are on the same plane horizontally
3432 if (wleft >= (signed)(winrect.x() - frame.rect.width() + 1) &&
3433 wleft < (signed)(winrect.x() + winrect.width() - 1)) {
3435 if (snap_to_windows == BScreen::WindowResistance) {
3436 dtop = wbottom - offsetrect.top();
3437 dbottom = offsetrect.bottom() - wtop;
3439 // snap top of other window?
3440 if (dtop >= 0 && dtop < resistance_size && dtop < (wbottom - wtop)) {
3441 dy = offsetrect.top() - frame.rect.height();
3444 // snap bottom of other window?
3445 else if (dbottom >= 0 && dbottom < resistance_size &&
3446 dbottom < (wbottom - wtop)) {
3447 dy = offsetrect.bottom() + 1;
3450 } else { // BScreen::WindowSnap
3451 dtop = abs(wbottom - offsetrect.top());
3452 dbottom = abs(wtop - offsetrect.bottom());
3454 // snap top of other window?
3455 if (dtop < snap_distance && dtop <= dbottom) {
3456 dy = offsetrect.top() - frame.rect.height();
3459 // snap bottom of other window?
3460 else if (dbottom < snap_distance) {
3461 dy = offsetrect.bottom() + 1;
3468 if (screen->getWindowCornerSnap()) {
3469 // try corner-snap to its other sides
3470 if (snap_to_windows == BScreen::WindowResistance) {
3471 dleft = winrect.left() - wleft;
3472 dright = wright - winrect.right();
3473 if (dleft > 0 && dleft < resistance_size) {
3474 // if we're already past the left edge, then don't provide
3476 if (moving.left() >= winrect.left())
3477 dx = winrect.left();
3478 } else if (dright > 0 && dright < resistance_size) {
3479 // if we're already past the right edge, then don't provide
3481 if (moving.right() <= winrect.right())
3482 dx = winrect.right() - frame.rect.width() + 1;
3484 } else { // BScreen::WindowSnap
3485 dleft = abs(wleft - winrect.left());
3486 dright = abs(wright - winrect.right());
3487 if (dleft < snap_distance && dleft <= dright)
3488 dx = winrect.left();
3489 else if (dright < snap_distance)
3490 dx = winrect.right() - frame.rect.width() + 1;
3500 if (snap_to_edges) {
3503 // snap to the screen edges (and screen boundaries for xinerama)
3505 if (screen->isXineramaActive() && blackbox->doXineramaSnapping()) {
3506 rectlist.insert(rectlist.begin(),
3507 screen->getXineramaAreas().begin(),
3508 screen->getXineramaAreas().end());
3511 rectlist.push_back(screen->getRect());
3513 RectList::const_iterator it, end = rectlist.end();
3514 for (it = rectlist.begin(); it != end; ++it) {
3515 const Rect &srect = *it;
3517 offsetrect.setCoords(srect.left() + snap_offset,
3518 srect.top() + snap_offset,
3519 srect.right() - snap_offset,
3520 srect.bottom() - snap_offset);
3522 if (snap_to_edges == BScreen::WindowResistance) {
3523 // if we're not in the rectangle then don't snap to it.
3524 if (! srect.contains(moving))
3526 } else { // BScreen::WindowSnap
3527 // if we're not in the rectangle then don't snap to it.
3528 if (! srect.intersects(Rect(wleft, wtop, frame.rect.width(),
3529 frame.rect.height())))
3533 if (snap_to_edges == BScreen::WindowResistance) {
3534 int dleft = offsetrect.left() - wleft,
3535 dright = wright - offsetrect.right(),
3536 dtop = offsetrect.top() - wtop,
3537 dbottom = wbottom - offsetrect.bottom();
3540 if (dleft > 0 && dleft < resistance_size)
3541 dx = offsetrect.left();
3543 else if (dright > 0 && dright < resistance_size)
3544 dx = offsetrect.right() - frame.rect.width() + 1;
3547 if (dtop > 0 && dtop < resistance_size)
3548 dy = offsetrect.top();
3550 else if (dbottom > 0 && dbottom < resistance_size)
3551 dy = offsetrect.bottom() - frame.rect.height() + 1;
3552 } else { // BScreen::WindowSnap
3553 int dleft = abs(wleft - offsetrect.left()),
3554 dright = abs(wright - offsetrect.right()),
3555 dtop = abs(wtop - offsetrect.top()),
3556 dbottom = abs(wbottom - offsetrect.bottom());
3559 if (dleft < snap_distance && dleft <= dright)
3560 dx = offsetrect.left();
3562 else if (dright < snap_distance)
3563 dx = offsetrect.right() - frame.rect.width() + 1;
3566 if (dtop < snap_distance && dtop <= dbottom)
3567 dy = offsetrect.top();
3569 else if (dbottom < snap_distance)
3570 dy = offsetrect.bottom() - frame.rect.height() + 1;
3577 void BlackboxWindow::endMove(void) {
3578 assert(flags.moving);
3579 assert(blackbox->getChangingWindow() == this);
3581 flags.moving = False;
3582 blackbox->setChangingWindow(0);
3584 if (! screen->doOpaqueMove()) {
3585 /* when drawing the rubber band, we need to make sure we only draw inside
3586 * the frame... frame.changing_* contain the new coords for the window,
3587 * so we need to subtract 1 from changing_w/changing_h every where we
3588 * draw the rubber band (for both moving and resizing)
3590 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3591 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3592 frame.changing.width() - 1, frame.changing.height() - 1);
3593 XUngrabServer(blackbox->getXDisplay());
3595 configure(frame.changing.x(), frame.changing.y(),
3596 frame.changing.width(), frame.changing.height());
3598 configure(frame.rect.x(), frame.rect.y(),
3599 frame.rect.width(), frame.rect.height());
3601 screen->hideGeometry();
3603 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3605 // if there are any left over motions from the move, drop them now
3606 XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
3608 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
3613 void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) {
3614 if (! (functions & Func_Resize)) return;
3616 assert(! (flags.resizing || flags.moving));
3619 Only one window can be moved/resized at a time. If another window is
3620 already being moved or resized, then stop it before whating to work with
3623 BlackboxWindow *changing = blackbox->getChangingWindow();
3624 if (changing && changing != this) {
3625 if (changing->flags.moving)
3626 changing->endMove();
3627 else // if (changing->flags.resizing)
3628 changing->endResize();
3636 switch (resize_dir) {
3639 cursor = blackbox->getLowerLeftAngleCursor();
3644 cursor = blackbox->getLowerRightAngleCursor();
3648 anchor = BottomRight;
3649 cursor = blackbox->getUpperLeftAngleCursor();
3653 anchor = BottomLeft;
3654 cursor = blackbox->getUpperRightAngleCursor();
3658 assert(false); // unhandled Corner
3659 return; // unreachable, for the compiler
3662 XGrabServer(blackbox->getXDisplay());
3663 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3664 PointerMotionMask | ButtonReleaseMask,
3665 GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
3667 flags.resizing = True;
3668 blackbox->setChangingWindow(this);
3670 unsigned int gw, gh;
3671 frame.changing = frame.rect;
3673 constrain(anchor, &gw, &gh);
3675 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3676 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3677 frame.changing.width() - 1, frame.changing.height() - 1);
3679 screen->showGeometry(gw, gh);
3681 frame.grab_x = x_root;
3682 frame.grab_y = y_root;
3686 void BlackboxWindow::doResize(int x_root, int y_root) {
3687 assert(flags.resizing);
3688 assert(blackbox->getChangingWindow() == this);
3690 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3691 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3692 frame.changing.width() - 1, frame.changing.height() - 1);
3694 unsigned int gw, gh;
3696 int dx, dy; // the amount of change in the size of the window
3698 switch (resize_dir) {
3701 dx = - (x_root - frame.grab_x);
3702 dy = + (y_root - frame.grab_y);
3706 dx = + (x_root - frame.grab_x);
3707 dy = + (y_root - frame.grab_y);
3710 anchor = BottomRight;
3711 dx = - (x_root - frame.grab_x);
3712 dy = - (y_root - frame.grab_y);
3715 anchor = BottomLeft;
3716 dx = + (x_root - frame.grab_x);
3717 dy = - (y_root - frame.grab_y);
3721 assert(false); // unhandled Corner
3722 return; // unreachable, for the compiler
3725 // make sure the user cant resize the window smaller than 0, which makes it
3726 // wrap around and become huge
3727 if (dx < -(signed)client.rect.width()) dx = -(signed)client.rect.width();
3728 if (dy < -(signed)client.rect.height()) dy = -(signed)client.rect.height();
3730 frame.changing.setSize(frame.rect.width() + dx, frame.rect.height() + dy);
3732 constrain(anchor, &gw, &gh);
3734 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3735 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3736 frame.changing.width() - 1, frame.changing.height() - 1);
3738 screen->showGeometry(gw, gh);
3742 void BlackboxWindow::endResize(void) {
3743 assert(flags.resizing);
3744 assert(blackbox->getChangingWindow() == this);
3746 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3747 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3748 frame.changing.width() - 1, frame.changing.height() - 1);
3749 XUngrabServer(blackbox->getXDisplay());
3751 // unset maximized state after resized when fully maximized
3752 if (flags.maximized == 1)
3755 flags.resizing = False;
3756 blackbox->setChangingWindow(0);
3758 configure(frame.changing.x(), frame.changing.y(),
3759 frame.changing.width(), frame.changing.height());
3760 screen->hideGeometry();
3762 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3764 // if there are any left over motions from the resize, drop them now
3765 XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
3767 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
3772 void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
3774 fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3779 doMove(me->x_root, me->y_root);
3780 } else if (flags.resizing) {
3781 doResize(me->x_root, me->y_root);
3783 if ((functions & Func_Move) &&
3784 (me->state & Button1Mask) &&
3785 (frame.title == me->window || frame.label == me->window ||
3786 frame.handle == me->window || frame.window == me->window)) {
3787 beginMove(me->x_root, me->y_root);
3788 } else if ((functions & Func_Resize) &&
3789 ((me->state & Button1Mask) &&
3790 (me->window == frame.right_grip ||
3791 me->window == frame.left_grip)) ||
3792 ((me->state & Button3Mask) && (me->state & mod_mask) &&
3793 (frame.title == me->window || frame.label == me->window ||
3794 frame.handle == me->window || frame.window == me->window ||
3795 frame.right_grip == me->window ||
3796 frame.left_grip == me->window))) {
3797 unsigned int zones = screen->getResizeZones();
3800 if (me->window == frame.left_grip) {
3801 corner = BottomLeft;
3802 } else if (me->window == frame.right_grip || zones == 1) {
3803 corner = BottomRight;
3806 bool left = (me->x_root - frame.rect.x() <=
3807 static_cast<signed>(frame.rect.width() / 2));
3810 else // (zones == 4)
3811 top = (me->y_root - frame.rect.y() <=
3812 static_cast<signed>(frame.rect.height() / 2));
3813 corner = (top ? (left ? TopLeft : TopRight) :
3814 (left ? BottomLeft : BottomRight));
3817 beginResize(me->x_root, me->y_root, corner);
3823 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent* ce) {
3824 if (! (screen->isSloppyFocus() && isVisible() && isNormal()))
3828 bool leave = False, inferior = False;
3830 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), ce->window,
3832 if (e.type == LeaveNotify && e.xcrossing.mode == NotifyNormal) {
3834 inferior = (e.xcrossing.detail == NotifyInferior);
3838 if (! leave || inferior) {
3839 if (! isFocused()) {
3840 bool success = setInputFocus();
3841 if (success) // if focus succeeded install the colormap
3842 installColormap(True); // XXX: shouldnt we honour no install?
3845 We only auto-raise when the window wasn't focused because otherwise
3846 we run into problems with gtk+ drop-down lists. The window ends up
3847 raising over the list.
3849 if (screen->doAutoRaise())
3856 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent*) {
3857 if (! (screen->isSloppyFocus() && screen->doAutoRaise() && isNormal()))
3860 installColormap(False);
3862 if (timer->isTiming())
3868 void BlackboxWindow::shapeEvent(XShapeEvent *e) {
3869 if (blackbox->hasShapeExtensions()) {
3870 if (! e->shaped && flags.shaped) {
3872 flags.shaped = False;
3873 } else if (e->shaped) {
3875 flags.shaped = True;
3882 bool BlackboxWindow::validateClient(void) const {
3883 XSync(blackbox->getXDisplay(), False);
3886 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3887 DestroyNotify, &e) ||
3888 XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3890 XPutBackEvent(blackbox->getXDisplay(), &e);
3899 void BlackboxWindow::restore(bool remap) {
3900 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeDelete);
3901 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
3902 XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask);
3904 // do not leave a shaded window as an icon unless it was an icon
3905 if (flags.shaded && ! flags.iconic)
3906 setState(NormalState);
3908 // erase the netwm stuff that we read when a window maps, so that it
3909 // doesn't persist between mappings.
3910 // (these are the ones read in getNetWMFlags().)
3911 xatom->eraseValue(client.window, XAtom::net_wm_desktop);
3912 xatom->eraseValue(client.window, XAtom::net_wm_state);
3914 restoreGravity(client.rect);
3916 XUnmapWindow(blackbox->getXDisplay(), frame.window);
3917 XUnmapWindow(blackbox->getXDisplay(), client.window);
3919 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, client.old_bw);
3922 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3923 ReparentNotify, &ev)) {
3926 // according to the ICCCM - if the client doesn't reparent to
3927 // root, then we have to do it for them
3928 XReparentWindow(blackbox->getXDisplay(), client.window,
3929 screen->getRootWindow(),
3930 client.rect.x(), client.rect.y());
3933 if (remap) XMapWindow(blackbox->getXDisplay(), client.window);
3937 // timer for autoraise
3938 void BlackboxWindow::timeout(void) {
3939 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3943 void BlackboxWindow::changeBlackboxHints(const BlackboxHints *net) {
3944 if ((net->flags & AttribShaded) &&
3945 ((blackbox_attrib.attrib & AttribShaded) !=
3946 (net->attrib & AttribShaded)))
3949 if (flags.visible && // watch out for requests when we can not be seen
3950 (net->flags & (AttribMaxVert | AttribMaxHoriz)) &&
3951 ((blackbox_attrib.attrib & (AttribMaxVert | AttribMaxHoriz)) !=
3952 (net->attrib & (AttribMaxVert | AttribMaxHoriz)))) {
3953 if (flags.maximized) {
3958 if ((net->flags & AttribMaxHoriz) && (net->flags & AttribMaxVert))
3959 button = ((net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0);
3960 else if (net->flags & AttribMaxVert)
3961 button = ((net->attrib & AttribMaxVert) ? 2 : 0);
3962 else if (net->flags & AttribMaxHoriz)
3963 button = ((net->attrib & AttribMaxHoriz) ? 3 : 0);
3969 if ((net->flags & AttribOmnipresent) &&
3970 ((blackbox_attrib.attrib & AttribOmnipresent) !=
3971 (net->attrib & AttribOmnipresent)))
3974 if ((net->flags & AttribWorkspace) &&
3975 (blackbox_attrib.workspace != net->workspace)) {
3976 screen->reassociateWindow(this, net->workspace, True);
3978 if (screen->getCurrentWorkspaceID() != net->workspace) {
3982 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3986 if (net->flags & AttribDecoration) {
3987 switch (net->decoration) {
4004 * Set the sizes of all components of the window frame
4005 * (the window decorations).
4006 * These values are based upon the current style settings and the client
4007 * window's dimensions.
4009 void BlackboxWindow::upsize(void) {
4010 frame.bevel_w = screen->getBevelWidth();
4012 if (decorations & Decor_Border) {
4013 frame.border_w = screen->getBorderWidth();
4014 if (! isTransient())
4015 frame.mwm_border_w = screen->getFrameWidth();
4017 frame.mwm_border_w = 0;
4019 frame.mwm_border_w = frame.border_w = 0;
4022 if (decorations & Decor_Titlebar) {
4023 // the height of the titlebar is based upon the height of the font being
4024 // used to display the window's title
4025 WindowStyle *style = screen->getWindowStyle();
4026 frame.title_h = style->font->height() + (frame.bevel_w * 2) + 2;
4028 frame.label_h = frame.title_h - (frame.bevel_w * 2);
4029 frame.button_w = (frame.label_h - 2);
4031 // set the top frame margin
4032 frame.margin.top = frame.border_w + frame.title_h +
4033 frame.border_w + frame.mwm_border_w;
4039 // set the top frame margin
4040 frame.margin.top = frame.border_w + frame.mwm_border_w;
4043 // set the left/right frame margin
4044 frame.margin.left = frame.margin.right = frame.border_w + frame.mwm_border_w;
4046 if (decorations & Decor_Handle) {
4047 frame.grip_w = frame.button_w * 2;
4048 frame.handle_h = screen->getHandleWidth();
4050 // set the bottom frame margin
4051 frame.margin.bottom = frame.border_w + frame.handle_h +
4052 frame.border_w + frame.mwm_border_w;
4057 // set the bottom frame margin
4058 frame.margin.bottom = frame.border_w + frame.mwm_border_w;
4062 We first get the normal dimensions and use this to define the inside_w/h
4063 then we modify the height if shading is in effect.
4064 If the shade state is not considered then frame.rect gets reset to the
4065 normal window size on a reconfigure() call resulting in improper
4066 dimensions appearing in move/resize and other events.
4069 height = client.rect.height() + frame.margin.top + frame.margin.bottom,
4070 width = client.rect.width() + frame.margin.left + frame.margin.right;
4072 frame.inside_w = width - (frame.border_w * 2);
4073 frame.inside_h = height - (frame.border_w * 2);
4076 height = frame.title_h + (frame.border_w * 2);
4077 frame.rect.setSize(width, height);
4082 * Calculate the size of the client window and constrain it to the
4083 * size specified by the size hints of the client window.
4085 * The logical width and height are placed into pw and ph, if they
4086 * are non-zero. Logical size refers to the users perception of
4087 * the window size (for example an xterm resizes in cells, not in pixels).
4088 * pw and ph are then used to display the geometry during window moves, resize,
4091 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4092 * Physical geometry refers to the geometry of the window in pixels.
4094 void BlackboxWindow::constrain(Corner anchor,
4095 unsigned int *pw, unsigned int *ph) {
4096 // frame.changing represents the requested frame size, we need to
4097 // strip the frame margin off and constrain the client size
4098 frame.changing.setCoords(frame.changing.left() + frame.margin.left,
4099 frame.changing.top() + frame.margin.top,
4100 frame.changing.right() - frame.margin.right,
4101 frame.changing.bottom() - frame.margin.bottom);
4103 unsigned int dw = frame.changing.width(), dh = frame.changing.height(),
4104 base_width = (client.base_width) ? client.base_width : client.min_width,
4105 base_height = (client.base_height) ? client.base_height :
4108 // constrain, but only if the min/max are being used. if they aren't, then
4109 // this resize is going to be from a ConfigureRequest because the window
4110 // isn't allowed to be resized by the user. And in that case, we don't want
4111 // to limit what the app can do
4112 if (client.max_width > client.min_width ||
4113 client.max_height > client.min_height) {
4114 if (dw < client.min_width) dw = client.min_width;
4115 if (dh < client.min_height) dh = client.min_height;
4116 if (dw > client.max_width) dw = client.max_width;
4117 if (dh > client.max_height) dh = client.max_height;
4120 if (client.width_inc > 1) {
4122 dw /= client.width_inc;
4124 if (client.height_inc > 1) {
4126 dh /= client.height_inc;
4135 if (client.width_inc > 1) {
4136 dw *= client.width_inc;
4139 if (client.height_inc > 1) {
4140 dh *= client.height_inc;
4144 frame.changing.setSize(dw, dh);
4146 // add the frame margin back onto frame.changing
4147 frame.changing.setCoords(frame.changing.left() - frame.margin.left,
4148 frame.changing.top() - frame.margin.top,
4149 frame.changing.right() + frame.margin.right,
4150 frame.changing.bottom() + frame.margin.bottom);
4152 // move frame.changing to the specified anchor
4160 dx = frame.rect.right() - frame.changing.right();
4164 dy = frame.rect.bottom() - frame.changing.bottom();
4168 dx = frame.rect.right() - frame.changing.right();
4169 dy = frame.rect.bottom() - frame.changing.bottom();
4173 assert(false); // unhandled corner
4175 frame.changing.setPos(frame.changing.x() + dx, frame.changing.y() + dy);
4179 void WindowStyle::doJustify(const std::string &text, int &start_pos,
4180 unsigned int max_length,
4181 unsigned int modifier) const {
4182 size_t text_len = text.size();
4183 unsigned int length;
4186 length = font->measureString(string(text, 0, text_len)) + modifier;
4187 } while (length > max_length && text_len-- > 0);
4191 start_pos += max_length - length;
4195 start_pos += (max_length - length) / 2;
4205 BWindowGroup::BWindowGroup(Blackbox *b, Window _group)
4206 : blackbox(b), group(_group) {
4207 XWindowAttributes wattrib;
4208 if (! XGetWindowAttributes(blackbox->getXDisplay(), group, &wattrib)) {
4209 // group window doesn't seem to exist anymore
4214 XSelectInput(blackbox->getXDisplay(), group,
4215 PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
4217 blackbox->saveGroupSearch(group, this);
4221 BWindowGroup::~BWindowGroup(void) {
4222 blackbox->removeGroupSearch(group);
4227 BWindowGroup::find(BScreen *screen, bool allow_transients) const {
4228 BlackboxWindow *ret = blackbox->getFocusedWindow();
4230 // does the focus window match (or any transient_fors)?
4231 for (; ret; ret = ret->getTransientFor()) {
4232 if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
4233 (! ret->isTransient() || allow_transients))
4237 if (ret) return ret;
4239 // the focus window didn't match, look in the group's window list
4240 BlackboxWindowList::const_iterator it, end = windowList.end();
4241 for (it = windowList.begin(); it != end; ++it) {
4243 if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
4244 (! ret->isTransient() || allow_transients))