1 // Window.cc for Openbox
2 // Copyright (c) 2002 - 2002 Ben Jansens (ben at orodu.net)
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry (shaleh at debian.org)
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes at tcac.net)
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.
24 // stupid macros needed to access some functions in version 2 of the GNU C
31 # include "../config.h"
32 #endif // HAVE_CONFIG_H
34 #include <X11/Xatom.h>
35 #include <X11/keysym.h>
39 #endif // HAVE_STRING_H
44 # endif // HAVE_STDIO_H
53 #include "Windowmenu.h"
54 #include "Workspace.h"
61 * Initializes the class with default values/the window's set initial values.
63 OpenboxWindow::OpenboxWindow(Openbox &o, Window w, BScreen *s) : openbox(o) {
65 fprintf(stderr, i18n(WindowSet, WindowCreating,
66 "OpenboxWindow::OpenboxWindow(): creating 0x%lx\n"),
71 display = openbox.getXDisplay();
74 if (! validateClient()) return;
76 // fetch client size and placement
77 XWindowAttributes wattrib;
78 if ((! XGetWindowAttributes(display, client.window, &wattrib)) ||
79 (! wattrib.screen) || wattrib.override_redirect) {
82 i18n(WindowSet, WindowXGetWindowAttributesFail,
83 "OpenboxWindow::OpenboxWindow(): XGetWindowAttributes "
94 screen = openbox.searchScreen(RootWindowOfScreen(wattrib.screen));
97 fprintf(stderr, i18n(WindowSet, WindowCannotFindScreen,
98 "OpenboxWindow::OpenboxWindow(): can't find screen\n"
99 "\tfor root window 0x%lx\n"),
100 RootWindowOfScreen(wattrib.screen));
108 flags.moving = flags.resizing = flags.shaded = flags.visible =
109 flags.iconic = flags.transient = flags.focused =
110 flags.stuck = flags.modal = flags.send_focus_message =
111 flags.shaped = flags.managed = False;
114 openbox_attrib.workspace = workspace_number = window_number = -1;
116 openbox_attrib.flags = openbox_attrib.attrib = openbox_attrib.stack
117 = openbox_attrib.decoration = 0l;
118 openbox_attrib.premax_x = openbox_attrib.premax_y = 0;
119 openbox_attrib.premax_w = openbox_attrib.premax_h = 0;
121 frame.window = frame.plate = frame.title = frame.handle = None;
122 frame.close_button = frame.iconify_button = frame.maximize_button = None;
123 frame.right_grip = frame.left_grip = None;
125 frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None;
126 frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None;
127 frame.pbutton = frame.ugrip = frame.fgrip = None;
129 decorations.titlebar = decorations.border = decorations.handle = True;
130 decorations.iconify = decorations.maximize = decorations.menu = True;
131 functions.resize = functions.move = functions.iconify =
132 functions.maximize = True;
133 functions.close = decorations.close = False;
135 client.wm_hint_flags = client.normal_hint_flags = 0;
136 client.transient_for = client.transient = 0;
138 client.title_len = 0;
139 client.icon_title = 0;
140 client.mwm_hint = (MwmHints *) 0;
141 client.openbox_hint = (OpenboxHints *) 0;
143 // get the initial size and location of client window (relative to the
144 // _root window_). This position is the reference point used with the
145 // window's gravity to find the window's initial position.
146 client.x = wattrib.x;
147 client.y = wattrib.y;
148 client.width = wattrib.width;
149 client.height = wattrib.height;
150 client.old_bw = wattrib.border_width;
153 lastButtonPressTime = 0;
154 image_ctrl = screen->getImageControl();
156 timer = new BTimer(openbox, *this);
157 timer->setTimeout(openbox.getAutoRaiseDelay());
158 timer->fireOnce(True);
161 if (! client.openbox_hint)
164 // get size, aspect, minimum/maximum size and other hints set by the
171 if (client.initial_state == WithdrawnState) {
172 screen->getSlit()->addClient(client.window);
179 flags.managed = True;
180 openbox.saveWindowSearch(client.window, this);
182 // determine if this is a transient window
184 if (XGetTransientForHint(display, client.window, &win)) {
185 if (win && (win != client.window)) {
187 if ((tr = openbox.searchWindow(win))) {
188 while (tr->client.transient) tr = tr->client.transient;
189 client.transient_for = tr;
190 tr->client.transient = this;
191 flags.stuck = client.transient_for->flags.stuck;
192 flags.transient = True;
193 } else if (win == client.window_group) {
194 if ((tr = openbox.searchGroup(win, this))) {
195 while (tr->client.transient) tr = tr->client.transient;
196 client.transient_for = tr;
197 tr->client.transient = this;
198 flags.stuck = client.transient_for->flags.stuck;
199 flags.transient = True;
204 if (win == screen->getRootWindow()) flags.modal = True;
207 // adjust the window decorations based on transience and window sizes
209 decorations.maximize = decorations.handle = functions.maximize = False;
211 if ((client.normal_hint_flags & PMinSize) &&
212 (client.normal_hint_flags & PMaxSize) &&
213 client.max_width <= client.min_width &&
214 client.max_height <= client.min_height) {
215 decorations.maximize = decorations.handle =
216 functions.resize = functions.maximize = False;
221 if (openbox.isStartup() || flags.transient ||
222 client.normal_hint_flags & (PPosition|USPosition)) {
225 if ((openbox.isStartup()) ||
227 (signed) (frame.y + frame.y_border) >= 0 &&
228 frame.x <= (signed) screen->size().w() &&
229 frame.y <= (signed) screen->size().h()))
230 place_window = false;
233 frame.window = createToplevelWindow(frame.x, frame.y, frame.width,
236 openbox.saveWindowSearch(frame.window, this);
238 frame.plate = createChildWindow(frame.window);
239 openbox.saveWindowSearch(frame.plate, this);
241 if (decorations.titlebar) {
242 frame.title = createChildWindow(frame.window);
243 frame.label = createChildWindow(frame.title);
244 openbox.saveWindowSearch(frame.title, this);
245 openbox.saveWindowSearch(frame.label, this);
248 if (decorations.handle) {
249 frame.handle = createChildWindow(frame.window);
250 openbox.saveWindowSearch(frame.handle, this);
253 createChildWindow(frame.handle, openbox.getLowerLeftAngleCursor());
254 openbox.saveWindowSearch(frame.left_grip, this);
257 createChildWindow(frame.handle, openbox.getLowerRightAngleCursor());
258 openbox.saveWindowSearch(frame.right_grip, this);
261 associateClientWindow();
263 if (! screen->sloppyFocus())
264 openbox.grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
265 GrabModeSync, GrabModeSync, frame.plate, None);
267 openbox.grabButton(Button1, Mod1Mask, frame.window, True,
268 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
269 GrabModeAsync, frame.window, openbox.getMoveCursor());
270 openbox.grabButton(Button2, Mod1Mask, frame.window, True,
271 ButtonReleaseMask, GrabModeAsync, GrabModeAsync, frame.window, None);
272 openbox.grabButton(Button3, Mod1Mask, frame.window, True,
273 ButtonReleaseMask | ButtonMotionMask, GrabModeAsync,
274 GrabModeAsync, frame.window, None);
277 XRaiseWindow(display, frame.plate);
278 XMapSubwindows(display, frame.plate);
279 if (decorations.titlebar) XMapSubwindows(display, frame.title);
280 XMapSubwindows(display, frame.window);
282 if (decorations.menu)
283 windowmenu = new Windowmenu(*this);
287 if (workspace_number < 0 || workspace_number >= screen->getWorkspaceCount())
288 screen->getCurrentWorkspace()->addWindow(this, place_window);
290 screen->getWorkspace(workspace_number)->addWindow(this, place_window);
292 configure(frame.x, frame.y, frame.width, frame.height);
295 flags.shaded = False;
299 if (flags.maximized && functions.maximize) {
300 unsigned int button = flags.maximized;
311 OpenboxWindow::~OpenboxWindow(void) {
312 if (flags.moving || flags.resizing) {
313 screen->hideGeometry();
314 XUngrabPointer(display, CurrentTime);
317 if (workspace_number != -1 && window_number != -1) {
319 // make sure no other workspaces think that we're focused
320 for (int i=0; i < screen->getWorkspaceCount(); i++)
321 screen->getWorkspace(i)->removeWindow(this);
323 screen->getWorkspace(workspace_number)->removeWindow(this);
324 } else if (flags.iconic)
325 screen->removeIcon(this);
328 if (timer->isTiming()) timer->stop();
332 if (windowmenu) delete windowmenu;
335 delete [] client.title;
337 if (client.icon_title)
338 delete [] client.icon_title;
341 XFree(client.mwm_hint);
343 if (client.openbox_hint)
344 XFree(client.openbox_hint);
346 if (client.window_group)
347 openbox.removeGroupSearch(client.window_group);
349 if (flags.transient && client.transient_for)
350 client.transient_for->client.transient = client.transient;
351 if (client.transient)
352 client.transient->client.transient_for = client.transient_for;
354 if (frame.close_button) {
355 openbox.removeWindowSearch(frame.close_button);
356 XDestroyWindow(display, frame.close_button);
359 if (frame.iconify_button) {
360 openbox.removeWindowSearch(frame.iconify_button);
361 XDestroyWindow(display, frame.iconify_button);
364 if (frame.maximize_button) {
365 openbox.removeWindowSearch(frame.maximize_button);
366 XDestroyWindow(display, frame.maximize_button);
371 image_ctrl->removeImage(frame.ftitle);
374 image_ctrl->removeImage(frame.utitle);
377 image_ctrl->removeImage(frame.flabel);
380 image_ctrl->removeImage(frame.ulabel);
382 openbox.removeWindowSearch(frame.label);
383 openbox.removeWindowSearch(frame.title);
384 XDestroyWindow(display, frame.label);
385 XDestroyWindow(display, frame.title);
390 image_ctrl->removeImage(frame.fhandle);
393 image_ctrl->removeImage(frame.uhandle);
396 image_ctrl->removeImage(frame.fgrip);
399 image_ctrl->removeImage(frame.ugrip);
401 openbox.removeWindowSearch(frame.handle);
402 openbox.removeWindowSearch(frame.right_grip);
403 openbox.removeWindowSearch(frame.left_grip);
404 XDestroyWindow(display, frame.right_grip);
405 XDestroyWindow(display, frame.left_grip);
406 XDestroyWindow(display, frame.handle);
410 image_ctrl->removeImage(frame.fbutton);
413 image_ctrl->removeImage(frame.ubutton);
416 image_ctrl->removeImage(frame.pbutton);
419 openbox.removeWindowSearch(frame.plate);
420 XDestroyWindow(display, frame.plate);
424 openbox.removeWindowSearch(frame.window);
425 XDestroyWindow(display, frame.window);
429 openbox.removeWindowSearch(client.window);
430 screen->removeNetizen(client.window);
436 * Creates a new top level window, with a given location, size, and border
438 * Returns: the newly created window
440 Window OpenboxWindow::createToplevelWindow(int x, int y, unsigned int width,
442 unsigned int borderwidth)
444 XSetWindowAttributes attrib_create;
445 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap |
446 CWOverrideRedirect | CWEventMask;
448 attrib_create.background_pixmap = None;
449 attrib_create.colormap = screen->getColormap();
450 attrib_create.override_redirect = True;
451 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
452 ButtonMotionMask | EnterWindowMask;
454 return XCreateWindow(display, screen->getRootWindow(), x, y, width, height,
455 borderwidth, screen->getDepth(), InputOutput,
456 screen->getVisual(), create_mask,
462 * Creates a child window, and optionally associates a given cursor with
465 Window OpenboxWindow::createChildWindow(Window parent, Cursor cursor) {
466 XSetWindowAttributes attrib_create;
467 unsigned long create_mask = CWBackPixmap | CWBorderPixel |
470 attrib_create.background_pixmap = None;
471 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
472 ButtonMotionMask | ExposureMask |
473 EnterWindowMask | LeaveWindowMask;
476 create_mask |= CWCursor;
477 attrib_create.cursor = cursor;
480 return XCreateWindow(display, parent, 0, 0, 1, 1, 0, screen->getDepth(),
481 InputOutput, screen->getVisual(), create_mask,
486 void OpenboxWindow::associateClientWindow(void) {
487 XSetWindowBorderWidth(display, client.window, 0);
491 XChangeSaveSet(display, client.window, SetModeInsert);
492 XSetWindowAttributes attrib_set;
494 XSelectInput(display, frame.plate, NoEventMask);
495 XReparentWindow(display, client.window, frame.plate, 0, 0);
496 XSelectInput(display, frame.plate, SubstructureRedirectMask);
500 attrib_set.event_mask = PropertyChangeMask | StructureNotifyMask |
502 attrib_set.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask |
505 XChangeWindowAttributes(display, client.window, CWEventMask|CWDontPropagate,
509 if (openbox.hasShapeExtensions()) {
510 XShapeSelectInput(display, client.window, ShapeNotifyMask);
515 XShapeQueryExtents(display, client.window, &flags.shaped, &foo, &foo,
516 &ufoo, &ufoo, &foo, &foo, &foo, &ufoo, &ufoo);
519 XShapeCombineShape(display, frame.window, ShapeBounding,
520 frame.mwm_border_w, frame.y_border +
521 frame.mwm_border_w, client.window,
522 ShapeBounding, ShapeSet);
526 xrect[0].x = xrect[0].y = 0;
527 xrect[0].width = frame.width;
528 xrect[0].height = frame.y_border;
530 if (decorations.handle) {
532 xrect[1].y = frame.y_handle;
533 xrect[1].width = frame.width;
534 xrect[1].height = frame.handle_h + frame.border_w;
538 XShapeCombineRectangles(display, frame.window, ShapeBounding, 0, 0,
539 xrect, num, ShapeUnion, Unsorted);
544 if (decorations.iconify) createIconifyButton();
545 if (decorations.maximize) createMaximizeButton();
546 if (decorations.close) createCloseButton();
550 void OpenboxWindow::decorate(void) {
551 Pixmap tmp = frame.fbutton;
552 BTexture *texture = &(screen->getWindowStyle()->b_focus);
553 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
554 frame.fbutton = None;
555 frame.fbutton_pixel = texture->getColor()->getPixel();
558 image_ctrl->renderImage(frame.button_w, frame.button_h, texture);
560 if (tmp) image_ctrl->removeImage(tmp);
563 texture = &(screen->getWindowStyle()->b_unfocus);
564 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
565 frame.ubutton = None;
566 frame.ubutton_pixel = texture->getColor()->getPixel();
569 image_ctrl->renderImage(frame.button_w, frame.button_h, texture);
571 if (tmp) image_ctrl->removeImage(tmp);
574 texture = &(screen->getWindowStyle()->b_pressed);
575 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
576 frame.pbutton = None;
577 frame.pbutton_pixel = texture->getColor()->getPixel();
580 image_ctrl->renderImage(frame.button_w, frame.button_h, texture);
582 if (tmp) image_ctrl->removeImage(tmp);
584 if (decorations.titlebar) {
586 texture = &(screen->getWindowStyle()->t_focus);
587 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
589 frame.ftitle_pixel = texture->getColor()->getPixel();
592 image_ctrl->renderImage(frame.width, frame.title_h, texture);
594 if (tmp) image_ctrl->removeImage(tmp);
597 texture = &(screen->getWindowStyle()->t_unfocus);
598 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
600 frame.utitle_pixel = texture->getColor()->getPixel();
603 image_ctrl->renderImage(frame.width, frame.title_h, texture);
605 if (tmp) image_ctrl->removeImage(tmp);
607 XSetWindowBorder(display, frame.title,
608 screen->getBorderColor()->getPixel());
613 if (decorations.border) {
614 frame.fborder_pixel = screen->getWindowStyle()->f_focus.getPixel();
615 frame.uborder_pixel = screen->getWindowStyle()->f_unfocus.getPixel();
616 openbox_attrib.flags |= AttribDecoration;
617 openbox_attrib.decoration = DecorNormal;
619 openbox_attrib.flags |= AttribDecoration;
620 openbox_attrib.decoration = DecorNone;
623 if (decorations.handle) {
625 texture = &(screen->getWindowStyle()->h_focus);
626 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
627 frame.fhandle = None;
628 frame.fhandle_pixel = texture->getColor()->getPixel();
631 image_ctrl->renderImage(frame.width, frame.handle_h, texture);
633 if (tmp) image_ctrl->removeImage(tmp);
636 texture = &(screen->getWindowStyle()->h_unfocus);
637 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
638 frame.uhandle = None;
639 frame.uhandle_pixel = texture->getColor()->getPixel();
642 image_ctrl->renderImage(frame.width, frame.handle_h, texture);
644 if (tmp) image_ctrl->removeImage(tmp);
647 texture = &(screen->getWindowStyle()->g_focus);
648 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
650 frame.fgrip_pixel = texture->getColor()->getPixel();
653 image_ctrl->renderImage(frame.grip_w, frame.grip_h, texture);
655 if (tmp) image_ctrl->removeImage(tmp);
658 texture = &(screen->getWindowStyle()->g_unfocus);
659 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
661 frame.ugrip_pixel = texture->getColor()->getPixel();
664 image_ctrl->renderImage(frame.grip_w, frame.grip_h, texture);
666 if (tmp) image_ctrl->removeImage(tmp);
668 XSetWindowBorder(display, frame.handle,
669 screen->getBorderColor()->getPixel());
670 XSetWindowBorder(display, frame.left_grip,
671 screen->getBorderColor()->getPixel());
672 XSetWindowBorder(display, frame.right_grip,
673 screen->getBorderColor()->getPixel());
676 XSetWindowBorder(display, frame.window,
677 screen->getBorderColor()->getPixel());
681 void OpenboxWindow::decorateLabel(void) {
682 Pixmap tmp = frame.flabel;
683 BTexture *texture = &(screen->getWindowStyle()->l_focus);
684 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
686 frame.flabel_pixel = texture->getColor()->getPixel();
689 image_ctrl->renderImage(frame.label_w, frame.label_h, texture);
691 if (tmp) image_ctrl->removeImage(tmp);
694 texture = &(screen->getWindowStyle()->l_unfocus);
695 if (texture->getTexture() == (BImage_Flat | BImage_Solid)) {
697 frame.ulabel_pixel = texture->getColor()->getPixel();
700 image_ctrl->renderImage(frame.label_w, frame.label_h, texture);
702 if (tmp) image_ctrl->removeImage(tmp);
706 void OpenboxWindow::createCloseButton(void) {
707 if (decorations.close && frame.title != None) {
708 frame.close_button = createChildWindow(frame.title);
709 openbox.saveWindowSearch(frame.close_button, this);
714 void OpenboxWindow::createIconifyButton(void) {
715 if (decorations.iconify && frame.title != None) {
716 frame.iconify_button = createChildWindow(frame.title);
717 openbox.saveWindowSearch(frame.iconify_button, this);
722 void OpenboxWindow::createMaximizeButton(void) {
723 if (decorations.maximize && frame.title != None) {
724 frame.maximize_button = createChildWindow(frame.title);
725 openbox.saveWindowSearch(frame.maximize_button, this);
730 void OpenboxWindow::positionButtons() {
731 const char *format = openbox.getTitleBarLayout();
732 const unsigned int bw = frame.bevel_w + 1;
733 const unsigned int by = frame.bevel_w + 1;
734 unsigned int bx = frame.bevel_w + 1;
735 unsigned int bcount = strlen(format) - 1;
737 if (!decorations.close)
739 if (!decorations.maximize)
741 if (!decorations.iconify)
743 frame.label_w = frame.width - bx * 2 - (frame.button_w + bw) * bcount;
745 bool hasclose, hasiconify, hasmaximize;
746 hasclose = hasiconify = hasmaximize = false;
748 for (int i = 0; format[i] != '\0' && i < 4; i++) {
751 if (decorations.close) {
752 if (frame.close_button == None)
754 XMoveResizeWindow(display, frame.close_button, bx, by,
755 frame.button_w, frame.button_h);
756 XMapWindow(display, frame.close_button);
757 XClearWindow(display, frame.close_button);
758 bx += frame.button_w + bw;
763 if (decorations.iconify) {
764 if (frame.iconify_button == None)
765 createIconifyButton();
766 XMoveResizeWindow(display, frame.iconify_button, bx, by,
767 frame.button_w, frame.button_h);
768 XMapWindow(display, frame.iconify_button);
769 XClearWindow(display, frame.iconify_button);
770 bx += frame.button_w + bw;
775 if (decorations.maximize) {
776 if (frame.maximize_button == None)
777 createMaximizeButton();
778 XMoveResizeWindow(display, frame.maximize_button, bx, by,
779 frame.button_w, frame.button_h);
780 XMapWindow(display, frame.maximize_button);
781 XClearWindow(display, frame.maximize_button);
782 bx += frame.button_w + bw;
787 XMoveResizeWindow(display, frame.label, bx, by - 1,
788 frame.label_w, frame.label_h);
789 bx += frame.label_w + bw;
794 if (!hasclose && frame.close_button) {
795 openbox.removeWindowSearch(frame.close_button);
796 XDestroyWindow(display, frame.close_button);
797 frame.close_button = None;
799 if (!hasiconify && frame.iconify_button) {
800 openbox.removeWindowSearch(frame.iconify_button);
801 XDestroyWindow(display, frame.iconify_button);
802 frame.iconify_button = None;
804 if (!hasmaximize && frame.iconify_button) {
805 openbox.removeWindowSearch(frame.maximize_button);
806 XDestroyWindow(display, frame.maximize_button);
807 frame.maximize_button = None;
815 void OpenboxWindow::reconfigure(void) {
818 client.x = frame.x + frame.mwm_border_w + frame.border_w;
819 client.y = frame.y + frame.y_border + frame.mwm_border_w +
823 if (i18n.multibyte()) {
824 XRectangle ink, logical;
825 XmbTextExtents(screen->getWindowStyle()->fontset,
826 client.title, client.title_len, &ink, &logical);
827 client.title_text_w = logical.width;
829 client.title_text_w = XTextWidth(screen->getWindowStyle()->font,
830 client.title, client.title_len);
832 client.title_text_w += (frame.bevel_w * 4);
838 XClearWindow(display, frame.window);
839 setFocusFlag(flags.focused);
841 configure(frame.x, frame.y, frame.width, frame.height);
843 if (! screen->sloppyFocus())
844 openbox.grabButton(Button1, 0, frame.plate, True, ButtonPressMask,
845 GrabModeSync, GrabModeSync, None, None);
847 openbox.ungrabButton(Button1, 0, frame.plate);
850 windowmenu->move(windowmenu->getX(), frame.y + frame.title_h);
851 windowmenu->reconfigure();
854 // re-get the timeout delay
855 timer->setTimeout(openbox.getAutoRaiseDelay());
859 void OpenboxWindow::positionWindows(void) {
860 XResizeWindow(display, frame.window, frame.width,
861 ((flags.shaded) ? frame.title_h : frame.height));
862 XSetWindowBorderWidth(display, frame.window, frame.border_w);
863 XSetWindowBorderWidth(display, frame.plate, frame.mwm_border_w);
864 XMoveResizeWindow(display, frame.plate, 0, frame.y_border,
865 client.width, client.height);
866 XMoveResizeWindow(display, client.window, 0, 0, client.width, client.height);
868 if (decorations.titlebar) {
869 XSetWindowBorderWidth(display, frame.title, frame.border_w);
870 XMoveResizeWindow(display, frame.title, -frame.border_w,
871 -frame.border_w, frame.width, frame.title_h);
874 } else if (frame.title) {
875 XUnmapWindow(display, frame.title);
877 if (decorations.handle) {
878 XSetWindowBorderWidth(display, frame.handle, frame.border_w);
879 XSetWindowBorderWidth(display, frame.left_grip, frame.border_w);
880 XSetWindowBorderWidth(display, frame.right_grip, frame.border_w);
882 XMoveResizeWindow(display, frame.handle, -frame.border_w,
883 frame.y_handle - frame.border_w,
884 frame.width, frame.handle_h);
885 XMoveResizeWindow(display, frame.left_grip, -frame.border_w,
886 -frame.border_w, frame.grip_w, frame.grip_h);
887 XMoveResizeWindow(display, frame.right_grip,
888 frame.width - frame.grip_w - frame.border_w,
889 -frame.border_w, frame.grip_w, frame.grip_h);
890 XMapSubwindows(display, frame.handle);
891 } else if (frame.handle) {
892 XUnmapWindow(display, frame.handle);
897 void OpenboxWindow::getWMName(void) {
899 delete [] client.title;
900 client.title = (char *) 0;
903 XTextProperty text_prop;
907 if (XGetWMName(display, client.window, &text_prop)) {
908 if (text_prop.value && text_prop.nitems > 0) {
909 if (text_prop.encoding != XA_STRING) {
910 text_prop.nitems = strlen((char *) text_prop.value);
912 if ((XmbTextPropertyToTextList(display, &text_prop,
913 &list, &num) == Success) &&
914 (num > 0) && *list) {
915 client.title = bstrdup(*list);
916 XFreeStringList(list);
918 client.title = bstrdup((char *) text_prop.value);
921 client.title = bstrdup((char *) text_prop.value);
923 XFree((char *) text_prop.value);
925 client.title = bstrdup(i18n(WindowSet, WindowUnnamed,
929 client.title = bstrdup(i18n(WindowSet, WindowUnnamed,
932 client.title_len = strlen(client.title);
934 if (i18n.multibyte()) {
935 XRectangle ink, logical;
936 XmbTextExtents(screen->getWindowStyle()->fontset,
937 client.title, client.title_len, &ink, &logical);
938 client.title_text_w = logical.width;
940 client.title_len = strlen(client.title);
941 client.title_text_w = XTextWidth(screen->getWindowStyle()->font,
942 client.title, client.title_len);
945 client.title_text_w += (frame.bevel_w * 4);
949 void OpenboxWindow::getWMIconName(void) {
950 if (client.icon_title) {
951 delete [] client.icon_title;
952 client.icon_title = (char *) 0;
955 XTextProperty text_prop;
959 if (XGetWMIconName(display, client.window, &text_prop)) {
960 if (text_prop.value && text_prop.nitems > 0) {
961 if (text_prop.encoding != XA_STRING) {
962 text_prop.nitems = strlen((char *) text_prop.value);
964 if ((XmbTextPropertyToTextList(display, &text_prop,
965 &list, &num) == Success) &&
966 (num > 0) && *list) {
967 client.icon_title = bstrdup(*list);
968 XFreeStringList(list);
970 client.icon_title = bstrdup((char *) text_prop.value);
973 client.icon_title = bstrdup((char *) text_prop.value);
975 XFree((char *) text_prop.value);
977 client.icon_title = bstrdup(client.title);
980 client.icon_title = bstrdup(client.title);
986 * Retrieve which WM Protocols are supported by the client window.
987 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
988 * window's decorations and allow the close behavior.
989 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
992 void OpenboxWindow::getWMProtocols(void) {
996 if (XGetWMProtocols(display, client.window, &proto, &num_return)) {
997 for (int i = 0; i < num_return; ++i) {
998 if (proto[i] == openbox.getWMDeleteAtom())
999 functions.close = decorations.close = True;
1000 else if (proto[i] == openbox.getWMTakeFocusAtom())
1001 flags.send_focus_message = True;
1002 else if (proto[i] == openbox.getOpenboxStructureMessagesAtom())
1003 screen->addNetizen(new Netizen(*screen, client.window));
1012 * Gets the value of the WM_HINTS property.
1013 * If the property is not set, then use a set of default values.
1015 void OpenboxWindow::getWMHints(void) {
1016 XWMHints *wmhint = XGetWMHints(display, client.window);
1018 flags.visible = True;
1019 flags.iconic = False;
1020 focus_mode = F_Passive;
1021 client.window_group = None;
1022 client.initial_state = NormalState;
1025 client.wm_hint_flags = wmhint->flags;
1026 if (wmhint->flags & InputHint) {
1027 if (wmhint->input == True) {
1028 if (flags.send_focus_message)
1029 focus_mode = F_LocallyActive;
1031 focus_mode = F_Passive;
1033 if (flags.send_focus_message)
1034 focus_mode = F_GloballyActive;
1036 focus_mode = F_NoInput;
1039 focus_mode = F_Passive;
1042 if (wmhint->flags & StateHint)
1043 client.initial_state = wmhint->initial_state;
1045 client.initial_state = NormalState;
1047 if (wmhint->flags & WindowGroupHint) {
1048 if (! client.window_group) {
1049 client.window_group = wmhint->window_group;
1050 openbox.saveGroupSearch(client.window_group, this);
1053 client.window_group = None;
1060 * Gets the value of the WM_NORMAL_HINTS property.
1061 * If the property is not set, then use a set of default values.
1063 void OpenboxWindow::getWMNormalHints(void) {
1065 XSizeHints sizehint;
1067 client.min_width = client.min_height =
1068 client.base_width = client.base_height =
1069 client.width_inc = client.height_inc = 1;
1070 client.max_width = screen->size().w();
1071 client.max_height = screen->size().h();
1072 client.min_aspect_x = client.min_aspect_y =
1073 client.max_aspect_x = client.max_aspect_y = 1;
1074 client.win_gravity = NorthWestGravity;
1076 if (! XGetWMNormalHints(display, client.window, &sizehint, &icccm_mask))
1079 client.normal_hint_flags = sizehint.flags;
1081 if (sizehint.flags & PMinSize) {
1082 client.min_width = sizehint.min_width;
1083 client.min_height = sizehint.min_height;
1086 if (sizehint.flags & PMaxSize) {
1087 client.max_width = sizehint.max_width;
1088 client.max_height = sizehint.max_height;
1091 if (sizehint.flags & PResizeInc) {
1092 client.width_inc = sizehint.width_inc;
1093 client.height_inc = sizehint.height_inc;
1096 if (sizehint.flags & PAspect) {
1097 client.min_aspect_x = sizehint.min_aspect.x;
1098 client.min_aspect_y = sizehint.min_aspect.y;
1099 client.max_aspect_x = sizehint.max_aspect.x;
1100 client.max_aspect_y = sizehint.max_aspect.y;
1103 if (sizehint.flags & PBaseSize) {
1104 client.base_width = sizehint.base_width;
1105 client.base_height = sizehint.base_height;
1108 if (sizehint.flags & PWinGravity)
1109 client.win_gravity = sizehint.win_gravity;
1114 * Gets the MWM hints for the class' contained window.
1115 * This is used while initializing the window to its first state, and not
1117 * Returns: true if the MWM hints are successfully retreived and applied; false
1120 void OpenboxWindow::getMWMHints(void) {
1123 unsigned long num, len;
1125 int ret = XGetWindowProperty(display, client.window,
1126 openbox.getMotifWMHintsAtom(), 0,
1127 PropMwmHintsElements, False,
1128 openbox.getMotifWMHintsAtom(), &atom_return,
1129 &format, &num, &len,
1130 (unsigned char **) &client.mwm_hint);
1132 if (ret != Success || !client.mwm_hint || num != PropMwmHintsElements)
1135 if (client.mwm_hint->flags & MwmHintsDecorations) {
1136 if (client.mwm_hint->decorations & MwmDecorAll) {
1137 decorations.titlebar = decorations.handle = decorations.border =
1138 decorations.iconify = decorations.maximize =
1139 decorations.close = decorations.menu = True;
1141 decorations.titlebar = decorations.handle = decorations.border =
1142 decorations.iconify = decorations.maximize =
1143 decorations.close = decorations.menu = False;
1145 if (client.mwm_hint->decorations & MwmDecorBorder)
1146 decorations.border = True;
1147 if (client.mwm_hint->decorations & MwmDecorHandle)
1148 decorations.handle = True;
1149 if (client.mwm_hint->decorations & MwmDecorTitle)
1150 decorations.titlebar = True;
1151 if (client.mwm_hint->decorations & MwmDecorMenu)
1152 decorations.menu = True;
1153 if (client.mwm_hint->decorations & MwmDecorIconify)
1154 decorations.iconify = True;
1155 if (client.mwm_hint->decorations & MwmDecorMaximize)
1156 decorations.maximize = True;
1160 if (client.mwm_hint->flags & MwmHintsFunctions) {
1161 if (client.mwm_hint->functions & MwmFuncAll) {
1162 functions.resize = functions.move = functions.iconify =
1163 functions.maximize = functions.close = True;
1165 functions.resize = functions.move = functions.iconify =
1166 functions.maximize = functions.close = False;
1168 if (client.mwm_hint->functions & MwmFuncResize)
1169 functions.resize = True;
1170 if (client.mwm_hint->functions & MwmFuncMove)
1171 functions.move = True;
1172 if (client.mwm_hint->functions & MwmFuncIconify)
1173 functions.iconify = True;
1174 if (client.mwm_hint->functions & MwmFuncMaximize)
1175 functions.maximize = True;
1176 if (client.mwm_hint->functions & MwmFuncClose)
1177 functions.close = True;
1184 * Gets the openbox hints from the class' contained window.
1185 * This is used while initializing the window to its first state, and not
1187 * Returns: true if the hints are successfully retreived and applied; false if
1190 void OpenboxWindow::getOpenboxHints(void) {
1193 unsigned long num, len;
1195 int ret = XGetWindowProperty(display, client.window,
1196 openbox.getOpenboxHintsAtom(), 0,
1197 PropOpenboxHintsElements, False,
1198 openbox.getOpenboxHintsAtom(), &atom_return,
1199 &format, &num, &len,
1200 (unsigned char **) &client.openbox_hint);
1201 if (ret != Success || !client.openbox_hint ||
1202 num != PropOpenboxHintsElements)
1205 if (client.openbox_hint->flags & AttribShaded)
1206 flags.shaded = (client.openbox_hint->attrib & AttribShaded);
1208 if ((client.openbox_hint->flags & AttribMaxHoriz) &&
1209 (client.openbox_hint->flags & AttribMaxVert))
1210 flags.maximized = (client.openbox_hint->attrib &
1211 (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1212 else if (client.openbox_hint->flags & AttribMaxVert)
1213 flags.maximized = (client.openbox_hint->attrib & AttribMaxVert) ? 2 : 0;
1214 else if (client.openbox_hint->flags & AttribMaxHoriz)
1215 flags.maximized = (client.openbox_hint->attrib & AttribMaxHoriz) ? 3 : 0;
1217 if (client.openbox_hint->flags & AttribOmnipresent)
1218 flags.stuck = (client.openbox_hint->attrib & AttribOmnipresent);
1220 if (client.openbox_hint->flags & AttribWorkspace)
1221 workspace_number = client.openbox_hint->workspace;
1223 // if (client.openbox_hint->flags & AttribStack)
1224 // don't yet have always on top/bottom for openbox yet... working
1227 if (client.openbox_hint->flags & AttribDecoration) {
1228 switch (client.openbox_hint->decoration) {
1230 decorations.titlebar = decorations.border = decorations.handle =
1231 decorations.iconify = decorations.maximize =
1232 decorations.menu = False;
1233 functions.resize = functions.move = functions.iconify =
1234 functions.maximize = False;
1239 decorations.titlebar = decorations.iconify = decorations.menu =
1240 functions.move = functions.iconify = True;
1241 decorations.border = decorations.handle = decorations.maximize =
1242 functions.resize = functions.maximize = False;
1247 decorations.titlebar = decorations.menu = functions.move = True;
1248 decorations.iconify = decorations.border = decorations.handle =
1249 decorations.maximize = functions.resize = functions.maximize =
1250 functions.iconify = False;
1256 decorations.titlebar = decorations.border = decorations.handle =
1257 decorations.iconify = decorations.maximize =
1258 decorations.menu = True;
1259 functions.resize = functions.move = functions.iconify =
1260 functions.maximize = True;
1270 void OpenboxWindow::configure(int dx, int dy,
1271 unsigned int dw, unsigned int dh) {
1272 Bool send_event = (frame.x != dx || frame.y != dy);
1274 if ((dw != frame.width) || (dh != frame.height)) {
1275 if ((((signed) frame.width) + dx) < 0) dx = 0;
1276 if ((((signed) frame.height) + dy) < 0) dy = 0;
1286 if (openbox.hasShapeExtensions() && flags.shaped) {
1287 XShapeCombineShape(display, frame.window, ShapeBounding,
1288 frame.mwm_border_w, frame.y_border +
1289 frame.mwm_border_w, client.window,
1290 ShapeBounding, ShapeSet);
1293 XRectangle xrect[2];
1294 xrect[0].x = xrect[0].y = 0;
1295 xrect[0].width = frame.width;
1296 xrect[0].height = frame.y_border;
1298 if (decorations.handle) {
1300 xrect[1].y = frame.y_handle;
1301 xrect[1].width = frame.width;
1302 xrect[1].height = frame.handle_h + frame.border_w;
1306 XShapeCombineRectangles(display, frame.window, ShapeBounding, 0, 0,
1307 xrect, num, ShapeUnion, Unsorted);
1311 XMoveWindow(display, frame.window, frame.x, frame.y);
1313 setFocusFlag(flags.focused);
1320 XMoveWindow(display, frame.window, frame.x, frame.y);
1322 if (! flags.moving) send_event = True;
1325 if (send_event && ! flags.moving) {
1326 client.x = dx + frame.mwm_border_w + frame.border_w;
1327 client.y = dy + frame.y_border + frame.mwm_border_w +
1331 event.type = ConfigureNotify;
1333 event.xconfigure.display = display;
1334 event.xconfigure.event = client.window;
1335 event.xconfigure.window = client.window;
1336 event.xconfigure.x = client.x;
1337 event.xconfigure.y = client.y;
1338 event.xconfigure.width = client.width;
1339 event.xconfigure.height = client.height;
1340 event.xconfigure.border_width = client.old_bw;
1341 event.xconfigure.above = frame.window;
1342 event.xconfigure.override_redirect = False;
1344 XSendEvent(display, client.window, True, NoEventMask, &event);
1346 screen->updateNetizenConfigNotify(&event);
1351 bool OpenboxWindow::setInputFocus(void) {
1352 if (((signed) (frame.x + frame.width)) < 0) {
1353 if (((signed) (frame.y + frame.y_border)) < 0)
1354 configure(frame.border_w, frame.border_w, frame.width, frame.height);
1355 else if (frame.y > (signed) screen->size().h())
1356 configure(frame.border_w, screen->size().h() - frame.height,
1357 frame.width, frame.height);
1359 configure(frame.border_w, frame.y + frame.border_w,
1360 frame.width, frame.height);
1361 } else if (frame.x > (signed) screen->size().w()) {
1362 if (((signed) (frame.y + frame.y_border)) < 0)
1363 configure(screen->size().w() - frame.width, frame.border_w,
1364 frame.width, frame.height);
1365 else if (frame.y > (signed) screen->size().h())
1366 configure(screen->size().w() - frame.width,
1367 screen->size().h() - frame.height, frame.width, frame.height);
1369 configure(screen->size().w() - frame.width,
1370 frame.y + frame.border_w, frame.width, frame.height);
1374 if (! validateClient()) return False;
1378 if (client.transient && flags.modal) {
1379 ret = client.transient->setInputFocus();
1380 } else if (! flags.focused) {
1381 if (focus_mode == F_LocallyActive || focus_mode == F_Passive) {
1382 XSetInputFocus(display, client.window,
1383 RevertToPointerRoot, CurrentTime);
1384 openbox.focusWindow(this);
1386 if (flags.send_focus_message) {
1388 ce.xclient.type = ClientMessage;
1389 ce.xclient.message_type = openbox.getWMProtocolsAtom();
1390 ce.xclient.display = display;
1391 ce.xclient.window = client.window;
1392 ce.xclient.format = 32;
1393 ce.xclient.data.l[0] = openbox.getWMTakeFocusAtom();
1394 ce.xclient.data.l[1] = openbox.getLastTime();
1395 ce.xclient.data.l[2] = 0l;
1396 ce.xclient.data.l[3] = 0l;
1397 ce.xclient.data.l[4] = 0l;
1398 XSendEvent(display, client.window, False, NoEventMask, &ce);
1401 if (screen->sloppyFocus() && screen->autoRaise())
1414 void OpenboxWindow::iconify(void) {
1415 if (flags.iconic) return;
1420 if (windowmenu) windowmenu->hide();
1422 setState(IconicState);
1424 XSelectInput(display, client.window, NoEventMask);
1425 XUnmapWindow(display, client.window);
1426 XSelectInput(display, client.window,
1427 PropertyChangeMask | StructureNotifyMask | FocusChangeMask);
1429 XUnmapWindow(display, frame.window);
1430 flags.visible = False;
1431 flags.iconic = True;
1433 screen->getWorkspace(workspace_number)->removeWindow(this);
1435 if (flags.transient && client.transient_for &&
1436 !client.transient_for->flags.iconic) {
1437 client.transient_for->iconify();
1439 screen->addIcon(this);
1441 if (client.transient && !client.transient->flags.iconic) {
1442 client.transient->iconify();
1447 void OpenboxWindow::deiconify(bool reassoc, bool raise, bool initial) {
1448 if (flags.iconic || reassoc)
1449 screen->reassociateWindow(this, -1, False);
1450 else if (workspace_number != screen->getCurrentWorkspace()->getWorkspaceID())
1453 setState(NormalState);
1455 XSelectInput(display, client.window, NoEventMask);
1456 XMapWindow(display, client.window);
1457 XSelectInput(display, client.window,
1458 PropertyChangeMask | StructureNotifyMask | FocusChangeMask);
1460 XMapSubwindows(display, frame.window);
1461 XMapWindow(display, frame.window);
1463 // if we're using the click to place placement type, then immediately
1464 // after the window is mapped, we need to start interactively moving it
1465 if (initial && place_window &&
1466 screen->placementPolicy() == BScreen::ClickMousePlacement) {
1470 XQueryPointer(openbox.getXDisplay(), screen->getRootWindow(),
1471 &r, &c, &rx, &ry, &x, &y, &m);
1475 if (flags.iconic && screen->focusNew()) setInputFocus();
1477 flags.visible = True;
1478 flags.iconic = False;
1480 if (reassoc && client.transient) client.transient->deiconify(True, False);
1483 screen->getWorkspace(workspace_number)->raiseWindow(this);
1487 void OpenboxWindow::close(void) {
1489 ce.xclient.type = ClientMessage;
1490 ce.xclient.message_type = openbox.getWMProtocolsAtom();
1491 ce.xclient.display = display;
1492 ce.xclient.window = client.window;
1493 ce.xclient.format = 32;
1494 ce.xclient.data.l[0] = openbox.getWMDeleteAtom();
1495 ce.xclient.data.l[1] = CurrentTime;
1496 ce.xclient.data.l[2] = 0l;
1497 ce.xclient.data.l[3] = 0l;
1498 ce.xclient.data.l[4] = 0l;
1499 XSendEvent(display, client.window, False, NoEventMask, &ce);
1503 void OpenboxWindow::withdraw(void) {
1507 flags.visible = False;
1508 flags.iconic = False;
1510 XUnmapWindow(display, frame.window);
1512 XSelectInput(display, client.window, NoEventMask);
1513 XUnmapWindow(display, client.window);
1514 XSelectInput(display, client.window,
1515 PropertyChangeMask | StructureNotifyMask | FocusChangeMask);
1517 if (windowmenu) windowmenu->hide();
1521 void OpenboxWindow::maximize(unsigned int button) {
1525 // handle case where menu is open then the max button is used instead
1526 if (windowmenu && windowmenu->isVisible()) windowmenu->hide();
1528 if (flags.maximized) {
1529 flags.maximized = 0;
1531 openbox_attrib.flags &= ! (AttribMaxHoriz | AttribMaxVert);
1532 openbox_attrib.attrib &= ! (AttribMaxHoriz | AttribMaxVert);
1534 // when a resize is begun, maximize(0) is called to clear any maximization
1535 // flags currently set. Otherwise it still thinks it is maximized.
1536 // so we do not need to call configure() because resizing will handle it
1537 if (!flags.resizing)
1538 configure(openbox_attrib.premax_x, openbox_attrib.premax_y,
1539 openbox_attrib.premax_w, openbox_attrib.premax_h);
1541 openbox_attrib.premax_x = openbox_attrib.premax_y = 0;
1542 openbox_attrib.premax_w = openbox_attrib.premax_h = 0;
1544 redrawMaximizeButton(flags.maximized);
1545 setState(current_state);
1549 openbox_attrib.premax_x = frame.x;
1550 openbox_attrib.premax_y = frame.y;
1551 openbox_attrib.premax_w = frame.width;
1552 openbox_attrib.premax_h = frame.height;
1554 Rect space = screen->availableArea();
1555 unsigned int dw = space.w(),
1557 dw -= frame.border_w * 2;
1558 dw -= frame.mwm_border_w * 2;
1559 dw -= client.base_width;
1561 dh -= frame.border_w * 2;
1562 dh -= frame.mwm_border_w * 2;
1563 dh -= ((frame.handle_h + frame.border_w) * decorations.handle);
1564 dh -= client.base_height;
1565 dh -= frame.y_border;
1567 if (dw < client.min_width) dw = client.min_width;
1568 if (dh < client.min_height) dh = client.min_height;
1569 if (dw > client.max_width) dw = client.max_width;
1570 if (dh > client.max_height) dh = client.max_height;
1572 dw -= (dw % client.width_inc);
1573 dw += client.base_width;
1574 dw += frame.mwm_border_w * 2;
1576 dh -= (dh % client.height_inc);
1577 dh += client.base_height;
1578 dh += frame.y_border;
1579 dh += ((frame.handle_h + frame.border_w) * decorations.handle);
1580 dh += frame.mwm_border_w * 2;
1582 int dx = space.x() + ((space.w() - dw) / 2) - frame.border_w,
1583 dy = space.y() + ((space.h() - dh) / 2) - frame.border_w;
1587 openbox_attrib.flags |= AttribMaxHoriz | AttribMaxVert;
1588 openbox_attrib.attrib |= AttribMaxHoriz | AttribMaxVert;
1592 openbox_attrib.flags |= AttribMaxVert;
1593 openbox_attrib.attrib |= AttribMaxVert;
1600 openbox_attrib.flags |= AttribMaxHoriz;
1601 openbox_attrib.attrib |= AttribMaxHoriz;
1609 openbox_attrib.flags ^= AttribShaded;
1610 openbox_attrib.attrib ^= AttribShaded;
1611 flags.shaded = False;
1614 flags.maximized = button;
1616 configure(dx, dy, dw, dh);
1617 screen->getWorkspace(workspace_number)->raiseWindow(this);
1618 redrawMaximizeButton(flags.maximized);
1619 setState(current_state);
1623 void OpenboxWindow::setWorkspace(int n) {
1624 ASSERT(n < screen->getWorkspaceCount());
1625 workspace_number = n;
1627 openbox_attrib.flags |= AttribWorkspace;
1628 openbox_attrib.workspace = workspace_number;
1632 void OpenboxWindow::shade(void) {
1633 if (!decorations.titlebar)
1637 XResizeWindow(display, frame.window, frame.width, frame.height);
1638 flags.shaded = False;
1639 openbox_attrib.flags ^= AttribShaded;
1640 openbox_attrib.attrib ^= AttribShaded;
1642 setState(NormalState);
1644 XResizeWindow(display, frame.window, frame.width, frame.title_h);
1645 flags.shaded = True;
1646 openbox_attrib.flags |= AttribShaded;
1647 openbox_attrib.attrib |= AttribShaded;
1649 setState(IconicState);
1654 void OpenboxWindow::stick(void) {
1656 openbox_attrib.flags ^= AttribOmnipresent;
1657 openbox_attrib.attrib ^= AttribOmnipresent;
1659 flags.stuck = False;
1662 screen->reassociateWindow(this, -1, True);
1664 setState(current_state);
1668 openbox_attrib.flags |= AttribOmnipresent;
1669 openbox_attrib.attrib |= AttribOmnipresent;
1671 setState(current_state);
1676 void OpenboxWindow::setFocusFlag(Bool focus) {
1677 flags.focused = focus;
1679 if (decorations.titlebar) {
1680 if (flags.focused) {
1682 XSetWindowBackgroundPixmap(display, frame.title, frame.ftitle);
1684 XSetWindowBackground(display, frame.title, frame.ftitle_pixel);
1687 XSetWindowBackgroundPixmap(display, frame.title, frame.utitle);
1689 XSetWindowBackground(display, frame.title, frame.utitle_pixel);
1691 XClearWindow(display, frame.title);
1697 if (decorations.handle) {
1698 if (flags.focused) {
1700 XSetWindowBackgroundPixmap(display, frame.handle, frame.fhandle);
1702 XSetWindowBackground(display, frame.handle, frame.fhandle_pixel);
1705 XSetWindowBackgroundPixmap(display, frame.right_grip, frame.fgrip);
1706 XSetWindowBackgroundPixmap(display, frame.left_grip, frame.fgrip);
1708 XSetWindowBackground(display, frame.right_grip, frame.fgrip_pixel);
1709 XSetWindowBackground(display, frame.left_grip, frame.fgrip_pixel);
1713 XSetWindowBackgroundPixmap(display, frame.handle, frame.uhandle);
1715 XSetWindowBackground(display, frame.handle, frame.uhandle_pixel);
1718 XSetWindowBackgroundPixmap(display, frame.right_grip, frame.ugrip);
1719 XSetWindowBackgroundPixmap(display, frame.left_grip, frame.ugrip);
1721 XSetWindowBackground(display, frame.right_grip, frame.ugrip_pixel);
1722 XSetWindowBackground(display, frame.left_grip, frame.ugrip_pixel);
1725 XClearWindow(display, frame.handle);
1726 XClearWindow(display, frame.right_grip);
1727 XClearWindow(display, frame.left_grip);
1730 if (decorations.border) {
1732 XSetWindowBorder(display, frame.plate, frame.fborder_pixel);
1734 XSetWindowBorder(display, frame.plate, frame.uborder_pixel);
1737 if (screen->sloppyFocus() && screen->autoRaise() && timer->isTiming())
1743 void OpenboxWindow::installColormap(Bool install) {
1745 if (! validateClient()) return;
1747 int i = 0, ncmap = 0;
1748 Colormap *cmaps = XListInstalledColormaps(display, client.window, &ncmap);
1749 XWindowAttributes wattrib;
1751 if (XGetWindowAttributes(display, client.window, &wattrib)) {
1753 // install the window's colormap
1754 for (i = 0; i < ncmap; i++) {
1755 if (*(cmaps + i) == wattrib.colormap)
1756 // this window is using an installed color map... do not install
1759 // otherwise, install the window's colormap
1761 XInstallColormap(display, wattrib.colormap);
1763 // uninstall the window's colormap
1764 for (i = 0; i < ncmap; i++) {
1765 if (*(cmaps + i) == wattrib.colormap)
1766 // we found the colormap to uninstall
1767 XUninstallColormap(display, wattrib.colormap);
1779 void OpenboxWindow::setState(unsigned long new_state) {
1780 current_state = new_state;
1782 unsigned long state[2];
1783 state[0] = (unsigned long) current_state;
1784 state[1] = (unsigned long) None;
1785 XChangeProperty(display, client.window, openbox.getWMStateAtom(),
1786 openbox.getWMStateAtom(), 32, PropModeReplace,
1787 (unsigned char *) state, 2);
1789 XChangeProperty(display, client.window,
1790 openbox.getOpenboxAttributesAtom(),
1791 openbox.getOpenboxAttributesAtom(), 32, PropModeReplace,
1792 (unsigned char *) &openbox_attrib,
1793 PropOpenboxAttributesElements);
1797 Bool OpenboxWindow::getState(void) {
1803 unsigned long *state, ulfoo, nitems;
1805 if ((XGetWindowProperty(display, client.window, openbox.getWMStateAtom(),
1806 0l, 2l, False, openbox.getWMStateAtom(),
1807 &atom_return, &foo, &nitems, &ulfoo,
1808 (unsigned char **) &state) != Success) ||
1815 current_state = (unsigned long) state[0];
1820 XFree((void *) state);
1826 void OpenboxWindow::setGravityOffsets(void) {
1827 // x coordinates for each gravity type
1828 const int x_west = client.x;
1829 const int x_east = client.x + client.width - frame.width;
1830 const int x_center = client.x + client.width - frame.width/2;
1831 // y coordinates for each gravity type
1832 const int y_north = client.y;
1833 const int y_south = client.y + client.height - frame.height;
1834 const int y_center = client.y + client.height - frame.height/2;
1836 switch (client.win_gravity) {
1837 case NorthWestGravity:
1846 case NorthEastGravity:
1850 case SouthWestGravity:
1858 case SouthEastGravity:
1876 frame.x = client.x - frame.mwm_border_w + frame.border_w;
1877 frame.y = client.y - frame.y_border - frame.mwm_border_w - frame.border_w;
1883 void OpenboxWindow::restoreAttributes(void) {
1884 if (! getState()) current_state = NormalState;
1888 unsigned long ulfoo, nitems;
1890 OpenboxAttributes *net;
1891 int ret = XGetWindowProperty(display, client.window,
1892 openbox.getOpenboxAttributesAtom(), 0l,
1893 PropOpenboxAttributesElements, False,
1894 openbox.getOpenboxAttributesAtom(),
1895 &atom_return, &foo, &nitems, &ulfoo,
1896 (unsigned char **) &net);
1897 if (ret != Success || !net || nitems != PropOpenboxAttributesElements)
1900 openbox_attrib.flags = net->flags;
1901 openbox_attrib.attrib = net->attrib;
1902 openbox_attrib.decoration = net->decoration;
1903 openbox_attrib.workspace = net->workspace;
1904 openbox_attrib.stack = net->stack;
1905 openbox_attrib.premax_x = net->premax_x;
1906 openbox_attrib.premax_y = net->premax_y;
1907 openbox_attrib.premax_w = net->premax_w;
1908 openbox_attrib.premax_h = net->premax_h;
1910 XFree((void *) net);
1912 if (openbox_attrib.flags & AttribShaded &&
1913 openbox_attrib.attrib & AttribShaded) {
1915 ((current_state == IconicState) ? NormalState : current_state);
1917 flags.shaded = False;
1920 current_state = save_state;
1923 if (((int) openbox_attrib.workspace != screen->getCurrentWorkspaceID()) &&
1924 ((int) openbox_attrib.workspace < screen->getWorkspaceCount())) {
1925 screen->reassociateWindow(this, openbox_attrib.workspace, True);
1927 if (current_state == NormalState) current_state = WithdrawnState;
1928 } else if (current_state == WithdrawnState) {
1929 current_state = NormalState;
1932 if (openbox_attrib.flags & AttribOmnipresent &&
1933 openbox_attrib.attrib & AttribOmnipresent) {
1934 flags.stuck = False;
1937 current_state = NormalState;
1940 if ((openbox_attrib.flags & AttribMaxHoriz) ||
1941 (openbox_attrib.flags & AttribMaxVert)) {
1942 int x = openbox_attrib.premax_x, y = openbox_attrib.premax_y;
1943 unsigned int w = openbox_attrib.premax_w, h = openbox_attrib.premax_h;
1944 flags.maximized = 0;
1946 unsigned int m = False;
1947 if ((openbox_attrib.flags & AttribMaxHoriz) &&
1948 (openbox_attrib.flags & AttribMaxVert))
1949 m = (openbox_attrib.attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0;
1950 else if (openbox_attrib.flags & AttribMaxVert)
1951 m = (openbox_attrib.attrib & AttribMaxVert) ? 2 : 0;
1952 else if (openbox_attrib.flags & AttribMaxHoriz)
1953 m = (openbox_attrib.attrib & AttribMaxHoriz) ? 3 : 0;
1957 openbox_attrib.premax_x = x;
1958 openbox_attrib.premax_y = y;
1959 openbox_attrib.premax_w = w;
1960 openbox_attrib.premax_h = h;
1963 setState(current_state);
1968 * The reverse of the setGravityOffsets function. Uses the frame window's
1969 * position to find the window's reference point.
1971 void OpenboxWindow::restoreGravity(void) {
1972 // x coordinates for each gravity type
1973 const int x_west = frame.x;
1974 const int x_east = frame.x + frame.width - client.width;
1975 const int x_center = frame.x + (frame.width/2) - client.width;
1976 // y coordinates for each gravity type
1977 const int y_north = frame.y;
1978 const int y_south = frame.y + frame.height - client.height;
1979 const int y_center = frame.y + (frame.height/2) - client.height;
1981 switch(client.win_gravity) {
1983 case NorthWestGravity:
1988 client.x = x_center;
1991 case NorthEastGravity:
1995 case SouthWestGravity:
2000 client.x = x_center;
2003 case SouthEastGravity:
2009 client.y = y_center;
2013 client.y = y_center;
2016 client.x = x_center;
2017 client.y = y_center;
2021 client.x = frame.x + frame.mwm_border_w + frame.border_w;
2022 client.y = frame.y + frame.y_border + frame.mwm_border_w +
2029 void OpenboxWindow::redrawLabel(void) {
2030 int dx = frame.bevel_w * 2, dlen = client.title_len;
2031 unsigned int l = client.title_text_w;
2033 if (flags.focused) {
2035 XSetWindowBackgroundPixmap(display, frame.label, frame.flabel);
2037 XSetWindowBackground(display, frame.label, frame.flabel_pixel);
2040 XSetWindowBackgroundPixmap(display, frame.label, frame.ulabel);
2042 XSetWindowBackground(display, frame.label, frame.ulabel_pixel);
2044 XClearWindow(display, frame.label);
2046 if (client.title_text_w > frame.label_w) {
2047 for (; dlen >= 0; dlen--) {
2048 if (i18n.multibyte()) {
2049 XRectangle ink, logical;
2050 XmbTextExtents(screen->getWindowStyle()->fontset, client.title, dlen,
2054 l = XTextWidth(screen->getWindowStyle()->font, client.title, dlen);
2056 l += (frame.bevel_w * 4);
2058 if (l < frame.label_w)
2063 switch (screen->getWindowStyle()->justify) {
2064 case BScreen::RightJustify:
2065 dx += frame.label_w - l;
2068 case BScreen::CenterJustify:
2069 dx += (frame.label_w - l) / 2;
2073 WindowStyle *style = screen->getWindowStyle();
2074 GC text_gc = (flags.focused) ? style->l_text_focus_gc :
2075 style->l_text_unfocus_gc;
2076 if (i18n.multibyte())
2077 XmbDrawString(display, frame.label, style->fontset, text_gc, dx,
2078 (1 - style->fontset_extents->max_ink_extent.y),
2079 client.title, dlen);
2081 XDrawString(display, frame.label, text_gc, dx,
2082 (style->font->ascent + 1), client.title, dlen);
2086 void OpenboxWindow::redrawAllButtons(void) {
2087 if (frame.iconify_button) redrawIconifyButton(False);
2088 if (frame.maximize_button) redrawMaximizeButton(flags.maximized);
2089 if (frame.close_button) redrawCloseButton(False);
2093 void OpenboxWindow::redrawIconifyButton(Bool pressed) {
2095 if (flags.focused) {
2097 XSetWindowBackgroundPixmap(display, frame.iconify_button,
2100 XSetWindowBackground(display, frame.iconify_button,
2101 frame.fbutton_pixel);
2104 XSetWindowBackgroundPixmap(display, frame.iconify_button,
2107 XSetWindowBackground(display, frame.iconify_button,
2108 frame.ubutton_pixel);
2112 XSetWindowBackgroundPixmap(display, frame.iconify_button, frame.pbutton);
2114 XSetWindowBackground(display, frame.iconify_button, frame.pbutton_pixel);
2116 XClearWindow(display, frame.iconify_button);
2118 XDrawRectangle(display, frame.iconify_button,
2119 ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc :
2120 screen->getWindowStyle()->b_pic_unfocus_gc),
2121 2, (frame.button_h - 5), (frame.button_w - 5), 2);
2125 void OpenboxWindow::redrawMaximizeButton(Bool pressed) {
2127 if (flags.focused) {
2129 XSetWindowBackgroundPixmap(display, frame.maximize_button,
2132 XSetWindowBackground(display, frame.maximize_button,
2133 frame.fbutton_pixel);
2136 XSetWindowBackgroundPixmap(display, frame.maximize_button,
2139 XSetWindowBackground(display, frame.maximize_button,
2140 frame.ubutton_pixel);
2144 XSetWindowBackgroundPixmap(display, frame.maximize_button,
2147 XSetWindowBackground(display, frame.maximize_button,
2148 frame.pbutton_pixel);
2150 XClearWindow(display, frame.maximize_button);
2152 XDrawRectangle(display, frame.maximize_button,
2153 ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc :
2154 screen->getWindowStyle()->b_pic_unfocus_gc),
2155 2, 2, (frame.button_w - 5), (frame.button_h - 5));
2156 XDrawLine(display, frame.maximize_button,
2157 ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc :
2158 screen->getWindowStyle()->b_pic_unfocus_gc),
2159 2, 3, (frame.button_w - 3), 3);
2163 void OpenboxWindow::redrawCloseButton(Bool pressed) {
2165 if (flags.focused) {
2167 XSetWindowBackgroundPixmap(display, frame.close_button,
2170 XSetWindowBackground(display, frame.close_button,
2171 frame.fbutton_pixel);
2174 XSetWindowBackgroundPixmap(display, frame.close_button,
2177 XSetWindowBackground(display, frame.close_button,
2178 frame.ubutton_pixel);
2182 XSetWindowBackgroundPixmap(display, frame.close_button, frame.pbutton);
2184 XSetWindowBackground(display, frame.close_button, frame.pbutton_pixel);
2186 XClearWindow(display, frame.close_button);
2188 XDrawLine(display, frame.close_button,
2189 ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc :
2190 screen->getWindowStyle()->b_pic_unfocus_gc), 2, 2,
2191 (frame.button_w - 3), (frame.button_h - 3));
2192 XDrawLine(display, frame.close_button,
2193 ((flags.focused) ? screen->getWindowStyle()->b_pic_focus_gc :
2194 screen->getWindowStyle()->b_pic_unfocus_gc), 2,
2195 (frame.button_h - 3),
2196 (frame.button_w - 3), 2);
2200 void OpenboxWindow::mapRequestEvent(XMapRequestEvent *re) {
2201 if (re->window == client.window) {
2203 fprintf(stderr, i18n(WindowSet, WindowMapRequest,
2204 "OpenboxWindow::mapRequestEvent() for 0x%lx\n"),
2209 if (! validateClient()) return;
2211 Bool get_state_ret = getState();
2212 if (! (get_state_ret && openbox.isStartup())) {
2213 if ((client.wm_hint_flags & StateHint) &&
2214 (! (current_state == NormalState || current_state == IconicState)))
2215 current_state = client.initial_state;
2217 current_state = NormalState;
2218 } else if (flags.iconic) {
2219 current_state = NormalState;
2222 switch (current_state) {
2227 case WithdrawnState:
2235 deiconify(False, True, True); // specify that we're initializing the
2245 void OpenboxWindow::mapNotifyEvent(XMapEvent *ne) {
2246 if ((ne->window == client.window) && (! ne->override_redirect)
2247 && (flags.visible)) {
2249 if (! validateClient()) return;
2251 setState(NormalState);
2253 if (flags.transient || screen->focusNew())
2256 setFocusFlag(False);
2258 flags.visible = True;
2259 flags.iconic = False;
2266 void OpenboxWindow::unmapNotifyEvent(XUnmapEvent *ue) {
2267 if (ue->window == client.window) {
2269 fprintf(stderr, i18n(WindowSet, WindowUnmapNotify,
2270 "OpenboxWindow::unmapNotifyEvent() for 0x%lx\n"),
2275 if (! validateClient()) return;
2280 XChangeSaveSet(display, client.window, SetModeDelete);
2281 XSelectInput(display, client.window, NoEventMask);
2283 XDeleteProperty(display, client.window, openbox.getWMStateAtom());
2284 XDeleteProperty(display, client.window,
2285 openbox.getOpenboxAttributesAtom());
2287 XUnmapWindow(display, frame.window);
2288 XUnmapWindow(display, client.window);
2291 if (! XCheckTypedWindowEvent(display, client.window, ReparentNotify,
2294 fprintf(stderr, i18n(WindowSet, WindowUnmapNotifyReparent,
2295 "OpenboxWindow::unmapNotifyEvent(): reparent 0x%lx to "
2296 "root.\n"), client.window);
2300 XReparentWindow(display, client.window, screen->getRootWindow(),
2301 client.x, client.y);
2313 void OpenboxWindow::destroyNotifyEvent(XDestroyWindowEvent *de) {
2314 if (de->window == client.window) {
2317 XUnmapWindow(display, frame.window);
2324 void OpenboxWindow::propertyNotifyEvent(Atom atom) {
2326 if (! validateClient()) return;
2330 case XA_WM_CLIENT_MACHINE:
2334 case XA_WM_TRANSIENT_FOR:
2335 // determine if this is a transient window
2337 if (XGetTransientForHint(display, client.window, &win)) {
2338 if (win && (win != client.window)) {
2339 if ((client.transient_for = openbox.searchWindow(win))) {
2340 client.transient_for->client.transient = this;
2341 flags.stuck = client.transient_for->flags.stuck;
2342 flags.transient = True;
2343 } else if (win == client.window_group) {
2344 //jr This doesn't look quite right...
2345 if ((client.transient_for = openbox.searchGroup(win, this))) {
2346 client.transient_for->client.transient = this;
2347 flags.stuck = client.transient_for->flags.stuck;
2348 flags.transient = True;
2353 if (win == screen->getRootWindow()) flags.modal = True;
2356 // adjust the window decorations based on transience
2357 if (flags.transient)
2358 decorations.maximize = decorations.handle = functions.maximize = False;
2368 case XA_WM_ICON_NAME:
2370 if (flags.iconic) screen->iconUpdate();
2376 if (decorations.titlebar)
2380 screen->getWorkspace(workspace_number)->update();
2384 case XA_WM_NORMAL_HINTS: {
2387 if ((client.normal_hint_flags & PMinSize) &&
2388 (client.normal_hint_flags & PMaxSize)) {
2389 if (client.max_width <= client.min_width &&
2390 client.max_height <= client.min_height)
2391 decorations.maximize = decorations.handle =
2392 functions.resize = functions.maximize = False;
2394 decorations.maximize = decorations.handle =
2395 functions.resize = functions.maximize = True;
2398 int x = frame.x, y = frame.y;
2399 unsigned int w = frame.width, h = frame.height;
2403 if ((x != frame.x) || (y != frame.y) ||
2404 (w != frame.width) || (h != frame.height))
2411 if (atom == openbox.getWMProtocolsAtom()) {
2414 if (decorations.close && (! frame.close_button)) {
2415 createCloseButton();
2416 if (decorations.titlebar) {
2420 if (windowmenu) windowmenu->reconfigure();
2431 void OpenboxWindow::exposeEvent(XExposeEvent *ee) {
2432 if (frame.label == ee->window && decorations.titlebar)
2434 else if (frame.close_button == ee->window)
2435 redrawCloseButton(False);
2436 else if (frame.maximize_button == ee->window)
2437 redrawMaximizeButton(flags.maximized);
2438 else if (frame.iconify_button == ee->window)
2439 redrawIconifyButton(False);
2443 void OpenboxWindow::configureRequestEvent(XConfigureRequestEvent *cr) {
2444 if (cr->window == client.window) {
2446 if (! validateClient()) return;
2448 int cx = frame.x, cy = frame.y;
2449 unsigned int cw = frame.width, ch = frame.height;
2451 if (cr->value_mask & CWBorderWidth)
2452 client.old_bw = cr->border_width;
2454 if (cr->value_mask & CWX)
2455 cx = cr->x - frame.mwm_border_w - frame.border_w;
2457 if (cr->value_mask & CWY)
2458 cy = cr->y - frame.y_border - frame.mwm_border_w -
2461 if (cr->value_mask & CWWidth)
2462 cw = cr->width + (frame.mwm_border_w * 2);
2464 if (cr->value_mask & CWHeight)
2465 ch = cr->height + frame.y_border + (frame.mwm_border_w * 2) +
2466 (frame.border_w * decorations.handle) + frame.handle_h;
2468 if (frame.x != cx || frame.y != cy ||
2469 frame.width != cw || frame.height != ch)
2470 configure(cx, cy, cw, ch);
2472 if (cr->value_mask & CWStackMode) {
2473 switch (cr->detail) {
2477 if (flags.iconic) deiconify();
2478 screen->getWorkspace(workspace_number)->raiseWindow(this);
2483 if (flags.iconic) deiconify();
2484 screen->getWorkspace(workspace_number)->lowerWindow(this);
2494 void OpenboxWindow::buttonPressEvent(XButtonEvent *be) {
2496 if (! validateClient())
2499 int stack_change = 1; // < 0 means to lower the window
2500 // > 0 means to raise the window
2501 // 0 means to leave it where it is
2503 // alt + left/right click begins interactively moving/resizing the window
2504 // when the mouse is moved
2505 if (be->state == Mod1Mask && (be->button == 1 || be->button == 3)) {
2506 if (be->button == 3) {
2507 if (screen->getWindowZones() == 4 &&
2508 be->y < (signed) frame.height / 2) {
2509 resize_zone = ZoneTop;
2511 resize_zone = ZoneBottom;
2513 if (screen->getWindowZones() >= 2 &&
2514 be->x < (signed) frame.width / 2) {
2515 resize_zone |= ZoneLeft;
2517 resize_zone |= ZoneRight;
2520 // control + left click on the titlebar shades the window
2521 } else if (be->state == ControlMask && be->button == 1) {
2522 if (be->window == frame.title ||
2523 be->window == frame.label)
2526 } else if (be->state == 0 && be->button == 1) {
2527 if (windowmenu && windowmenu->isVisible())
2530 if (be->window == frame.maximize_button) {
2531 redrawMaximizeButton(True);
2532 } else if (be->window == frame.iconify_button) {
2533 redrawIconifyButton(True);
2534 } else if (be->window == frame.close_button) {
2535 redrawCloseButton(True);
2536 } else if (be->window == frame.plate) {
2537 XAllowEvents(display, ReplayPointer, be->time);
2538 } else if (be->window == frame.title ||
2539 be->window == frame.label) {
2540 // shade the window when the titlebar is double clicked
2541 if ( (be->time - lastButtonPressTime) <=
2542 openbox.getDoubleClickInterval()) {
2543 lastButtonPressTime = 0;
2546 lastButtonPressTime = be->time;
2548 // clicking and dragging on the titlebar moves the window, so on a click
2549 // we need to save the coords of the click in case the user drags
2550 frame.grab_x = be->x_root - frame.x - frame.border_w;
2551 frame.grab_y = be->y_root - frame.y - frame.border_w;
2552 } else if (be->window == frame.handle ||
2553 be->window == frame.left_grip ||
2554 be->window == frame.right_grip ||
2555 be->window == frame.window) {
2556 // clicking and dragging on the window's frame moves the window, so on a
2557 // click we need to save the coords of the click in case the user drags
2558 frame.grab_x = be->x_root - frame.x - frame.border_w;
2559 frame.grab_y = be->y_root - frame.y - frame.border_w;
2560 if (be->window == frame.left_grip)
2561 resize_zone = ZoneBottom | ZoneLeft;
2562 else if (be->window == frame.right_grip)
2563 resize_zone = ZoneBottom | ZoneRight;
2566 } else if (be->state == 0 && be->button == 2) {
2567 if (be->window == frame.maximize_button) {
2568 redrawMaximizeButton(True);
2569 // a middle click anywhere on the window's frame except for on the buttons
2570 // will lower the window
2571 } else if (! (be->window == frame.iconify_button ||
2572 be->window == frame.close_button) ) {
2576 } else if (be->state == 0 && be->button == 3) {
2577 if (be->window == frame.maximize_button) {
2578 redrawMaximizeButton(True);
2579 // a right click on the window's frame will show or hide the window's
2581 } else if (be->window == frame.title ||
2582 be->window == frame.label ||
2583 be->window == frame.handle ||
2584 be->window == frame.window) {
2587 if (windowmenu->isVisible()) {
2590 // get the coords for the menu
2591 mx = be->x_root - windowmenu->getWidth() / 2;
2592 if (be->window == frame.title || be->window == frame.label) {
2593 my = frame.y + frame.title_h;
2594 } else if (be->window == frame.handle) {
2595 my = frame.y + frame.y_handle - windowmenu->getHeight();
2596 } else { // (be->window == frame.window)
2597 if (be->y <= (signed) frame.bevel_w) {
2598 my = frame.y + frame.y_border;
2600 my = be->y_root - (windowmenu->getHeight() / 2);
2604 if (mx > (signed) (frame.x + frame.width -
2605 windowmenu->getWidth())) {
2606 mx = frame.x + frame.width - windowmenu->getWidth();
2607 } else if (mx < frame.x) {
2611 if (my > (signed) (frame.y + frame.y_handle -
2612 windowmenu->getHeight())) {
2613 my = frame.y + frame.y_handle - windowmenu->getHeight();
2614 } else if (my < (signed) (frame.y +
2615 ((decorations.titlebar) ? frame.title_h : frame.y_border))) {
2617 ((decorations.titlebar) ? frame.title_h : frame.y_border);
2620 windowmenu->move(mx, my);
2622 XRaiseWindow(display, windowmenu->getWindowID());
2623 XRaiseWindow(display, windowmenu->getSendToMenu()->getWindowID());
2624 stack_change = 0; // dont raise the window overtop of the menu
2629 } else if (be->state == 0 && be->button == 4) {
2630 if ((be->window == frame.label ||
2631 be->window == frame.title) &&
2635 } else if (be->state == 0 && be->button == 5) {
2636 if ((be->window == frame.label ||
2637 be->window == frame.title) &&
2642 if (! (flags.focused || screen->sloppyFocus()) ) {
2643 setInputFocus(); // any click focus' the window in 'click to focus'
2645 if (stack_change < 0) {
2646 screen->getWorkspace(workspace_number)->lowerWindow(this);
2647 } else if (stack_change > 0) {
2648 screen->getWorkspace(workspace_number)->raiseWindow(this);
2655 void OpenboxWindow::buttonReleaseEvent(XButtonEvent *re) {
2657 if (! validateClient())
2660 // alt + middle button released
2661 if (re->state == (Mod1Mask & Button2Mask) && re->button == 2) {
2662 if (re->window == frame.window) {
2663 XUngrabPointer(display, CurrentTime); // why? i dont know
2665 // left button released
2666 } else if (re->button == 1) {
2667 if (re->window == frame.maximize_button) {
2668 if (re->state == Button1Mask && // only the left button was depressed
2669 (re->x >= 0) && ((unsigned) re->x <= frame.button_w) &&
2670 (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) {
2671 maximize(re->button);
2673 redrawMaximizeButton(False);
2675 } else if (re->window == frame.iconify_button) {
2676 if (re->state == Button1Mask && // only the left button was depressed
2677 (re->x >= 0) && ((unsigned) re->x <= frame.button_w) &&
2678 (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) {
2681 redrawIconifyButton(False);
2683 } else if (re->window == frame.close_button) {
2684 if (re->state == Button1Mask && // only the left button was depressed
2685 (re->x >= 0) && ((unsigned) re->x <= frame.button_w) &&
2686 (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) {
2689 //we should always redraw the close button. some applications
2690 //eg. acroread don't honour the close.
2691 redrawCloseButton(False);
2693 // middle button released
2694 } else if (re->button == 2) {
2695 if (re->window == frame.maximize_button) {
2696 if (re->state == Button2Mask && // only the middle button was depressed
2697 (re->x >= 0) && ((unsigned) re->x <= frame.button_w) &&
2698 (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) {
2699 maximize(re->button);
2701 redrawMaximizeButton(False);
2704 // right button released
2705 } else if (re->button == 3) {
2706 if (re->window == frame.maximize_button) {
2707 if (re->state == Button3Mask && // only the right button was depressed
2708 (re->x >= 0) && ((unsigned) re->x <= frame.button_w) &&
2709 (re->y >= 0) && ((unsigned) re->y <= frame.button_h)) {
2710 maximize(re->button);
2712 redrawMaximizeButton(False);
2717 // when the window is being interactively moved, a button release stops the
2721 // when the window is being interactively resized, a button release stops the
2723 } else if (flags.resizing) {
2724 flags.resizing = False;
2725 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2726 frame.resize_x, frame.resize_y,
2727 frame.resize_w - 1, frame.resize_h - 1);
2728 screen->hideGeometry();
2729 if (resize_zone & ZoneLeft) {
2731 } else { // when resizing with "Alt+Button3", the resize is the same as if
2732 // done with the right grip (the right side of the window is what
2736 // unset maximized state when resized after fully maximized
2737 if (flags.maximized == 1) {
2740 configure(frame.resize_x, frame.resize_y,
2741 frame.resize_w - (frame.border_w * 2),
2742 frame.resize_h - (frame.border_w * 2));
2744 XUngrabPointer(display, CurrentTime);
2752 void OpenboxWindow::startMove(int x, int y) {
2753 ASSERT(!flags.moving);
2755 // make sure only one window is moving at a time
2756 OpenboxWindow *w = openbox.getMaskedWindow();
2757 if (w != (OpenboxWindow *) 0 && w->flags.moving)
2760 XGrabPointer(display, frame.window, False, PointerMotionMask |
2761 ButtonReleaseMask, GrabModeAsync, GrabModeAsync,
2762 None, openbox.getMoveCursor(), CurrentTime);
2764 if (windowmenu && windowmenu->isVisible())
2767 flags.moving = True;
2769 openbox.maskWindowEvents(client.window, this);
2771 if (! screen->opaqueMove()) {
2774 frame.move_x = frame.x;
2775 frame.move_y = frame.y;
2776 frame.resize_w = frame.width + (frame.border_w * 2);
2777 frame.resize_h = ((flags.shaded) ? frame.title_h : frame.height) +
2778 (frame.border_w * 2);
2780 screen->showPosition(frame.x, frame.y);
2782 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2783 frame.move_x, frame.move_y,
2784 frame.resize_w - 1, frame.resize_h - 1);
2786 frame.grab_x = x - frame.x - frame.border_w;
2787 frame.grab_y = y - frame.y - frame.border_w;
2791 void OpenboxWindow::doMove(int x, int y) {
2792 ASSERT(flags.moving);
2794 int dx = x - frame.grab_x, dy = y - frame.grab_y;
2796 dx -= frame.border_w;
2797 dy -= frame.border_w;
2799 int snap_distance = screen->edgeSnapThreshold();
2800 // width/height of the snapping window
2801 unsigned int snap_w = frame.width + (frame.border_w * 2);
2802 unsigned int snap_h = area().h() + (frame.border_w * 2);
2803 if (snap_distance) {
2804 int drx = screen->size().w() - (dx + snap_w);
2806 if (dx < drx && (dx > 0 && dx < snap_distance) ||
2807 (dx < 0 && dx > -snap_distance) )
2809 else if ( (drx > 0 && drx < snap_distance) ||
2810 (drx < 0 && drx > -snap_distance) )
2811 dx = screen->size().w() - snap_w;
2813 int dtty, dbby, dty, dby;
2814 switch (screen->getToolbar()->placement()) {
2815 case Toolbar::TopLeft:
2816 case Toolbar::TopCenter:
2817 case Toolbar::TopRight:
2818 dtty = screen->getToolbar()->getExposedHeight() +
2820 dbby = screen->size().h();
2825 dbby = screen->getToolbar()->area().y();
2830 dby = dbby - (dy + snap_h);
2832 if ( (dy > 0 && dty < snap_distance) ||
2833 (dy < 0 && dty > -snap_distance) )
2835 else if ( (dby > 0 && dby < snap_distance) ||
2836 (dby < 0 && dby > -snap_distance) )
2840 if (screen->opaqueMove()) {
2841 configure(dx, dy, frame.width, frame.height);
2843 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2844 frame.move_x, frame.move_y, frame.resize_w - 1,
2845 frame.resize_h - 1);
2850 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2851 frame.move_x, frame.move_y, frame.resize_w - 1,
2852 frame.resize_h - 1);
2855 screen->showPosition(dx, dy);
2859 void OpenboxWindow::endMove() {
2860 ASSERT(flags.moving);
2862 flags.moving = False;
2864 openbox.maskWindowEvents(0, (OpenboxWindow *) 0);
2865 if (!screen->opaqueMove()) {
2866 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2867 frame.move_x, frame.move_y, frame.resize_w - 1,
2868 frame.resize_h - 1);
2870 configure(frame.move_x, frame.move_y, frame.width, frame.height);
2873 configure(frame.x, frame.y, frame.width, frame.height);
2875 screen->hideGeometry();
2876 XUngrabPointer(display, CurrentTime);
2877 // if there are any left over motions from the move, drop them now cuz they
2880 while (XCheckTypedWindowEvent(display, frame.window, MotionNotify, &e));
2884 void OpenboxWindow::motionNotifyEvent(XMotionEvent *me) {
2886 doMove(me->x_root, me->y_root);
2887 else if (!flags.resizing && (me->state & Button1Mask) && functions.move &&
2888 (frame.title == me->window || frame.label == me->window ||
2889 frame.handle == me->window || frame.window == me->window))
2890 startMove(me->x_root, me->y_root);
2891 else if (functions.resize &&
2892 (((me->state & Button1Mask) && (me->window == frame.right_grip ||
2893 me->window == frame.left_grip)) ||
2894 (me->state == (Mod1Mask | Button3Mask) &&
2895 me->window == frame.window))) {
2896 Bool left = resize_zone & ZoneLeft;
2898 if (! flags.resizing) {
2900 if (resize_zone & ZoneTop)
2901 cursor = (resize_zone & ZoneLeft) ?
2902 openbox.getUpperLeftAngleCursor() :
2903 openbox.getUpperRightAngleCursor();
2905 cursor = (resize_zone & ZoneLeft) ?
2906 openbox.getLowerLeftAngleCursor() :
2907 openbox.getLowerRightAngleCursor();
2908 XGrabPointer(display, me->window, False, ButtonMotionMask |
2909 ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None,
2910 cursor, CurrentTime);
2912 flags.resizing = True;
2917 if (resize_zone & ZoneRight)
2918 frame.grab_x = me->x - screen->getBorderWidth();
2920 frame.grab_x = me->x + screen->getBorderWidth();
2921 if (resize_zone & ZoneTop)
2922 frame.grab_y = me->y + screen->getBorderWidth() * 2;
2924 frame.grab_y = me->y - screen->getBorderWidth() * 2;
2925 frame.resize_x = frame.x;
2926 frame.resize_y = frame.y;
2927 frame.resize_w = frame.width + (frame.border_w * 2);
2928 frame.resize_h = frame.height + (frame.border_w * 2);
2931 left_fixsize(&gx, &gy);
2933 right_fixsize(&gx, &gy);
2935 screen->showGeometry(gx, gy);
2937 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2938 frame.resize_x, frame.resize_y,
2939 frame.resize_w - 1, frame.resize_h - 1);
2941 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2942 frame.resize_x, frame.resize_y,
2943 frame.resize_w - 1, frame.resize_h - 1);
2947 if (resize_zone & ZoneTop)
2948 frame.resize_h = frame.height - (me->y - frame.grab_y);
2950 frame.resize_h = frame.height + (me->y - frame.grab_y);
2951 if (frame.resize_h < 1) frame.resize_h = 1;
2954 frame.resize_x = me->x_root - frame.grab_x;
2955 if (frame.resize_x > (signed) (frame.x + frame.width))
2956 frame.resize_x = frame.resize_x + frame.width - 1;
2958 left_fixsize(&gx, &gy);
2960 frame.resize_w = frame.width + (me->x - frame.grab_x);
2961 if (frame.resize_w < 1) frame.resize_w = 1;
2963 right_fixsize(&gx, &gy);
2966 XDrawRectangle(display, screen->getRootWindow(), screen->getOpGC(),
2967 frame.resize_x, frame.resize_y,
2968 frame.resize_w - 1, frame.resize_h - 1);
2970 screen->showGeometry(gx, gy);
2977 void OpenboxWindow::shapeEvent(XShapeEvent *) {
2978 if (openbox.hasShapeExtensions()) {
2981 if (! validateClient()) return;
2982 XShapeCombineShape(display, frame.window, ShapeBounding,
2983 frame.mwm_border_w, frame.y_border +
2984 frame.mwm_border_w, client.window,
2985 ShapeBounding, ShapeSet);
2988 XRectangle xrect[2];
2989 xrect[0].x = xrect[0].y = 0;
2990 xrect[0].width = frame.width;
2991 xrect[0].height = frame.y_border;
2993 if (decorations.handle) {
2995 xrect[1].y = frame.y_handle;
2996 xrect[1].width = frame.width;
2997 xrect[1].height = frame.handle_h + frame.border_w;
3001 XShapeCombineRectangles(display, frame.window, ShapeBounding, 0, 0,
3002 xrect, num, ShapeUnion, Unsorted);
3010 bool OpenboxWindow::validateClient(void) {
3011 XSync(display, False);
3014 if (XCheckTypedWindowEvent(display, client.window, DestroyNotify, &e) ||
3015 XCheckTypedWindowEvent(display, client.window, UnmapNotify, &e)) {
3016 XPutBackEvent(display, &e);
3026 void OpenboxWindow::restore(void) {
3027 XChangeSaveSet(display, client.window, SetModeDelete);
3028 XSelectInput(display, client.window, NoEventMask);
3032 XUnmapWindow(display, frame.window);
3033 XUnmapWindow(display, client.window);
3035 XSetWindowBorderWidth(display, client.window, client.old_bw);
3036 XReparentWindow(display, client.window, screen->getRootWindow(),
3037 client.x, client.y);
3038 XMapWindow(display, client.window);
3046 void OpenboxWindow::timeout(void) {
3047 screen->getWorkspace(workspace_number)->raiseWindow(this);
3051 void OpenboxWindow::changeOpenboxHints(OpenboxHints *net) {
3052 if ((net->flags & AttribShaded) &&
3053 ((openbox_attrib.attrib & AttribShaded) !=
3054 (net->attrib & AttribShaded)))
3057 if (flags.visible && // watch out for requests when we can not be seen
3058 (net->flags & (AttribMaxVert | AttribMaxHoriz)) &&
3059 ((openbox_attrib.attrib & (AttribMaxVert | AttribMaxHoriz)) !=
3060 (net->attrib & (AttribMaxVert | AttribMaxHoriz)))) {
3061 if (flags.maximized) {
3066 if ((net->flags & AttribMaxHoriz) && (net->flags & AttribMaxVert))
3067 button = ((net->attrib & (AttribMaxHoriz | AttribMaxVert)) ? 1 : 0);
3068 else if (net->flags & AttribMaxVert)
3069 button = ((net->attrib & AttribMaxVert) ? 2 : 0);
3070 else if (net->flags & AttribMaxHoriz)
3071 button = ((net->attrib & AttribMaxHoriz) ? 3 : 0);
3077 if ((net->flags & AttribOmnipresent) &&
3078 ((openbox_attrib.attrib & AttribOmnipresent) !=
3079 (net->attrib & AttribOmnipresent)))
3082 if ((net->flags & AttribWorkspace) &&
3083 (workspace_number != (signed) net->workspace)) {
3084 screen->reassociateWindow(this, net->workspace, True);
3086 if (screen->getCurrentWorkspaceID() != (signed) net->workspace) withdraw();
3090 if (net->flags & AttribDecoration) {
3091 switch (net->decoration) {
3093 decorations.titlebar = decorations.border = decorations.handle =
3094 decorations.iconify = decorations.maximize = decorations.menu = False;
3100 decorations.titlebar = decorations.iconify = decorations.menu =
3101 decorations.border = True;
3102 decorations.handle = (functions.resize && !flags.transient);
3103 decorations.maximize = functions.maximize;
3108 decorations.titlebar = decorations.iconify = decorations.menu = True;
3109 decorations.border = decorations.border = decorations.handle = False;
3110 decorations.maximize = functions.maximize;
3115 decorations.titlebar = decorations.menu = True;
3116 decorations.iconify = decorations.border = False;
3117 decorations.handle = (functions.resize && !flags.transient);
3118 decorations.maximize = functions.maximize;
3123 XMapSubwindows(display, frame.window);
3124 XMapWindow(display, frame.window);
3128 setState(current_state);
3134 * Set the sizes of all components of the window frame
3135 * (the window decorations).
3136 * These values are based upon the current style settings and the client
3137 * window's dimentions.
3139 void OpenboxWindow::upsize(void) {
3140 frame.bevel_w = screen->getBevelWidth();
3142 if (decorations.border) {
3143 frame.border_w = screen->getBorderWidth();
3144 if (!flags.transient)
3145 frame.mwm_border_w = screen->getFrameWidth();
3147 frame.mwm_border_w = 0;
3149 frame.mwm_border_w = frame.border_w = 0;
3152 if (decorations.titlebar) {
3153 // the height of the titlebar is based upon the height of the font being
3154 // used to display the window's title
3155 WindowStyle *style = screen->getWindowStyle();
3156 if (i18n.multibyte())
3157 frame.title_h = (style->fontset_extents->max_ink_extent.height +
3158 (frame.bevel_w * 2) + 2);
3160 frame.title_h = (style->font->ascent + style->font->descent +
3161 (frame.bevel_w * 2) + 2);
3163 frame.label_h = frame.title_h - (frame.bevel_w * 2);
3164 frame.button_w = frame.button_h = (frame.label_h - 2);
3165 frame.y_border = frame.title_h + frame.border_w;
3169 frame.button_w = frame.button_h = 0;
3173 frame.border_h = client.height + frame.mwm_border_w * 2;
3175 if (decorations.handle) {
3176 frame.y_handle = frame.y_border + frame.border_h + frame.border_w;
3177 frame.grip_w = frame.button_w * 2;
3178 frame.grip_h = frame.handle_h = screen->getHandleWidth();
3180 frame.y_handle = frame.y_border + frame.border_h;
3182 frame.grip_w = frame.grip_h = 0;
3185 frame.width = client.width + (frame.mwm_border_w * 2);
3186 frame.height = frame.y_handle + frame.handle_h;
3191 * Set the size and position of the client window.
3192 * These values are based upon the current style settings and the frame
3193 * window's dimensions.
3195 void OpenboxWindow::downsize(void) {
3196 frame.y_handle = frame.height - frame.handle_h;
3197 frame.border_h = frame.y_handle - frame.y_border -
3198 (decorations.handle ? frame.border_w : 0);
3200 client.x = frame.x + frame.mwm_border_w + frame.border_w;
3201 client.y = frame.y + frame.y_border + frame.mwm_border_w + frame.border_w;
3203 client.width = frame.width - (frame.mwm_border_w * 2);
3204 client.height = frame.height - frame.y_border - (frame.mwm_border_w * 2)
3205 - frame.handle_h - (decorations.handle ? frame.border_w : 0);
3207 frame.y_handle = frame.border_h + frame.y_border + frame.border_w;
3211 void OpenboxWindow::right_fixsize(int *gx, int *gy) {
3212 // calculate the size of the client window and conform it to the
3213 // size specified by the size hints of the client window...
3214 int dx = 1 + frame.resize_w - client.base_width - (frame.mwm_border_w * 2) -
3215 (frame.border_w * 2) + (client.width_inc / 2);
3216 int dy = 1 + frame.resize_h - frame.y_border - client.base_height -
3217 frame.handle_h - (frame.border_w * 3) - (frame.mwm_border_w * 2)
3218 + (client.height_inc / 2);
3220 if (dx < (signed) client.min_width) dx = client.min_width;
3221 if (dy < (signed) client.min_height) dy = client.min_height;
3222 if ((unsigned) dx > client.max_width) dx = client.max_width;
3223 if ((unsigned) dy > client.max_height) dy = client.max_height;
3225 dx /= client.width_inc;
3226 dy /= client.height_inc;
3231 dx = (dx * client.width_inc) + client.base_width;
3232 dy = (dy * client.height_inc) + client.base_height;
3234 frame.resize_w = dx + (frame.mwm_border_w * 2) + (frame.border_w * 2) - 1;
3235 frame.resize_h = dy + frame.y_border + frame.handle_h +
3236 (frame.mwm_border_w * 2) + (frame.border_w * 3) - 1;
3237 if (resize_zone & ZoneTop)
3238 frame.resize_y = frame.y + frame.height - frame.resize_h +
3239 screen->getBorderWidth() * 2;
3243 void OpenboxWindow::left_fixsize(int *gx, int *gy) {
3244 // calculate the size of the client window and conform it to the
3245 // size specified by the size hints of the client window...
3246 int dx = 1 + frame.x + frame.width - frame.resize_x - client.base_width -
3247 (frame.mwm_border_w * 2) + (client.width_inc / 2);
3248 int dy = 1 + frame.resize_h - frame.y_border - client.base_height -
3249 frame.handle_h - (frame.border_w * 3) - (frame.mwm_border_w * 2)
3250 + (client.height_inc / 2);
3252 if (dx < (signed) client.min_width) dx = client.min_width;
3253 if (dy < (signed) client.min_height) dy = client.min_height;
3254 if ((unsigned) dx > client.max_width) dx = client.max_width;
3255 if ((unsigned) dy > client.max_height) dy = client.max_height;
3257 dx /= client.width_inc;
3258 dy /= client.height_inc;
3263 dx = (dx * client.width_inc) + client.base_width;
3264 dy = (dy * client.height_inc) + client.base_height;
3266 frame.resize_w = dx + (frame.mwm_border_w * 2) + (frame.border_w * 2) - 1;
3267 frame.resize_x = frame.x + frame.width - frame.resize_w +
3268 (frame.border_w * 2);
3269 frame.resize_h = dy + frame.y_border + frame.handle_h +
3270 (frame.mwm_border_w * 2) + (frame.border_w * 3) - 1;
3271 if (resize_zone & ZoneTop)
3272 frame.resize_y = frame.y + frame.height - frame.resize_h +
3273 screen->getBorderWidth() * 2;