1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
5 #endif // HAVE_CONFIG_H
9 #include <X11/keysym.h>
13 #endif // HAVE_STRING_H
18 # endif // HAVE_STDIO_H
23 #endif // HAVE_STDLIB_H
26 #include "blackbox.hh"
32 #include "bbwindow.hh"
33 #include "workspace.hh"
41 * Initializes the class with default values/the window's set initial values.
43 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
44 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
45 // sizeof(BlackboxWindow));
48 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
52 set timer to zero... it is initialized properly later, so we check
53 if timer is zero in the destructor, and assume that the window is not
54 fully constructed if timer is zero...
60 xatom
= blackbox
->getXAtom();
62 if (! validateClient()) {
67 // fetch client size and placement
68 XWindowAttributes wattrib
;
69 if (! XGetWindowAttributes(otk::OBDisplay::display
,
70 client
.window
, &wattrib
) ||
71 ! wattrib
.screen
|| wattrib
.override_redirect
) {
74 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
81 // set the eventmask early in the game so that we make sure we get
82 // all the events we are interested in
83 XSetWindowAttributes attrib_set
;
84 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
86 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
88 XChangeWindowAttributes(otk::OBDisplay::display
, client
.window
,
89 CWEventMask
|CWDontPropagate
, &attrib_set
);
91 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
92 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
93 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
94 flags
.skip_pager
= flags
.fullscreen
= False
;
97 blackbox_attrib
.workspace
= window_number
= BSENTINEL
;
99 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
= 0l;
100 blackbox_attrib
.decoration
= DecorNormal
;
101 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
102 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
105 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
106 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
=
107 frame
.stick_button
= None
;
108 frame
.right_grip
= frame
.left_grip
= None
;
110 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
111 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
112 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.uborder_pixel
=
113 frame
.fborder_pixel
= frame
.ugrip_pixel
= frame
.fgrip_pixel
= 0;
114 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
115 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
116 frame
.ugrip
= frame
.fgrip
= None
;
118 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
119 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
120 Decor_Iconify
| Decor_Maximize
;
122 client
.normal_hint_flags
= 0;
123 client
.window_group
= None
;
124 client
.transient_for
= 0;
126 current_state
= NormalState
;
129 set the initial size and location of client window (relative to the
130 _root window_). This position is the reference point used with the
131 window's gravity to find the window's initial position.
133 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
134 client
.old_bw
= wattrib
.border_width
;
136 lastButtonPressTime
= 0;
138 timer
= new otk::OBTimer(Openbox::instance
->timerManager(),
139 (otk::OBTimeoutHandler
)timeout
,
141 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
143 // get size, aspect, minimum/maximum size and other hints set by the
146 if (! getBlackboxHints())
153 frame
.window
= createToplevelWindow();
155 blackbox
->saveWindowSearch(frame
.window
, this);
157 frame
.plate
= createChildWindow(frame
.window
, ExposureMask
);
158 blackbox
->saveWindowSearch(frame
.plate
, this);
160 // determine if this is a transient window
163 // determine the window's type, so we can decide its decorations and
164 // functionality, or if we should not manage it at all
165 if (getWindowType()) {
166 // adjust the window decorations/behavior based on the window type
167 switch (window_type
) {
171 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
172 flags
.stuck
= True
; // we show up on all workspaces
174 // none of these windows are manipulated by the window manager
180 // these windows get less functionality
181 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
185 // dialogs cannot be maximized
186 functions
&= ~Func_Maximize
;
190 // normal windows retain all of the possible decorations and
198 // further adjeust the window's decorations/behavior based on window sizes
199 if ((client
.normal_hint_flags
& PMinSize
) &&
200 (client
.normal_hint_flags
& PMaxSize
) &&
201 client
.max_width
<= client
.min_width
&&
202 client
.max_height
<= client
.min_height
) {
203 functions
&= ~(Func_Resize
| Func_Maximize
);
210 if (decorations
& Decor_Titlebar
)
213 if (decorations
& Decor_Handle
)
216 // apply the size and gravity hint to the frame
220 bool place_window
= True
;
221 if (blackbox
->state() == Openbox::State_Starting
|| isTransient() ||
222 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
223 applyGravity(frame
.rect
);
225 if (blackbox
->state() == Openbox::State_Starting
||
226 client
.rect
.intersects(screen
->getRect()))
227 place_window
= False
;
230 // add the window's strut. note this is done *after* placing the window.
231 screen
->addStrut(&client
.strut
);
235 the server needs to be grabbed here to prevent client's from sending
236 events while we are in the process of configuring their window.
237 We hold the grab until after we are done moving the window around.
240 XGrabServer(otk::OBDisplay::display
);
242 associateClientWindow();
244 blackbox
->saveWindowSearch(client
.window
, this);
246 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
247 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
249 screen
->getWorkspace(blackbox_attrib
.workspace
)->
250 addWindow(this, place_window
);
252 if (! place_window
) {
253 // don't need to call configure if we are letting the workspace
255 configure(frame
.rect
.x(), frame
.rect
.y(),
256 frame
.rect
.width(), frame
.rect
.height());
262 XUngrabServer(otk::OBDisplay::display
);
265 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
269 // now that we know where to put the window and what it should look like
270 // we apply the decorations
275 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
277 // this ensures the title, buttons, and other decor are properly displayed
280 // preserve the window's initial state on first map, and its current state
282 unsigned long initial_state
= current_state
;
284 current_state
= initial_state
;
286 // get sticky state from our parent window if we've got one
287 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
288 client
.transient_for
->isStuck() != flags
.stuck
)
292 flags
.shaded
= False
;
293 initial_state
= current_state
;
297 At this point in the life of a window, current_state should only be set
298 to IconicState if the window was an *icon*, not if it was shaded.
300 if (initial_state
!= IconicState
)
301 current_state
= NormalState
;
309 if (flags
.maximized
&& (functions
& Func_Maximize
))
314 BlackboxWindow::~BlackboxWindow(void) {
316 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
320 if (! timer
) // window not managed...
326 screen
->removeStrut(&client
.strut
);
327 screen
->updateAvailableArea();
329 // We don't need to worry about resizing because resizing always grabs the X
330 // server. This should only ever happen if using opaque moving.
336 if (client
.window_group
) {
337 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
338 if (group
) group
->removeWindow(this);
341 // remove ourselves from our transient_for
343 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
344 client
.transient_for
->client
.transientList
.remove(this);
345 client
.transient_for
= (BlackboxWindow
*) 0;
348 if (client
.transientList
.size() > 0) {
349 // reset transient_for for all transients
350 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
351 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
352 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
362 blackbox
->removeWindowSearch(frame
.plate
);
363 XDestroyWindow(otk::OBDisplay::display
, frame
.plate
);
367 blackbox
->removeWindowSearch(frame
.window
);
368 XDestroyWindow(otk::OBDisplay::display
, frame
.window
);
371 blackbox
->removeWindowSearch(client
.window
);
375 void BlackboxWindow::enableDecor(bool enable
) {
376 blackbox_attrib
.flags
|= AttribDecoration
;
377 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
380 // we can not be shaded if we lack a titlebar
381 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
384 if (flags
.visible
&& frame
.window
) {
385 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
386 XMapWindow(otk::OBDisplay::display
, frame
.window
);
390 setState(current_state
);
394 void BlackboxWindow::setupDecor() {
395 if (blackbox_attrib
.decoration
!= DecorNone
) {
396 // start with everything on
397 decorations
= Decor_Close
|
398 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
399 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
400 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
401 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
402 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
404 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
405 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
406 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
407 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
409 switch (window_type
) {
414 // none of these windows are decorated by the window manager at all
420 decorations
&= ~(Decor_Border
);
424 decorations
&= ~Decor_Handle
;
436 * Creates a new top level window, with a given location, size, and border
438 * Returns: the newly created window
440 Window
BlackboxWindow::createToplevelWindow(void) {
441 XSetWindowAttributes attrib_create
;
442 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
443 CWOverrideRedirect
| CWEventMask
;
445 attrib_create
.background_pixmap
= None
;
446 attrib_create
.colormap
= screen
->getColormap();
447 attrib_create
.override_redirect
= True
;
448 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
|
451 We catch button presses because other wise they get passed down to the
452 root window, which will then cause root menus to show when you click the
456 return XCreateWindow(otk::OBDisplay::display
, screen
->getRootWindow(),
457 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
458 InputOutput
, screen
->getVisual(), create_mask
,
464 * Creates a child window, and optionally associates a given cursor with
467 Window
BlackboxWindow::createChildWindow(Window parent
,
468 unsigned long event_mask
,
470 XSetWindowAttributes attrib_create
;
471 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
474 attrib_create
.background_pixmap
= None
;
475 attrib_create
.event_mask
= event_mask
;
478 create_mask
|= CWCursor
;
479 attrib_create
.cursor
= cursor
;
482 return XCreateWindow(otk::OBDisplay::display
, parent
, 0, 0, 1, 1, 0,
483 screen
->getDepth(), InputOutput
, screen
->getVisual(),
484 create_mask
, &attrib_create
);
488 void BlackboxWindow::associateClientWindow(void) {
489 XSetWindowBorderWidth(otk::OBDisplay::display
, client
.window
, 0);
493 XChangeSaveSet(otk::OBDisplay::display
, client
.window
, SetModeInsert
);
495 XSelectInput(otk::OBDisplay::display
, frame
.plate
, SubstructureRedirectMask
);
498 note we used to grab around this call to XReparentWindow however the
499 server is now grabbed before this method is called
501 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
503 XSelectInput(otk::OBDisplay::display
, client
.window
,
504 event_mask
& ~StructureNotifyMask
);
505 XReparentWindow(otk::OBDisplay::display
, client
.window
, frame
.plate
, 0, 0);
506 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
508 XRaiseWindow(otk::OBDisplay::display
, frame
.plate
);
509 XMapSubwindows(otk::OBDisplay::display
, frame
.plate
);
512 if (blackbox
->hasShapeExtensions()) {
513 XShapeSelectInput(otk::OBDisplay::display
, client
.window
,
520 XShapeQueryExtents(otk::OBDisplay::display
, client
.window
, &shaped
,
521 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
523 flags
.shaped
= shaped
;
529 void BlackboxWindow::decorate(void) {
530 otk::BTexture
* texture
;
532 texture
= &(screen
->getWindowStyle()->b_focus
);
533 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
536 frame
.fbutton_pixel
= texture
->color().pixel();
538 texture
= &(screen
->getWindowStyle()->b_unfocus
);
539 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
542 frame
.ubutton_pixel
= texture
->color().pixel();
544 unsigned char needsPressed
= 0;
546 texture
= &(screen
->getWindowStyle()->b_pressed_focus
);
548 if (texture
->texture() != otk::BTexture::NoTexture
) {
549 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
551 if (! frame
.pfbutton
)
552 frame
.pfbutton_pixel
= texture
->color().pixel();
557 texture
= &(screen
->getWindowStyle()->b_pressed_unfocus
);
559 if (texture
->texture() != otk::BTexture::NoTexture
) {
560 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
562 if (! frame
.pubutton
)
563 frame
.pubutton
= texture
->color().pixel();
568 // if we either pressed unfocused, or pressed focused were undefined,
569 // make them inherit from the old resource. It's a hack for sure, but
570 // it allows for some backwards and forwards compatibility.
572 texture
= &(screen
->getWindowStyle()->b_pressed
);
574 if (needsPressed
& 0x1) {
575 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
577 if (! frame
.pfbutton
)
578 frame
.pfbutton_pixel
= texture
->color().pixel();
580 if (needsPressed
& 0x2) {
581 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
583 if (! frame
.pubutton
)
584 frame
.pubutton
= texture
->color().pixel();
589 if (decorations
& Decor_Titlebar
) {
590 texture
= &(screen
->getWindowStyle()->t_focus
);
591 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
594 frame
.ftitle_pixel
= texture
->color().pixel();
596 texture
= &(screen
->getWindowStyle()->t_unfocus
);
597 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
600 frame
.utitle_pixel
= texture
->color().pixel();
602 XSetWindowBorder(otk::OBDisplay::display
, frame
.title
,
603 screen
->getBorderColor()->pixel());
608 if (decorations
& Decor_Border
) {
609 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.color().pixel();
610 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().pixel();
613 if (decorations
& Decor_Handle
) {
614 texture
= &(screen
->getWindowStyle()->h_focus
);
615 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
618 frame
.fhandle_pixel
= texture
->color().pixel();
620 texture
= &(screen
->getWindowStyle()->h_unfocus
);
621 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
624 frame
.uhandle_pixel
= texture
->color().pixel();
626 texture
= &(screen
->getWindowStyle()->g_focus
);
627 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
629 frame
.fgrip_pixel
= texture
->color().pixel();
631 texture
= &(screen
->getWindowStyle()->g_unfocus
);
632 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
634 frame
.ugrip_pixel
= texture
->color().pixel();
636 XSetWindowBorder(otk::OBDisplay::display
, frame
.handle
,
637 screen
->getBorderColor()->pixel());
638 XSetWindowBorder(otk::OBDisplay::display
, frame
.left_grip
,
639 screen
->getBorderColor()->pixel());
640 XSetWindowBorder(otk::OBDisplay::display
, frame
.right_grip
,
641 screen
->getBorderColor()->pixel());
644 XSetWindowBorder(otk::OBDisplay::display
, frame
.window
,
645 screen
->getBorderColor()->pixel());
649 void BlackboxWindow::decorateLabel(void) {
650 otk::BTexture
*texture
;
652 texture
= &(screen
->getWindowStyle()->l_focus
);
653 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
655 frame
.flabel_pixel
= texture
->color().pixel();
657 texture
= &(screen
->getWindowStyle()->l_unfocus
);
658 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
660 frame
.ulabel_pixel
= texture
->color().pixel();
664 void BlackboxWindow::createHandle(void) {
665 frame
.handle
= createChildWindow(frame
.window
,
666 ButtonPressMask
| ButtonReleaseMask
|
667 ButtonMotionMask
| ExposureMask
);
668 blackbox
->saveWindowSearch(frame
.handle
, this);
671 createChildWindow(frame
.handle
,
672 ButtonPressMask
| ButtonReleaseMask
|
673 ButtonMotionMask
| ExposureMask
,
674 blackbox
->getLowerLeftAngleCursor());
675 blackbox
->saveWindowSearch(frame
.left_grip
, this);
678 createChildWindow(frame
.handle
,
679 ButtonPressMask
| ButtonReleaseMask
|
680 ButtonMotionMask
| ExposureMask
,
681 blackbox
->getLowerRightAngleCursor());
682 blackbox
->saveWindowSearch(frame
.right_grip
, this);
686 void BlackboxWindow::destroyHandle(void) {
688 screen
->getImageControl()->removeImage(frame
.fhandle
);
691 screen
->getImageControl()->removeImage(frame
.uhandle
);
694 screen
->getImageControl()->removeImage(frame
.fgrip
);
697 screen
->getImageControl()->removeImage(frame
.ugrip
);
699 blackbox
->removeWindowSearch(frame
.left_grip
);
700 blackbox
->removeWindowSearch(frame
.right_grip
);
702 XDestroyWindow(otk::OBDisplay::display
, frame
.left_grip
);
703 XDestroyWindow(otk::OBDisplay::display
, frame
.right_grip
);
704 frame
.left_grip
= frame
.right_grip
= None
;
706 blackbox
->removeWindowSearch(frame
.handle
);
707 XDestroyWindow(otk::OBDisplay::display
, frame
.handle
);
712 void BlackboxWindow::createTitlebar(void) {
713 frame
.title
= createChildWindow(frame
.window
,
714 ButtonPressMask
| ButtonReleaseMask
|
715 ButtonMotionMask
| ExposureMask
);
716 frame
.label
= createChildWindow(frame
.title
,
717 ButtonPressMask
| ButtonReleaseMask
|
718 ButtonMotionMask
| ExposureMask
);
719 blackbox
->saveWindowSearch(frame
.title
, this);
720 blackbox
->saveWindowSearch(frame
.label
, this);
722 if (decorations
& Decor_Iconify
) createIconifyButton();
723 if (decorations
& Decor_Maximize
) createMaximizeButton();
724 if (decorations
& Decor_Close
) createCloseButton();
728 void BlackboxWindow::destroyTitlebar(void) {
729 if (frame
.close_button
)
730 destroyCloseButton();
732 if (frame
.iconify_button
)
733 destroyIconifyButton();
735 if (frame
.maximize_button
)
736 destroyMaximizeButton();
738 if (frame
.stick_button
)
739 destroyStickyButton();
742 screen
->getImageControl()->removeImage(frame
.ftitle
);
745 screen
->getImageControl()->removeImage(frame
.utitle
);
748 screen
->getImageControl()->removeImage(frame
.flabel
);
751 screen
->getImageControl()->removeImage(frame
.ulabel
);
754 screen
->getImageControl()->removeImage(frame
.fbutton
);
757 screen
->getImageControl()->removeImage(frame
.ubutton
);
759 blackbox
->removeWindowSearch(frame
.title
);
760 blackbox
->removeWindowSearch(frame
.label
);
762 XDestroyWindow(otk::OBDisplay::display
, frame
.label
);
763 XDestroyWindow(otk::OBDisplay::display
, frame
.title
);
764 frame
.title
= frame
.label
= None
;
768 void BlackboxWindow::createCloseButton(void) {
769 if (frame
.title
!= None
) {
770 frame
.close_button
= createChildWindow(frame
.title
,
773 ButtonMotionMask
| ExposureMask
);
774 blackbox
->saveWindowSearch(frame
.close_button
, this);
779 void BlackboxWindow::destroyCloseButton(void) {
780 blackbox
->removeWindowSearch(frame
.close_button
);
781 XDestroyWindow(otk::OBDisplay::display
, frame
.close_button
);
782 frame
.close_button
= None
;
786 void BlackboxWindow::createIconifyButton(void) {
787 if (frame
.title
!= None
) {
788 frame
.iconify_button
= createChildWindow(frame
.title
,
791 ButtonMotionMask
| ExposureMask
);
792 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
797 void BlackboxWindow::destroyIconifyButton(void) {
798 blackbox
->removeWindowSearch(frame
.iconify_button
);
799 XDestroyWindow(otk::OBDisplay::display
, frame
.iconify_button
);
800 frame
.iconify_button
= None
;
804 void BlackboxWindow::createMaximizeButton(void) {
805 if (frame
.title
!= None
) {
806 frame
.maximize_button
= createChildWindow(frame
.title
,
809 ButtonMotionMask
| ExposureMask
);
810 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
815 void BlackboxWindow::destroyMaximizeButton(void) {
816 blackbox
->removeWindowSearch(frame
.maximize_button
);
817 XDestroyWindow(otk::OBDisplay::display
, frame
.maximize_button
);
818 frame
.maximize_button
= None
;
821 void BlackboxWindow::createStickyButton(void) {
822 if (frame
.title
!= None
) {
823 frame
.stick_button
= createChildWindow(frame
.title
,
826 ButtonMotionMask
| ExposureMask
);
827 blackbox
->saveWindowSearch(frame
.stick_button
, this);
831 void BlackboxWindow::destroyStickyButton(void) {
832 blackbox
->removeWindowSearch(frame
.stick_button
);
833 XDestroyWindow(otk::OBDisplay::display
, frame
.stick_button
);
834 frame
.stick_button
= None
;
837 void BlackboxWindow::positionButtons(bool redecorate_label
) {
838 string layout
= blackbox
->getTitlebarLayout();
841 bool hasclose
, hasiconify
, hasmaximize
, haslabel
, hasstick
;
842 hasclose
= hasiconify
= hasmaximize
= haslabel
= hasstick
= false;
844 string::const_iterator it
, end
;
845 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
848 if (! hasclose
&& (decorations
& Decor_Close
)) {
854 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
866 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
880 if (! hasclose
&& frame
.close_button
)
881 destroyCloseButton();
882 if (! hasiconify
&& frame
.iconify_button
)
883 destroyIconifyButton();
884 if (! hasmaximize
&& frame
.maximize_button
)
885 destroyMaximizeButton();
886 if (! hasstick
&& frame
.stick_button
)
887 destroyStickyButton();
889 parsed
+= 'L'; // require that the label be in the layout
891 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
892 const unsigned int by
= frame
.bevel_w
+ 1;
893 const unsigned int ty
= frame
.bevel_w
;
895 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
896 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
898 unsigned int x
= bsep
;
899 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
902 if (! frame
.close_button
) createCloseButton();
903 XMoveResizeWindow(otk::OBDisplay::display
, frame
.close_button
, x
, by
,
904 frame
.button_w
, frame
.button_w
);
905 x
+= frame
.button_w
+ bsep
;
908 if (! frame
.iconify_button
) createIconifyButton();
909 XMoveResizeWindow(otk::OBDisplay::display
, frame
.iconify_button
, x
, by
,
910 frame
.button_w
, frame
.button_w
);
911 x
+= frame
.button_w
+ bsep
;
914 if (! frame
.stick_button
) createStickyButton();
915 XMoveResizeWindow(otk::OBDisplay::display
, frame
.stick_button
, x
, by
,
916 frame
.button_w
, frame
.button_w
);
917 x
+= frame
.button_w
+ bsep
;
920 if (! frame
.maximize_button
) createMaximizeButton();
921 XMoveResizeWindow(otk::OBDisplay::display
, frame
.maximize_button
, x
, by
,
922 frame
.button_w
, frame
.button_w
);
923 x
+= frame
.button_w
+ bsep
;
926 XMoveResizeWindow(otk::OBDisplay::display
, frame
.label
, x
, ty
,
927 frame
.label_w
, frame
.label_h
);
928 x
+= frame
.label_w
+ bsep
;
933 if (redecorate_label
) decorateLabel();
939 void BlackboxWindow::reconfigure(void) {
940 restoreGravity(client
.rect
);
942 applyGravity(frame
.rect
);
952 void BlackboxWindow::grabButtons(void) {
953 mod_mask
= blackbox
->getMouseModMask();
955 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
956 // grab button 1 for changing focus/raising
957 otk::OBDisplay::grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
958 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
959 screen
->allowScrollLock());
961 if (functions
& Func_Move
)
962 otk::OBDisplay::grabButton(Button1
, mod_mask
, frame
.window
, True
,
963 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
964 GrabModeAsync
, frame
.window
, None
,
965 screen
->allowScrollLock());
966 if (functions
& Func_Resize
)
967 otk::OBDisplay::grabButton(Button3
, mod_mask
, frame
.window
, True
,
968 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
969 GrabModeAsync
, frame
.window
, None
,
970 screen
->allowScrollLock());
971 // alt+middle lowers the window
972 otk::OBDisplay::grabButton(Button2
, mod_mask
, frame
.window
, True
,
973 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
974 frame
.window
, None
, screen
->allowScrollLock());
978 void BlackboxWindow::ungrabButtons(void) {
979 otk::OBDisplay::ungrabButton(Button1
, 0, frame
.plate
);
980 otk::OBDisplay::ungrabButton(Button1
, mod_mask
, frame
.window
);
981 otk::OBDisplay::ungrabButton(Button2
, mod_mask
, frame
.window
);
982 otk::OBDisplay::ungrabButton(Button3
, mod_mask
, frame
.window
);
986 void BlackboxWindow::positionWindows(void) {
987 XMoveResizeWindow(otk::OBDisplay::display
, frame
.window
,
988 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
989 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
990 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.window
,
992 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.plate
,
994 XMoveResizeWindow(otk::OBDisplay::display
, frame
.plate
,
995 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
996 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
997 client
.rect
.width(), client
.rect
.height());
998 XMoveResizeWindow(otk::OBDisplay::display
, client
.window
,
999 0, 0, client
.rect
.width(), client
.rect
.height());
1000 // ensure client.rect contains the real location
1001 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1002 frame
.rect
.top() + frame
.margin
.top
);
1004 if (decorations
& Decor_Titlebar
) {
1005 if (frame
.title
== None
) createTitlebar();
1007 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.title
,
1009 XMoveResizeWindow(otk::OBDisplay::display
, frame
.title
, -frame
.border_w
,
1010 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
1013 XMapSubwindows(otk::OBDisplay::display
, frame
.title
);
1014 XMapWindow(otk::OBDisplay::display
, frame
.title
);
1015 } else if (frame
.title
) {
1018 if (decorations
& Decor_Handle
) {
1019 if (frame
.handle
== None
) createHandle();
1020 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.handle
,
1022 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.left_grip
,
1024 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.right_grip
,
1027 // use client.rect here so the value is correct even if shaded
1028 XMoveResizeWindow(otk::OBDisplay::display
, frame
.handle
,
1030 client
.rect
.height() + frame
.margin
.top
+
1031 frame
.mwm_border_w
- frame
.border_w
,
1032 frame
.inside_w
, frame
.handle_h
);
1033 XMoveResizeWindow(otk::OBDisplay::display
, frame
.left_grip
,
1034 -frame
.border_w
, -frame
.border_w
,
1035 frame
.grip_w
, frame
.handle_h
);
1036 XMoveResizeWindow(otk::OBDisplay::display
, frame
.right_grip
,
1037 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
1038 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
1040 XMapSubwindows(otk::OBDisplay::display
, frame
.handle
);
1041 XMapWindow(otk::OBDisplay::display
, frame
.handle
);
1042 } else if (frame
.handle
) {
1045 XSync(otk::OBDisplay::display
, False
);
1049 void BlackboxWindow::updateStrut(void) {
1050 unsigned long num
= 4;
1051 unsigned long *data
;
1052 if (! xatom
->get(client
.window
, otk::OBProperty::net_wm_strut
,
1053 otk::OBProperty::Atom_Cardinal
,
1058 client
.strut
.left
= data
[0];
1059 client
.strut
.right
= data
[1];
1060 client
.strut
.top
= data
[2];
1061 client
.strut
.bottom
= data
[3];
1063 screen
->updateAvailableArea();
1070 bool BlackboxWindow::getWindowType(void) {
1071 window_type
= (WindowType
) -1;
1074 unsigned long num
= (unsigned) -1;
1075 if (xatom
->get(client
.window
, otk::OBProperty::net_wm_window_type
,
1076 otk::OBProperty::Atom_Atom
,
1078 for (unsigned long i
= 0; i
< num
; ++i
) {
1079 if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_desktop
))
1080 window_type
= Type_Desktop
;
1081 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_dock
))
1082 window_type
= Type_Dock
;
1083 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_toolbar
))
1084 window_type
= Type_Toolbar
;
1085 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_menu
))
1086 window_type
= Type_Menu
;
1087 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_utility
))
1088 window_type
= Type_Utility
;
1089 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_splash
))
1090 window_type
= Type_Splash
;
1091 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_dialog
))
1092 window_type
= Type_Dialog
;
1093 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_normal
))
1094 window_type
= Type_Normal
;
1096 xatom
->atom(otk::OBProperty::kde_net_wm_window_type_override
))
1097 mwm_decorations
= 0; // prevent this window from getting any decor
1102 if (window_type
== (WindowType
) -1) {
1104 * the window type hint was not set, which means we either classify ourself
1105 * as a normal window or a dialog, depending on if we are a transient.
1108 window_type
= Type_Dialog
;
1110 window_type
= Type_Normal
;
1119 void BlackboxWindow::getWMName(void) {
1120 if (xatom
->get(client
.window
, otk::OBProperty::net_wm_name
,
1121 otk::OBProperty::utf8
, &client
.title
) &&
1122 !client
.title
.empty()) {
1123 xatom
->erase(client
.window
, otk::OBProperty::net_wm_visible_name
);
1126 //fall through to using WM_NAME
1127 if (xatom
->get(client
.window
, otk::OBProperty::wm_name
,
1128 otk::OBProperty::ascii
, &client
.title
)
1129 && !client
.title
.empty()) {
1130 xatom
->erase(client
.window
, otk::OBProperty::net_wm_visible_name
);
1133 // fall back to an internal default
1134 client
.title
= "Unnamed";
1135 xatom
->set(client
.window
, otk::OBProperty::net_wm_visible_name
,
1136 otk::OBProperty::utf8
, client
.title
);
1138 #ifdef DEBUG_WITH_ID
1139 // the 16 is the 8 chars of the debug text plus the number
1140 char *tmp
= new char[client
.title
.length() + 16];
1141 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1148 void BlackboxWindow::getWMIconName(void) {
1149 if (xatom
->get(client
.window
, otk::OBProperty::net_wm_icon_name
,
1150 otk::OBProperty::utf8
, &client
.icon_title
) &&
1151 !client
.icon_title
.empty()) {
1152 xatom
->erase(client
.window
, otk::OBProperty::net_wm_visible_icon_name
);
1155 //fall through to using WM_ICON_NAME
1156 if (xatom
->get(client
.window
, otk::OBProperty::wm_icon_name
,
1157 otk::OBProperty::ascii
,
1158 &client
.icon_title
) &&
1159 !client
.icon_title
.empty()) {
1160 xatom
->erase(client
.window
, otk::OBProperty::net_wm_visible_icon_name
);
1163 // fall back to using the main name
1164 client
.icon_title
= client
.title
;
1165 xatom
->set(client
.window
, otk::OBProperty::net_wm_visible_icon_name
,
1166 otk::OBProperty::utf8
,
1172 * Retrieve which WM Protocols are supported by the client window.
1173 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1174 * window's decorations and allow the close behavior.
1175 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1178 void BlackboxWindow::getWMProtocols(void) {
1182 if (XGetWMProtocols(otk::OBDisplay::display
, client
.window
,
1183 &proto
, &num_return
)) {
1184 for (int i
= 0; i
< num_return
; ++i
) {
1185 if (proto
[i
] == xatom
->atom(otk::OBProperty::wm_delete_window
)) {
1186 decorations
|= Decor_Close
;
1187 functions
|= Func_Close
;
1188 } else if (proto
[i
] == xatom
->atom(otk::OBProperty::wm_take_focus
))
1189 flags
.send_focus_message
= True
;
1198 * Gets the value of the WM_HINTS property.
1199 * If the property is not set, then use a set of default values.
1201 void BlackboxWindow::getWMHints(void) {
1202 focus_mode
= F_Passive
;
1204 // remove from current window group
1205 if (client
.window_group
) {
1206 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1207 if (group
) group
->removeWindow(this);
1209 client
.window_group
= None
;
1211 XWMHints
*wmhint
= XGetWMHints(otk::OBDisplay::display
, client
.window
);
1216 if (wmhint
->flags
& InputHint
) {
1217 if (wmhint
->input
== True
) {
1218 if (flags
.send_focus_message
)
1219 focus_mode
= F_LocallyActive
;
1221 if (flags
.send_focus_message
)
1222 focus_mode
= F_GloballyActive
;
1224 focus_mode
= F_NoInput
;
1228 if (wmhint
->flags
& StateHint
)
1229 current_state
= wmhint
->initial_state
;
1231 if (wmhint
->flags
& WindowGroupHint
) {
1232 client
.window_group
= wmhint
->window_group
;
1234 // add window to the appropriate group
1235 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1236 if (! group
) { // no group found, create it!
1237 new BWindowGroup(blackbox
, client
.window_group
);
1238 group
= blackbox
->searchGroup(client
.window_group
);
1241 group
->addWindow(this);
1249 * Gets the value of the WM_NORMAL_HINTS property.
1250 * If the property is not set, then use a set of default values.
1252 void BlackboxWindow::getWMNormalHints(void) {
1254 XSizeHints sizehint
;
1256 client
.min_width
= client
.min_height
=
1257 client
.width_inc
= client
.height_inc
= 1;
1258 client
.base_width
= client
.base_height
= 0;
1259 client
.win_gravity
= NorthWestGravity
;
1261 client
.min_aspect_x
= client
.min_aspect_y
=
1262 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1265 // don't limit the size of a window, the default max width is the biggest
1267 client
.max_width
= (unsigned) -1;
1268 client
.max_height
= (unsigned) -1;
1271 if (! XGetWMNormalHints(otk::OBDisplay::display
, client
.window
,
1272 &sizehint
, &icccm_mask
))
1275 client
.normal_hint_flags
= sizehint
.flags
;
1277 if (sizehint
.flags
& PMinSize
) {
1278 if (sizehint
.min_width
>= 0)
1279 client
.min_width
= sizehint
.min_width
;
1280 if (sizehint
.min_height
>= 0)
1281 client
.min_height
= sizehint
.min_height
;
1284 if (sizehint
.flags
& PMaxSize
) {
1285 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1286 client
.max_width
= sizehint
.max_width
;
1288 client
.max_width
= client
.min_width
;
1290 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1291 client
.max_height
= sizehint
.max_height
;
1293 client
.max_height
= client
.min_height
;
1296 if (sizehint
.flags
& PResizeInc
) {
1297 client
.width_inc
= sizehint
.width_inc
;
1298 client
.height_inc
= sizehint
.height_inc
;
1301 #if 0 // we do not support this at the moment
1302 if (sizehint
.flags
& PAspect
) {
1303 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1304 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1305 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1306 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1310 if (sizehint
.flags
& PBaseSize
) {
1311 client
.base_width
= sizehint
.base_width
;
1312 client
.base_height
= sizehint
.base_height
;
1315 if (sizehint
.flags
& PWinGravity
)
1316 client
.win_gravity
= sizehint
.win_gravity
;
1321 * Gets the NETWM hints for the class' contained window.
1323 void BlackboxWindow::getNetWMHints(void) {
1324 unsigned long workspace
;
1326 if (xatom
->get(client
.window
, otk::OBProperty::net_wm_desktop
,
1327 otk::OBProperty::Atom_Cardinal
,
1329 if (workspace
== 0xffffffff)
1332 blackbox_attrib
.workspace
= workspace
;
1335 unsigned long *state
;
1336 unsigned long num
= (unsigned) -1;
1337 if (xatom
->get(client
.window
, otk::OBProperty::net_wm_state
,
1338 otk::OBProperty::Atom_Atom
,
1342 for (unsigned long i
= 0; i
< num
; ++i
) {
1343 if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_modal
))
1345 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_shaded
))
1346 flags
.shaded
= True
;
1347 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
1348 flags
.skip_taskbar
= True
;
1349 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_skip_pager
))
1350 flags
.skip_pager
= True
;
1351 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_fullscreen
))
1352 flags
.fullscreen
= True
;
1353 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_hidden
))
1354 setState(IconicState
);
1355 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
1357 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
1361 flags
.maximized
= 1;
1363 flags
.maximized
= 2;
1365 flags
.maximized
= 3;
1373 * Gets the MWM hints for the class' contained window.
1374 * This is used while initializing the window to its first state, and not
1376 * Returns: true if the MWM hints are successfully retreived and applied;
1377 * false if they are not.
1379 void BlackboxWindow::getMWMHints(void) {
1383 num
= PropMwmHintsElements
;
1384 if (! xatom
->get(client
.window
, otk::OBProperty::motif_wm_hints
,
1385 otk::OBProperty::motif_wm_hints
, &num
,
1386 (unsigned long **)&mwm_hint
))
1388 if (num
< PropMwmHintsElements
) {
1393 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1394 if (mwm_hint
->decorations
& MwmDecorAll
) {
1395 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1396 Decor_Iconify
| Decor_Maximize
;
1398 mwm_decorations
= 0;
1400 if (mwm_hint
->decorations
& MwmDecorBorder
)
1401 mwm_decorations
|= Decor_Border
;
1402 if (mwm_hint
->decorations
& MwmDecorHandle
)
1403 mwm_decorations
|= Decor_Handle
;
1404 if (mwm_hint
->decorations
& MwmDecorTitle
)
1405 mwm_decorations
|= Decor_Titlebar
;
1406 if (mwm_hint
->decorations
& MwmDecorIconify
)
1407 mwm_decorations
|= Decor_Iconify
;
1408 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1409 mwm_decorations
|= Decor_Maximize
;
1413 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1414 if (mwm_hint
->functions
& MwmFuncAll
) {
1415 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1420 if (mwm_hint
->functions
& MwmFuncResize
)
1421 functions
|= Func_Resize
;
1422 if (mwm_hint
->functions
& MwmFuncMove
)
1423 functions
|= Func_Move
;
1424 if (mwm_hint
->functions
& MwmFuncIconify
)
1425 functions
|= Func_Iconify
;
1426 if (mwm_hint
->functions
& MwmFuncMaximize
)
1427 functions
|= Func_Maximize
;
1428 if (mwm_hint
->functions
& MwmFuncClose
)
1429 functions
|= Func_Close
;
1437 * Gets the blackbox hints from the class' contained window.
1438 * This is used while initializing the window to its first state, and not
1440 * Returns: true if the hints are successfully retreived and applied; false if
1443 bool BlackboxWindow::getBlackboxHints(void) {
1445 BlackboxHints
*blackbox_hint
;
1447 num
= PropBlackboxHintsElements
;
1448 if (! xatom
->get(client
.window
, otk::OBProperty::blackbox_hints
,
1449 otk::OBProperty::blackbox_hints
, &num
,
1450 (unsigned long **)&blackbox_hint
))
1452 if (num
< PropBlackboxHintsElements
) {
1453 delete [] blackbox_hint
;
1457 if (blackbox_hint
->flags
& AttribShaded
)
1458 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1460 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1461 (blackbox_hint
->flags
& AttribMaxVert
))
1462 flags
.maximized
= (blackbox_hint
->attrib
&
1463 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1464 else if (blackbox_hint
->flags
& AttribMaxVert
)
1465 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1466 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1467 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1469 if (blackbox_hint
->flags
& AttribOmnipresent
)
1470 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1472 if (blackbox_hint
->flags
& AttribWorkspace
)
1473 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1475 // if (blackbox_hint->flags & AttribStack)
1476 // don't yet have always on top/bottom for blackbox yet... working
1479 if (blackbox_hint
->flags
& AttribDecoration
) {
1480 switch (blackbox_hint
->decoration
) {
1482 blackbox_attrib
.decoration
= DecorNone
;
1489 // blackbox_attrib.decoration defaults to DecorNormal
1494 delete [] blackbox_hint
;
1500 void BlackboxWindow::getTransientInfo(void) {
1501 if (client
.transient_for
&&
1502 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1503 // reset transient_for in preparation of looking for a new owner
1504 client
.transient_for
->client
.transientList
.remove(this);
1507 // we have no transient_for until we find a new one
1508 client
.transient_for
= (BlackboxWindow
*) 0;
1511 if (! XGetTransientForHint(otk::OBDisplay::display
, client
.window
,
1513 // transient_for hint not set
1517 if (trans_for
== client
.window
) {
1518 // wierd client... treat this window as a normal window
1522 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1523 // this is an undocumented interpretation of the ICCCM. a transient
1524 // associated with None/Root/itself is assumed to be a modal root
1525 // transient. we don't support the concept of a global transient,
1526 // so we just associate this transient with nothing, and perhaps
1527 // we will add support later for global modality.
1528 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1533 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1534 if (! client
.transient_for
&&
1535 client
.window_group
&& trans_for
== client
.window_group
) {
1536 // no direct transient_for, perhaps this is a group transient?
1537 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1538 if (group
) client
.transient_for
= group
->find(screen
);
1541 if (! client
.transient_for
|| client
.transient_for
== this) {
1542 // no transient_for found, or we have a wierd client that wants to be
1543 // a transient for itself, so we treat this window as a normal window
1544 client
.transient_for
= (BlackboxWindow
*) 0;
1548 // Check for a circular transient state: this can lock up Blackbox
1549 // when it tries to find the non-transient window for a transient.
1550 BlackboxWindow
*w
= this;
1551 while(w
->client
.transient_for
&&
1552 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1553 if(w
->client
.transient_for
== this) {
1554 client
.transient_for
= (BlackboxWindow
*) 0;
1557 w
= w
->client
.transient_for
;
1560 if (client
.transient_for
&&
1561 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1562 // register ourselves with our new transient_for
1563 client
.transient_for
->client
.transientList
.push_back(this);
1564 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1569 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1570 if (client
.transient_for
&&
1571 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1572 return client
.transient_for
;
1578 * This function is responsible for updating both the client and the frame
1580 * According to the ICCCM a client message is not sent for a resize, only a
1583 void BlackboxWindow::configure(int dx
, int dy
,
1584 unsigned int dw
, unsigned int dh
) {
1585 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1588 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1589 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1590 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1591 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1593 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1594 frame
.rect
.setPos(0, 0);
1596 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1597 frame
.rect
.top() + frame
.margin
.top
,
1598 frame
.rect
.right() - frame
.margin
.right
,
1599 frame
.rect
.bottom() - frame
.margin
.bottom
);
1602 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1609 redrawWindowFrame();
1611 frame
.rect
.setPos(dx
, dy
);
1613 XMoveWindow(otk::OBDisplay::display
, frame
.window
,
1614 frame
.rect
.x(), frame
.rect
.y());
1616 we may have been called just after an opaque window move, so even though
1617 the old coords match the new ones no ConfigureNotify has been sent yet.
1618 There are likely other times when this will be relevant as well.
1620 if (! flags
.moving
) send_event
= True
;
1624 // if moving, the update and event will occur when the move finishes
1625 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1626 frame
.rect
.top() + frame
.margin
.top
);
1629 event
.type
= ConfigureNotify
;
1631 event
.xconfigure
.display
= otk::OBDisplay::display
;
1632 event
.xconfigure
.event
= client
.window
;
1633 event
.xconfigure
.window
= client
.window
;
1634 event
.xconfigure
.x
= client
.rect
.x();
1635 event
.xconfigure
.y
= client
.rect
.y();
1636 event
.xconfigure
.width
= client
.rect
.width();
1637 event
.xconfigure
.height
= client
.rect
.height();
1638 event
.xconfigure
.border_width
= client
.old_bw
;
1639 event
.xconfigure
.above
= frame
.window
;
1640 event
.xconfigure
.override_redirect
= False
;
1642 XSendEvent(otk::OBDisplay::display
, client
.window
, False
,
1643 StructureNotifyMask
, &event
);
1644 XFlush(otk::OBDisplay::display
);
1650 void BlackboxWindow::configureShape(void) {
1651 XShapeCombineShape(otk::OBDisplay::display
, frame
.window
, ShapeBounding
,
1652 frame
.margin
.left
- frame
.border_w
,
1653 frame
.margin
.top
- frame
.border_w
,
1654 client
.window
, ShapeBounding
, ShapeSet
);
1657 XRectangle xrect
[2];
1659 if (decorations
& Decor_Titlebar
) {
1660 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1661 xrect
[0].width
= frame
.rect
.width();
1662 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1666 if (decorations
& Decor_Handle
) {
1667 xrect
[1].x
= -frame
.border_w
;
1668 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1669 frame
.mwm_border_w
- frame
.border_w
;
1670 xrect
[1].width
= frame
.rect
.width();
1671 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1675 XShapeCombineRectangles(otk::OBDisplay::display
, frame
.window
,
1676 ShapeBounding
, 0, 0, xrect
, num
,
1677 ShapeUnion
, Unsorted
);
1681 void BlackboxWindow::clearShape(void) {
1682 XShapeCombineMask(otk::OBDisplay::display
, frame
.window
, ShapeBounding
,
1683 frame
.margin
.left
- frame
.border_w
,
1684 frame
.margin
.top
- frame
.border_w
,
1690 bool BlackboxWindow::setInputFocus(void) {
1691 if (flags
.focused
) return True
;
1693 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1694 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1697 We only do this check for normal windows and dialogs because other windows
1698 do this on purpose, such as kde's kicker, and we don't want to go moving
1701 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1702 if (! frame
.rect
.intersects(screen
->getRect())) {
1703 // client is outside the screen, move it to the center
1704 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1705 (screen
->getHeight() - frame
.rect
.height()) / 2,
1706 frame
.rect
.width(), frame
.rect
.height());
1709 if (client
.transientList
.size() > 0) {
1710 // transfer focus to any modal transients
1711 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1712 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1713 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1717 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1718 XSetInputFocus(otk::OBDisplay::display
, client
.window
,
1719 RevertToPointerRoot
, CurrentTime
);
1721 /* we could set the focus to none, since the window doesn't accept focus,
1722 * but we shouldn't set focus to nothing since this would surely make
1728 if (flags
.send_focus_message
) {
1730 ce
.xclient
.type
= ClientMessage
;
1731 ce
.xclient
.message_type
= xatom
->atom(otk::OBProperty::wm_protocols
);
1732 ce
.xclient
.display
= otk::OBDisplay::display
;
1733 ce
.xclient
.window
= client
.window
;
1734 ce
.xclient
.format
= 32;
1735 ce
.xclient
.data
.l
[0] = xatom
->atom(otk::OBProperty::wm_take_focus
);
1736 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1737 ce
.xclient
.data
.l
[2] = 0l;
1738 ce
.xclient
.data
.l
[3] = 0l;
1739 ce
.xclient
.data
.l
[4] = 0l;
1740 XSendEvent(otk::OBDisplay::display
, client
.window
, False
,
1742 XFlush(otk::OBDisplay::display
);
1749 void BlackboxWindow::iconify(void) {
1750 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1752 // We don't need to worry about resizing because resizing always grabs the X
1753 // server. This should only ever happen if using opaque moving.
1758 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1759 * we need to clear the event mask on client.window for a split second.
1760 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1761 * split second, leaving us with a ghost window... so, we need to do this
1762 * while the X server is grabbed
1764 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1765 StructureNotifyMask
;
1766 XGrabServer(otk::OBDisplay::display
);
1767 XSelectInput(otk::OBDisplay::display
, client
.window
,
1768 event_mask
& ~StructureNotifyMask
);
1769 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
1770 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
1771 XUngrabServer(otk::OBDisplay::display
);
1773 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
1774 flags
.visible
= False
;
1775 flags
.iconic
= True
;
1777 setState(IconicState
);
1779 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1781 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1782 if (i
!= blackbox_attrib
.workspace
)
1783 screen
->getWorkspace(i
)->removeWindow(this, True
);
1786 if (isTransient()) {
1787 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1788 ! client
.transient_for
->flags
.iconic
) {
1789 // iconify our transient_for
1790 client
.transient_for
->iconify();
1794 screen
->addIcon(this);
1796 if (client
.transientList
.size() > 0) {
1797 // iconify all transients
1798 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1799 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1800 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1803 screen
->updateStackingList();
1807 void BlackboxWindow::show(void) {
1808 flags
.visible
= True
;
1809 flags
.iconic
= False
;
1811 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1812 setState(current_state
);
1814 XMapWindow(otk::OBDisplay::display
, client
.window
);
1815 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
1816 XMapWindow(otk::OBDisplay::display
, frame
.window
);
1821 XTranslateCoordinates(otk::OBDisplay::display
, client
.window
,
1822 screen
->getRootWindow(),
1823 0, 0, &real_x
, &real_y
, &child
);
1824 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1825 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1826 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1831 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1832 if (flags
.iconic
|| reassoc
)
1833 screen
->reassociateWindow(this, BSENTINEL
, False
);
1834 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1839 // reassociate and deiconify all transients
1840 if (reassoc
&& client
.transientList
.size() > 0) {
1841 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1842 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1843 (*it
)->deiconify(True
, False
);
1847 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1851 void BlackboxWindow::close(void) {
1852 if (! (functions
& Func_Close
)) return;
1855 ce
.xclient
.type
= ClientMessage
;
1856 ce
.xclient
.message_type
= xatom
->atom(otk::OBProperty::wm_protocols
);
1857 ce
.xclient
.display
= otk::OBDisplay::display
;
1858 ce
.xclient
.window
= client
.window
;
1859 ce
.xclient
.format
= 32;
1860 ce
.xclient
.data
.l
[0] = xatom
->atom(otk::OBProperty::wm_delete_window
);
1861 ce
.xclient
.data
.l
[1] = CurrentTime
;
1862 ce
.xclient
.data
.l
[2] = 0l;
1863 ce
.xclient
.data
.l
[3] = 0l;
1864 ce
.xclient
.data
.l
[4] = 0l;
1865 XSendEvent(otk::OBDisplay::display
, client
.window
, False
, NoEventMask
, &ce
);
1866 XFlush(otk::OBDisplay::display
);
1870 void BlackboxWindow::withdraw(void) {
1871 // We don't need to worry about resizing because resizing always grabs the X
1872 // server. This should only ever happen if using opaque moving.
1876 flags
.visible
= False
;
1877 flags
.iconic
= False
;
1879 setState(current_state
);
1881 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
1883 XGrabServer(otk::OBDisplay::display
);
1885 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1886 StructureNotifyMask
;
1887 XSelectInput(otk::OBDisplay::display
, client
.window
,
1888 event_mask
& ~StructureNotifyMask
);
1889 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
1890 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
1892 XUngrabServer(otk::OBDisplay::display
);
1896 void BlackboxWindow::maximize(unsigned int button
) {
1897 if (! (functions
& Func_Maximize
)) return;
1899 // We don't need to worry about resizing because resizing always grabs the X
1900 // server. This should only ever happen if using opaque moving.
1904 if (flags
.maximized
) {
1905 flags
.maximized
= 0;
1907 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1908 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1911 when a resize finishes, maximize(0) is called to clear any maximization
1912 flags currently set. Otherwise it still thinks it is maximized.
1913 so we do not need to call configure() because resizing will handle it
1915 if (! flags
.resizing
)
1916 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1917 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1919 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1920 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1922 redrawAllButtons(); // in case it is not called in configure()
1923 setState(current_state
);
1927 blackbox_attrib
.premax_x
= frame
.rect
.x();
1928 blackbox_attrib
.premax_y
= frame
.rect
.y();
1929 blackbox_attrib
.premax_w
= frame
.rect
.width();
1930 // use client.rect so that clients can be restored even if shaded
1931 blackbox_attrib
.premax_h
=
1932 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1935 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1936 // find the area to use
1937 RectList availableAreas
= screen
->allAvailableAreas();
1938 RectList::iterator it
, end
= availableAreas
.end();
1940 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1941 if (it
->intersects(frame
.rect
)) break;
1942 if (it
== end
) // the window isn't inside an area
1943 it
= availableAreas
.begin(); // so just default to the first one
1945 frame
.changing
= *it
;
1948 frame
.changing
= screen
->availableArea();
1952 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1953 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1957 blackbox_attrib
.flags
|= AttribMaxVert
;
1958 blackbox_attrib
.attrib
|= AttribMaxVert
;
1960 frame
.changing
.setX(frame
.rect
.x());
1961 frame
.changing
.setWidth(frame
.rect
.width());
1965 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1966 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1968 frame
.changing
.setY(frame
.rect
.y());
1969 frame
.changing
.setHeight(frame
.rect
.height());
1976 blackbox_attrib
.flags
^= AttribShaded
;
1977 blackbox_attrib
.attrib
^= AttribShaded
;
1978 flags
.shaded
= False
;
1981 flags
.maximized
= button
;
1983 configure(frame
.changing
.x(), frame
.changing
.y(),
1984 frame
.changing
.width(), frame
.changing
.height());
1986 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1987 redrawAllButtons(); // in case it is not called in configure()
1988 setState(current_state
);
1992 // re-maximizes the window to take into account availableArea changes
1993 void BlackboxWindow::remaximize(void) {
1995 // we only update the window's attributes otherwise we lose the shade bit
1996 switch(flags
.maximized
) {
1998 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1999 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
2003 blackbox_attrib
.flags
|= AttribMaxVert
;
2004 blackbox_attrib
.attrib
|= AttribMaxVert
;
2008 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2009 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2015 // save the original dimensions because maximize will wipe them out
2016 int premax_x
= blackbox_attrib
.premax_x
,
2017 premax_y
= blackbox_attrib
.premax_y
,
2018 premax_w
= blackbox_attrib
.premax_w
,
2019 premax_h
= blackbox_attrib
.premax_h
;
2021 unsigned int button
= flags
.maximized
;
2022 flags
.maximized
= 0; // trick maximize() into working
2025 // restore saved values
2026 blackbox_attrib
.premax_x
= premax_x
;
2027 blackbox_attrib
.premax_y
= premax_y
;
2028 blackbox_attrib
.premax_w
= premax_w
;
2029 blackbox_attrib
.premax_h
= premax_h
;
2033 void BlackboxWindow::setWorkspace(unsigned int n
) {
2034 blackbox_attrib
.flags
|= AttribWorkspace
;
2035 blackbox_attrib
.workspace
= n
;
2036 if (n
== BSENTINEL
) { // iconified window
2038 we set the workspace to 'all workspaces' so that taskbars will show the
2039 window. otherwise, it made uniconifying a window imposible without the
2040 blackbox workspace menu
2044 xatom
->set(client
.window
, otk::OBProperty::net_wm_desktop
,
2045 otk::OBProperty::Atom_Cardinal
, n
);
2049 void BlackboxWindow::shade(void) {
2051 XResizeWindow(otk::OBDisplay::display
, frame
.window
,
2052 frame
.inside_w
, frame
.inside_h
);
2053 flags
.shaded
= False
;
2054 blackbox_attrib
.flags
^= AttribShaded
;
2055 blackbox_attrib
.attrib
^= AttribShaded
;
2057 setState(NormalState
);
2059 // set the frame rect to the normal size
2060 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2061 frame
.margin
.bottom
);
2063 if (! (decorations
& Decor_Titlebar
))
2064 return; // can't shade it without a titlebar!
2066 XResizeWindow(otk::OBDisplay::display
, frame
.window
,
2067 frame
.inside_w
, frame
.title_h
);
2068 flags
.shaded
= True
;
2069 blackbox_attrib
.flags
|= AttribShaded
;
2070 blackbox_attrib
.attrib
|= AttribShaded
;
2072 setState(IconicState
);
2074 // set the frame rect to the shaded size
2075 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2081 * (Un)Sticks a window and its relatives.
2083 void BlackboxWindow::stick(void) {
2085 blackbox_attrib
.flags
^= AttribOmnipresent
;
2086 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2088 flags
.stuck
= False
;
2090 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2091 if (i
!= blackbox_attrib
.workspace
)
2092 screen
->getWorkspace(i
)->removeWindow(this, True
);
2095 screen
->reassociateWindow(this, BSENTINEL
, True
);
2096 // temporary fix since sticky windows suck. set the hint to what we
2097 // actually hold in our data.
2098 xatom
->set(client
.window
, otk::OBProperty::net_wm_desktop
,
2099 otk::OBProperty::Atom_Cardinal
,
2100 blackbox_attrib
.workspace
);
2102 setState(current_state
);
2106 blackbox_attrib
.flags
|= AttribOmnipresent
;
2107 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2109 // temporary fix since sticky windows suck. set the hint to a different
2110 // value than that contained in the class' data.
2111 xatom
->set(client
.window
, otk::OBProperty::net_wm_desktop
,
2112 otk::OBProperty::Atom_Cardinal
,
2115 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2116 if (i
!= blackbox_attrib
.workspace
)
2117 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2119 setState(current_state
);
2125 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2126 client
.transient_for
->isStuck() != flags
.stuck
)
2127 client
.transient_for
->stick();
2128 // go down the chain
2129 BlackboxWindowList::iterator it
;
2130 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2131 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2132 if ((*it
)->isStuck() != flags
.stuck
)
2137 void BlackboxWindow::redrawWindowFrame(void) const {
2138 if (decorations
& Decor_Titlebar
) {
2139 if (flags
.focused
) {
2141 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2142 frame
.title
, frame
.ftitle
);
2144 XSetWindowBackground(otk::OBDisplay::display
,
2145 frame
.title
, frame
.ftitle_pixel
);
2148 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2149 frame
.title
, frame
.utitle
);
2151 XSetWindowBackground(otk::OBDisplay::display
,
2152 frame
.title
, frame
.utitle_pixel
);
2154 XClearWindow(otk::OBDisplay::display
, frame
.title
);
2160 if (decorations
& Decor_Handle
) {
2161 if (flags
.focused
) {
2163 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2164 frame
.handle
, frame
.fhandle
);
2166 XSetWindowBackground(otk::OBDisplay::display
,
2167 frame
.handle
, frame
.fhandle_pixel
);
2170 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2171 frame
.left_grip
, frame
.fgrip
);
2172 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2173 frame
.right_grip
, frame
.fgrip
);
2175 XSetWindowBackground(otk::OBDisplay::display
,
2176 frame
.left_grip
, frame
.fgrip_pixel
);
2177 XSetWindowBackground(otk::OBDisplay::display
,
2178 frame
.right_grip
, frame
.fgrip_pixel
);
2182 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2183 frame
.handle
, frame
.uhandle
);
2185 XSetWindowBackground(otk::OBDisplay::display
,
2186 frame
.handle
, frame
.uhandle_pixel
);
2189 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2190 frame
.left_grip
, frame
.ugrip
);
2191 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2192 frame
.right_grip
, frame
.ugrip
);
2194 XSetWindowBackground(otk::OBDisplay::display
,
2195 frame
.left_grip
, frame
.ugrip_pixel
);
2196 XSetWindowBackground(otk::OBDisplay::display
,
2197 frame
.right_grip
, frame
.ugrip_pixel
);
2200 XClearWindow(otk::OBDisplay::display
, frame
.handle
);
2201 XClearWindow(otk::OBDisplay::display
, frame
.left_grip
);
2202 XClearWindow(otk::OBDisplay::display
, frame
.right_grip
);
2205 if (decorations
& Decor_Border
) {
2207 XSetWindowBorder(otk::OBDisplay::display
,
2208 frame
.plate
, frame
.fborder_pixel
);
2210 XSetWindowBorder(otk::OBDisplay::display
,
2211 frame
.plate
, frame
.uborder_pixel
);
2216 void BlackboxWindow::setFocusFlag(bool focus
) {
2217 // only focus a window if it is visible
2218 if (focus
&& ! flags
.visible
)
2221 flags
.focused
= focus
;
2223 redrawWindowFrame();
2226 blackbox
->setFocusedWindow(this);
2230 void BlackboxWindow::installColormap(bool install
) {
2231 int i
= 0, ncmap
= 0;
2232 Colormap
*cmaps
= XListInstalledColormaps(otk::OBDisplay::display
,
2233 client
.window
, &ncmap
);
2235 XWindowAttributes wattrib
;
2236 if (XGetWindowAttributes(otk::OBDisplay::display
,
2237 client
.window
, &wattrib
)) {
2239 // install the window's colormap
2240 for (i
= 0; i
< ncmap
; i
++) {
2241 if (*(cmaps
+ i
) == wattrib
.colormap
)
2242 // this window is using an installed color map... do not install
2245 // otherwise, install the window's colormap
2247 XInstallColormap(otk::OBDisplay::display
, wattrib
.colormap
);
2249 // uninstall the window's colormap
2250 for (i
= 0; i
< ncmap
; i
++) {
2251 if (*(cmaps
+ i
) == wattrib
.colormap
)
2252 // we found the colormap to uninstall
2253 XUninstallColormap(otk::OBDisplay::display
, wattrib
.colormap
);
2263 void BlackboxWindow::setAllowedActions(void) {
2267 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_shade
);
2268 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_change_desktop
);
2269 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_close
);
2271 if (functions
& Func_Move
)
2272 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_move
);
2273 if (functions
& Func_Resize
)
2274 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_resize
);
2275 if (functions
& Func_Maximize
) {
2276 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_maximize_horz
);
2277 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_maximize_vert
);
2280 xatom
->set(client
.window
, otk::OBProperty::net_wm_allowed_actions
,
2281 otk::OBProperty::Atom_Atom
,
2286 void BlackboxWindow::setState(unsigned long new_state
) {
2287 current_state
= new_state
;
2289 unsigned long state
[2];
2290 state
[0] = current_state
;
2292 xatom
->set(client
.window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
, state
, 2);
2294 xatom
->set(client
.window
, otk::OBProperty::blackbox_attributes
,
2295 otk::OBProperty::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2296 PropBlackboxAttributesElements
);
2301 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_modal
);
2303 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_shaded
);
2305 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_hidden
);
2306 if (flags
.skip_taskbar
)
2307 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
2308 if (flags
.skip_pager
)
2309 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_skip_pager
);
2310 if (flags
.fullscreen
)
2311 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_fullscreen
);
2312 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2313 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
2314 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2315 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
2316 xatom
->set(client
.window
, otk::OBProperty::net_wm_state
,
2317 otk::OBProperty::Atom_Atom
,
2322 bool BlackboxWindow::getState(void) {
2323 bool ret
= xatom
->get(client
.window
, otk::OBProperty::wm_state
,
2324 otk::OBProperty::wm_state
, ¤t_state
);
2325 if (! ret
) current_state
= 0;
2330 void BlackboxWindow::restoreAttributes(void) {
2331 unsigned long num
= PropBlackboxAttributesElements
;
2332 BlackboxAttributes
*net
;
2333 if (! xatom
->get(client
.window
, otk::OBProperty::blackbox_attributes
,
2334 otk::OBProperty::blackbox_attributes
, &num
,
2335 (unsigned long **)&net
))
2337 if (num
< PropBlackboxAttributesElements
) {
2342 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2343 flags
.shaded
= False
;
2344 unsigned long orig_state
= current_state
;
2348 At this point in the life of a window, current_state should only be set
2349 to IconicState if the window was an *icon*, not if it was shaded.
2351 if (orig_state
!= IconicState
)
2352 current_state
= WithdrawnState
;
2355 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2356 net
->workspace
< screen
->getWorkspaceCount())
2357 screen
->reassociateWindow(this, net
->workspace
, True
);
2359 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2360 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2361 // set to WithdrawnState so it will be mapped on the new workspace
2362 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2363 } else if (current_state
== WithdrawnState
) {
2364 // the window is on this workspace and is Withdrawn, so it is waiting to
2366 current_state
= NormalState
;
2369 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2373 // if the window was on another workspace, it was going to be hidden. this
2374 // specifies that the window should be mapped since it is sticky.
2375 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2378 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2379 int x
= net
->premax_x
, y
= net
->premax_y
;
2380 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2381 flags
.maximized
= 0;
2384 if ((net
->flags
& AttribMaxHoriz
) &&
2385 (net
->flags
& AttribMaxVert
))
2386 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2387 else if (net
->flags
& AttribMaxVert
)
2388 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2389 else if (net
->flags
& AttribMaxHoriz
)
2390 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2394 blackbox_attrib
.premax_x
= x
;
2395 blackbox_attrib
.premax_y
= y
;
2396 blackbox_attrib
.premax_w
= w
;
2397 blackbox_attrib
.premax_h
= h
;
2400 if (net
->flags
& AttribDecoration
) {
2401 switch (net
->decoration
) {
2406 /* since tools only let you toggle this anyways, we'll just make that all
2407 it supports for now.
2418 // with the state set it will then be the map event's job to read the
2419 // window's state and behave accordingly
2426 * Positions the Rect r according the the client window position and
2429 void BlackboxWindow::applyGravity(otk::Rect
&r
) {
2430 // apply horizontal window gravity
2431 switch (client
.win_gravity
) {
2433 case NorthWestGravity
:
2434 case SouthWestGravity
:
2436 r
.setX(client
.rect
.x());
2442 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2445 case NorthEastGravity
:
2446 case SouthEastGravity
:
2448 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2453 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2457 // apply vertical window gravity
2458 switch (client
.win_gravity
) {
2460 case NorthWestGravity
:
2461 case NorthEastGravity
:
2463 r
.setY(client
.rect
.y());
2469 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2472 case SouthWestGravity
:
2473 case SouthEastGravity
:
2475 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2480 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2487 * The reverse of the applyGravity function.
2489 * Positions the Rect r according to the frame window position and
2492 void BlackboxWindow::restoreGravity(otk::Rect
&r
) {
2493 // restore horizontal window gravity
2494 switch (client
.win_gravity
) {
2496 case NorthWestGravity
:
2497 case SouthWestGravity
:
2499 r
.setX(frame
.rect
.x());
2505 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2508 case NorthEastGravity
:
2509 case SouthEastGravity
:
2511 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2516 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2520 // restore vertical window gravity
2521 switch (client
.win_gravity
) {
2523 case NorthWestGravity
:
2524 case NorthEastGravity
:
2526 r
.setY(frame
.rect
.y());
2532 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2535 case SouthWestGravity
:
2536 case SouthEastGravity
:
2538 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2543 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2549 void BlackboxWindow::redrawLabel(void) const {
2550 if (flags
.focused
) {
2552 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2553 frame
.label
, frame
.flabel
);
2555 XSetWindowBackground(otk::OBDisplay::display
,
2556 frame
.label
, frame
.flabel_pixel
);
2559 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2560 frame
.label
, frame
.ulabel
);
2562 XSetWindowBackground(otk::OBDisplay::display
,
2563 frame
.label
, frame
.ulabel_pixel
);
2565 XClearWindow(otk::OBDisplay::display
, frame
.label
);
2567 WindowStyle
*style
= screen
->getWindowStyle();
2569 int pos
= frame
.bevel_w
* 2;
2570 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2571 style
->font
->drawString(frame
.label
, pos
, 1,
2572 (flags
.focused
? style
->l_text_focus
:
2573 style
->l_text_unfocus
),
2578 void BlackboxWindow::redrawAllButtons(void) const {
2579 if (frame
.iconify_button
) redrawIconifyButton(False
);
2580 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2581 if (frame
.close_button
) redrawCloseButton(False
);
2582 if (frame
.stick_button
) redrawStickyButton(flags
.stuck
);
2586 void BlackboxWindow::redrawButton(bool pressed
, Window win
,
2587 Pixmap fppix
, unsigned long fppixel
,
2588 Pixmap uppix
, unsigned long uppixel
,
2589 Pixmap fpix
, unsigned long fpixel
,
2590 Pixmap upix
, unsigned long upixel
) const {
2595 if (flags
.focused
) {
2603 if (flags
.focused
) {
2613 XSetWindowBackgroundPixmap(otk::OBDisplay::display
, win
, p
);
2615 XSetWindowBackground(otk::OBDisplay::display
, win
, pix
);
2619 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2620 redrawButton(pressed
, frame
.iconify_button
,
2621 frame
.pfbutton
, frame
.pfbutton_pixel
,
2622 frame
.pubutton
, frame
.pubutton_pixel
,
2623 frame
.fbutton
, frame
.fbutton_pixel
,
2624 frame
.ubutton
, frame
.ubutton_pixel
);
2626 XClearWindow(otk::OBDisplay::display
, frame
.iconify_button
);
2627 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2628 screen
->getWindowStyle()->b_pic_unfocus
);
2630 PixmapMask pm
= screen
->getWindowStyle()->icon_button
;
2632 if (screen
->getWindowStyle()->icon_button
.mask
!= None
) {
2633 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2634 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2635 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2637 XFillRectangle(otk::OBDisplay::display
, frame
.iconify_button
, pen
.gc(),
2638 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2639 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2641 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), None
);
2642 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0);
2644 XDrawRectangle(otk::OBDisplay::display
, frame
.iconify_button
, pen
.gc(),
2645 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2650 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2651 redrawButton(pressed
, frame
.maximize_button
,
2652 frame
.pfbutton
, frame
.pfbutton_pixel
,
2653 frame
.pubutton
, frame
.pubutton_pixel
,
2654 frame
.fbutton
, frame
.fbutton_pixel
,
2655 frame
.ubutton
, frame
.ubutton_pixel
);
2657 XClearWindow(otk::OBDisplay::display
, frame
.maximize_button
);
2659 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2660 screen
->getWindowStyle()->b_pic_unfocus
);
2662 PixmapMask pm
= screen
->getWindowStyle()->max_button
;
2664 if (pm
.mask
!= None
) {
2665 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2666 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2667 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2669 XFillRectangle(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2670 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2671 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2673 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2674 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2676 XDrawRectangle(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2677 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2678 XDrawLine(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2679 2, 3, (frame
.button_w
- 3), 3);
2684 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2685 redrawButton(pressed
, frame
.close_button
,
2686 frame
.pfbutton
, frame
.pfbutton_pixel
,
2687 frame
.pubutton
, frame
.pubutton_pixel
,
2688 frame
.fbutton
, frame
.fbutton_pixel
,
2689 frame
.ubutton
, frame
.ubutton_pixel
);
2691 XClearWindow(otk::OBDisplay::display
, frame
.close_button
);
2693 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2694 screen
->getWindowStyle()->b_pic_unfocus
);
2696 PixmapMask pm
= screen
->getWindowStyle()->close_button
;
2698 if (pm
.mask
!= None
) {
2699 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2700 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2701 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2703 XFillRectangle(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2704 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2705 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2708 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2709 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2711 XDrawLine(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2712 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2713 XDrawLine(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2714 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2718 void BlackboxWindow::redrawStickyButton(bool pressed
) const {
2719 redrawButton(pressed
, frame
.stick_button
,
2720 frame
.pfbutton
, frame
.pfbutton_pixel
,
2721 frame
.pubutton
, frame
.pubutton_pixel
,
2722 frame
.fbutton
, frame
.fbutton_pixel
,
2723 frame
.ubutton
, frame
.ubutton_pixel
);
2725 XClearWindow(otk::OBDisplay::display
, frame
.stick_button
);
2727 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2728 screen
->getWindowStyle()->b_pic_unfocus
);
2730 PixmapMask pm
= screen
->getWindowStyle()->stick_button
;
2732 if (pm
.mask
!= None
) {
2733 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2734 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2735 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2737 XFillRectangle(otk::OBDisplay::display
, frame
.stick_button
, pen
.gc(),
2738 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2739 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2742 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2743 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2745 XFillRectangle(otk::OBDisplay::display
, frame
.stick_button
, pen
.gc(),
2746 frame
.button_w
/2 - 1, frame
.button_w
/2 -1, 2, 2 );
2750 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2751 if (re
->window
!= client
.window
)
2755 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2760 Even though the window wants to be shown, if it is not on the current
2761 workspace, then it isn't going to be shown right now.
2763 if (! flags
.stuck
&&
2764 blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2765 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2766 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2768 switch (current_state
) {
2773 case WithdrawnState
:
2782 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2784 if (blackbox
->state() != Openbox::State_Starting
) {
2785 XSync(otk::OBDisplay::display
, False
); // make sure the frame is mapped
2786 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2787 getTransientFor()->isFocused())) {
2790 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2794 XQueryPointer(otk::OBDisplay::display
, screen
->getRootWindow(),
2795 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2805 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2806 if (ue
->window
!= client
.window
)
2810 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2814 screen
->unmanageWindow(this, False
);
2818 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2819 if (de
->window
!= client
.window
)
2823 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2827 screen
->unmanageWindow(this, False
);
2831 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2832 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2836 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2837 "0x%lx.\n", client
.window
, re
->parent
);
2842 XPutBackEvent(otk::OBDisplay::display
, &ev
);
2843 screen
->unmanageWindow(this, True
);
2847 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2848 if (pe
->state
== PropertyDelete
|| ! validateClient())
2852 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2858 case XA_WM_CLIENT_MACHINE
:
2862 case XA_WM_TRANSIENT_FOR
: {
2863 bool s
= flags
.stuck
;
2865 // determine if this is a transient window
2868 if (flags
.stuck
!= s
) stick();
2870 // adjust the window decorations based on transience
2871 if (isTransient()) {
2872 functions
&= ~Func_Maximize
;
2873 setAllowedActions();
2885 case XA_WM_ICON_NAME
:
2887 if (flags
.iconic
) screen
->propagateWindowName(this);
2890 case otk::OBProperty::net_wm_name
:
2894 if (decorations
& Decor_Titlebar
)
2897 screen
->propagateWindowName(this);
2900 case XA_WM_NORMAL_HINTS
: {
2903 if ((client
.normal_hint_flags
& PMinSize
) &&
2904 (client
.normal_hint_flags
& PMaxSize
)) {
2905 // the window now can/can't resize itself, so the buttons need to be
2908 if (client
.max_width
<= client
.min_width
&&
2909 client
.max_height
<= client
.min_height
) {
2910 functions
&= ~(Func_Resize
| Func_Maximize
);
2912 if (! isTransient())
2913 functions
|= Func_Maximize
;
2914 functions
|= Func_Resize
;
2917 setAllowedActions();
2921 otk::Rect old_rect
= frame
.rect
;
2925 if (old_rect
!= frame
.rect
)
2932 if (pe
->atom
== xatom
->atom(otk::OBProperty::wm_protocols
)) {
2935 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2936 createCloseButton();
2937 if (decorations
& Decor_Titlebar
) {
2938 positionButtons(True
);
2939 XMapSubwindows(otk::OBDisplay::display
, frame
.title
);
2942 } else if (pe
->atom
== xatom
->atom(otk::OBProperty::net_wm_strut
)) {
2951 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2953 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2956 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2958 else if (frame
.close_button
== ee
->window
)
2959 redrawCloseButton(False
);
2960 else if (frame
.maximize_button
== ee
->window
)
2961 redrawMaximizeButton(flags
.maximized
);
2962 else if (frame
.iconify_button
== ee
->window
)
2963 redrawIconifyButton(False
);
2964 else if (frame
.stick_button
== ee
->window
)
2965 redrawStickyButton(flags
.stuck
);
2969 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2970 if (cr
->window
!= client
.window
|| flags
.iconic
)
2973 if (cr
->value_mask
& CWBorderWidth
)
2974 client
.old_bw
= cr
->border_width
;
2976 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2977 frame
.changing
= frame
.rect
;
2979 if (cr
->value_mask
& (CWX
| CWY
)) {
2980 if (cr
->value_mask
& CWX
)
2981 client
.rect
.setX(cr
->x
);
2982 if (cr
->value_mask
& CWY
)
2983 client
.rect
.setY(cr
->y
);
2985 applyGravity(frame
.changing
);
2988 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
2989 if (cr
->value_mask
& CWWidth
)
2990 frame
.changing
.setWidth(cr
->width
+
2991 frame
.margin
.left
+ frame
.margin
.right
);
2993 if (cr
->value_mask
& CWHeight
)
2994 frame
.changing
.setHeight(cr
->height
+
2995 frame
.margin
.top
+ frame
.margin
.bottom
);
2998 if a position change has been specified, then that position will be
2999 used instead of determining a position based on the window's gravity.
3001 if (! (cr
->value_mask
& (CWX
| CWY
))) {
3003 switch (client
.win_gravity
) {
3004 case NorthEastGravity
:
3008 case SouthWestGravity
:
3010 corner
= BottomLeft
;
3012 case SouthEastGravity
:
3013 corner
= BottomRight
;
3015 default: // NorthWest, Static, etc
3022 configure(frame
.changing
.x(), frame
.changing
.y(),
3023 frame
.changing
.width(), frame
.changing
.height());
3026 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
3027 switch (cr
->detail
) {
3030 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3036 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3043 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
3045 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3049 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
3050 redrawMaximizeButton(True
);
3051 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
3052 if (! flags
.focused
)
3055 if (frame
.iconify_button
== be
->window
) {
3056 redrawIconifyButton(True
);
3057 } else if (frame
.close_button
== be
->window
) {
3058 redrawCloseButton(True
);
3059 } else if (frame
.stick_button
== be
->window
) {
3060 redrawStickyButton(True
);
3061 } else if (frame
.plate
== be
->window
) {
3062 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3064 XAllowEvents(otk::OBDisplay::display
, ReplayPointer
, be
->time
);
3066 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
3067 if (((be
->time
- lastButtonPressTime
) <=
3068 blackbox
->getDoubleClickInterval()) ||
3069 (be
->state
== ControlMask
)) {
3070 lastButtonPressTime
= 0;
3073 lastButtonPressTime
= be
->time
;
3077 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3079 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
3080 (be
->window
!= frame
.close_button
) &&
3081 (be
->window
!= frame
.stick_button
)) {
3082 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3084 } else if (be
->button
== 4) {
3085 if ((be
->window
== frame
.label
||
3086 be
->window
== frame
.title
||
3087 be
->window
== frame
.maximize_button
||
3088 be
->window
== frame
.iconify_button
||
3089 be
->window
== frame
.close_button
||
3090 be
->window
== frame
.stick_button
) &&
3094 } else if (be
->button
== 5) {
3095 if ((be
->window
== frame
.label
||
3096 be
->window
== frame
.title
||
3097 be
->window
== frame
.maximize_button
||
3098 be
->window
== frame
.iconify_button
||
3099 be
->window
== frame
.close_button
||
3100 be
->window
== frame
.stick_button
) &&
3107 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3109 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3113 if (re
->window
== frame
.maximize_button
&&
3114 re
->button
>= 1 && re
->button
<= 3) {
3115 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3116 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3117 maximize(re
->button
);
3119 redrawMaximizeButton(flags
.maximized
);
3121 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3122 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3123 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3126 redrawIconifyButton(False
);
3128 } else if (re
->window
== frame
.stick_button
&& re
->button
== 1) {
3129 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3130 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3133 redrawStickyButton(False
);
3135 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3136 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3137 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3139 redrawCloseButton(False
);
3140 } else if (flags
.moving
) {
3142 } else if (flags
.resizing
) {
3144 } else if (re
->window
== frame
.window
) {
3145 if (re
->button
== 2 && re
->state
== mod_mask
)
3146 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3152 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3153 if (! (functions
& Func_Move
)) return;
3155 assert(! (flags
.resizing
|| flags
.moving
));
3158 Only one window can be moved/resized at a time. If another window is already
3159 being moved or resized, then stop it before whating to work with this one.
3161 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3162 if (changing
&& changing
!= this) {
3163 if (changing
->flags
.moving
)
3164 changing
->endMove();
3165 else // if (changing->flags.resizing)
3166 changing
->endResize();
3169 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3170 PointerMotionMask
| ButtonReleaseMask
,
3171 GrabModeAsync
, GrabModeAsync
,
3172 None
, blackbox
->getMoveCursor(), CurrentTime
);
3174 flags
.moving
= True
;
3175 blackbox
->setChangingWindow(this);
3177 if (! screen
->doOpaqueMove()) {
3178 XGrabServer(otk::OBDisplay::display
);
3180 frame
.changing
= frame
.rect
;
3181 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3183 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3187 frame
.changing
.width() - 1,
3188 frame
.changing
.height() - 1);
3191 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3192 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3196 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3197 assert(flags
.moving
);
3198 assert(blackbox
->getChangingWindow() == this);
3200 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3201 dx
-= frame
.border_w
;
3202 dy
-= frame
.border_w
;
3204 doWindowSnapping(dx
, dy
);
3206 if (screen
->doOpaqueMove()) {
3207 if (screen
->doWorkspaceWarping())
3208 doWorkspaceWarping(x_root
, y_root
, dx
);
3210 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3212 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3216 frame
.changing
.width() - 1,
3217 frame
.changing
.height() - 1);
3219 if (screen
->doWorkspaceWarping())
3220 doWorkspaceWarping(x_root
, y_root
, dx
);
3222 frame
.changing
.setPos(dx
, dy
);
3224 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3228 frame
.changing
.width() - 1,
3229 frame
.changing
.height() - 1);
3232 screen
->showPosition(dx
, dy
);
3236 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3237 // workspace warping
3239 unsigned int dest
= screen
->getCurrentWorkspaceID();
3243 if (dest
> 0) dest
--;
3244 else dest
= screen
->getNumberOfWorkspaces() - 1;
3246 } else if (x_root
>= screen
->getRect().right()) {
3249 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3255 bool focus
= flags
.focused
; // had focus while moving?
3257 int dest_x
= x_root
;
3259 dest_x
+= screen
->getRect().width() - 1;
3260 dx
+= screen
->getRect().width() - 1;
3262 dest_x
-= screen
->getRect().width() - 1;
3263 dx
-= screen
->getRect().width() - 1;
3267 screen
->reassociateWindow(this, dest
, False
);
3268 screen
->changeWorkspaceID(dest
);
3270 if (screen
->doOpaqueMove())
3271 XGrabServer(otk::OBDisplay::display
);
3273 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3274 XWarpPointer(otk::OBDisplay::display
, None
,
3275 screen
->getRootWindow(), 0, 0, 0, 0,
3277 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3278 PointerMotionMask
| ButtonReleaseMask
,
3279 GrabModeAsync
, GrabModeAsync
,
3280 None
, blackbox
->getMoveCursor(), CurrentTime
);
3282 if (screen
->doOpaqueMove())
3283 XUngrabServer(otk::OBDisplay::display
);
3291 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3292 // how much resistance to edges to provide
3293 const int resistance_size
= screen
->getResistanceSize();
3295 // how far away to snap
3296 const int snap_distance
= screen
->getSnapThreshold();
3298 // how to snap windows
3299 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3300 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3301 // the amount of space away from the edge to provide resistance/snap
3302 const int snap_offset
= screen
->getSnapOffset();
3304 // find the geomeetery where the moving window currently is
3305 const otk::Rect
&moving
=
3306 screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3309 const int wleft
= dx
,
3310 wright
= dx
+ frame
.rect
.width() - 1,
3312 wbottom
= dy
+ frame
.rect
.height() - 1;
3314 if (snap_to_windows
) {
3315 otk::RectList rectlist
;
3317 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3320 // add windows on the workspace to the rect list
3321 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3322 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3323 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3324 if (*st_it
!= this) // don't snap to ourself
3325 rectlist
.push_back( (*st_it
)->frameRect() );
3327 otk::RectList::const_iterator it
, end
= rectlist
.end();
3328 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3329 bool snapped
= False
;
3330 const otk::Rect
&winrect
= *it
;
3331 otk::Rect offsetrect
;
3332 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3333 winrect
.top() - snap_offset
,
3334 winrect
.right() + snap_offset
,
3335 winrect
.bottom() + snap_offset
);
3337 if (snap_to_windows
== BScreen::WindowResistance
)
3338 // if the window is already over top of this snap target, then
3339 // resistance is futile, so just ignore it
3340 if (winrect
.intersects(moving
))
3343 int dleft
, dright
, dtop
, dbottom
;
3345 // if the windows are in the same plane vertically
3346 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3347 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3349 if (snap_to_windows
== BScreen::WindowResistance
) {
3350 dleft
= wright
- offsetrect
.left();
3351 dright
= offsetrect
.right() - wleft
;
3353 // snap left of other window?
3354 if (dleft
>= 0 && dleft
< resistance_size
&&
3355 dleft
< (wright
- wleft
)) {
3356 dx
= offsetrect
.left() - frame
.rect
.width();
3359 // snap right of other window?
3360 else if (dright
>= 0 && dright
< resistance_size
&&
3361 dright
< (wright
- wleft
)) {
3362 dx
= offsetrect
.right() + 1;
3365 } else { // BScreen::WindowSnap
3366 dleft
= abs(wright
- offsetrect
.left());
3367 dright
= abs(wleft
- offsetrect
.right());
3369 // snap left of other window?
3370 if (dleft
< snap_distance
&& dleft
<= dright
) {
3371 dx
= offsetrect
.left() - frame
.rect
.width();
3374 // snap right of other window?
3375 else if (dright
< snap_distance
) {
3376 dx
= offsetrect
.right() + 1;
3382 if (screen
->getWindowCornerSnap()) {
3383 // try corner-snap to its other sides
3384 if (snap_to_windows
== BScreen::WindowResistance
) {
3385 dtop
= winrect
.top() - wtop
;
3386 dbottom
= wbottom
- winrect
.bottom();
3387 if (dtop
> 0 && dtop
< resistance_size
) {
3388 // if we're already past the top edge, then don't provide
3390 if (moving
.top() >= winrect
.top())
3392 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3393 // if we're already past the bottom edge, then don't provide
3395 if (moving
.bottom() <= winrect
.bottom())
3396 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3398 } else { // BScreen::WindowSnap
3399 dtop
= abs(wtop
- winrect
.top());
3400 dbottom
= abs(wbottom
- winrect
.bottom());
3401 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3403 else if (dbottom
< snap_distance
)
3404 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3412 // if the windows are on the same plane horizontally
3413 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3414 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3416 if (snap_to_windows
== BScreen::WindowResistance
) {
3417 dtop
= wbottom
- offsetrect
.top();
3418 dbottom
= offsetrect
.bottom() - wtop
;
3420 // snap top of other window?
3421 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3422 dy
= offsetrect
.top() - frame
.rect
.height();
3425 // snap bottom of other window?
3426 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3427 dbottom
< (wbottom
- wtop
)) {
3428 dy
= offsetrect
.bottom() + 1;
3431 } else { // BScreen::WindowSnap
3432 dtop
= abs(wbottom
- offsetrect
.top());
3433 dbottom
= abs(wtop
- offsetrect
.bottom());
3435 // snap top of other window?
3436 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3437 dy
= offsetrect
.top() - frame
.rect
.height();
3440 // snap bottom of other window?
3441 else if (dbottom
< snap_distance
) {
3442 dy
= offsetrect
.bottom() + 1;
3449 if (screen
->getWindowCornerSnap()) {
3450 // try corner-snap to its other sides
3451 if (snap_to_windows
== BScreen::WindowResistance
) {
3452 dleft
= winrect
.left() - wleft
;
3453 dright
= wright
- winrect
.right();
3454 if (dleft
> 0 && dleft
< resistance_size
) {
3455 // if we're already past the left edge, then don't provide
3457 if (moving
.left() >= winrect
.left())
3458 dx
= winrect
.left();
3459 } else if (dright
> 0 && dright
< resistance_size
) {
3460 // if we're already past the right edge, then don't provide
3462 if (moving
.right() <= winrect
.right())
3463 dx
= winrect
.right() - frame
.rect
.width() + 1;
3465 } else { // BScreen::WindowSnap
3466 dleft
= abs(wleft
- winrect
.left());
3467 dright
= abs(wright
- winrect
.right());
3468 if (dleft
< snap_distance
&& dleft
<= dright
)
3469 dx
= winrect
.left();
3470 else if (dright
< snap_distance
)
3471 dx
= winrect
.right() - frame
.rect
.width() + 1;
3481 if (snap_to_edges
) {
3482 otk::RectList rectlist
;
3484 // snap to the screen edges (and screen boundaries for xinerama)
3486 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3487 rectlist
.insert(rectlist
.begin(),
3488 screen
->getXineramaAreas().begin(),
3489 screen
->getXineramaAreas().end());
3492 rectlist
.push_back(screen
->getRect());
3494 otk::RectList::const_iterator it
, end
= rectlist
.end();
3495 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3496 const otk::Rect
&srect
= *it
;
3497 otk::Rect offsetrect
;
3498 offsetrect
.setCoords(srect
.left() + snap_offset
,
3499 srect
.top() + snap_offset
,
3500 srect
.right() - snap_offset
,
3501 srect
.bottom() - snap_offset
);
3503 if (snap_to_edges
== BScreen::WindowResistance
) {
3504 // if we're not in the rectangle then don't snap to it.
3505 if (! srect
.contains(moving
))
3507 } else { // BScreen::WindowSnap
3508 // if we're not in the rectangle then don't snap to it.
3509 if (! srect
.intersects(otk::Rect(wleft
, wtop
, frame
.rect
.width(),
3510 frame
.rect
.height())))
3514 if (snap_to_edges
== BScreen::WindowResistance
) {
3515 int dleft
= offsetrect
.left() - wleft
,
3516 dright
= wright
- offsetrect
.right(),
3517 dtop
= offsetrect
.top() - wtop
,
3518 dbottom
= wbottom
- offsetrect
.bottom();
3521 if (dleft
> 0 && dleft
< resistance_size
)
3522 dx
= offsetrect
.left();
3524 else if (dright
> 0 && dright
< resistance_size
)
3525 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3528 if (dtop
> 0 && dtop
< resistance_size
)
3529 dy
= offsetrect
.top();
3531 else if (dbottom
> 0 && dbottom
< resistance_size
)
3532 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3533 } else { // BScreen::WindowSnap
3534 int dleft
= abs(wleft
- offsetrect
.left()),
3535 dright
= abs(wright
- offsetrect
.right()),
3536 dtop
= abs(wtop
- offsetrect
.top()),
3537 dbottom
= abs(wbottom
- offsetrect
.bottom());
3540 if (dleft
< snap_distance
&& dleft
<= dright
)
3541 dx
= offsetrect
.left();
3543 else if (dright
< snap_distance
)
3544 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3547 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3548 dy
= offsetrect
.top();
3550 else if (dbottom
< snap_distance
)
3551 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3558 void BlackboxWindow::endMove(void) {
3559 assert(flags
.moving
);
3560 assert(blackbox
->getChangingWindow() == this);
3562 flags
.moving
= False
;
3563 blackbox
->setChangingWindow(0);
3565 if (! screen
->doOpaqueMove()) {
3566 /* when drawing the rubber band, we need to make sure we only draw inside
3567 * the frame... frame.changing_* contain the new coords for the window,
3568 * so we need to subtract 1 from changing_w/changing_h every where we
3569 * draw the rubber band (for both moving and resizing)
3571 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3572 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3573 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3574 XUngrabServer(otk::OBDisplay::display
);
3576 configure(frame
.changing
.x(), frame
.changing
.y(),
3577 frame
.changing
.width(), frame
.changing
.height());
3579 configure(frame
.rect
.x(), frame
.rect
.y(),
3580 frame
.rect
.width(), frame
.rect
.height());
3582 screen
->hideGeometry();
3584 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3586 // if there are any left over motions from the move, drop them now
3587 XSync(otk::OBDisplay::display
, false); // make sure we don't miss any
3589 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, frame
.window
,
3594 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3595 if (! (functions
& Func_Resize
)) return;
3597 assert(! (flags
.resizing
|| flags
.moving
));
3600 Only one window can be moved/resized at a time. If another window is
3601 already being moved or resized, then stop it before whating to work with
3604 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3605 if (changing
&& changing
!= this) {
3606 if (changing
->flags
.moving
)
3607 changing
->endMove();
3608 else // if (changing->flags.resizing)
3609 changing
->endResize();
3617 switch (resize_dir
) {
3620 cursor
= blackbox
->getLowerLeftAngleCursor();
3625 cursor
= blackbox
->getLowerRightAngleCursor();
3629 anchor
= BottomRight
;
3630 cursor
= blackbox
->getUpperLeftAngleCursor();
3634 anchor
= BottomLeft
;
3635 cursor
= blackbox
->getUpperRightAngleCursor();
3639 assert(false); // unhandled Corner
3640 return; // unreachable, for the compiler
3643 XGrabServer(otk::OBDisplay::display
);
3644 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3645 PointerMotionMask
| ButtonReleaseMask
,
3646 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3648 flags
.resizing
= True
;
3649 blackbox
->setChangingWindow(this);
3651 unsigned int gw
, gh
;
3652 frame
.changing
= frame
.rect
;
3654 constrain(anchor
, &gw
, &gh
);
3656 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3657 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3658 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3660 screen
->showGeometry(gw
, gh
);
3662 frame
.grab_x
= x_root
;
3663 frame
.grab_y
= y_root
;
3667 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3668 assert(flags
.resizing
);
3669 assert(blackbox
->getChangingWindow() == this);
3671 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3672 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3673 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3675 unsigned int gw
, gh
;
3677 int dx
, dy
; // the amount of change in the size of the window
3679 switch (resize_dir
) {
3682 dx
= - (x_root
- frame
.grab_x
);
3683 dy
= + (y_root
- frame
.grab_y
);
3687 dx
= + (x_root
- frame
.grab_x
);
3688 dy
= + (y_root
- frame
.grab_y
);
3691 anchor
= BottomRight
;
3692 dx
= - (x_root
- frame
.grab_x
);
3693 dy
= - (y_root
- frame
.grab_y
);
3696 anchor
= BottomLeft
;
3697 dx
= + (x_root
- frame
.grab_x
);
3698 dy
= - (y_root
- frame
.grab_y
);
3702 assert(false); // unhandled Corner
3703 return; // unreachable, for the compiler
3706 // make sure the user cant resize the window smaller than 0, which makes it
3707 // wrap around and become huge
3708 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3709 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3711 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3713 constrain(anchor
, &gw
, &gh
);
3715 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3716 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3717 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3719 screen
->showGeometry(gw
, gh
);
3723 void BlackboxWindow::endResize(void) {
3724 assert(flags
.resizing
);
3725 assert(blackbox
->getChangingWindow() == this);
3727 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3728 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3729 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3730 XUngrabServer(otk::OBDisplay::display
);
3732 // unset maximized state after resized when fully maximized
3733 if (flags
.maximized
== 1)
3736 flags
.resizing
= False
;
3737 blackbox
->setChangingWindow(0);
3739 configure(frame
.changing
.x(), frame
.changing
.y(),
3740 frame
.changing
.width(), frame
.changing
.height());
3741 screen
->hideGeometry();
3743 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3745 // if there are any left over motions from the resize, drop them now
3746 XSync(otk::OBDisplay::display
, false); // make sure we don't miss any
3748 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, frame
.window
,
3753 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3755 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3760 doMove(me
->x_root
, me
->y_root
);
3761 } else if (flags
.resizing
) {
3762 doResize(me
->x_root
, me
->y_root
);
3764 if ((functions
& Func_Move
) &&
3765 (me
->state
& Button1Mask
) &&
3766 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3767 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3768 beginMove(me
->x_root
, me
->y_root
);
3769 } else if ((functions
& Func_Resize
) &&
3770 ((me
->state
& Button1Mask
) &&
3771 (me
->window
== frame
.right_grip
||
3772 me
->window
== frame
.left_grip
)) ||
3773 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3774 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3775 frame
.handle
== me
->window
|| frame
.window
== me
->window
||
3776 frame
.right_grip
== me
->window
||
3777 frame
.left_grip
== me
->window
))) {
3778 unsigned int zones
= screen
->getResizeZones();
3781 if (me
->window
== frame
.left_grip
) {
3782 corner
= BottomLeft
;
3783 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3784 corner
= BottomRight
;
3787 bool left
= (me
->x_root
- frame
.rect
.x() <=
3788 static_cast<signed>(frame
.rect
.width() / 2));
3791 else // (zones == 4)
3792 top
= (me
->y_root
- frame
.rect
.y() <=
3793 static_cast<signed>(frame
.rect
.height() / 2));
3794 corner
= (top
? (left
? TopLeft
: TopRight
) :
3795 (left
? BottomLeft
: BottomRight
));
3798 beginResize(me
->x_root
, me
->y_root
, corner
);
3804 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3805 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3809 bool leave
= False
, inferior
= False
;
3811 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, ce
->window
,
3813 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3815 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3819 if (! leave
|| inferior
) {
3820 if (! isFocused()) {
3821 bool success
= setInputFocus();
3822 if (success
) // if focus succeeded install the colormap
3823 installColormap(True
); // XXX: shouldnt we honour no install?
3826 We only auto-raise when the window wasn't focused because otherwise
3827 we run into problems with gtk+ drop-down lists. The window ends up
3828 raising over the list.
3830 if (screen
->doAutoRaise())
3837 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3838 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3841 installColormap(False
);
3848 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3849 if (blackbox
->hasShapeExtensions()) {
3850 if (! e
->shaped
&& flags
.shaped
) {
3852 flags
.shaped
= False
;
3853 } else if (e
->shaped
) {
3855 flags
.shaped
= True
;
3862 bool BlackboxWindow::validateClient(void) const {
3863 XSync(otk::OBDisplay::display
, False
);
3866 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3867 DestroyNotify
, &e
) ||
3868 XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3870 XPutBackEvent(otk::OBDisplay::display
, &e
);
3879 void BlackboxWindow::restore(bool remap
) {
3880 XChangeSaveSet(otk::OBDisplay::display
, client
.window
, SetModeDelete
);
3881 XSelectInput(otk::OBDisplay::display
, client
.window
, NoEventMask
);
3882 XSelectInput(otk::OBDisplay::display
, frame
.plate
, NoEventMask
);
3884 // do not leave a shaded window as an icon unless it was an icon
3885 if (flags
.shaded
&& ! flags
.iconic
)
3886 setState(NormalState
);
3888 // erase the netwm stuff that we read when a window maps, so that it
3889 // doesn't persist between mappings.
3890 // (these are the ones read in getNetWMFlags().)
3891 xatom
->erase(client
.window
, otk::OBProperty::net_wm_desktop
);
3892 xatom
->erase(client
.window
, otk::OBProperty::net_wm_state
);
3894 restoreGravity(client
.rect
);
3896 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
3897 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
3899 XSetWindowBorderWidth(otk::OBDisplay::display
, client
.window
, client
.old_bw
);
3902 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3903 ReparentNotify
, &ev
)) {
3906 // according to the ICCCM - if the client doesn't reparent to
3907 // root, then we have to do it for them
3908 XReparentWindow(otk::OBDisplay::display
, client
.window
,
3909 screen
->getRootWindow(),
3910 client
.rect
.x(), client
.rect
.y());
3913 if (remap
) XMapWindow(otk::OBDisplay::display
, client
.window
);
3917 // timer for autoraise
3918 void BlackboxWindow::timeout(BlackboxWindow
*t
) {
3919 t
->screen
->getWorkspace(t
->blackbox_attrib
.workspace
)->raiseWindow(t
);
3920 printf("TIMED OUT YA YAY\n");
3924 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3925 if ((net
->flags
& AttribShaded
) &&
3926 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3927 (net
->attrib
& AttribShaded
)))
3930 if (flags
.visible
&& // watch out for requests when we can not be seen
3931 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3932 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3933 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3934 if (flags
.maximized
) {
3939 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3940 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3941 else if (net
->flags
& AttribMaxVert
)
3942 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3943 else if (net
->flags
& AttribMaxHoriz
)
3944 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3950 if ((net
->flags
& AttribOmnipresent
) &&
3951 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3952 (net
->attrib
& AttribOmnipresent
)))
3955 if ((net
->flags
& AttribWorkspace
) &&
3956 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3957 screen
->reassociateWindow(this, net
->workspace
, True
);
3959 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3963 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3967 if (net
->flags
& AttribDecoration
) {
3968 switch (net
->decoration
) {
3985 * Set the sizes of all components of the window frame
3986 * (the window decorations).
3987 * These values are based upon the current style settings and the client
3988 * window's dimensions.
3990 void BlackboxWindow::upsize(void) {
3991 frame
.bevel_w
= screen
->getBevelWidth();
3993 if (decorations
& Decor_Border
) {
3994 frame
.border_w
= screen
->getBorderWidth();
3995 if (! isTransient())
3996 frame
.mwm_border_w
= screen
->getFrameWidth();
3998 frame
.mwm_border_w
= 0;
4000 frame
.mwm_border_w
= frame
.border_w
= 0;
4003 if (decorations
& Decor_Titlebar
) {
4004 // the height of the titlebar is based upon the height of the font being
4005 // used to display the window's title
4006 WindowStyle
*style
= screen
->getWindowStyle();
4007 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
4009 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
4010 frame
.button_w
= (frame
.label_h
- 2);
4012 // set the top frame margin
4013 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
4014 frame
.border_w
+ frame
.mwm_border_w
;
4020 // set the top frame margin
4021 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
4024 // set the left/right frame margin
4025 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
4027 if (decorations
& Decor_Handle
) {
4028 frame
.grip_w
= frame
.button_w
* 2;
4029 frame
.handle_h
= screen
->getHandleWidth();
4031 // set the bottom frame margin
4032 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
4033 frame
.border_w
+ frame
.mwm_border_w
;
4038 // set the bottom frame margin
4039 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
4043 We first get the normal dimensions and use this to define the inside_w/h
4044 then we modify the height if shading is in effect.
4045 If the shade state is not considered then frame.rect gets reset to the
4046 normal window size on a reconfigure() call resulting in improper
4047 dimensions appearing in move/resize and other events.
4050 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
4051 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4053 frame
.inside_w
= width
- (frame
.border_w
* 2);
4054 frame
.inside_h
= height
- (frame
.border_w
* 2);
4057 height
= frame
.title_h
+ (frame
.border_w
* 2);
4058 frame
.rect
.setSize(width
, height
);
4063 * Calculate the size of the client window and constrain it to the
4064 * size specified by the size hints of the client window.
4066 * The logical width and height are placed into pw and ph, if they
4067 * are non-zero. Logical size refers to the users perception of
4068 * the window size (for example an xterm resizes in cells, not in pixels).
4069 * pw and ph are then used to display the geometry during window moves, resize,
4072 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4073 * Physical geometry refers to the geometry of the window in pixels.
4075 void BlackboxWindow::constrain(Corner anchor
,
4076 unsigned int *pw
, unsigned int *ph
) {
4077 // frame.changing represents the requested frame size, we need to
4078 // strip the frame margin off and constrain the client size
4079 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4080 frame
.changing
.top() + frame
.margin
.top
,
4081 frame
.changing
.right() - frame
.margin
.right
,
4082 frame
.changing
.bottom() - frame
.margin
.bottom
);
4084 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4085 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4086 base_height
= (client
.base_height
) ? client
.base_height
:
4089 // constrain, but only if the min/max are being used. if they aren't, then
4090 // this resize is going to be from a ConfigureRequest because the window
4091 // isn't allowed to be resized by the user. And in that case, we don't want
4092 // to limit what the app can do
4093 if (client
.max_width
> client
.min_width
||
4094 client
.max_height
> client
.min_height
) {
4095 if (dw
< client
.min_width
) dw
= client
.min_width
;
4096 if (dh
< client
.min_height
) dh
= client
.min_height
;
4097 if (dw
> client
.max_width
) dw
= client
.max_width
;
4098 if (dh
> client
.max_height
) dh
= client
.max_height
;
4101 if (client
.width_inc
> 1) {
4103 dw
/= client
.width_inc
;
4105 if (client
.height_inc
> 1) {
4107 dh
/= client
.height_inc
;
4116 if (client
.width_inc
> 1) {
4117 dw
*= client
.width_inc
;
4120 if (client
.height_inc
> 1) {
4121 dh
*= client
.height_inc
;
4125 frame
.changing
.setSize(dw
, dh
);
4127 // add the frame margin back onto frame.changing
4128 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4129 frame
.changing
.top() - frame
.margin
.top
,
4130 frame
.changing
.right() + frame
.margin
.right
,
4131 frame
.changing
.bottom() + frame
.margin
.bottom
);
4133 // move frame.changing to the specified anchor
4141 dx
= frame
.rect
.right() - frame
.changing
.right();
4145 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4149 dx
= frame
.rect
.right() - frame
.changing
.right();
4150 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4154 assert(false); // unhandled corner
4156 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4160 void WindowStyle::doJustify(const std::string
&text
, int &start_pos
,
4161 unsigned int max_length
,
4162 unsigned int modifier
) const {
4163 size_t text_len
= text
.size();
4164 unsigned int length
;
4167 length
= font
->measureString(string(text
, 0, text_len
)) + modifier
;
4168 } while (length
> max_length
&& text_len
-- > 0);
4172 start_pos
+= max_length
- length
;
4176 start_pos
+= (max_length
- length
) / 2;
4186 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4187 : blackbox(b
), group(_group
) {
4188 XWindowAttributes wattrib
;
4189 if (! XGetWindowAttributes(otk::OBDisplay::display
, group
, &wattrib
)) {
4190 // group window doesn't seem to exist anymore
4195 XSelectInput(otk::OBDisplay::display
, group
,
4196 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4198 blackbox
->saveGroupSearch(group
, this);
4202 BWindowGroup::~BWindowGroup(void) {
4203 blackbox
->removeGroupSearch(group
);
4208 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4209 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4211 // does the focus window match (or any transient_fors)?
4212 for (; ret
; ret
= ret
->getTransientFor()) {
4213 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4214 (! ret
->isTransient() || allow_transients
))
4218 if (ret
) return ret
;
4220 // the focus window didn't match, look in the group's window list
4221 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4222 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4224 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4225 (! ret
->isTransient() || allow_transients
))