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
48 #include "blackbox.hh"
49 #include "Clientmenu.hh"
52 #include "Iconmenu.hh"
58 #include "Windowmenu.hh"
59 #include "Workspace.hh"
66 * Initializes the class with default values/the window's set initial values.
68 BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
69 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
70 // sizeof(BlackboxWindow));
73 fprintf(stderr, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w);
77 set timer to zero... it is initialized properly later, so we check
78 if timer is zero in the destructor, and assume that the window is not
79 fully constructed if timer is zero...
85 xatom = blackbox->getXAtom();
87 if (! validateClient()) {
92 // fetch client size and placement
93 XWindowAttributes wattrib;
94 if (! XGetWindowAttributes(blackbox->getXDisplay(),
95 client.window, &wattrib) ||
96 ! wattrib.screen || wattrib.override_redirect) {
99 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
106 // set the eventmask early in the game so that we make sure we get
107 // all the events we are interested in
108 XSetWindowAttributes attrib_set;
109 attrib_set.event_mask = PropertyChangeMask | FocusChangeMask |
111 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
113 XChangeWindowAttributes(blackbox->getXDisplay(), client.window,
114 CWEventMask|CWDontPropagate, &attrib_set);
116 flags.moving = flags.resizing = flags.shaded = flags.visible =
117 flags.iconic = flags.focused = flags.stuck = flags.modal =
118 flags.send_focus_message = flags.shaped = flags.skip_taskbar =
119 flags.skip_pager = flags.fullscreen = False;
122 blackbox_attrib.workspace = window_number = BSENTINEL;
124 blackbox_attrib.flags = blackbox_attrib.attrib = blackbox_attrib.stack = 0l;
125 blackbox_attrib.decoration = DecorNormal;
126 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
127 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
130 frame.window = frame.plate = frame.title = frame.handle = None;
131 frame.close_button = frame.iconify_button = frame.maximize_button = None;
132 frame.right_grip = frame.left_grip = None;
134 frame.ulabel_pixel = frame.flabel_pixel = frame.utitle_pixel =
135 frame.ftitle_pixel = frame.uhandle_pixel = frame.fhandle_pixel =
136 frame.ubutton_pixel = frame.fbutton_pixel = frame.pbutton_pixel =
137 frame.uborder_pixel = frame.fborder_pixel = frame.ugrip_pixel =
138 frame.fgrip_pixel = 0;
139 frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None;
140 frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None;
141 frame.pbutton = frame.ugrip = frame.fgrip = None;
143 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize;
144 mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
145 Decor_Iconify | Decor_Maximize;
147 client.normal_hint_flags = 0;
148 client.window_group = None;
149 client.transient_for = 0;
151 current_state = NormalState;
156 set the initial size and location of client window (relative to the
157 _root window_). This position is the reference point used with the
158 window's gravity to find the window's initial position.
160 client.rect.setRect(wattrib.x, wattrib.y, wattrib.width, wattrib.height);
161 client.old_bw = wattrib.border_width;
163 lastButtonPressTime = 0;
165 timer = new BTimer(blackbox, this);
166 timer->setTimeout(blackbox->getAutoRaiseDelay());
168 // get size, aspect, minimum/maximum size and other hints set by the
171 if (! getBlackboxHints())
178 frame.window = createToplevelWindow();
180 blackbox->saveWindowSearch(frame.window, this);
182 frame.plate = createChildWindow(frame.window, ExposureMask);
183 blackbox->saveWindowSearch(frame.plate, this);
185 // determine if this is a transient window
188 // determine the window's type, so we can decide its decorations and
189 // functionality, or if we should not manage it at all
190 if (getWindowType()) {
191 // adjust the window decorations/behavior based on the window type
192 switch (window_type) {
196 blackbox_attrib.workspace = 0; // we do need to belong to a workspace
197 flags.stuck = True; // we show up on all workspaces
199 // none of these windows are manipulated by the window manager
205 // these windows get less functionality
206 functions &= ~(Func_Maximize | Func_Resize | Func_Iconify);
210 // dialogs cannot be maximized
211 functions &= ~Func_Maximize;
215 // normal windows retain all of the possible decorations and
223 // further adjeust the window's decorations/behavior based on window sizes
224 if ((client.normal_hint_flags & PMinSize) &&
225 (client.normal_hint_flags & PMaxSize) &&
226 client.max_width <= client.min_width &&
227 client.max_height <= client.min_height) {
228 functions &= ~(Func_Resize | Func_Maximize);
235 if (decorations & Decor_Titlebar)
238 if (decorations & Decor_Handle)
241 // apply the size and gravity hint to the frame
245 bool place_window = True;
246 if (blackbox->isStartup() || isTransient() ||
247 client.normal_hint_flags & (PPosition|USPosition)) {
248 applyGravity(frame.rect);
250 if (blackbox->isStartup() || client.rect.intersects(screen->getRect()))
251 place_window = False;
254 // add the window's strut. note this is done *after* placing the window.
255 screen->addStrut(&client.strut);
259 the server needs to be grabbed here to prevent client's from sending
260 events while we are in the process of configuring their window.
261 We hold the grab until after we are done moving the window around.
264 XGrabServer(blackbox->getXDisplay());
266 associateClientWindow();
268 blackbox->saveWindowSearch(client.window, this);
270 if (blackbox_attrib.workspace >= screen->getWorkspaceCount())
271 screen->getCurrentWorkspace()->addWindow(this, place_window);
273 screen->getWorkspace(blackbox_attrib.workspace)->
274 addWindow(this, place_window);
276 if (! place_window) {
277 // don't need to call configure if we are letting the workspace
279 configure(frame.rect.x(), frame.rect.y(),
280 frame.rect.width(), frame.rect.height());
286 XUngrabServer(blackbox->getXDisplay());
289 if (blackbox->hasShapeExtensions() && flags.shaped)
293 // now that we know where to put the window and what it should look like
294 // we apply the decorations
299 XMapSubwindows(blackbox->getXDisplay(), frame.window);
301 // this ensures the title, buttons, and other decor are properly displayed
304 // preserve the window's initial state on first map, and its current state
306 unsigned long initial_state = current_state;
308 current_state = initial_state;
310 // get sticky state from our parent window if we've got one
311 if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
312 client.transient_for->isStuck() != flags.stuck)
316 flags.shaded = False;
317 initial_state = current_state;
321 At this point in the life of a window, current_state should only be set
322 to IconicState if the window was an *icon*, not if it was shaded.
324 if (initial_state != IconicState)
325 current_state = NormalState;
333 if (flags.maximized && (functions & Func_Maximize))
336 // create this last so it only needs to be configured once
337 windowmenu = new Windowmenu(this);
341 BlackboxWindow::~BlackboxWindow(void) {
343 fprintf(stderr, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
347 if (! timer) // window not managed...
353 screen->removeStrut(&client.strut);
354 screen->updateAvailableArea();
356 // We don't need to worry about resizing because resizing always grabs the X
357 // server. This should only ever happen if using opaque moving.
365 if (client.window_group) {
366 BWindowGroup *group = blackbox->searchGroup(client.window_group);
367 if (group) group->removeWindow(this);
370 // remove ourselves from our transient_for
372 if (client.transient_for != (BlackboxWindow *) ~0ul)
373 client.transient_for->client.transientList.remove(this);
374 client.transient_for = (BlackboxWindow*) 0;
377 if (client.transientList.size() > 0) {
378 // reset transient_for for all transients
379 BlackboxWindowList::iterator it, end = client.transientList.end();
380 for (it = client.transientList.begin(); it != end; ++it)
381 (*it)->client.transient_for = (BlackboxWindow*) 0;
391 blackbox->removeWindowSearch(frame.plate);
392 XDestroyWindow(blackbox->getXDisplay(), frame.plate);
396 blackbox->removeWindowSearch(frame.window);
397 XDestroyWindow(blackbox->getXDisplay(), frame.window);
400 blackbox->removeWindowSearch(client.window);
404 void BlackboxWindow::enableDecor(bool enable) {
405 blackbox_attrib.flags |= AttribDecoration;
406 blackbox_attrib.decoration = enable ? DecorNormal : DecorNone;
409 // we can not be shaded if we lack a titlebar
410 if (! (decorations & Decor_Titlebar) && flags.shaded)
413 if (flags.visible && frame.window) {
414 XMapSubwindows(blackbox->getXDisplay(), frame.window);
415 XMapWindow(blackbox->getXDisplay(), frame.window);
419 setState(current_state);
423 void BlackboxWindow::setupDecor() {
424 if (blackbox_attrib.decoration != DecorNone) {
425 // start with everything on
426 decorations = Decor_Close |
427 (mwm_decorations & Decor_Titlebar ? Decor_Titlebar : 0) |
428 (mwm_decorations & Decor_Border ? Decor_Border : 0) |
429 (mwm_decorations & Decor_Handle ? Decor_Handle : 0) |
430 (mwm_decorations & Decor_Iconify ? Decor_Iconify : 0) |
431 (mwm_decorations & Decor_Maximize ? Decor_Maximize : 0);
433 if (! (functions & Func_Close)) decorations &= ~Decor_Close;
434 if (! (functions & Func_Maximize)) decorations &= ~Decor_Maximize;
435 if (! (functions & Func_Iconify)) decorations &= ~Decor_Iconify;
436 if (! (functions & Func_Resize)) decorations &= ~Decor_Handle;
438 switch (window_type) {
443 // none of these windows are decorated by the window manager at all
449 decorations &= ~(Decor_Border);
453 decorations &= ~Decor_Handle;
465 * Creates a new top level window, with a given location, size, and border
467 * Returns: the newly created window
469 Window BlackboxWindow::createToplevelWindow(void) {
470 XSetWindowAttributes attrib_create;
471 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
472 CWOverrideRedirect | CWEventMask;
474 attrib_create.background_pixmap = None;
475 attrib_create.colormap = screen->getColormap();
476 attrib_create.override_redirect = True;
477 attrib_create.event_mask = EnterWindowMask | LeaveWindowMask;
479 return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(),
480 0, 0, 1, 1, frame.border_w, screen->getDepth(),
481 InputOutput, screen->getVisual(), create_mask,
487 * Creates a child window, and optionally associates a given cursor with
490 Window BlackboxWindow::createChildWindow(Window parent,
491 unsigned long event_mask,
493 XSetWindowAttributes attrib_create;
494 unsigned long create_mask = CWBackPixmap | CWBorderPixel |
497 attrib_create.background_pixmap = None;
498 attrib_create.event_mask = event_mask;
501 create_mask |= CWCursor;
502 attrib_create.cursor = cursor;
505 return XCreateWindow(blackbox->getXDisplay(), parent, 0, 0, 1, 1, 0,
506 screen->getDepth(), InputOutput, screen->getVisual(),
507 create_mask, &attrib_create);
511 void BlackboxWindow::associateClientWindow(void) {
512 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, 0);
516 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeInsert);
518 XSelectInput(blackbox->getXDisplay(), frame.plate, SubstructureRedirectMask);
521 note we used to grab around this call to XReparentWindow however the
522 server is now grabbed before this method is called
524 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
526 XSelectInput(blackbox->getXDisplay(), client.window,
527 event_mask & ~StructureNotifyMask);
528 XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0);
529 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
531 XRaiseWindow(blackbox->getXDisplay(), frame.plate);
532 XMapSubwindows(blackbox->getXDisplay(), frame.plate);
535 if (blackbox->hasShapeExtensions()) {
536 XShapeSelectInput(blackbox->getXDisplay(), client.window,
543 XShapeQueryExtents(blackbox->getXDisplay(), client.window, &shaped,
544 &foo, &foo, &ufoo, &ufoo, &foo, &foo, &foo,
546 flags.shaped = shaped;
552 void BlackboxWindow::decorate(void) {
555 texture = &(screen->getWindowStyle()->b_focus);
556 frame.fbutton = texture->render(frame.button_w, frame.button_w,
559 frame.fbutton_pixel = texture->color().pixel();
561 texture = &(screen->getWindowStyle()->b_unfocus);
562 frame.ubutton = texture->render(frame.button_w, frame.button_w,
565 frame.ubutton_pixel = texture->color().pixel();
567 texture = &(screen->getWindowStyle()->b_pressed);
568 frame.pbutton = texture->render(frame.button_w, frame.button_w,
571 frame.pbutton_pixel = texture->color().pixel();
573 if (decorations & Decor_Titlebar) {
574 texture = &(screen->getWindowStyle()->t_focus);
575 frame.ftitle = texture->render(frame.inside_w, frame.title_h,
578 frame.ftitle_pixel = texture->color().pixel();
580 texture = &(screen->getWindowStyle()->t_unfocus);
581 frame.utitle = texture->render(frame.inside_w, frame.title_h,
584 frame.utitle_pixel = texture->color().pixel();
586 XSetWindowBorder(blackbox->getXDisplay(), frame.title,
587 screen->getBorderColor()->pixel());
592 if (decorations & Decor_Border) {
593 frame.fborder_pixel = screen->getWindowStyle()->f_focus.color().pixel();
594 frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.color().pixel();
597 if (decorations & Decor_Handle) {
598 texture = &(screen->getWindowStyle()->h_focus);
599 frame.fhandle = texture->render(frame.inside_w, frame.handle_h,
602 frame.fhandle_pixel = texture->color().pixel();
604 texture = &(screen->getWindowStyle()->h_unfocus);
605 frame.uhandle = texture->render(frame.inside_w, frame.handle_h,
608 frame.uhandle_pixel = texture->color().pixel();
610 texture = &(screen->getWindowStyle()->g_focus);
611 frame.fgrip = texture->render(frame.grip_w, frame.handle_h, frame.fgrip);
613 frame.fgrip_pixel = texture->color().pixel();
615 texture = &(screen->getWindowStyle()->g_unfocus);
616 frame.ugrip = texture->render(frame.grip_w, frame.handle_h, frame.ugrip);
618 frame.ugrip_pixel = texture->color().pixel();
620 XSetWindowBorder(blackbox->getXDisplay(), frame.handle,
621 screen->getBorderColor()->pixel());
622 XSetWindowBorder(blackbox->getXDisplay(), frame.left_grip,
623 screen->getBorderColor()->pixel());
624 XSetWindowBorder(blackbox->getXDisplay(), frame.right_grip,
625 screen->getBorderColor()->pixel());
628 XSetWindowBorder(blackbox->getXDisplay(), frame.window,
629 screen->getBorderColor()->pixel());
633 void BlackboxWindow::decorateLabel(void) {
636 texture = &(screen->getWindowStyle()->l_focus);
637 frame.flabel = texture->render(frame.label_w, frame.label_h, frame.flabel);
639 frame.flabel_pixel = texture->color().pixel();
641 texture = &(screen->getWindowStyle()->l_unfocus);
642 frame.ulabel = texture->render(frame.label_w, frame.label_h, frame.ulabel);
644 frame.ulabel_pixel = texture->color().pixel();
648 void BlackboxWindow::createHandle(void) {
649 frame.handle = createChildWindow(frame.window,
650 ButtonPressMask | ButtonReleaseMask |
651 ButtonMotionMask | ExposureMask);
652 blackbox->saveWindowSearch(frame.handle, this);
655 createChildWindow(frame.handle,
656 ButtonPressMask | ButtonReleaseMask |
657 ButtonMotionMask | ExposureMask,
658 blackbox->getLowerLeftAngleCursor());
659 blackbox->saveWindowSearch(frame.left_grip, this);
662 createChildWindow(frame.handle,
663 ButtonPressMask | ButtonReleaseMask |
664 ButtonMotionMask | ExposureMask,
665 blackbox->getLowerRightAngleCursor());
666 blackbox->saveWindowSearch(frame.right_grip, this);
670 void BlackboxWindow::destroyHandle(void) {
672 screen->getImageControl()->removeImage(frame.fhandle);
675 screen->getImageControl()->removeImage(frame.uhandle);
678 screen->getImageControl()->removeImage(frame.fgrip);
681 screen->getImageControl()->removeImage(frame.ugrip);
683 blackbox->removeWindowSearch(frame.left_grip);
684 blackbox->removeWindowSearch(frame.right_grip);
686 XDestroyWindow(blackbox->getXDisplay(), frame.left_grip);
687 XDestroyWindow(blackbox->getXDisplay(), frame.right_grip);
688 frame.left_grip = frame.right_grip = None;
690 blackbox->removeWindowSearch(frame.handle);
691 XDestroyWindow(blackbox->getXDisplay(), frame.handle);
696 void BlackboxWindow::createTitlebar(void) {
697 frame.title = createChildWindow(frame.window,
698 ButtonPressMask | ButtonReleaseMask |
699 ButtonMotionMask | ExposureMask);
700 frame.label = createChildWindow(frame.title,
701 ButtonPressMask | ButtonReleaseMask |
702 ButtonMotionMask | ExposureMask);
703 blackbox->saveWindowSearch(frame.title, this);
704 blackbox->saveWindowSearch(frame.label, this);
706 if (decorations & Decor_Iconify) createIconifyButton();
707 if (decorations & Decor_Maximize) createMaximizeButton();
708 if (decorations & Decor_Close) createCloseButton();
712 void BlackboxWindow::destroyTitlebar(void) {
713 if (frame.close_button)
714 destroyCloseButton();
716 if (frame.iconify_button)
717 destroyIconifyButton();
719 if (frame.maximize_button)
720 destroyMaximizeButton();
723 screen->getImageControl()->removeImage(frame.ftitle);
726 screen->getImageControl()->removeImage(frame.utitle);
729 screen->getImageControl()->removeImage(frame.flabel);
732 screen->getImageControl()->removeImage(frame.ulabel);
735 screen->getImageControl()->removeImage(frame.fbutton);
738 screen->getImageControl()->removeImage(frame.ubutton);
741 screen->getImageControl()->removeImage(frame.pbutton);
743 blackbox->removeWindowSearch(frame.title);
744 blackbox->removeWindowSearch(frame.label);
746 XDestroyWindow(blackbox->getXDisplay(), frame.label);
747 XDestroyWindow(blackbox->getXDisplay(), frame.title);
748 frame.title = frame.label = None;
752 void BlackboxWindow::createCloseButton(void) {
753 if (frame.title != None) {
754 frame.close_button = createChildWindow(frame.title,
757 ButtonMotionMask | ExposureMask);
758 blackbox->saveWindowSearch(frame.close_button, this);
763 void BlackboxWindow::destroyCloseButton(void) {
764 blackbox->removeWindowSearch(frame.close_button);
765 XDestroyWindow(blackbox->getXDisplay(), frame.close_button);
766 frame.close_button = None;
770 void BlackboxWindow::createIconifyButton(void) {
771 if (frame.title != None) {
772 frame.iconify_button = createChildWindow(frame.title,
775 ButtonMotionMask | ExposureMask);
776 blackbox->saveWindowSearch(frame.iconify_button, this);
781 void BlackboxWindow::destroyIconifyButton(void) {
782 blackbox->removeWindowSearch(frame.iconify_button);
783 XDestroyWindow(blackbox->getXDisplay(), frame.iconify_button);
784 frame.iconify_button = None;
788 void BlackboxWindow::createMaximizeButton(void) {
789 if (frame.title != None) {
790 frame.maximize_button = createChildWindow(frame.title,
793 ButtonMotionMask | ExposureMask);
794 blackbox->saveWindowSearch(frame.maximize_button, this);
799 void BlackboxWindow::destroyMaximizeButton(void) {
800 blackbox->removeWindowSearch(frame.maximize_button);
801 XDestroyWindow(blackbox->getXDisplay(), frame.maximize_button);
802 frame.maximize_button = None;
806 void BlackboxWindow::positionButtons(bool redecorate_label) {
807 string layout = blackbox->getTitlebarLayout();
810 bool hasclose, hasiconify, hasmaximize, haslabel;
811 hasclose = hasiconify = hasmaximize = haslabel = false;
813 string::const_iterator it, end;
814 for (it = layout.begin(), end = layout.end(); it != end; ++it) {
817 if (! hasclose && (decorations & Decor_Close)) {
823 if (! hasiconify && (decorations & Decor_Iconify)) {
829 if (! hasmaximize && (decorations & Decor_Maximize)) {
841 if (! hasclose && frame.close_button)
842 destroyCloseButton();
843 if (! hasiconify && frame.iconify_button)
844 destroyIconifyButton();
845 if (! hasmaximize && frame.maximize_button)
846 destroyMaximizeButton();
848 parsed += 'L'; // require that the label be in the layout
850 const unsigned int bsep = frame.bevel_w + 1; // separation between elements
851 const unsigned int by = frame.bevel_w + 1;
852 const unsigned int ty = frame.bevel_w;
854 frame.label_w = frame.inside_w - bsep * 2 -
855 (frame.button_w + bsep) * (parsed.size() - 1);
857 unsigned int x = bsep;
858 for (it = parsed.begin(), end = parsed.end(); it != end; ++it) {
861 if (! frame.close_button) createCloseButton();
862 XMoveResizeWindow(blackbox->getXDisplay(), frame.close_button, x, by,
863 frame.button_w, frame.button_w);
864 x += frame.button_w + bsep;
867 if (! frame.iconify_button) createIconifyButton();
868 XMoveResizeWindow(blackbox->getXDisplay(), frame.iconify_button, x, by,
869 frame.button_w, frame.button_w);
870 x += frame.button_w + bsep;
873 if (! frame.maximize_button) createMaximizeButton();
874 XMoveResizeWindow(blackbox->getXDisplay(), frame.maximize_button, x, by,
875 frame.button_w, frame.button_w);
876 x += frame.button_w + bsep;
879 XMoveResizeWindow(blackbox->getXDisplay(), frame.label, x, ty,
880 frame.label_w, frame.label_h);
881 x += frame.label_w + bsep;
886 if (redecorate_label) decorateLabel();
892 void BlackboxWindow::reconfigure(void) {
893 restoreGravity(client.rect);
895 applyGravity(frame.rect);
904 windowmenu->move(windowmenu->getX(), frame.rect.y() + frame.title_h);
905 windowmenu->reconfigure();
910 void BlackboxWindow::grabButtons(void) {
911 mod_mask = blackbox->getMouseModMask();
913 if (! screen->isSloppyFocus() || screen->doClickRaise())
914 // grab button 1 for changing focus/raising
915 blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
916 GrabModeSync, GrabModeSync, frame.plate, None,
917 screen->allowScrollLock());
919 if (functions & Func_Move)
920 blackbox->grabButton(Button1, mod_mask, frame.window, True,
921 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
922 GrabModeAsync, frame.window, None,
923 screen->allowScrollLock());
924 if (functions & Func_Resize)
925 blackbox->grabButton(Button3, mod_mask, frame.window, True,
926 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
927 GrabModeAsync, frame.window, None,
928 screen->allowScrollLock());
929 // alt+middle lowers the window
930 blackbox->grabButton(Button2, mod_mask, frame.window, True,
931 ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
932 frame.window, None, screen->allowScrollLock());
936 void BlackboxWindow::ungrabButtons(void) {
937 blackbox->ungrabButton(Button1, 0, frame.plate);
938 blackbox->ungrabButton(Button1, mod_mask, frame.window);
939 blackbox->ungrabButton(Button2, mod_mask, frame.window);
940 blackbox->ungrabButton(Button3, mod_mask, frame.window);
944 void BlackboxWindow::positionWindows(void) {
945 XMoveResizeWindow(blackbox->getXDisplay(), frame.window,
946 frame.rect.x(), frame.rect.y(), frame.inside_w,
947 (flags.shaded) ? frame.title_h : frame.inside_h);
948 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.window,
950 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.plate,
952 XMoveResizeWindow(blackbox->getXDisplay(), frame.plate,
953 frame.margin.left - frame.mwm_border_w - frame.border_w,
954 frame.margin.top - frame.mwm_border_w - frame.border_w,
955 client.rect.width(), client.rect.height());
956 XMoveResizeWindow(blackbox->getXDisplay(), client.window,
957 0, 0, client.rect.width(), client.rect.height());
958 // ensure client.rect contains the real location
959 client.rect.setPos(frame.rect.left() + frame.margin.left,
960 frame.rect.top() + frame.margin.top);
962 if (decorations & Decor_Titlebar) {
963 if (frame.title == None) createTitlebar();
965 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.title,
967 XMoveResizeWindow(blackbox->getXDisplay(), frame.title, -frame.border_w,
968 -frame.border_w, frame.inside_w, frame.title_h);
971 XMapSubwindows(blackbox->getXDisplay(), frame.title);
972 XMapWindow(blackbox->getXDisplay(), frame.title);
973 } else if (frame.title) {
976 if (decorations & Decor_Handle) {
977 if (frame.handle == None) createHandle();
978 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.handle,
980 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.left_grip,
982 XSetWindowBorderWidth(blackbox->getXDisplay(), frame.right_grip,
985 // use client.rect here so the value is correct even if shaded
986 XMoveResizeWindow(blackbox->getXDisplay(), frame.handle,
988 client.rect.height() + frame.margin.top +
989 frame.mwm_border_w - frame.border_w,
990 frame.inside_w, frame.handle_h);
991 XMoveResizeWindow(blackbox->getXDisplay(), frame.left_grip,
992 -frame.border_w, -frame.border_w,
993 frame.grip_w, frame.handle_h);
994 XMoveResizeWindow(blackbox->getXDisplay(), frame.right_grip,
995 frame.inside_w - frame.grip_w - frame.border_w,
996 -frame.border_w, frame.grip_w, frame.handle_h);
998 XMapSubwindows(blackbox->getXDisplay(), frame.handle);
999 XMapWindow(blackbox->getXDisplay(), frame.handle);
1000 } else if (frame.handle) {
1003 XSync(blackbox->getXDisplay(), False);
1007 void BlackboxWindow::updateStrut(void) {
1008 unsigned long num = 4;
1009 unsigned long *data;
1010 if (! xatom->getValue(client.window, XAtom::net_wm_strut, XAtom::cardinal,
1015 client.strut.left = data[0];
1016 client.strut.right = data[1];
1017 client.strut.top = data[2];
1018 client.strut.bottom = data[3];
1020 screen->updateAvailableArea();
1027 bool BlackboxWindow::getWindowType(void) {
1028 window_type = (WindowType) -1;
1031 unsigned long num = (unsigned) -1;
1032 if (xatom->getValue(client.window, XAtom::net_wm_window_type, XAtom::atom,
1034 for (unsigned long i = 0; i < num; ++i) {
1035 if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_desktop))
1036 window_type = Type_Desktop;
1037 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dock))
1038 window_type = Type_Dock;
1039 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_toolbar))
1040 window_type = Type_Toolbar;
1041 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_menu))
1042 window_type = Type_Menu;
1043 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_utility))
1044 window_type = Type_Utility;
1045 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_splash))
1046 window_type = Type_Splash;
1047 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_dialog))
1048 window_type = Type_Dialog;
1049 else if (val[i] == xatom->getAtom(XAtom::net_wm_window_type_normal))
1050 window_type = Type_Normal;
1052 xatom->getAtom(XAtom::kde_net_wm_window_type_override))
1053 mwm_decorations = 0; // prevent this window from getting any decor
1058 if (window_type == (WindowType) -1) {
1060 * the window type hint was not set, which means we either classify ourself
1061 * as a normal window or a dialog, depending on if we are a transient.
1064 window_type = Type_Dialog;
1066 window_type = Type_Normal;
1075 void BlackboxWindow::getWMName(void) {
1076 if (xatom->getValue(client.window, XAtom::net_wm_name,
1077 XAtom::utf8, client.title) &&
1078 !client.title.empty()) {
1079 xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
1082 //fall through to using WM_NAME
1083 if (xatom->getValue(client.window, XAtom::wm_name, XAtom::ansi, client.title)
1084 && !client.title.empty()) {
1085 xatom->eraseValue(client.window, XAtom::net_wm_visible_name);
1088 // fall back to an internal default
1089 client.title = i18n(WindowSet, WindowUnnamed, "Unnamed");
1090 xatom->setValue(client.window, XAtom::net_wm_visible_name, XAtom::utf8,
1093 #define DEBUG_WITH_ID 1
1094 #ifdef DEBUG_WITH_ID
1095 // the 16 is the 8 chars of the debug text plus the number
1096 char *tmp = new char[client.title.length() + 16];
1097 sprintf(tmp, "%s; id: 0x%lx", client.title.c_str(), client.window);
1104 void BlackboxWindow::getWMIconName(void) {
1105 if (xatom->getValue(client.window, XAtom::net_wm_icon_name,
1106 XAtom::utf8, client.icon_title) &&
1107 !client.icon_title.empty()) {
1108 xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
1111 //fall through to using WM_ICON_NAME
1112 if (xatom->getValue(client.window, XAtom::wm_icon_name, XAtom::ansi,
1113 client.icon_title) &&
1114 !client.icon_title.empty()) {
1115 xatom->eraseValue(client.window, XAtom::net_wm_visible_icon_name);
1118 // fall back to using the main name
1119 client.icon_title = client.title;
1120 xatom->setValue(client.window, XAtom::net_wm_visible_icon_name, XAtom::utf8,
1126 * Retrieve which WM Protocols are supported by the client window.
1127 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1128 * window's decorations and allow the close behavior.
1129 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1132 void BlackboxWindow::getWMProtocols(void) {
1136 if (XGetWMProtocols(blackbox->getXDisplay(), client.window,
1137 &proto, &num_return)) {
1138 for (int i = 0; i < num_return; ++i) {
1139 if (proto[i] == xatom->getAtom(XAtom::wm_delete_window)) {
1140 decorations |= Decor_Close;
1141 functions |= Func_Close;
1142 } else if (proto[i] == xatom->getAtom(XAtom::wm_take_focus))
1143 flags.send_focus_message = True;
1144 else if (proto[i] == xatom->getAtom(XAtom::blackbox_structure_messages))
1145 screen->addNetizen(new Netizen(screen, client.window));
1154 * Gets the value of the WM_HINTS property.
1155 * If the property is not set, then use a set of default values.
1157 void BlackboxWindow::getWMHints(void) {
1158 focus_mode = F_Passive;
1160 // remove from current window group
1161 if (client.window_group) {
1162 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1163 if (group) group->removeWindow(this);
1165 client.window_group = None;
1167 XWMHints *wmhint = XGetWMHints(blackbox->getXDisplay(), client.window);
1172 if (wmhint->flags & InputHint) {
1173 if (wmhint->input == True) {
1174 if (flags.send_focus_message)
1175 focus_mode = F_LocallyActive;
1177 if (flags.send_focus_message)
1178 focus_mode = F_GloballyActive;
1180 focus_mode = F_NoInput;
1184 if (wmhint->flags & StateHint)
1185 current_state = wmhint->initial_state;
1187 if (wmhint->flags & WindowGroupHint) {
1188 client.window_group = wmhint->window_group;
1190 // add window to the appropriate group
1191 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1192 if (! group) { // no group found, create it!
1193 new BWindowGroup(blackbox, client.window_group);
1194 group = blackbox->searchGroup(client.window_group);
1197 group->addWindow(this);
1205 * Gets the value of the WM_NORMAL_HINTS property.
1206 * If the property is not set, then use a set of default values.
1208 void BlackboxWindow::getWMNormalHints(void) {
1210 XSizeHints sizehint;
1212 client.min_width = client.min_height =
1213 client.width_inc = client.height_inc = 1;
1214 client.base_width = client.base_height = 0;
1215 client.win_gravity = NorthWestGravity;
1217 client.min_aspect_x = client.min_aspect_y =
1218 client.max_aspect_x = client.max_aspect_y = 1;
1221 // set no limit to how big a window can be by default
1222 client.max_width = (unsigned) -1;
1223 client.max_height = (unsigned) -1;
1225 if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window,
1226 &sizehint, &icccm_mask))
1229 client.normal_hint_flags = sizehint.flags;
1231 if (sizehint.flags & PMinSize) {
1232 if (sizehint.min_width >= 0)
1233 client.min_width = sizehint.min_width;
1234 if (sizehint.min_height >= 0)
1235 client.min_height = sizehint.min_height;
1238 if (sizehint.flags & PMaxSize) {
1239 if (sizehint.max_width > static_cast<signed>(client.min_width))
1240 client.max_width = sizehint.max_width;
1242 client.max_width = client.min_width;
1244 if (sizehint.max_height > static_cast<signed>(client.min_height))
1245 client.max_height = sizehint.max_height;
1247 client.max_height = client.min_height;
1250 if (sizehint.flags & PResizeInc) {
1251 client.width_inc = sizehint.width_inc;
1252 client.height_inc = sizehint.height_inc;
1255 #if 0 // we do not support this at the moment
1256 if (sizehint.flags & PAspect) {
1257 client.min_aspect_x = sizehint.min_aspect.x;
1258 client.min_aspect_y = sizehint.min_aspect.y;
1259 client.max_aspect_x = sizehint.max_aspect.x;
1260 client.max_aspect_y = sizehint.max_aspect.y;
1264 if (sizehint.flags & PBaseSize) {
1265 client.base_width = sizehint.base_width;
1266 client.base_height = sizehint.base_height;
1269 if (sizehint.flags & PWinGravity)
1270 client.win_gravity = sizehint.win_gravity;
1275 * Gets the NETWM hints for the class' contained window.
1277 void BlackboxWindow::getNetWMHints(void) {
1278 unsigned long workspace;
1280 if (xatom->getValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
1282 if (workspace == 0xffffffff)
1285 blackbox_attrib.workspace = workspace;
1288 unsigned long *state;
1289 unsigned long num = (unsigned) -1;
1290 if (xatom->getValue(client.window, XAtom::net_wm_state, XAtom::atom,
1294 for (unsigned long i = 0; i < num; ++i) {
1295 if (state[i] == xatom->getAtom(XAtom::net_wm_state_modal))
1297 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_shaded))
1298 flags.shaded = True;
1299 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_taskbar))
1300 flags.skip_taskbar = True;
1301 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_skip_pager))
1302 flags.skip_pager = True;
1303 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_fullscreen))
1304 flags.fullscreen = True;
1305 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_hidden))
1306 setState(IconicState);
1307 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_vert))
1309 else if (state[i] == xatom->getAtom(XAtom::net_wm_state_maximized_horz))
1313 flags.maximized = 1;
1315 flags.maximized = 2;
1317 flags.maximized = 3;
1325 * Gets the MWM hints for the class' contained window.
1326 * This is used while initializing the window to its first state, and not
1328 * Returns: true if the MWM hints are successfully retreived and applied;
1329 * false if they are not.
1331 void BlackboxWindow::getMWMHints(void) {
1335 num = PropMwmHintsElements;
1336 if (! xatom->getValue(client.window, XAtom::motif_wm_hints,
1337 XAtom::motif_wm_hints, num,
1338 (unsigned long **)&mwm_hint))
1340 if (num < PropMwmHintsElements) {
1345 if (mwm_hint->flags & MwmHintsDecorations) {
1346 if (mwm_hint->decorations & MwmDecorAll) {
1347 mwm_decorations = Decor_Titlebar | Decor_Handle | Decor_Border |
1348 Decor_Iconify | Decor_Maximize;
1350 mwm_decorations = 0;
1352 if (mwm_hint->decorations & MwmDecorBorder)
1353 mwm_decorations |= Decor_Border;
1354 if (mwm_hint->decorations & MwmDecorHandle)
1355 mwm_decorations |= Decor_Handle;
1356 if (mwm_hint->decorations & MwmDecorTitle)
1357 mwm_decorations |= Decor_Titlebar;
1358 if (mwm_hint->decorations & MwmDecorIconify)
1359 mwm_decorations |= Decor_Iconify;
1360 if (mwm_hint->decorations & MwmDecorMaximize)
1361 mwm_decorations |= Decor_Maximize;
1365 if (mwm_hint->flags & MwmHintsFunctions) {
1366 if (mwm_hint->functions & MwmFuncAll) {
1367 functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize |
1372 if (mwm_hint->functions & MwmFuncResize)
1373 functions |= Func_Resize;
1374 if (mwm_hint->functions & MwmFuncMove)
1375 functions |= Func_Move;
1376 if (mwm_hint->functions & MwmFuncIconify)
1377 functions |= Func_Iconify;
1378 if (mwm_hint->functions & MwmFuncMaximize)
1379 functions |= Func_Maximize;
1380 if (mwm_hint->functions & MwmFuncClose)
1381 functions |= Func_Close;
1389 * Gets the blackbox hints from the class' contained window.
1390 * This is used while initializing the window to its first state, and not
1392 * Returns: true if the hints are successfully retreived and applied; false if
1395 bool BlackboxWindow::getBlackboxHints(void) {
1397 BlackboxHints *blackbox_hint;
1399 num = PropBlackboxHintsElements;
1400 if (! xatom->getValue(client.window, XAtom::blackbox_hints,
1401 XAtom::blackbox_hints, num,
1402 (unsigned long **)&blackbox_hint))
1404 if (num < PropBlackboxHintsElements) {
1405 delete [] blackbox_hint;
1409 if (blackbox_hint->flags & AttribShaded)
1410 flags.shaded = (blackbox_hint->attrib & AttribShaded);
1412 if ((blackbox_hint->flags & AttribMaxHoriz) &&
1413 (blackbox_hint->flags & AttribMaxVert))
1414 flags.maximized = (blackbox_hint->attrib &
1415 (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1416 else if (blackbox_hint->flags & AttribMaxVert)
1417 flags.maximized = (blackbox_hint->attrib & AttribMaxVert) ? 2 : 0;
1418 else if (blackbox_hint->flags & AttribMaxHoriz)
1419 flags.maximized = (blackbox_hint->attrib & AttribMaxHoriz) ? 3 : 0;
1421 if (blackbox_hint->flags & AttribOmnipresent)
1422 flags.stuck = (blackbox_hint->attrib & AttribOmnipresent);
1424 if (blackbox_hint->flags & AttribWorkspace)
1425 blackbox_attrib.workspace = blackbox_hint->workspace;
1427 // if (blackbox_hint->flags & AttribStack)
1428 // don't yet have always on top/bottom for blackbox yet... working
1431 if (blackbox_hint->flags & AttribDecoration) {
1432 switch (blackbox_hint->decoration) {
1434 blackbox_attrib.decoration = DecorNone;
1441 // blackbox_attrib.decoration defaults to DecorNormal
1446 delete [] blackbox_hint;
1452 void BlackboxWindow::getTransientInfo(void) {
1453 if (client.transient_for &&
1454 client.transient_for != (BlackboxWindow *) ~0ul) {
1455 // reset transient_for in preparation of looking for a new owner
1456 client.transient_for->client.transientList.remove(this);
1459 // we have no transient_for until we find a new one
1460 client.transient_for = (BlackboxWindow *) 0;
1463 if (! XGetTransientForHint(blackbox->getXDisplay(), client.window,
1465 // transient_for hint not set
1469 if (trans_for == client.window) {
1470 // wierd client... treat this window as a normal window
1474 if (trans_for == None || trans_for == screen->getRootWindow()) {
1475 // this is an undocumented interpretation of the ICCCM. a transient
1476 // associated with None/Root/itself is assumed to be a modal root
1477 // transient. we don't support the concept of a global transient,
1478 // so we just associate this transient with nothing, and perhaps
1479 // we will add support later for global modality.
1480 client.transient_for = (BlackboxWindow *) ~0ul;
1485 client.transient_for = blackbox->searchWindow(trans_for);
1486 if (! client.transient_for &&
1487 client.window_group && trans_for == client.window_group) {
1488 // no direct transient_for, perhaps this is a group transient?
1489 BWindowGroup *group = blackbox->searchGroup(client.window_group);
1490 if (group) client.transient_for = group->find(screen);
1493 if (! client.transient_for || client.transient_for == this) {
1494 // no transient_for found, or we have a wierd client that wants to be
1495 // a transient for itself, so we treat this window as a normal window
1496 client.transient_for = (BlackboxWindow*) 0;
1500 // Check for a circular transient state: this can lock up Blackbox
1501 // when it tries to find the non-transient window for a transient.
1502 BlackboxWindow *w = this;
1503 while(w->client.transient_for &&
1504 w->client.transient_for != (BlackboxWindow *) ~0ul) {
1505 if(w->client.transient_for == this) {
1506 client.transient_for = (BlackboxWindow*) 0;
1509 w = w->client.transient_for;
1512 if (client.transient_for &&
1513 client.transient_for != (BlackboxWindow *) ~0ul) {
1514 // register ourselves with our new transient_for
1515 client.transient_for->client.transientList.push_back(this);
1516 flags.stuck = client.transient_for->flags.stuck;
1521 BlackboxWindow *BlackboxWindow::getTransientFor(void) const {
1522 if (client.transient_for &&
1523 client.transient_for != (BlackboxWindow*) ~0ul)
1524 return client.transient_for;
1530 * This function is responsible for updating both the client and the frame
1532 * According to the ICCCM a client message is not sent for a resize, only a
1535 void BlackboxWindow::configure(int dx, int dy,
1536 unsigned int dw, unsigned int dh) {
1537 bool send_event = ((frame.rect.x() != dx || frame.rect.y() != dy) &&
1540 if (dw != frame.rect.width() || dh != frame.rect.height()) {
1541 frame.rect.setRect(dx, dy, dw, dh);
1542 frame.inside_w = frame.rect.width() - (frame.border_w * 2);
1543 frame.inside_h = frame.rect.height() - (frame.border_w * 2);
1545 if (frame.rect.right() <= 0 || frame.rect.bottom() <= 0)
1546 frame.rect.setPos(0, 0);
1548 client.rect.setCoords(frame.rect.left() + frame.margin.left,
1549 frame.rect.top() + frame.margin.top,
1550 frame.rect.right() - frame.margin.right,
1551 frame.rect.bottom() - frame.margin.bottom);
1554 if (blackbox->hasShapeExtensions() && flags.shaped) {
1561 redrawWindowFrame();
1563 frame.rect.setPos(dx, dy);
1565 XMoveWindow(blackbox->getXDisplay(), frame.window,
1566 frame.rect.x(), frame.rect.y());
1568 we may have been called just after an opaque window move, so even though
1569 the old coords match the new ones no ConfigureNotify has been sent yet.
1570 There are likely other times when this will be relevant as well.
1572 if (! flags.moving) send_event = True;
1576 // if moving, the update and event will occur when the move finishes
1577 client.rect.setPos(frame.rect.left() + frame.margin.left,
1578 frame.rect.top() + frame.margin.top);
1581 event.type = ConfigureNotify;
1583 event.xconfigure.display = blackbox->getXDisplay();
1584 event.xconfigure.event = client.window;
1585 event.xconfigure.window = client.window;
1586 event.xconfigure.x = client.rect.x();
1587 event.xconfigure.y = client.rect.y();
1588 event.xconfigure.width = client.rect.width();
1589 event.xconfigure.height = client.rect.height();
1590 event.xconfigure.border_width = client.old_bw;
1591 event.xconfigure.above = frame.window;
1592 event.xconfigure.override_redirect = False;
1594 XSendEvent(blackbox->getXDisplay(), client.window, False,
1595 StructureNotifyMask, &event);
1596 screen->updateNetizenConfigNotify(&event);
1597 XFlush(blackbox->getXDisplay());
1603 void BlackboxWindow::configureShape(void) {
1604 XShapeCombineShape(blackbox->getXDisplay(), frame.window, ShapeBounding,
1605 frame.margin.left - frame.border_w,
1606 frame.margin.top - frame.border_w,
1607 client.window, ShapeBounding, ShapeSet);
1610 XRectangle xrect[2];
1612 if (decorations & Decor_Titlebar) {
1613 xrect[0].x = xrect[0].y = -frame.border_w;
1614 xrect[0].width = frame.rect.width();
1615 xrect[0].height = frame.title_h + (frame.border_w * 2);
1619 if (decorations & Decor_Handle) {
1620 xrect[1].x = -frame.border_w;
1621 xrect[1].y = frame.rect.height() - frame.margin.bottom +
1622 frame.mwm_border_w - frame.border_w;
1623 xrect[1].width = frame.rect.width();
1624 xrect[1].height = frame.handle_h + (frame.border_w * 2);
1628 XShapeCombineRectangles(blackbox->getXDisplay(), frame.window,
1629 ShapeBounding, 0, 0, xrect, num,
1630 ShapeUnion, Unsorted);
1635 bool BlackboxWindow::setInputFocus(void) {
1636 if (flags.focused) return True;
1638 assert(flags.stuck || // window must be on the current workspace or sticky
1639 blackbox_attrib.workspace == screen->getCurrentWorkspaceID());
1642 We only do this check for normal windows and dialogs because other windows
1643 do this on purpose, such as kde's kicker, and we don't want to go moving
1646 if (window_type == Type_Normal || window_type == Type_Dialog)
1647 if (! frame.rect.intersects(screen->getRect())) {
1648 // client is outside the screen, move it to the center
1649 configure((screen->getWidth() - frame.rect.width()) / 2,
1650 (screen->getHeight() - frame.rect.height()) / 2,
1651 frame.rect.width(), frame.rect.height());
1654 if (client.transientList.size() > 0) {
1655 // transfer focus to any modal transients
1656 BlackboxWindowList::iterator it, end = client.transientList.end();
1657 for (it = client.transientList.begin(); it != end; ++it)
1658 if ((*it)->flags.modal) return (*it)->setInputFocus();
1662 if (focus_mode == F_LocallyActive || focus_mode == F_Passive) {
1663 XSetInputFocus(blackbox->getXDisplay(), client.window,
1664 RevertToPointerRoot, CurrentTime);
1666 /* we could set the focus to none, since the window doesn't accept focus,
1667 * but we shouldn't set focus to nothing since this would surely make
1673 if (flags.send_focus_message) {
1675 ce.xclient.type = ClientMessage;
1676 ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
1677 ce.xclient.display = blackbox->getXDisplay();
1678 ce.xclient.window = client.window;
1679 ce.xclient.format = 32;
1680 ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_take_focus);
1681 ce.xclient.data.l[1] = blackbox->getLastTime();
1682 ce.xclient.data.l[2] = 0l;
1683 ce.xclient.data.l[3] = 0l;
1684 ce.xclient.data.l[4] = 0l;
1685 XSendEvent(blackbox->getXDisplay(), client.window, False,
1687 XFlush(blackbox->getXDisplay());
1694 void BlackboxWindow::iconify(void) {
1695 if (flags.iconic || ! (functions & Func_Iconify)) return;
1697 // We don't need to worry about resizing because resizing always grabs the X
1698 // server. This should only ever happen if using opaque moving.
1702 if (windowmenu) windowmenu->hide();
1705 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1706 * we need to clear the event mask on client.window for a split second.
1707 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1708 * split second, leaving us with a ghost window... so, we need to do this
1709 * while the X server is grabbed
1711 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
1712 StructureNotifyMask;
1713 XGrabServer(blackbox->getXDisplay());
1714 XSelectInput(blackbox->getXDisplay(), client.window,
1715 event_mask & ~StructureNotifyMask);
1716 XUnmapWindow(blackbox->getXDisplay(), client.window);
1717 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
1718 XUngrabServer(blackbox->getXDisplay());
1720 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1721 flags.visible = False;
1722 flags.iconic = True;
1724 setState(IconicState);
1726 screen->getWorkspace(blackbox_attrib.workspace)->removeWindow(this);
1728 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
1729 if (i != blackbox_attrib.workspace)
1730 screen->getWorkspace(i)->removeWindow(this, True);
1733 if (isTransient()) {
1734 if (client.transient_for != (BlackboxWindow *) ~0ul &&
1735 ! client.transient_for->flags.iconic) {
1736 // iconify our transient_for
1737 client.transient_for->iconify();
1741 screen->addIcon(this);
1743 if (client.transientList.size() > 0) {
1744 // iconify all transients
1745 BlackboxWindowList::iterator it, end = client.transientList.end();
1746 for (it = client.transientList.begin(); it != end; ++it) {
1747 if (! (*it)->flags.iconic) (*it)->iconify();
1750 screen->updateStackingList();
1754 void BlackboxWindow::show(void) {
1755 flags.visible = True;
1756 flags.iconic = False;
1758 current_state = (flags.shaded) ? IconicState : NormalState;
1759 setState(current_state);
1761 XMapWindow(blackbox->getXDisplay(), client.window);
1762 XMapSubwindows(blackbox->getXDisplay(), frame.window);
1763 XMapWindow(blackbox->getXDisplay(), frame.window);
1768 XTranslateCoordinates(blackbox->getXDisplay(), client.window,
1769 screen->getRootWindow(),
1770 0, 0, &real_x, &real_y, &child);
1771 fprintf(stderr, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1772 client.rect.left(), client.rect.top(), real_x, real_y);
1773 assert(client.rect.left() == real_x && client.rect.top() == real_y);
1778 void BlackboxWindow::deiconify(bool reassoc, bool raise) {
1779 if (flags.iconic || reassoc)
1780 screen->reassociateWindow(this, BSENTINEL, False);
1781 else if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID())
1786 // reassociate and deiconify all transients
1787 if (reassoc && client.transientList.size() > 0) {
1788 BlackboxWindowList::iterator it, end = client.transientList.end();
1789 for (it = client.transientList.begin(); it != end; ++it)
1790 (*it)->deiconify(True, False);
1794 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1798 void BlackboxWindow::close(void) {
1799 if (! (functions & Func_Close)) return;
1802 ce.xclient.type = ClientMessage;
1803 ce.xclient.message_type = xatom->getAtom(XAtom::wm_protocols);
1804 ce.xclient.display = blackbox->getXDisplay();
1805 ce.xclient.window = client.window;
1806 ce.xclient.format = 32;
1807 ce.xclient.data.l[0] = xatom->getAtom(XAtom::wm_delete_window);
1808 ce.xclient.data.l[1] = CurrentTime;
1809 ce.xclient.data.l[2] = 0l;
1810 ce.xclient.data.l[3] = 0l;
1811 ce.xclient.data.l[4] = 0l;
1812 XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce);
1813 XFlush(blackbox->getXDisplay());
1817 void BlackboxWindow::withdraw(void) {
1818 // We don't need to worry about resizing because resizing always grabs the X
1819 // server. This should only ever happen if using opaque moving.
1823 flags.visible = False;
1824 flags.iconic = False;
1826 setState(current_state);
1828 XUnmapWindow(blackbox->getXDisplay(), frame.window);
1830 XGrabServer(blackbox->getXDisplay());
1832 unsigned long event_mask = PropertyChangeMask | FocusChangeMask |
1833 StructureNotifyMask;
1834 XSelectInput(blackbox->getXDisplay(), client.window,
1835 event_mask & ~StructureNotifyMask);
1836 XUnmapWindow(blackbox->getXDisplay(), client.window);
1837 XSelectInput(blackbox->getXDisplay(), client.window, event_mask);
1839 XUngrabServer(blackbox->getXDisplay());
1841 if (windowmenu) windowmenu->hide();
1845 void BlackboxWindow::maximize(unsigned int button) {
1846 if (! (functions & Func_Maximize)) return;
1848 // We don't need to worry about resizing because resizing always grabs the X
1849 // server. This should only ever happen if using opaque moving.
1853 // handle case where menu is open then the max button is used instead
1854 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
1856 if (flags.maximized) {
1857 flags.maximized = 0;
1859 blackbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert);
1860 blackbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert);
1863 when a resize finishes, maximize(0) is called to clear any maximization
1864 flags currently set. Otherwise it still thinks it is maximized.
1865 so we do not need to call configure() because resizing will handle it
1867 if (! flags.resizing)
1868 configure(blackbox_attrib.premax_x, blackbox_attrib.premax_y,
1869 blackbox_attrib.premax_w, blackbox_attrib.premax_h);
1871 blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0;
1872 blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0;
1874 redrawAllButtons(); // in case it is not called in configure()
1875 setState(current_state);
1879 blackbox_attrib.premax_x = frame.rect.x();
1880 blackbox_attrib.premax_y = frame.rect.y();
1881 blackbox_attrib.premax_w = frame.rect.width();
1882 // use client.rect so that clients can be restored even if shaded
1883 blackbox_attrib.premax_h =
1884 client.rect.height() + frame.margin.top + frame.margin.bottom;
1887 if (screen->isXineramaActive() && blackbox->doXineramaMaximizing()) {
1888 // find the area to use
1889 RectList availableAreas = screen->allAvailableAreas();
1890 RectList::iterator it, end = availableAreas.end();
1892 for (it = availableAreas.begin(); it != end; ++it)
1893 if (it->intersects(frame.rect)) break;
1894 if (it == end) // the window isn't inside an area
1895 it = availableAreas.begin(); // so just default to the first one
1897 frame.changing = *it;
1900 frame.changing = screen->availableArea();
1904 blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
1905 blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
1909 blackbox_attrib.flags |= AttribMaxVert;
1910 blackbox_attrib.attrib |= AttribMaxVert;
1912 frame.changing.setX(frame.rect.x());
1913 frame.changing.setWidth(frame.rect.width());
1917 blackbox_attrib.flags |= AttribMaxHoriz;
1918 blackbox_attrib.attrib |= AttribMaxHoriz;
1920 frame.changing.setY(frame.rect.y());
1921 frame.changing.setHeight(frame.rect.height());
1928 blackbox_attrib.flags ^= AttribShaded;
1929 blackbox_attrib.attrib ^= AttribShaded;
1930 flags.shaded = False;
1933 flags.maximized = button;
1935 configure(frame.changing.x(), frame.changing.y(),
1936 frame.changing.width(), frame.changing.height());
1938 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
1939 redrawAllButtons(); // in case it is not called in configure()
1940 setState(current_state);
1944 // re-maximizes the window to take into account availableArea changes
1945 void BlackboxWindow::remaximize(void) {
1947 // we only update the window's attributes otherwise we lose the shade bit
1948 switch(flags.maximized) {
1950 blackbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
1951 blackbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
1955 blackbox_attrib.flags |= AttribMaxVert;
1956 blackbox_attrib.attrib |= AttribMaxVert;
1960 blackbox_attrib.flags |= AttribMaxHoriz;
1961 blackbox_attrib.attrib |= AttribMaxHoriz;
1967 // save the original dimensions because maximize will wipe them out
1968 int premax_x = blackbox_attrib.premax_x,
1969 premax_y = blackbox_attrib.premax_y,
1970 premax_w = blackbox_attrib.premax_w,
1971 premax_h = blackbox_attrib.premax_h;
1973 unsigned int button = flags.maximized;
1974 flags.maximized = 0; // trick maximize() into working
1977 // restore saved values
1978 blackbox_attrib.premax_x = premax_x;
1979 blackbox_attrib.premax_y = premax_y;
1980 blackbox_attrib.premax_w = premax_w;
1981 blackbox_attrib.premax_h = premax_h;
1985 void BlackboxWindow::setWorkspace(unsigned int n) {
1986 blackbox_attrib.flags |= AttribWorkspace;
1987 blackbox_attrib.workspace = n;
1988 if (n == BSENTINEL) { // iconified window
1990 we set the workspace to 'all workspaces' so that taskbars will show the
1991 window. otherwise, it made uniconifying a window imposible without the
1992 blackbox workspace menu
1996 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n);
2000 void BlackboxWindow::shade(void) {
2002 XResizeWindow(blackbox->getXDisplay(), frame.window,
2003 frame.inside_w, frame.inside_h);
2004 flags.shaded = False;
2005 blackbox_attrib.flags ^= AttribShaded;
2006 blackbox_attrib.attrib ^= AttribShaded;
2008 setState(NormalState);
2010 // set the frame rect to the normal size
2011 frame.rect.setHeight(client.rect.height() + frame.margin.top +
2012 frame.margin.bottom);
2014 if (! (decorations & Decor_Titlebar))
2015 return; // can't shade it without a titlebar!
2017 XResizeWindow(blackbox->getXDisplay(), frame.window,
2018 frame.inside_w, frame.title_h);
2019 flags.shaded = True;
2020 blackbox_attrib.flags |= AttribShaded;
2021 blackbox_attrib.attrib |= AttribShaded;
2023 setState(IconicState);
2025 // set the frame rect to the shaded size
2026 frame.rect.setHeight(frame.title_h + (frame.border_w * 2));
2032 * (Un)Sticks a window and its relatives.
2034 void BlackboxWindow::stick(void) {
2036 blackbox_attrib.flags ^= AttribOmnipresent;
2037 blackbox_attrib.attrib ^= AttribOmnipresent;
2039 flags.stuck = False;
2041 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
2042 if (i != blackbox_attrib.workspace)
2043 screen->getWorkspace(i)->removeWindow(this, True);
2046 screen->reassociateWindow(this, BSENTINEL, True);
2047 // temporary fix since sticky windows suck. set the hint to what we
2048 // actually hold in our data.
2049 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
2050 blackbox_attrib.workspace);
2052 setState(current_state);
2056 blackbox_attrib.flags |= AttribOmnipresent;
2057 blackbox_attrib.attrib |= AttribOmnipresent;
2059 // temporary fix since sticky windows suck. set the hint to a different
2060 // value than that contained in the class' data.
2061 xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal,
2064 for (unsigned int i = 0; i < screen->getNumberOfWorkspaces(); ++i)
2065 if (i != blackbox_attrib.workspace)
2066 screen->getWorkspace(i)->addWindow(this, False, True);
2068 setState(current_state);
2071 if (isTransient() && client.transient_for != (BlackboxWindow *) ~0ul &&
2072 client.transient_for->isStuck() != flags.stuck)
2073 client.transient_for->stick();
2074 // go down the chain
2075 BlackboxWindowList::iterator it;
2076 const BlackboxWindowList::iterator end = client.transientList.end();
2077 for (it = client.transientList.begin(); it != end; ++it)
2078 if ((*it)->isStuck() != flags.stuck)
2083 void BlackboxWindow::redrawWindowFrame(void) const {
2084 if (decorations & Decor_Titlebar) {
2085 if (flags.focused) {
2087 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2088 frame.title, frame.ftitle);
2090 XSetWindowBackground(blackbox->getXDisplay(),
2091 frame.title, frame.ftitle_pixel);
2094 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2095 frame.title, frame.utitle);
2097 XSetWindowBackground(blackbox->getXDisplay(),
2098 frame.title, frame.utitle_pixel);
2100 XClearWindow(blackbox->getXDisplay(), frame.title);
2106 if (decorations & Decor_Handle) {
2107 if (flags.focused) {
2109 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2110 frame.handle, frame.fhandle);
2112 XSetWindowBackground(blackbox->getXDisplay(),
2113 frame.handle, frame.fhandle_pixel);
2116 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2117 frame.left_grip, frame.fgrip);
2118 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2119 frame.right_grip, frame.fgrip);
2121 XSetWindowBackground(blackbox->getXDisplay(),
2122 frame.left_grip, frame.fgrip_pixel);
2123 XSetWindowBackground(blackbox->getXDisplay(),
2124 frame.right_grip, frame.fgrip_pixel);
2128 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2129 frame.handle, frame.uhandle);
2131 XSetWindowBackground(blackbox->getXDisplay(),
2132 frame.handle, frame.uhandle_pixel);
2135 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2136 frame.left_grip, frame.ugrip);
2137 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2138 frame.right_grip, frame.ugrip);
2140 XSetWindowBackground(blackbox->getXDisplay(),
2141 frame.left_grip, frame.ugrip_pixel);
2142 XSetWindowBackground(blackbox->getXDisplay(),
2143 frame.right_grip, frame.ugrip_pixel);
2146 XClearWindow(blackbox->getXDisplay(), frame.handle);
2147 XClearWindow(blackbox->getXDisplay(), frame.left_grip);
2148 XClearWindow(blackbox->getXDisplay(), frame.right_grip);
2151 if (decorations & Decor_Border) {
2153 XSetWindowBorder(blackbox->getXDisplay(),
2154 frame.plate, frame.fborder_pixel);
2156 XSetWindowBorder(blackbox->getXDisplay(),
2157 frame.plate, frame.uborder_pixel);
2162 void BlackboxWindow::setFocusFlag(bool focus) {
2163 // only focus a window if it is visible
2164 if (focus && ! flags.visible)
2167 flags.focused = focus;
2169 redrawWindowFrame();
2172 blackbox->setFocusedWindow(this);
2174 if (! flags.iconic) {
2175 // iconic windows arent in a workspace menu!
2177 screen->getCurrentWorkspace()->setFocused(this, isFocused());
2179 screen->getWorkspace(blackbox_attrib.workspace)->
2180 setFocused(this, flags.focused);
2185 void BlackboxWindow::installColormap(bool install) {
2186 int i = 0, ncmap = 0;
2187 Colormap *cmaps = XListInstalledColormaps(blackbox->getXDisplay(),
2188 client.window, &ncmap);
2190 XWindowAttributes wattrib;
2191 if (XGetWindowAttributes(blackbox->getXDisplay(),
2192 client.window, &wattrib)) {
2194 // install the window's colormap
2195 for (i = 0; i < ncmap; i++) {
2196 if (*(cmaps + i) == wattrib.colormap)
2197 // this window is using an installed color map... do not install
2200 // otherwise, install the window's colormap
2202 XInstallColormap(blackbox->getXDisplay(), wattrib.colormap);
2204 // uninstall the window's colormap
2205 for (i = 0; i < ncmap; i++) {
2206 if (*(cmaps + i) == wattrib.colormap)
2207 // we found the colormap to uninstall
2208 XUninstallColormap(blackbox->getXDisplay(), wattrib.colormap);
2218 void BlackboxWindow::setAllowedActions(void) {
2222 actions[num++] = xatom->getAtom(XAtom::net_wm_action_shade);
2223 actions[num++] = xatom->getAtom(XAtom::net_wm_action_change_desktop);
2224 actions[num++] = xatom->getAtom(XAtom::net_wm_action_close);
2226 if (functions & Func_Move)
2227 actions[num++] = xatom->getAtom(XAtom::net_wm_action_move);
2228 if (functions & Func_Resize)
2229 actions[num++] = xatom->getAtom(XAtom::net_wm_action_resize);
2230 if (functions & Func_Maximize) {
2231 actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_horz);
2232 actions[num++] = xatom->getAtom(XAtom::net_wm_action_maximize_vert);
2235 xatom->setValue(client.window, XAtom::net_wm_allowed_actions, XAtom::atom,
2240 void BlackboxWindow::setState(unsigned long new_state) {
2241 current_state = new_state;
2243 unsigned long state[2];
2244 state[0] = current_state;
2246 xatom->setValue(client.window, XAtom::wm_state, XAtom::wm_state, state, 2);
2248 xatom->setValue(client.window, XAtom::blackbox_attributes,
2249 XAtom::blackbox_attributes, (unsigned long *)&blackbox_attrib,
2250 PropBlackboxAttributesElements);
2255 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_modal);
2257 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_shaded);
2259 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_hidden);
2260 if (flags.skip_taskbar)
2261 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_taskbar);
2262 if (flags.skip_pager)
2263 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_skip_pager);
2264 if (flags.fullscreen)
2265 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_fullscreen);
2266 if (flags.maximized == 1 || flags.maximized == 2)
2267 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_vert);
2268 if (flags.maximized == 1 || flags.maximized == 3)
2269 netstate[num++] = xatom->getAtom(XAtom::net_wm_state_maximized_horz);
2270 xatom->setValue(client.window, XAtom::net_wm_state, XAtom::atom,
2275 bool BlackboxWindow::getState(void) {
2276 bool ret = xatom->getValue(client.window, XAtom::wm_state, XAtom::wm_state,
2278 if (! ret) current_state = 0;
2283 void BlackboxWindow::restoreAttributes(void) {
2284 unsigned long num = PropBlackboxAttributesElements;
2285 BlackboxAttributes *net;
2286 if (! xatom->getValue(client.window, XAtom::blackbox_attributes,
2287 XAtom::blackbox_attributes, num,
2288 (unsigned long **)&net))
2290 if (num < PropBlackboxAttributesElements) {
2295 if (net->flags & AttribShaded && net->attrib & AttribShaded) {
2296 flags.shaded = False;
2297 unsigned long orig_state = current_state;
2301 At this point in the life of a window, current_state should only be set
2302 to IconicState if the window was an *icon*, not if it was shaded.
2304 if (orig_state != IconicState)
2305 current_state = WithdrawnState;
2308 if (net->workspace != screen->getCurrentWorkspaceID() &&
2309 net->workspace < screen->getWorkspaceCount())
2310 screen->reassociateWindow(this, net->workspace, True);
2312 if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) &&
2313 (blackbox_attrib.workspace < screen->getWorkspaceCount())) {
2314 // set to WithdrawnState so it will be mapped on the new workspace
2315 if (current_state == NormalState) current_state = WithdrawnState;
2316 } else if (current_state == WithdrawnState) {
2317 // the window is on this workspace and is Withdrawn, so it is waiting to
2319 current_state = NormalState;
2322 if (net->flags & AttribOmnipresent && net->attrib & AttribOmnipresent &&
2326 // if the window was on another workspace, it was going to be hidden. this
2327 // specifies that the window should be mapped since it is sticky.
2328 if (current_state == WithdrawnState) current_state = NormalState;
2331 if (net->flags & AttribMaxHoriz || net->flags & AttribMaxVert) {
2332 int x = net->premax_x, y = net->premax_y;
2333 unsigned int w = net->premax_w, h = net->premax_h;
2334 flags.maximized = 0;
2337 if ((net->flags & AttribMaxHoriz) &&
2338 (net->flags & AttribMaxVert))
2339 m = (net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
2340 else if (net->flags & AttribMaxVert)
2341 m = (net->attrib & AttribMaxVert) ? 2 : 0;
2342 else if (net->flags & AttribMaxHoriz)
2343 m = (net->attrib & AttribMaxHoriz) ? 3 : 0;
2347 blackbox_attrib.premax_x = x;
2348 blackbox_attrib.premax_y = y;
2349 blackbox_attrib.premax_w = w;
2350 blackbox_attrib.premax_h = h;
2353 if (net->flags & AttribDecoration) {
2354 switch (net->decoration) {
2359 /* since tools only let you toggle this anyways, we'll just make that all
2360 it supports for now.
2371 // with the state set it will then be the map event's job to read the
2372 // window's state and behave accordingly
2379 * Positions the Rect r according the the client window position and
2382 void BlackboxWindow::applyGravity(Rect &r) {
2383 // apply horizontal window gravity
2384 switch (client.win_gravity) {
2386 case NorthWestGravity:
2387 case SouthWestGravity:
2389 r.setX(client.rect.x());
2395 r.setX(client.rect.x() - (frame.margin.left + frame.margin.right) / 2);
2398 case NorthEastGravity:
2399 case SouthEastGravity:
2401 r.setX(client.rect.x() - frame.margin.left - frame.margin.right + 2);
2406 r.setX(client.rect.x() - frame.margin.left);
2410 // apply vertical window gravity
2411 switch (client.win_gravity) {
2413 case NorthWestGravity:
2414 case NorthEastGravity:
2416 r.setY(client.rect.y());
2422 r.setY(client.rect.y() - (frame.margin.top + frame.margin.bottom) / 2);
2425 case SouthWestGravity:
2426 case SouthEastGravity:
2428 r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom + 2);
2433 r.setY(client.rect.y() - frame.margin.top);
2440 * The reverse of the applyGravity function.
2442 * Positions the Rect r according to the frame window position and
2445 void BlackboxWindow::restoreGravity(Rect &r) {
2446 // restore horizontal window gravity
2447 switch (client.win_gravity) {
2449 case NorthWestGravity:
2450 case SouthWestGravity:
2452 r.setX(frame.rect.x());
2458 r.setX(frame.rect.x() + (frame.margin.left + frame.margin.right) / 2);
2461 case NorthEastGravity:
2462 case SouthEastGravity:
2464 r.setX(frame.rect.x() + frame.margin.left + frame.margin.right - 2);
2469 r.setX(frame.rect.x() + frame.margin.left);
2473 // restore vertical window gravity
2474 switch (client.win_gravity) {
2476 case NorthWestGravity:
2477 case NorthEastGravity:
2479 r.setY(frame.rect.y());
2485 r.setY(frame.rect.y() + (frame.margin.top + frame.margin.bottom) / 2);
2488 case SouthWestGravity:
2489 case SouthEastGravity:
2491 r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom - 2);
2496 r.setY(frame.rect.y() + frame.margin.top);
2502 void BlackboxWindow::redrawLabel(void) const {
2503 if (flags.focused) {
2505 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2506 frame.label, frame.flabel);
2508 XSetWindowBackground(blackbox->getXDisplay(),
2509 frame.label, frame.flabel_pixel);
2512 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2513 frame.label, frame.ulabel);
2515 XSetWindowBackground(blackbox->getXDisplay(),
2516 frame.label, frame.ulabel_pixel);
2518 XClearWindow(blackbox->getXDisplay(), frame.label);
2520 WindowStyle *style = screen->getWindowStyle();
2522 int pos = frame.bevel_w * 2;
2523 style->doJustify(client.title.c_str(), pos, frame.label_w, frame.bevel_w * 4);
2524 style->font->drawString(frame.label, pos, 1,
2525 (flags.focused ? style->l_text_focus :
2526 style->l_text_unfocus),
2531 void BlackboxWindow::redrawAllButtons(void) const {
2532 if (frame.iconify_button) redrawIconifyButton(False);
2533 if (frame.maximize_button) redrawMaximizeButton(flags.maximized);
2534 if (frame.close_button) redrawCloseButton(False);
2538 void BlackboxWindow::redrawIconifyButton(bool pressed) const {
2540 if (flags.focused) {
2542 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2543 frame.iconify_button, frame.fbutton);
2545 XSetWindowBackground(blackbox->getXDisplay(),
2546 frame.iconify_button, frame.fbutton_pixel);
2549 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2550 frame.iconify_button, frame.ubutton);
2552 XSetWindowBackground(blackbox->getXDisplay(), frame.iconify_button,
2553 frame.ubutton_pixel);
2557 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2558 frame.iconify_button, frame.pbutton);
2560 XSetWindowBackground(blackbox->getXDisplay(),
2561 frame.iconify_button, frame.pbutton_pixel);
2563 XClearWindow(blackbox->getXDisplay(), frame.iconify_button);
2565 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2566 screen->getWindowStyle()->b_pic_unfocus);
2567 XDrawRectangle(blackbox->getXDisplay(), frame.iconify_button, pen.gc(),
2568 2, (frame.button_w - 5), (frame.button_w - 5), 2);
2572 void BlackboxWindow::redrawMaximizeButton(bool pressed) const {
2574 if (flags.focused) {
2576 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2577 frame.maximize_button, frame.fbutton);
2579 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2580 frame.fbutton_pixel);
2583 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2584 frame.maximize_button, frame.ubutton);
2586 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2587 frame.ubutton_pixel);
2591 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2592 frame.maximize_button, frame.pbutton);
2594 XSetWindowBackground(blackbox->getXDisplay(), frame.maximize_button,
2595 frame.pbutton_pixel);
2597 XClearWindow(blackbox->getXDisplay(), frame.maximize_button);
2599 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2600 screen->getWindowStyle()->b_pic_unfocus);
2601 XDrawRectangle(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2602 2, 2, (frame.button_w - 5), (frame.button_w - 5));
2603 XDrawLine(blackbox->getXDisplay(), frame.maximize_button, pen.gc(),
2604 2, 3, (frame.button_w - 3), 3);
2608 void BlackboxWindow::redrawCloseButton(bool pressed) const {
2610 if (flags.focused) {
2612 XSetWindowBackgroundPixmap(blackbox->getXDisplay(), frame.close_button,
2615 XSetWindowBackground(blackbox->getXDisplay(), frame.close_button,
2616 frame.fbutton_pixel);
2619 XSetWindowBackgroundPixmap(blackbox->getXDisplay(), frame.close_button,
2622 XSetWindowBackground(blackbox->getXDisplay(), frame.close_button,
2623 frame.ubutton_pixel);
2627 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
2628 frame.close_button, frame.pbutton);
2630 XSetWindowBackground(blackbox->getXDisplay(),
2631 frame.close_button, frame.pbutton_pixel);
2633 XClearWindow(blackbox->getXDisplay(), frame.close_button);
2635 BPen pen((flags.focused) ? screen->getWindowStyle()->b_pic_focus :
2636 screen->getWindowStyle()->b_pic_unfocus);
2637 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2638 2, 2, (frame.button_w - 3), (frame.button_w - 3));
2639 XDrawLine(blackbox->getXDisplay(), frame.close_button, pen.gc(),
2640 2, (frame.button_w - 3), (frame.button_w - 3), 2);
2644 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) {
2645 if (re->window != client.window)
2649 fprintf(stderr, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2654 Even though the window wants to be shown, if it is not on the current
2655 workspace, then it isn't going to be shown right now.
2657 if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID() &&
2658 blackbox_attrib.workspace < screen->getWorkspaceCount())
2659 if (current_state == NormalState) current_state = WithdrawnState;
2661 switch (current_state) {
2666 case WithdrawnState:
2675 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2677 if (! blackbox->isStartup()) {
2678 XSync(blackbox->getXDisplay(), False); // make sure the frame is mapped
2679 if (screen->doFocusNew() || (isTransient() && getTransientFor() &&
2680 getTransientFor()->isFocused())) {
2683 if (screen->getPlacementPolicy() == BScreen::ClickMousePlacement) {
2687 XQueryPointer(blackbox->getXDisplay(), screen->getRootWindow(),
2688 &r, &c, &rx, &ry, &x, &y, &m);
2698 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent *ue) {
2699 if (ue->window != client.window)
2703 fprintf(stderr, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2707 screen->unmanageWindow(this, False);
2711 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent *de) {
2712 if (de->window != client.window)
2716 fprintf(stderr, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2720 screen->unmanageWindow(this, False);
2724 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent *re) {
2725 if (re->window != client.window || re->parent == frame.plate)
2729 fprintf(stderr, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2730 "0x%lx.\n", client.window, re->parent);
2735 XPutBackEvent(blackbox->getXDisplay(), &ev);
2736 screen->unmanageWindow(this, True);
2740 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) {
2741 if (pe->state == PropertyDelete || ! validateClient())
2745 fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2751 case XA_WM_CLIENT_MACHINE:
2755 case XA_WM_TRANSIENT_FOR: {
2756 bool s = flags.stuck;
2758 // determine if this is a transient window
2761 if (flags.stuck != s) stick();
2763 // adjust the window decorations based on transience
2764 if (isTransient()) {
2765 functions &= ~Func_Maximize;
2766 setAllowedActions();
2778 case XA_WM_ICON_NAME:
2780 if (flags.iconic) screen->propagateWindowName(this);
2783 case XAtom::net_wm_name:
2787 if (decorations & Decor_Titlebar)
2790 screen->propagateWindowName(this);
2793 case XA_WM_NORMAL_HINTS: {
2796 if ((client.normal_hint_flags & PMinSize) &&
2797 (client.normal_hint_flags & PMaxSize)) {
2798 // the window now can/can't resize itself, so the buttons need to be
2801 if (client.max_width <= client.min_width &&
2802 client.max_height <= client.min_height) {
2803 functions &= ~(Func_Resize | Func_Maximize);
2805 if (! isTransient())
2806 functions |= Func_Maximize;
2807 functions |= Func_Resize;
2810 setAllowedActions();
2814 Rect old_rect = frame.rect;
2818 if (old_rect != frame.rect)
2825 if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) {
2828 if ((decorations & Decor_Close) && (! frame.close_button)) {
2829 createCloseButton();
2830 if (decorations & Decor_Titlebar) {
2831 positionButtons(True);
2832 XMapSubwindows(blackbox->getXDisplay(), frame.title);
2834 if (windowmenu) windowmenu->reconfigure();
2836 } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) {
2845 void BlackboxWindow::exposeEvent(const XExposeEvent *ee) {
2847 fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window);
2850 if (frame.label == ee->window && (decorations & Decor_Titlebar))
2852 else if (frame.close_button == ee->window)
2853 redrawCloseButton(False);
2854 else if (frame.maximize_button == ee->window)
2855 redrawMaximizeButton(flags.maximized);
2856 else if (frame.iconify_button == ee->window)
2857 redrawIconifyButton(False);
2861 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) {
2862 if (cr->window != client.window || flags.iconic)
2865 if (cr->value_mask & CWBorderWidth)
2866 client.old_bw = cr->border_width;
2868 if (cr->value_mask & (CWX | CWY | CWWidth | CWHeight)) {
2869 frame.changing = frame.rect;
2871 if (cr->value_mask & (CWX | CWY)) {
2872 if (cr->value_mask & CWX)
2873 client.rect.setX(cr->x);
2874 if (cr->value_mask & CWY)
2875 client.rect.setY(cr->y);
2877 applyGravity(frame.changing);
2880 if (cr->value_mask & (CWWidth | CWHeight)) {
2881 if (cr->value_mask & CWWidth)
2882 frame.changing.setWidth(cr->width +
2883 frame.margin.left + frame.margin.right);
2885 if (cr->value_mask & CWHeight)
2886 frame.changing.setHeight(cr->height +
2887 frame.margin.top + frame.margin.bottom);
2890 if a position change ha been specified, then that position will be used
2891 instead of determining a position based on the window's gravity.
2893 if (cr->value_mask & (CWX | CWY)) {
2895 switch (client.win_gravity) {
2896 case NorthEastGravity:
2900 case SouthWestGravity:
2902 corner = BottomLeft;
2904 case SouthEastGravity:
2905 corner = BottomRight;
2907 default: // NorthWest, Static, etc
2914 configure(frame.changing.x(), frame.changing.y(),
2915 frame.changing.width(), frame.changing.height());
2918 if (cr->value_mask & CWStackMode && !isDesktop()) {
2919 switch (cr->detail) {
2922 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
2928 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2935 void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) {
2937 fprintf(stderr, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
2941 if (frame.maximize_button == be->window && be->button <= 3) {
2942 redrawMaximizeButton(True);
2943 } else if (be->button == 1 || (be->button == 3 && be->state == mod_mask)) {
2944 if (! flags.focused)
2947 if (frame.iconify_button == be->window) {
2948 redrawIconifyButton(True);
2949 } else if (frame.close_button == be->window) {
2950 redrawCloseButton(True);
2951 } else if (frame.plate == be->window) {
2952 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
2954 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2956 XAllowEvents(blackbox->getXDisplay(), ReplayPointer, be->time);
2958 if (frame.title == be->window || frame.label == be->window) {
2959 if (((be->time - lastButtonPressTime) <=
2960 blackbox->getDoubleClickInterval()) ||
2961 (be->state == ControlMask)) {
2962 lastButtonPressTime = 0;
2965 lastButtonPressTime = be->time;
2969 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
2971 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
2973 } else if (be->button == 2 && (be->window != frame.iconify_button) &&
2974 (be->window != frame.close_button)) {
2975 screen->getWorkspace(blackbox_attrib.workspace)->lowerWindow(this);
2976 } else if (windowmenu && be->button == 3 &&
2977 (frame.title == be->window || frame.label == be->window ||
2978 frame.handle == be->window || frame.window == be->window)) {
2979 if (windowmenu->isVisible()) {
2982 int mx = be->x_root - windowmenu->getWidth() / 2,
2983 my = be->y_root - windowmenu->getHeight() / 2;
2985 // snap the window menu into a corner/side if necessary
2986 int left_edge, right_edge, top_edge, bottom_edge;
2989 the " + (frame.border_w * 2) - 1" bits are to get the proper width
2990 and height of the menu, as the sizes returned by it do not include
2993 left_edge = frame.rect.x();
2994 right_edge = frame.rect.right() -
2995 (windowmenu->getWidth() + (frame.border_w * 2) - 1);
2996 top_edge = client.rect.top() - (frame.border_w + frame.mwm_border_w);
2997 bottom_edge = client.rect.bottom() -
2998 (windowmenu->getHeight() + (frame.border_w * 2) - 1) +
2999 (frame.border_w + frame.mwm_border_w);
3003 if (mx > right_edge)
3007 if (my > bottom_edge)
3010 windowmenu->move(mx, my);
3012 XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID());
3013 XRaiseWindow(blackbox->getXDisplay(),
3014 windowmenu->getSendToMenu()->getWindowID());
3017 } else if (be->button == 4) {
3018 if ((be->window == frame.label ||
3019 be->window == frame.title ||
3020 be->window == frame.maximize_button ||
3021 be->window == frame.iconify_button ||
3022 be->window == frame.close_button) &&
3026 } else if (be->button == 5) {
3027 if ((be->window == frame.label ||
3028 be->window == frame.title ||
3029 be->window == frame.maximize_button ||
3030 be->window == frame.iconify_button ||
3031 be->window == frame.close_button) &&
3038 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) {
3040 fprintf(stderr, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3044 if (re->window == frame.maximize_button &&
3045 re->button >= 1 && re->button <= 3) {
3046 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3047 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
3048 maximize(re->button);
3050 redrawMaximizeButton(flags.maximized);
3052 } else if (re->window == frame.iconify_button && re->button == 1) {
3053 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3054 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
3057 redrawIconifyButton(False);
3059 } else if (re->window == frame.close_button & re->button == 1) {
3060 if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
3061 (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w)))
3063 redrawCloseButton(False);
3064 } else if (flags.moving) {
3066 } else if (flags.resizing) {
3068 } else if (re->window == frame.window) {
3069 if (re->button == 2 && re->state == mod_mask)
3070 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3076 void BlackboxWindow::beginMove(int x_root, int y_root) {
3077 if (! (functions & Func_Move)) return;
3079 assert(! (flags.resizing || flags.moving));
3082 Only one window can be moved/resized at a time. If another window is already
3083 being moved or resized, then stop it before whating to work with this one.
3085 BlackboxWindow *changing = blackbox->getChangingWindow();
3086 if (changing && changing != this) {
3087 if (changing->flags.moving)
3088 changing->endMove();
3089 else // if (changing->flags.resizing)
3090 changing->endResize();
3093 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3094 PointerMotionMask | ButtonReleaseMask,
3095 GrabModeAsync, GrabModeAsync,
3096 None, blackbox->getMoveCursor(), CurrentTime);
3098 if (windowmenu && windowmenu->isVisible())
3101 flags.moving = True;
3102 blackbox->setChangingWindow(this);
3104 if (! screen->doOpaqueMove()) {
3105 XGrabServer(blackbox->getXDisplay());
3107 frame.changing = frame.rect;
3108 screen->showPosition(frame.changing.x(), frame.changing.y());
3110 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3114 frame.changing.width() - 1,
3115 frame.changing.height() - 1);
3118 frame.grab_x = x_root - frame.rect.x() - frame.border_w;
3119 frame.grab_y = y_root - frame.rect.y() - frame.border_w;
3123 void BlackboxWindow::doMove(int x_root, int y_root) {
3124 assert(flags.moving);
3125 assert(blackbox->getChangingWindow() == this);
3127 int dx = x_root - frame.grab_x, dy = y_root - frame.grab_y;
3128 dx -= frame.border_w;
3129 dy -= frame.border_w;
3131 doWindowSnapping(dx, dy);
3133 if (screen->doOpaqueMove()) {
3134 if (screen->doWorkspaceWarping())
3135 doWorkspaceWarping(x_root, y_root, dx);
3137 configure(dx, dy, frame.rect.width(), frame.rect.height());
3139 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3143 frame.changing.width() - 1,
3144 frame.changing.height() - 1);
3146 if (screen->doWorkspaceWarping())
3147 doWorkspaceWarping(x_root, y_root, dx);
3149 frame.changing.setPos(dx, dy);
3151 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3155 frame.changing.width() - 1,
3156 frame.changing.height() - 1);
3159 screen->showPosition(dx, dy);
3163 void BlackboxWindow::doWorkspaceWarping(int x_root, int y_root, int &dx) {
3164 // workspace warping
3166 unsigned int dest = screen->getCurrentWorkspaceID();
3170 if (dest > 0) dest--;
3171 else dest = screen->getNumberOfWorkspaces() - 1;
3173 } else if (x_root >= screen->getRect().right()) {
3176 if (dest < screen->getNumberOfWorkspaces() - 1) dest++;
3182 bool focus = flags.focused; // had focus while moving?
3184 int dest_x = x_root;
3186 dest_x += screen->getRect().width() - 1;
3187 dx += screen->getRect().width() - 1;
3189 dest_x -= screen->getRect().width() - 1;
3190 dx -= screen->getRect().width() - 1;
3194 screen->reassociateWindow(this, dest, False);
3195 screen->changeWorkspaceID(dest);
3197 if (screen->doOpaqueMove())
3198 XGrabServer(blackbox->getXDisplay());
3200 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3201 XWarpPointer(blackbox->getXDisplay(), None,
3202 screen->getRootWindow(), 0, 0, 0, 0,
3204 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3205 PointerMotionMask | ButtonReleaseMask,
3206 GrabModeAsync, GrabModeAsync,
3207 None, blackbox->getMoveCursor(), CurrentTime);
3209 if (screen->doOpaqueMove())
3210 XUngrabServer(blackbox->getXDisplay());
3218 void BlackboxWindow::doWindowSnapping(int &dx, int &dy) {
3219 // how much resistance to edges to provide
3220 const int resistance_size = screen->getResistanceSize();
3222 // how far away to snap
3223 const int snap_distance = screen->getSnapThreshold();
3225 // how to snap windows
3226 const int snap_to_windows = screen->getWindowToWindowSnap();
3227 const int snap_to_edges = screen->getWindowToEdgeSnap();
3228 // the amount of space away from the edge to provide resistance/snap
3229 const int snap_offset = screen->getSnapOffset();
3231 // find the geomeetery where the moving window currently is
3232 const Rect &moving = screen->doOpaqueMove() ? frame.rect : frame.changing;
3235 const int wleft = dx,
3236 wright = dx + frame.rect.width() - 1,
3238 wbottom = dy + frame.rect.height() - 1;
3240 if (snap_to_windows) {
3243 Workspace *w = screen->getWorkspace(getWorkspaceNumber());
3246 // add windows on the workspace to the rect list
3247 const BlackboxWindowList& stack_list = w->getStackingList();
3248 BlackboxWindowList::const_iterator st_it, st_end = stack_list.end();
3249 for (st_it = stack_list.begin(); st_it != st_end; ++st_it)
3250 if (*st_it != this) // don't snap to ourself
3251 rectlist.push_back( (*st_it)->frameRect() );
3253 // add the toolbar and the slit to the rect list.
3254 // (only if they are not hidden)
3255 Toolbar *tbar = screen->getToolbar();
3256 Slit *slit = screen->getSlit();
3257 Rect tbar_rect, slit_rect;
3258 unsigned int bwidth = screen->getBorderWidth() * 2;
3260 if (! (screen->doHideToolbar() || tbar->isHidden())) {
3261 tbar_rect.setRect(tbar->getX(), tbar->getY(), tbar->getWidth() + bwidth,
3262 tbar->getHeight() + bwidth);
3263 rectlist.push_back(tbar_rect);
3266 if (! slit->isHidden()) {
3267 slit_rect.setRect(slit->getX(), slit->getY(), slit->getWidth() + bwidth,
3268 slit->getHeight() + bwidth);
3269 rectlist.push_back(slit_rect);
3272 RectList::const_iterator it, end = rectlist.end();
3273 for (it = rectlist.begin(); it != end; ++it) {
3274 bool snapped = False;
3275 const Rect &winrect = *it;
3277 offsetrect.setCoords(winrect.left() - snap_offset,
3278 winrect.top() - snap_offset,
3279 winrect.right() + snap_offset,
3280 winrect.bottom() + snap_offset);
3282 if (snap_to_windows == BScreen::WindowResistance)
3283 // if the window is already over top of this snap target, then
3284 // resistance is futile, so just ignore it
3285 if (winrect.intersects(moving))
3288 int dleft, dright, dtop, dbottom;
3290 // if the windows are in the same plane vertically
3291 if (wtop >= (signed)(winrect.y() - frame.rect.height() + 1) &&
3292 wtop < (signed)(winrect.y() + winrect.height() - 1)) {
3294 if (snap_to_windows == BScreen::WindowResistance) {
3295 dleft = wright - offsetrect.left();
3296 dright = offsetrect.right() - wleft;
3298 // snap left of other window?
3299 if (dleft >= 0 && dleft < resistance_size &&
3300 dleft < (wright - wleft)) {
3301 dx = offsetrect.left() - frame.rect.width();
3304 // snap right of other window?
3305 else if (dright >= 0 && dright < resistance_size &&
3306 dright < (wright - wleft)) {
3307 dx = offsetrect.right() + 1;
3310 } else { // BScreen::WindowSnap
3311 dleft = abs(wright - offsetrect.left());
3312 dright = abs(wleft - offsetrect.right());
3314 // snap left of other window?
3315 if (dleft < snap_distance && dleft <= dright) {
3316 dx = offsetrect.left() - frame.rect.width();
3319 // snap right of other window?
3320 else if (dright < snap_distance) {
3321 dx = offsetrect.right() + 1;
3327 if (screen->getWindowCornerSnap()) {
3328 // try corner-snap to its other sides
3329 if (snap_to_windows == BScreen::WindowResistance) {
3330 dtop = winrect.top() - wtop;
3331 dbottom = wbottom - winrect.bottom();
3332 if (dtop > 0 && dtop < resistance_size) {
3333 // if we're already past the top edge, then don't provide
3335 if (moving.top() >= winrect.top())
3337 } else if (dbottom > 0 && dbottom < resistance_size) {
3338 // if we're already past the bottom edge, then don't provide
3340 if (moving.bottom() <= winrect.bottom())
3341 dy = winrect.bottom() - frame.rect.height() + 1;
3343 } else { // BScreen::WindowSnap
3344 dtop = abs(wtop - winrect.top());
3345 dbottom = abs(wbottom - winrect.bottom());
3346 if (dtop < snap_distance && dtop <= dbottom)
3348 else if (dbottom < snap_distance)
3349 dy = winrect.bottom() - frame.rect.height() + 1;
3357 // if the windows are on the same plane horizontally
3358 if (wleft >= (signed)(winrect.x() - frame.rect.width() + 1) &&
3359 wleft < (signed)(winrect.x() + winrect.width() - 1)) {
3361 if (snap_to_windows == BScreen::WindowResistance) {
3362 dtop = wbottom - offsetrect.top();
3363 dbottom = offsetrect.bottom() - wtop;
3365 // snap top of other window?
3366 if (dtop >= 0 && dtop < resistance_size && dtop < (wbottom - wtop)) {
3367 dy = offsetrect.top() - frame.rect.height();
3370 // snap bottom of other window?
3371 else if (dbottom >= 0 && dbottom < resistance_size &&
3372 dbottom < (wbottom - wtop)) {
3373 dy = offsetrect.bottom() + 1;
3376 } else { // BScreen::WindowSnap
3377 dtop = abs(wbottom - offsetrect.top());
3378 dbottom = abs(wtop - offsetrect.bottom());
3380 // snap top of other window?
3381 if (dtop < snap_distance && dtop <= dbottom) {
3382 dy = offsetrect.top() - frame.rect.height();
3385 // snap bottom of other window?
3386 else if (dbottom < snap_distance) {
3387 dy = offsetrect.bottom() + 1;
3394 if (screen->getWindowCornerSnap()) {
3395 // try corner-snap to its other sides
3396 if (snap_to_windows == BScreen::WindowResistance) {
3397 dleft = winrect.left() - wleft;
3398 dright = wright - winrect.right();
3399 if (dleft > 0 && dleft < resistance_size) {
3400 // if we're already past the left edge, then don't provide
3402 if (moving.left() >= winrect.left())
3403 dx = winrect.left();
3404 } else if (dright > 0 && dright < resistance_size) {
3405 // if we're already past the right edge, then don't provide
3407 if (moving.right() <= winrect.right())
3408 dx = winrect.right() - frame.rect.width() + 1;
3410 } else { // BScreen::WindowSnap
3411 dleft = abs(wleft - winrect.left());
3412 dright = abs(wright - winrect.right());
3413 if (dleft < snap_distance && dleft <= dright)
3414 dx = winrect.left();
3415 else if (dright < snap_distance)
3416 dx = winrect.right() - frame.rect.width() + 1;
3426 if (snap_to_edges) {
3429 // snap to the screen edges (and screen boundaries for xinerama)
3431 if (screen->isXineramaActive() && blackbox->doXineramaSnapping()) {
3432 rectlist.insert(rectlist.begin(),
3433 screen->getXineramaAreas().begin(),
3434 screen->getXineramaAreas().end());
3437 rectlist.push_back(screen->getRect());
3439 RectList::const_iterator it, end = rectlist.end();
3440 for (it = rectlist.begin(); it != end; ++it) {
3441 const Rect &srect = *it;
3443 offsetrect.setCoords(srect.left() + snap_offset,
3444 srect.top() + snap_offset,
3445 srect.right() - snap_offset,
3446 srect.bottom() - snap_offset);
3448 if (snap_to_edges == BScreen::WindowResistance) {
3449 // if we're not in the rectangle then don't snap to it.
3450 if (! srect.contains(moving))
3452 } else { // BScreen::WindowSnap
3453 // if we're not in the rectangle then don't snap to it.
3454 if (! srect.intersects(Rect(wleft, wtop, frame.rect.width(),
3455 frame.rect.height())))
3459 if (snap_to_edges == BScreen::WindowResistance) {
3460 int dleft = offsetrect.left() - wleft,
3461 dright = wright - offsetrect.right(),
3462 dtop = offsetrect.top() - wtop,
3463 dbottom = wbottom - offsetrect.bottom();
3466 if (dleft > 0 && dleft < resistance_size)
3467 dx = offsetrect.left();
3469 else if (dright > 0 && dright < resistance_size)
3470 dx = offsetrect.right() - frame.rect.width() + 1;
3473 if (dtop > 0 && dtop < resistance_size)
3474 dy = offsetrect.top();
3476 else if (dbottom > 0 && dbottom < resistance_size)
3477 dy = offsetrect.bottom() - frame.rect.height() + 1;
3478 } else { // BScreen::WindowSnap
3479 int dleft = abs(wleft - offsetrect.left()),
3480 dright = abs(wright - offsetrect.right()),
3481 dtop = abs(wtop - offsetrect.top()),
3482 dbottom = abs(wbottom - offsetrect.bottom());
3485 if (dleft < snap_distance && dleft <= dright)
3486 dx = offsetrect.left();
3488 else if (dright < snap_distance)
3489 dx = offsetrect.right() - frame.rect.width() + 1;
3492 if (dtop < snap_distance && dtop <= dbottom)
3493 dy = offsetrect.top();
3495 else if (dbottom < snap_distance)
3496 dy = offsetrect.bottom() - frame.rect.height() + 1;
3503 void BlackboxWindow::endMove(void) {
3504 assert(flags.moving);
3505 assert(blackbox->getChangingWindow() == this);
3507 flags.moving = False;
3508 blackbox->setChangingWindow(0);
3510 if (! screen->doOpaqueMove()) {
3511 /* when drawing the rubber band, we need to make sure we only draw inside
3512 * the frame... frame.changing_* contain the new coords for the window,
3513 * so we need to subtract 1 from changing_w/changing_h every where we
3514 * draw the rubber band (for both moving and resizing)
3516 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3517 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3518 frame.changing.width() - 1, frame.changing.height() - 1);
3519 XUngrabServer(blackbox->getXDisplay());
3521 configure(frame.changing.x(), frame.changing.y(),
3522 frame.changing.width(), frame.changing.height());
3524 configure(frame.rect.x(), frame.rect.y(),
3525 frame.rect.width(), frame.rect.height());
3527 screen->hideGeometry();
3529 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3531 // if there are any left over motions from the move, drop them now
3532 XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
3534 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
3539 void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) {
3540 if (! (functions & Func_Resize)) return;
3542 assert(! (flags.resizing || flags.moving));
3545 Only one window can be moved/resized at a time. If another window is
3546 already being moved or resized, then stop it before whating to work with
3549 BlackboxWindow *changing = blackbox->getChangingWindow();
3550 if (changing && changing != this) {
3551 if (changing->flags.moving)
3552 changing->endMove();
3553 else // if (changing->flags.resizing)
3554 changing->endResize();
3562 switch (resize_dir) {
3565 cursor = blackbox->getLowerLeftAngleCursor();
3570 cursor = blackbox->getLowerRightAngleCursor();
3574 anchor = BottomRight;
3575 cursor = blackbox->getUpperLeftAngleCursor();
3579 anchor = BottomLeft;
3580 cursor = blackbox->getUpperRightAngleCursor();
3584 assert(false); // unhandled Corner
3585 return; // unreachable, for the compiler
3588 XGrabServer(blackbox->getXDisplay());
3589 XGrabPointer(blackbox->getXDisplay(), frame.window, False,
3590 PointerMotionMask | ButtonReleaseMask,
3591 GrabModeAsync, GrabModeAsync, None, cursor, CurrentTime);
3593 flags.resizing = True;
3594 blackbox->setChangingWindow(this);
3596 unsigned int gw, gh;
3597 frame.changing = frame.rect;
3599 constrain(anchor, &gw, &gh);
3601 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3602 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3603 frame.changing.width() - 1, frame.changing.height() - 1);
3605 screen->showGeometry(gw, gh);
3607 frame.grab_x = x_root;
3608 frame.grab_y = y_root;
3612 void BlackboxWindow::doResize(int x_root, int y_root) {
3613 assert(flags.resizing);
3614 assert(blackbox->getChangingWindow() == this);
3616 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3617 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3618 frame.changing.width() - 1, frame.changing.height() - 1);
3620 unsigned int gw, gh;
3623 switch (resize_dir) {
3626 frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
3627 frame.rect.height() + (y_root - frame.grab_y));
3631 frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
3632 frame.rect.height() + (y_root - frame.grab_y));
3635 anchor = BottomRight;
3636 frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x),
3637 frame.rect.height() - (y_root - frame.grab_y));
3640 anchor = BottomLeft;
3641 frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x),
3642 frame.rect.height() - (y_root - frame.grab_y));
3646 assert(false); // unhandled Corner
3647 return; // unreachable, for the compiler
3650 constrain(anchor, &gw, &gh);
3652 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3653 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3654 frame.changing.width() - 1, frame.changing.height() - 1);
3656 screen->showGeometry(gw, gh);
3660 void BlackboxWindow::endResize(void) {
3661 assert(flags.resizing);
3662 assert(blackbox->getChangingWindow() == this);
3664 XDrawRectangle(blackbox->getXDisplay(), screen->getRootWindow(),
3665 screen->getOpGC(), frame.changing.x(), frame.changing.y(),
3666 frame.changing.width() - 1, frame.changing.height() - 1);
3667 XUngrabServer(blackbox->getXDisplay());
3669 // unset maximized state after resized when fully maximized
3670 if (flags.maximized == 1)
3673 flags.resizing = False;
3674 blackbox->setChangingWindow(0);
3676 configure(frame.changing.x(), frame.changing.y(),
3677 frame.changing.width(), frame.changing.height());
3678 screen->hideGeometry();
3680 XUngrabPointer(blackbox->getXDisplay(), CurrentTime);
3682 // if there are any left over motions from the resize, drop them now
3683 XSync(blackbox->getXDisplay(), false); // make sure we don't miss any
3685 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), frame.window,
3690 void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
3692 fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3697 doMove(me->x_root, me->y_root);
3698 } else if (flags.resizing) {
3699 doResize(me->x_root, me->y_root);
3701 if ((functions & Func_Move) &&
3702 (me->state & Button1Mask) &&
3703 (frame.title == me->window || frame.label == me->window ||
3704 frame.handle == me->window || frame.window == me->window)) {
3705 beginMove(me->x_root, me->y_root);
3706 } else if ((functions & Func_Resize) &&
3707 ((me->state & Button1Mask) && (me->window == frame.right_grip ||
3708 me->window == frame.left_grip)) ||
3709 ((me->state & Button3Mask) && (me->state & mod_mask) &&
3710 (frame.title == me->window || frame.label == me->window ||
3711 frame.handle == me->window || frame.window == me->window))) {
3712 unsigned int zones = screen->getResizeZones();
3715 if (me->window == frame.left_grip) {
3716 corner = BottomLeft;
3717 } else if (me->window == frame.right_grip || zones == 1) {
3718 corner = BottomRight;
3721 bool left = (me->x_root - frame.rect.x() <=
3722 static_cast<signed>(frame.rect.width() / 2));
3725 else // (zones == 4)
3726 top = (me->y_root - frame.rect.y() <=
3727 static_cast<signed>(frame.rect.height() / 2));
3728 corner = (top ? (left ? TopLeft : TopRight) :
3729 (left ? BottomLeft : BottomRight));
3732 beginResize(me->x_root, me->y_root, corner);
3738 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent* ce) {
3739 if (! (screen->isSloppyFocus() && isVisible() && isNormal()))
3743 bool leave = False, inferior = False;
3745 while (XCheckTypedWindowEvent(blackbox->getXDisplay(), ce->window,
3747 if (e.type == LeaveNotify && e.xcrossing.mode == NotifyNormal) {
3749 inferior = (e.xcrossing.detail == NotifyInferior);
3753 if (! leave || inferior) {
3754 if (! isFocused()) {
3755 bool success = setInputFocus();
3756 if (success) // if focus succeeded install the colormap
3757 installColormap(True); // XXX: shouldnt we honour no install?
3760 if (screen->doAutoRaise())
3766 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent*) {
3767 if (! (screen->isSloppyFocus() && screen->doAutoRaise() && isNormal()))
3770 installColormap(False);
3772 if (timer->isTiming())
3778 void BlackboxWindow::shapeEvent(XShapeEvent *) {
3779 if (blackbox->hasShapeExtensions() && flags.shaped) {
3786 bool BlackboxWindow::validateClient(void) const {
3787 XSync(blackbox->getXDisplay(), False);
3790 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3791 DestroyNotify, &e) ||
3792 XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3794 XPutBackEvent(blackbox->getXDisplay(), &e);
3803 void BlackboxWindow::restore(bool remap) {
3804 XChangeSaveSet(blackbox->getXDisplay(), client.window, SetModeDelete);
3805 XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
3806 XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask);
3808 // do not leave a shaded window as an icon unless it was an icon
3809 if (flags.shaded && ! flags.iconic)
3810 setState(NormalState);
3812 // erase the netwm stuff that we read when a window maps, so that it
3813 // doesn't persist between mappings.
3814 // (these are the ones read in getNetWMFlags().)
3815 xatom->eraseValue(client.window, XAtom::net_wm_desktop);
3816 xatom->eraseValue(client.window, XAtom::net_wm_state);
3818 restoreGravity(client.rect);
3820 XUnmapWindow(blackbox->getXDisplay(), frame.window);
3821 XUnmapWindow(blackbox->getXDisplay(), client.window);
3823 XSetWindowBorderWidth(blackbox->getXDisplay(), client.window, client.old_bw);
3826 if (XCheckTypedWindowEvent(blackbox->getXDisplay(), client.window,
3827 ReparentNotify, &ev)) {
3830 // according to the ICCCM - if the client doesn't reparent to
3831 // root, then we have to do it for them
3832 XReparentWindow(blackbox->getXDisplay(), client.window,
3833 screen->getRootWindow(),
3834 client.rect.x(), client.rect.y());
3837 if (remap) XMapWindow(blackbox->getXDisplay(), client.window);
3841 // timer for autoraise
3842 void BlackboxWindow::timeout(void) {
3843 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3847 void BlackboxWindow::changeBlackboxHints(const BlackboxHints *net) {
3848 if ((net->flags & AttribShaded) &&
3849 ((blackbox_attrib.attrib & AttribShaded) !=
3850 (net->attrib & AttribShaded)))
3853 if (flags.visible && // watch out for requests when we can not be seen
3854 (net->flags & (AttribMaxVert | AttribMaxHoriz)) &&
3855 ((blackbox_attrib.attrib & (AttribMaxVert | AttribMaxHoriz)) !=
3856 (net->attrib & (AttribMaxVert | AttribMaxHoriz)))) {
3857 if (flags.maximized) {
3862 if ((net->flags & AttribMaxHoriz) && (net->flags & AttribMaxVert))
3863 button = ((net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0);
3864 else if (net->flags & AttribMaxVert)
3865 button = ((net->attrib & AttribMaxVert) ? 2 : 0);
3866 else if (net->flags & AttribMaxHoriz)
3867 button = ((net->attrib & AttribMaxHoriz) ? 3 : 0);
3873 if ((net->flags & AttribOmnipresent) &&
3874 ((blackbox_attrib.attrib & AttribOmnipresent) !=
3875 (net->attrib & AttribOmnipresent)))
3878 if ((net->flags & AttribWorkspace) &&
3879 (blackbox_attrib.workspace != net->workspace)) {
3880 screen->reassociateWindow(this, net->workspace, True);
3882 if (screen->getCurrentWorkspaceID() != net->workspace) {
3886 screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this);
3890 if (net->flags & AttribDecoration) {
3891 switch (net->decoration) {
3908 * Set the sizes of all components of the window frame
3909 * (the window decorations).
3910 * These values are based upon the current style settings and the client
3911 * window's dimensions.
3913 void BlackboxWindow::upsize(void) {
3914 frame.bevel_w = screen->getBevelWidth();
3916 if (decorations & Decor_Border) {
3917 frame.border_w = screen->getBorderWidth();
3918 if (! isTransient())
3919 frame.mwm_border_w = screen->getFrameWidth();
3921 frame.mwm_border_w = 0;
3923 frame.mwm_border_w = frame.border_w = 0;
3926 if (decorations & Decor_Titlebar) {
3927 // the height of the titlebar is based upon the height of the font being
3928 // used to display the window's title
3929 WindowStyle *style = screen->getWindowStyle();
3930 frame.title_h = style->font->height() + (frame.bevel_w * 2) + 2;
3932 frame.label_h = frame.title_h - (frame.bevel_w * 2);
3933 frame.button_w = (frame.label_h - 2);
3935 // set the top frame margin
3936 frame.margin.top = frame.border_w + frame.title_h +
3937 frame.border_w + frame.mwm_border_w;
3943 // set the top frame margin
3944 frame.margin.top = frame.border_w + frame.mwm_border_w;
3947 // set the left/right frame margin
3948 frame.margin.left = frame.margin.right = frame.border_w + frame.mwm_border_w;
3950 if (decorations & Decor_Handle) {
3951 frame.grip_w = frame.button_w * 2;
3952 frame.handle_h = screen->getHandleWidth();
3954 // set the bottom frame margin
3955 frame.margin.bottom = frame.border_w + frame.handle_h +
3956 frame.border_w + frame.mwm_border_w;
3961 // set the bottom frame margin
3962 frame.margin.bottom = frame.border_w + frame.mwm_border_w;
3966 We first get the normal dimensions and use this to define the inside_w/h
3967 then we modify the height if shading is in effect.
3968 If the shade state is not considered then frame.rect gets reset to the
3969 normal window size on a reconfigure() call resulting in improper
3970 dimensions appearing in move/resize and other events.
3973 height = client.rect.height() + frame.margin.top + frame.margin.bottom,
3974 width = client.rect.width() + frame.margin.left + frame.margin.right;
3976 frame.inside_w = width - (frame.border_w * 2);
3977 frame.inside_h = height - (frame.border_w * 2);
3980 height = frame.title_h + (frame.border_w * 2);
3981 frame.rect.setSize(width, height);
3986 * Calculate the size of the client window and constrain it to the
3987 * size specified by the size hints of the client window.
3989 * The logical width and height are placed into pw and ph, if they
3990 * are non-zero. Logical size refers to the users perception of
3991 * the window size (for example an xterm resizes in cells, not in pixels).
3992 * pw and ph are then used to display the geometry during window moves, resize,
3995 * The physical geometry is placed into frame.changing_{x,y,width,height}.
3996 * Physical geometry refers to the geometry of the window in pixels.
3998 void BlackboxWindow::constrain(Corner anchor,
3999 unsigned int *pw, unsigned int *ph) {
4000 // frame.changing represents the requested frame size, we need to
4001 // strip the frame margin off and constrain the client size
4002 frame.changing.setCoords(frame.changing.left() + frame.margin.left,
4003 frame.changing.top() + frame.margin.top,
4004 frame.changing.right() - frame.margin.right,
4005 frame.changing.bottom() - frame.margin.bottom);
4007 unsigned int dw = frame.changing.width(), dh = frame.changing.height(),
4008 base_width = (client.base_width) ? client.base_width : client.min_width,
4009 base_height = (client.base_height) ? client.base_height :
4013 if (dw < client.min_width) dw = client.min_width;
4014 if (dh < client.min_height) dh = client.min_height;
4015 if (dw > client.max_width) dw = client.max_width;
4016 if (dh > client.max_height) dh = client.max_height;
4018 assert(dw >= base_width && dh >= base_height);
4020 if (client.width_inc > 1) {
4022 dw /= client.width_inc;
4024 if (client.height_inc > 1) {
4026 dh /= client.height_inc;
4035 if (client.width_inc > 1) {
4036 dw *= client.width_inc;
4039 if (client.height_inc > 1) {
4040 dh *= client.height_inc;
4044 frame.changing.setSize(dw, dh);
4046 // add the frame margin back onto frame.changing
4047 frame.changing.setCoords(frame.changing.left() - frame.margin.left,
4048 frame.changing.top() - frame.margin.top,
4049 frame.changing.right() + frame.margin.right,
4050 frame.changing.bottom() + frame.margin.bottom);
4052 // move frame.changing to the specified anchor
4060 dx = frame.rect.right() - frame.changing.right();
4064 dy = frame.rect.bottom() - frame.changing.bottom();
4068 dx = frame.rect.right() - frame.changing.right();
4069 dy = frame.rect.bottom() - frame.changing.bottom();
4073 assert(false); // unhandled corner
4075 frame.changing.setPos(frame.changing.x() + dx, frame.changing.y() + dy);
4079 void WindowStyle::doJustify(const std::string &text, int &start_pos,
4080 unsigned int max_length,
4081 unsigned int modifier) const {
4082 size_t text_len = text.size();
4083 unsigned int length;
4086 length = font->measureString(string(text, 0, text_len)) + modifier;
4087 } while (length > max_length && text_len-- > 0);
4091 start_pos += max_length - length;
4095 start_pos += (max_length - length) / 2;
4105 BWindowGroup::BWindowGroup(Blackbox *b, Window _group)
4106 : blackbox(b), group(_group) {
4107 XWindowAttributes wattrib;
4108 if (! XGetWindowAttributes(blackbox->getXDisplay(), group, &wattrib)) {
4109 // group window doesn't seem to exist anymore
4114 XSelectInput(blackbox->getXDisplay(), group,
4115 PropertyChangeMask | FocusChangeMask | StructureNotifyMask);
4117 blackbox->saveGroupSearch(group, this);
4121 BWindowGroup::~BWindowGroup(void) {
4122 blackbox->removeGroupSearch(group);
4127 BWindowGroup::find(BScreen *screen, bool allow_transients) const {
4128 BlackboxWindow *ret = blackbox->getFocusedWindow();
4130 // does the focus window match (or any transient_fors)?
4131 for (; ret; ret = ret->getTransientFor()) {
4132 if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
4133 (! ret->isTransient() || allow_transients))
4137 if (ret) return ret;
4139 // the focus window didn't match, look in the group's window list
4140 BlackboxWindowList::const_iterator it, end = windowList.end();
4141 for (it = windowList.begin(); it != end; ++it) {
4143 if (ret->getScreen() == screen && ret->getGroupWindow() == group &&
4144 (! ret->isTransient() || allow_transients))