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"
31 #include "bbwindow.hh"
32 #include "workspace.hh"
34 #include "otk/util.hh"
35 #include "otk/style.hh"
43 * Initializes the class with default values/the window's set initial values.
45 BlackboxWindow::BlackboxWindow(Blackbox
*b
, Window w
, BScreen
*s
) {
46 // fprintf(stderr, "BlackboxWindow size: %d bytes\n",
47 // sizeof(BlackboxWindow));
50 fprintf(stderr
, "BlackboxWindow::BlackboxWindow(): creating 0x%lx\n", w
);
54 set timer to zero... it is initialized properly later, so we check
55 if timer is zero in the destructor, and assume that the window is not
56 fully constructed if timer is zero...
62 xatom
= blackbox
->getXAtom();
64 if (! validateClient()) {
69 // fetch client size and placement
70 XWindowAttributes wattrib
;
71 if (! XGetWindowAttributes(otk::OBDisplay::display
,
72 client
.window
, &wattrib
) ||
73 ! wattrib
.screen
|| wattrib
.override_redirect
) {
76 "BlackboxWindow::BlackboxWindow(): XGetWindowAttributes failed\n");
83 // set the eventmask early in the game so that we make sure we get
84 // all the events we are interested in
85 XSetWindowAttributes attrib_set
;
86 attrib_set
.event_mask
= PropertyChangeMask
| FocusChangeMask
|
88 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
90 XChangeWindowAttributes(otk::OBDisplay::display
, client
.window
,
91 CWEventMask
|CWDontPropagate
, &attrib_set
);
93 flags
.moving
= flags
.resizing
= flags
.shaded
= flags
.visible
=
94 flags
.iconic
= flags
.focused
= flags
.stuck
= flags
.modal
=
95 flags
.send_focus_message
= flags
.shaped
= flags
.skip_taskbar
=
96 flags
.skip_pager
= flags
.fullscreen
= False
;
99 blackbox_attrib
.workspace
= window_number
= otk::BSENTINEL
;
101 blackbox_attrib
.flags
= blackbox_attrib
.attrib
= blackbox_attrib
.stack
= 0l;
102 blackbox_attrib
.decoration
= DecorNormal
;
103 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
104 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
107 frame
.window
= frame
.plate
= frame
.title
= frame
.handle
= None
;
108 frame
.close_button
= frame
.iconify_button
= frame
.maximize_button
=
109 frame
.stick_button
= None
;
110 frame
.right_grip
= frame
.left_grip
= None
;
112 frame
.ulabel_pixel
= frame
.flabel_pixel
= frame
.utitle_pixel
=
113 frame
.ftitle_pixel
= frame
.uhandle_pixel
= frame
.fhandle_pixel
=
114 frame
.ubutton_pixel
= frame
.fbutton_pixel
= frame
.uborder_pixel
=
115 frame
.fborder_pixel
= frame
.ugrip_pixel
= frame
.fgrip_pixel
= 0;
116 frame
.utitle
= frame
.ftitle
= frame
.uhandle
= frame
.fhandle
= None
;
117 frame
.ulabel
= frame
.flabel
= frame
.ubutton
= frame
.fbutton
= None
;
118 frame
.ugrip
= frame
.fgrip
= None
;
120 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
;
121 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
122 Decor_Iconify
| Decor_Maximize
;
124 client
.normal_hint_flags
= 0;
125 client
.window_group
= None
;
126 client
.transient_for
= 0;
128 current_state
= NormalState
;
131 set the initial size and location of client window (relative to the
132 _root window_). This position is the reference point used with the
133 window's gravity to find the window's initial position.
135 client
.rect
.setRect(wattrib
.x
, wattrib
.y
, wattrib
.width
, wattrib
.height
);
136 client
.old_bw
= wattrib
.border_width
;
138 lastButtonPressTime
= 0;
140 timer
= new otk::OBTimer(Openbox::instance
->timerManager(),
141 (otk::OBTimeoutHandler
)timeout
,
143 timer
->setTimeout(blackbox
->getAutoRaiseDelay());
145 // get size, aspect, minimum/maximum size and other hints set by the
148 if (! getBlackboxHints())
155 frame
.window
= createToplevelWindow();
157 blackbox
->saveWindowSearch(frame
.window
, this);
159 frame
.plate
= createChildWindow(frame
.window
, ExposureMask
);
160 blackbox
->saveWindowSearch(frame
.plate
, this);
162 // determine if this is a transient window
165 // determine the window's type, so we can decide its decorations and
166 // functionality, or if we should not manage it at all
167 if (getWindowType()) {
168 // adjust the window decorations/behavior based on the window type
169 switch (window_type
) {
173 blackbox_attrib
.workspace
= 0; // we do need to belong to a workspace
174 flags
.stuck
= True
; // we show up on all workspaces
176 // none of these windows are manipulated by the window manager
182 // these windows get less functionality
183 functions
&= ~(Func_Maximize
| Func_Resize
| Func_Iconify
);
187 // dialogs cannot be maximized
188 functions
&= ~Func_Maximize
;
192 // normal windows retain all of the possible decorations and
200 // further adjeust the window's decorations/behavior based on window sizes
201 if ((client
.normal_hint_flags
& PMinSize
) &&
202 (client
.normal_hint_flags
& PMaxSize
) &&
203 client
.max_width
<= client
.min_width
&&
204 client
.max_height
<= client
.min_height
) {
205 functions
&= ~(Func_Resize
| Func_Maximize
);
212 if (decorations
& Decor_Titlebar
)
215 if (decorations
& Decor_Handle
)
218 // apply the size and gravity hint to the frame
222 bool place_window
= True
;
223 if (blackbox
->state() == Openbox::State_Starting
|| isTransient() ||
224 client
.normal_hint_flags
& (PPosition
|USPosition
)) {
225 applyGravity(frame
.rect
);
227 if (blackbox
->state() == Openbox::State_Starting
||
228 client
.rect
.intersects(screen
->getRect()))
229 place_window
= False
;
232 // add the window's strut. note this is done *after* placing the window.
233 screen
->addStrut(&client
.strut
);
237 the server needs to be grabbed here to prevent client's from sending
238 events while we are in the process of configuring their window.
239 We hold the grab until after we are done moving the window around.
242 XGrabServer(otk::OBDisplay::display
);
244 associateClientWindow();
246 blackbox
->saveWindowSearch(client
.window
, this);
248 if (blackbox_attrib
.workspace
>= screen
->getWorkspaceCount())
249 screen
->getCurrentWorkspace()->addWindow(this, place_window
);
251 screen
->getWorkspace(blackbox_attrib
.workspace
)->
252 addWindow(this, place_window
);
254 if (! place_window
) {
255 // don't need to call configure if we are letting the workspace
257 configure(frame
.rect
.x(), frame
.rect
.y(),
258 frame
.rect
.width(), frame
.rect
.height());
264 XUngrabServer(otk::OBDisplay::display
);
267 if (blackbox
->hasShapeExtensions() && flags
.shaped
)
271 // now that we know where to put the window and what it should look like
272 // we apply the decorations
277 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
279 // this ensures the title, buttons, and other decor are properly displayed
282 // preserve the window's initial state on first map, and its current state
284 unsigned long initial_state
= current_state
;
286 current_state
= initial_state
;
288 // get sticky state from our parent window if we've got one
289 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
290 client
.transient_for
->isStuck() != flags
.stuck
)
294 flags
.shaded
= False
;
295 initial_state
= current_state
;
299 At this point in the life of a window, current_state should only be set
300 to IconicState if the window was an *icon*, not if it was shaded.
302 if (initial_state
!= IconicState
)
303 current_state
= NormalState
;
311 if (flags
.maximized
&& (functions
& Func_Maximize
))
316 BlackboxWindow::~BlackboxWindow(void) {
318 fprintf(stderr
, "BlackboxWindow::~BlackboxWindow: destroying 0x%lx\n",
322 if (! timer
) // window not managed...
328 screen
->removeStrut(&client
.strut
);
329 screen
->updateAvailableArea();
331 // We don't need to worry about resizing because resizing always grabs the X
332 // server. This should only ever happen if using opaque moving.
338 if (client
.window_group
) {
339 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
340 if (group
) group
->removeWindow(this);
343 // remove ourselves from our transient_for
345 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul)
346 client
.transient_for
->client
.transientList
.remove(this);
347 client
.transient_for
= (BlackboxWindow
*) 0;
350 if (client
.transientList
.size() > 0) {
351 // reset transient_for for all transients
352 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
353 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
354 (*it
)->client
.transient_for
= (BlackboxWindow
*) 0;
364 blackbox
->removeWindowSearch(frame
.plate
);
365 XDestroyWindow(otk::OBDisplay::display
, frame
.plate
);
369 blackbox
->removeWindowSearch(frame
.window
);
370 XDestroyWindow(otk::OBDisplay::display
, frame
.window
);
373 blackbox
->removeWindowSearch(client
.window
);
377 void BlackboxWindow::enableDecor(bool enable
) {
378 blackbox_attrib
.flags
|= AttribDecoration
;
379 blackbox_attrib
.decoration
= enable
? DecorNormal
: DecorNone
;
382 // we can not be shaded if we lack a titlebar
383 if (! (decorations
& Decor_Titlebar
) && flags
.shaded
)
386 if (flags
.visible
&& frame
.window
) {
387 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
388 XMapWindow(otk::OBDisplay::display
, frame
.window
);
392 setState(current_state
);
396 void BlackboxWindow::setupDecor() {
397 if (blackbox_attrib
.decoration
!= DecorNone
) {
398 // start with everything on
399 decorations
= Decor_Close
|
400 (mwm_decorations
& Decor_Titlebar
? Decor_Titlebar
: 0) |
401 (mwm_decorations
& Decor_Border
? Decor_Border
: 0) |
402 (mwm_decorations
& Decor_Handle
? Decor_Handle
: 0) |
403 (mwm_decorations
& Decor_Iconify
? Decor_Iconify
: 0) |
404 (mwm_decorations
& Decor_Maximize
? Decor_Maximize
: 0);
406 if (! (functions
& Func_Close
)) decorations
&= ~Decor_Close
;
407 if (! (functions
& Func_Maximize
)) decorations
&= ~Decor_Maximize
;
408 if (! (functions
& Func_Iconify
)) decorations
&= ~Decor_Iconify
;
409 if (! (functions
& Func_Resize
)) decorations
&= ~Decor_Handle
;
411 switch (window_type
) {
416 // none of these windows are decorated by the window manager at all
422 decorations
&= ~(Decor_Border
);
426 decorations
&= ~Decor_Handle
;
438 * Creates a new top level window, with a given location, size, and border
440 * Returns: the newly created window
442 Window
BlackboxWindow::createToplevelWindow(void) {
443 XSetWindowAttributes attrib_create
;
444 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
| CWColormap
|
445 CWOverrideRedirect
| CWEventMask
;
447 attrib_create
.background_pixmap
= None
;
448 attrib_create
.colormap
= screen
->getColormap();
449 attrib_create
.override_redirect
= True
;
450 attrib_create
.event_mask
= EnterWindowMask
| LeaveWindowMask
|
453 We catch button presses because other wise they get passed down to the
454 root window, which will then cause root menus to show when you click the
458 return XCreateWindow(otk::OBDisplay::display
, screen
->getRootWindow(),
459 0, 0, 1, 1, frame
.border_w
, screen
->getDepth(),
460 InputOutput
, screen
->getVisual(), create_mask
,
466 * Creates a child window, and optionally associates a given cursor with
469 Window
BlackboxWindow::createChildWindow(Window parent
,
470 unsigned long event_mask
,
472 XSetWindowAttributes attrib_create
;
473 unsigned long create_mask
= CWBackPixmap
| CWBorderPixel
|
476 attrib_create
.background_pixmap
= None
;
477 attrib_create
.event_mask
= event_mask
;
480 create_mask
|= CWCursor
;
481 attrib_create
.cursor
= cursor
;
484 return XCreateWindow(otk::OBDisplay::display
, parent
, 0, 0, 1, 1, 0,
485 screen
->getDepth(), InputOutput
, screen
->getVisual(),
486 create_mask
, &attrib_create
);
490 void BlackboxWindow::associateClientWindow(void) {
491 XSetWindowBorderWidth(otk::OBDisplay::display
, client
.window
, 0);
495 XChangeSaveSet(otk::OBDisplay::display
, client
.window
, SetModeInsert
);
497 XSelectInput(otk::OBDisplay::display
, frame
.plate
, SubstructureRedirectMask
);
500 note we used to grab around this call to XReparentWindow however the
501 server is now grabbed before this method is called
503 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
505 XSelectInput(otk::OBDisplay::display
, client
.window
,
506 event_mask
& ~StructureNotifyMask
);
507 XReparentWindow(otk::OBDisplay::display
, client
.window
, frame
.plate
, 0, 0);
508 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
510 XRaiseWindow(otk::OBDisplay::display
, frame
.plate
);
511 XMapSubwindows(otk::OBDisplay::display
, frame
.plate
);
514 if (blackbox
->hasShapeExtensions()) {
515 XShapeSelectInput(otk::OBDisplay::display
, client
.window
,
522 XShapeQueryExtents(otk::OBDisplay::display
, client
.window
, &shaped
,
523 &foo
, &foo
, &ufoo
, &ufoo
, &foo
, &foo
, &foo
,
525 flags
.shaped
= shaped
;
531 void BlackboxWindow::decorate(void) {
532 otk::BTexture
* texture
;
534 texture
= &(screen
->getWindowStyle()->b_focus
);
535 frame
.fbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
538 frame
.fbutton_pixel
= texture
->color().pixel();
540 texture
= &(screen
->getWindowStyle()->b_unfocus
);
541 frame
.ubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
544 frame
.ubutton_pixel
= texture
->color().pixel();
546 unsigned char needsPressed
= 0;
548 texture
= &(screen
->getWindowStyle()->b_pressed_focus
);
550 if (texture
->texture() != otk::BTexture::NoTexture
) {
551 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
553 if (! frame
.pfbutton
)
554 frame
.pfbutton_pixel
= texture
->color().pixel();
559 texture
= &(screen
->getWindowStyle()->b_pressed_unfocus
);
561 if (texture
->texture() != otk::BTexture::NoTexture
) {
562 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
564 if (! frame
.pubutton
)
565 frame
.pubutton
= texture
->color().pixel();
570 // if we either pressed unfocused, or pressed focused were undefined,
571 // make them inherit from the old resource. It's a hack for sure, but
572 // it allows for some backwards and forwards compatibility.
574 texture
= &(screen
->getWindowStyle()->b_pressed
);
576 if (needsPressed
& 0x1) {
577 frame
.pfbutton
= texture
->render(frame
.button_w
, frame
.button_w
,
579 if (! frame
.pfbutton
)
580 frame
.pfbutton_pixel
= texture
->color().pixel();
582 if (needsPressed
& 0x2) {
583 frame
.pubutton
= texture
->render(frame
.button_w
, frame
.button_w
,
585 if (! frame
.pubutton
)
586 frame
.pubutton
= texture
->color().pixel();
591 if (decorations
& Decor_Titlebar
) {
592 texture
= &(screen
->getWindowStyle()->t_focus
);
593 frame
.ftitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
596 frame
.ftitle_pixel
= texture
->color().pixel();
598 texture
= &(screen
->getWindowStyle()->t_unfocus
);
599 frame
.utitle
= texture
->render(frame
.inside_w
, frame
.title_h
,
602 frame
.utitle_pixel
= texture
->color().pixel();
604 XSetWindowBorder(otk::OBDisplay::display
, frame
.title
,
605 screen
->getBorderColor()->pixel());
610 if (decorations
& Decor_Border
) {
611 frame
.fborder_pixel
= screen
->getWindowStyle()->f_focus
.color().pixel();
612 frame
.uborder_pixel
= screen
->getWindowStyle()->f_unfocus
.color().pixel();
615 if (decorations
& Decor_Handle
) {
616 texture
= &(screen
->getWindowStyle()->h_focus
);
617 frame
.fhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
620 frame
.fhandle_pixel
= texture
->color().pixel();
622 texture
= &(screen
->getWindowStyle()->h_unfocus
);
623 frame
.uhandle
= texture
->render(frame
.inside_w
, frame
.handle_h
,
626 frame
.uhandle_pixel
= texture
->color().pixel();
628 texture
= &(screen
->getWindowStyle()->g_focus
);
629 frame
.fgrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.fgrip
);
631 frame
.fgrip_pixel
= texture
->color().pixel();
633 texture
= &(screen
->getWindowStyle()->g_unfocus
);
634 frame
.ugrip
= texture
->render(frame
.grip_w
, frame
.handle_h
, frame
.ugrip
);
636 frame
.ugrip_pixel
= texture
->color().pixel();
638 XSetWindowBorder(otk::OBDisplay::display
, frame
.handle
,
639 screen
->getBorderColor()->pixel());
640 XSetWindowBorder(otk::OBDisplay::display
, frame
.left_grip
,
641 screen
->getBorderColor()->pixel());
642 XSetWindowBorder(otk::OBDisplay::display
, frame
.right_grip
,
643 screen
->getBorderColor()->pixel());
646 XSetWindowBorder(otk::OBDisplay::display
, frame
.window
,
647 screen
->getBorderColor()->pixel());
651 void BlackboxWindow::decorateLabel(void) {
652 otk::BTexture
*texture
;
654 texture
= &(screen
->getWindowStyle()->l_focus
);
655 frame
.flabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.flabel
);
657 frame
.flabel_pixel
= texture
->color().pixel();
659 texture
= &(screen
->getWindowStyle()->l_unfocus
);
660 frame
.ulabel
= texture
->render(frame
.label_w
, frame
.label_h
, frame
.ulabel
);
662 frame
.ulabel_pixel
= texture
->color().pixel();
666 void BlackboxWindow::createHandle(void) {
667 frame
.handle
= createChildWindow(frame
.window
,
668 ButtonPressMask
| ButtonReleaseMask
|
669 ButtonMotionMask
| ExposureMask
);
670 blackbox
->saveWindowSearch(frame
.handle
, this);
673 createChildWindow(frame
.handle
,
674 ButtonPressMask
| ButtonReleaseMask
|
675 ButtonMotionMask
| ExposureMask
,
676 blackbox
->getLowerLeftAngleCursor());
677 blackbox
->saveWindowSearch(frame
.left_grip
, this);
680 createChildWindow(frame
.handle
,
681 ButtonPressMask
| ButtonReleaseMask
|
682 ButtonMotionMask
| ExposureMask
,
683 blackbox
->getLowerRightAngleCursor());
684 blackbox
->saveWindowSearch(frame
.right_grip
, this);
688 void BlackboxWindow::destroyHandle(void) {
690 screen
->getImageControl()->removeImage(frame
.fhandle
);
693 screen
->getImageControl()->removeImage(frame
.uhandle
);
696 screen
->getImageControl()->removeImage(frame
.fgrip
);
699 screen
->getImageControl()->removeImage(frame
.ugrip
);
701 blackbox
->removeWindowSearch(frame
.left_grip
);
702 blackbox
->removeWindowSearch(frame
.right_grip
);
704 XDestroyWindow(otk::OBDisplay::display
, frame
.left_grip
);
705 XDestroyWindow(otk::OBDisplay::display
, frame
.right_grip
);
706 frame
.left_grip
= frame
.right_grip
= None
;
708 blackbox
->removeWindowSearch(frame
.handle
);
709 XDestroyWindow(otk::OBDisplay::display
, frame
.handle
);
714 void BlackboxWindow::createTitlebar(void) {
715 frame
.title
= createChildWindow(frame
.window
,
716 ButtonPressMask
| ButtonReleaseMask
|
717 ButtonMotionMask
| ExposureMask
);
718 frame
.label
= createChildWindow(frame
.title
,
719 ButtonPressMask
| ButtonReleaseMask
|
720 ButtonMotionMask
| ExposureMask
);
721 blackbox
->saveWindowSearch(frame
.title
, this);
722 blackbox
->saveWindowSearch(frame
.label
, this);
724 if (decorations
& Decor_Iconify
) createIconifyButton();
725 if (decorations
& Decor_Maximize
) createMaximizeButton();
726 if (decorations
& Decor_Close
) createCloseButton();
730 void BlackboxWindow::destroyTitlebar(void) {
731 if (frame
.close_button
)
732 destroyCloseButton();
734 if (frame
.iconify_button
)
735 destroyIconifyButton();
737 if (frame
.maximize_button
)
738 destroyMaximizeButton();
740 if (frame
.stick_button
)
741 destroyStickyButton();
744 screen
->getImageControl()->removeImage(frame
.ftitle
);
747 screen
->getImageControl()->removeImage(frame
.utitle
);
750 screen
->getImageControl()->removeImage(frame
.flabel
);
753 screen
->getImageControl()->removeImage(frame
.ulabel
);
756 screen
->getImageControl()->removeImage(frame
.fbutton
);
759 screen
->getImageControl()->removeImage(frame
.ubutton
);
761 blackbox
->removeWindowSearch(frame
.title
);
762 blackbox
->removeWindowSearch(frame
.label
);
764 XDestroyWindow(otk::OBDisplay::display
, frame
.label
);
765 XDestroyWindow(otk::OBDisplay::display
, frame
.title
);
766 frame
.title
= frame
.label
= None
;
770 void BlackboxWindow::createCloseButton(void) {
771 if (frame
.title
!= None
) {
772 frame
.close_button
= createChildWindow(frame
.title
,
775 ButtonMotionMask
| ExposureMask
);
776 blackbox
->saveWindowSearch(frame
.close_button
, this);
781 void BlackboxWindow::destroyCloseButton(void) {
782 blackbox
->removeWindowSearch(frame
.close_button
);
783 XDestroyWindow(otk::OBDisplay::display
, frame
.close_button
);
784 frame
.close_button
= None
;
788 void BlackboxWindow::createIconifyButton(void) {
789 if (frame
.title
!= None
) {
790 frame
.iconify_button
= createChildWindow(frame
.title
,
793 ButtonMotionMask
| ExposureMask
);
794 blackbox
->saveWindowSearch(frame
.iconify_button
, this);
799 void BlackboxWindow::destroyIconifyButton(void) {
800 blackbox
->removeWindowSearch(frame
.iconify_button
);
801 XDestroyWindow(otk::OBDisplay::display
, frame
.iconify_button
);
802 frame
.iconify_button
= None
;
806 void BlackboxWindow::createMaximizeButton(void) {
807 if (frame
.title
!= None
) {
808 frame
.maximize_button
= createChildWindow(frame
.title
,
811 ButtonMotionMask
| ExposureMask
);
812 blackbox
->saveWindowSearch(frame
.maximize_button
, this);
817 void BlackboxWindow::destroyMaximizeButton(void) {
818 blackbox
->removeWindowSearch(frame
.maximize_button
);
819 XDestroyWindow(otk::OBDisplay::display
, frame
.maximize_button
);
820 frame
.maximize_button
= None
;
823 void BlackboxWindow::createStickyButton(void) {
824 if (frame
.title
!= None
) {
825 frame
.stick_button
= createChildWindow(frame
.title
,
828 ButtonMotionMask
| ExposureMask
);
829 blackbox
->saveWindowSearch(frame
.stick_button
, this);
833 void BlackboxWindow::destroyStickyButton(void) {
834 blackbox
->removeWindowSearch(frame
.stick_button
);
835 XDestroyWindow(otk::OBDisplay::display
, frame
.stick_button
);
836 frame
.stick_button
= None
;
839 void BlackboxWindow::positionButtons(bool redecorate_label
) {
840 string layout
= blackbox
->getTitlebarLayout();
843 bool hasclose
, hasiconify
, hasmaximize
, haslabel
, hasstick
;
844 hasclose
= hasiconify
= hasmaximize
= haslabel
= hasstick
= false;
846 string::const_iterator it
, end
;
847 for (it
= layout
.begin(), end
= layout
.end(); it
!= end
; ++it
) {
850 if (! hasclose
&& (decorations
& Decor_Close
)) {
856 if (! hasiconify
&& (decorations
& Decor_Iconify
)) {
868 if (! hasmaximize
&& (decorations
& Decor_Maximize
)) {
882 if (! hasclose
&& frame
.close_button
)
883 destroyCloseButton();
884 if (! hasiconify
&& frame
.iconify_button
)
885 destroyIconifyButton();
886 if (! hasmaximize
&& frame
.maximize_button
)
887 destroyMaximizeButton();
888 if (! hasstick
&& frame
.stick_button
)
889 destroyStickyButton();
891 parsed
+= 'L'; // require that the label be in the layout
893 const unsigned int bsep
= frame
.bevel_w
+ 1; // separation between elements
894 const unsigned int by
= frame
.bevel_w
+ 1;
895 const unsigned int ty
= frame
.bevel_w
;
897 frame
.label_w
= frame
.inside_w
- bsep
* 2 -
898 (frame
.button_w
+ bsep
) * (parsed
.size() - 1);
900 unsigned int x
= bsep
;
901 for (it
= parsed
.begin(), end
= parsed
.end(); it
!= end
; ++it
) {
904 if (! frame
.close_button
) createCloseButton();
905 XMoveResizeWindow(otk::OBDisplay::display
, frame
.close_button
, x
, by
,
906 frame
.button_w
, frame
.button_w
);
907 x
+= frame
.button_w
+ bsep
;
910 if (! frame
.iconify_button
) createIconifyButton();
911 XMoveResizeWindow(otk::OBDisplay::display
, frame
.iconify_button
, x
, by
,
912 frame
.button_w
, frame
.button_w
);
913 x
+= frame
.button_w
+ bsep
;
916 if (! frame
.stick_button
) createStickyButton();
917 XMoveResizeWindow(otk::OBDisplay::display
, frame
.stick_button
, x
, by
,
918 frame
.button_w
, frame
.button_w
);
919 x
+= frame
.button_w
+ bsep
;
922 if (! frame
.maximize_button
) createMaximizeButton();
923 XMoveResizeWindow(otk::OBDisplay::display
, frame
.maximize_button
, x
, by
,
924 frame
.button_w
, frame
.button_w
);
925 x
+= frame
.button_w
+ bsep
;
928 XMoveResizeWindow(otk::OBDisplay::display
, frame
.label
, x
, ty
,
929 frame
.label_w
, frame
.label_h
);
930 x
+= frame
.label_w
+ bsep
;
935 if (redecorate_label
) decorateLabel();
941 void BlackboxWindow::reconfigure(void) {
942 restoreGravity(client
.rect
);
944 applyGravity(frame
.rect
);
954 void BlackboxWindow::grabButtons(void) {
955 mod_mask
= blackbox
->getMouseModMask();
957 if (! screen
->isSloppyFocus() || screen
->doClickRaise())
958 // grab button 1 for changing focus/raising
959 otk::OBDisplay::grabButton(Button1
, 0, frame
.plate
, True
, ButtonPressMask
,
960 GrabModeSync
, GrabModeSync
, frame
.plate
, None
,
961 screen
->allowScrollLock());
963 if (functions
& Func_Move
)
964 otk::OBDisplay::grabButton(Button1
, mod_mask
, frame
.window
, True
,
965 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
966 GrabModeAsync
, frame
.window
, None
,
967 screen
->allowScrollLock());
968 if (functions
& Func_Resize
)
969 otk::OBDisplay::grabButton(Button3
, mod_mask
, frame
.window
, True
,
970 ButtonReleaseMask
| ButtonMotionMask
, GrabModeAsync
,
971 GrabModeAsync
, frame
.window
, None
,
972 screen
->allowScrollLock());
973 // alt+middle lowers the window
974 otk::OBDisplay::grabButton(Button2
, mod_mask
, frame
.window
, True
,
975 ButtonReleaseMask
, GrabModeAsync
, GrabModeAsync
,
976 frame
.window
, None
, screen
->allowScrollLock());
980 void BlackboxWindow::ungrabButtons(void) {
981 otk::OBDisplay::ungrabButton(Button1
, 0, frame
.plate
);
982 otk::OBDisplay::ungrabButton(Button1
, mod_mask
, frame
.window
);
983 otk::OBDisplay::ungrabButton(Button2
, mod_mask
, frame
.window
);
984 otk::OBDisplay::ungrabButton(Button3
, mod_mask
, frame
.window
);
988 void BlackboxWindow::positionWindows(void) {
989 XMoveResizeWindow(otk::OBDisplay::display
, frame
.window
,
990 frame
.rect
.x(), frame
.rect
.y(), frame
.inside_w
,
991 (flags
.shaded
) ? frame
.title_h
: frame
.inside_h
);
992 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.window
,
994 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.plate
,
996 XMoveResizeWindow(otk::OBDisplay::display
, frame
.plate
,
997 frame
.margin
.left
- frame
.mwm_border_w
- frame
.border_w
,
998 frame
.margin
.top
- frame
.mwm_border_w
- frame
.border_w
,
999 client
.rect
.width(), client
.rect
.height());
1000 XMoveResizeWindow(otk::OBDisplay::display
, client
.window
,
1001 0, 0, client
.rect
.width(), client
.rect
.height());
1002 // ensure client.rect contains the real location
1003 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1004 frame
.rect
.top() + frame
.margin
.top
);
1006 if (decorations
& Decor_Titlebar
) {
1007 if (frame
.title
== None
) createTitlebar();
1009 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.title
,
1011 XMoveResizeWindow(otk::OBDisplay::display
, frame
.title
, -frame
.border_w
,
1012 -frame
.border_w
, frame
.inside_w
, frame
.title_h
);
1015 XMapSubwindows(otk::OBDisplay::display
, frame
.title
);
1016 XMapWindow(otk::OBDisplay::display
, frame
.title
);
1017 } else if (frame
.title
) {
1020 if (decorations
& Decor_Handle
) {
1021 if (frame
.handle
== None
) createHandle();
1022 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.handle
,
1024 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.left_grip
,
1026 XSetWindowBorderWidth(otk::OBDisplay::display
, frame
.right_grip
,
1029 // use client.rect here so the value is correct even if shaded
1030 XMoveResizeWindow(otk::OBDisplay::display
, frame
.handle
,
1032 client
.rect
.height() + frame
.margin
.top
+
1033 frame
.mwm_border_w
- frame
.border_w
,
1034 frame
.inside_w
, frame
.handle_h
);
1035 XMoveResizeWindow(otk::OBDisplay::display
, frame
.left_grip
,
1036 -frame
.border_w
, -frame
.border_w
,
1037 frame
.grip_w
, frame
.handle_h
);
1038 XMoveResizeWindow(otk::OBDisplay::display
, frame
.right_grip
,
1039 frame
.inside_w
- frame
.grip_w
- frame
.border_w
,
1040 -frame
.border_w
, frame
.grip_w
, frame
.handle_h
);
1042 XMapSubwindows(otk::OBDisplay::display
, frame
.handle
);
1043 XMapWindow(otk::OBDisplay::display
, frame
.handle
);
1044 } else if (frame
.handle
) {
1047 XSync(otk::OBDisplay::display
, False
);
1051 void BlackboxWindow::updateStrut(void) {
1052 unsigned long num
= 4;
1053 unsigned long *data
;
1054 if (! xatom
->get(client
.window
, otk::OBProperty::net_wm_strut
,
1055 otk::OBProperty::Atom_Cardinal
,
1060 client
.strut
.left
= data
[0];
1061 client
.strut
.right
= data
[1];
1062 client
.strut
.top
= data
[2];
1063 client
.strut
.bottom
= data
[3];
1065 screen
->updateAvailableArea();
1072 bool BlackboxWindow::getWindowType(void) {
1073 window_type
= (WindowType
) -1;
1076 unsigned long num
= (unsigned) -1;
1077 if (xatom
->get(client
.window
, otk::OBProperty::net_wm_window_type
,
1078 otk::OBProperty::Atom_Atom
,
1080 for (unsigned long i
= 0; i
< num
; ++i
) {
1081 if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_desktop
))
1082 window_type
= Type_Desktop
;
1083 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_dock
))
1084 window_type
= Type_Dock
;
1085 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_toolbar
))
1086 window_type
= Type_Toolbar
;
1087 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_menu
))
1088 window_type
= Type_Menu
;
1089 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_utility
))
1090 window_type
= Type_Utility
;
1091 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_splash
))
1092 window_type
= Type_Splash
;
1093 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_dialog
))
1094 window_type
= Type_Dialog
;
1095 else if (val
[i
] == xatom
->atom(otk::OBProperty::net_wm_window_type_normal
))
1096 window_type
= Type_Normal
;
1098 xatom
->atom(otk::OBProperty::kde_net_wm_window_type_override
))
1099 mwm_decorations
= 0; // prevent this window from getting any decor
1104 if (window_type
== (WindowType
) -1) {
1106 * the window type hint was not set, which means we either classify ourself
1107 * as a normal window or a dialog, depending on if we are a transient.
1110 window_type
= Type_Dialog
;
1112 window_type
= Type_Normal
;
1121 void BlackboxWindow::getWMName(void) {
1122 if (xatom
->get(client
.window
, otk::OBProperty::net_wm_name
,
1123 otk::OBProperty::utf8
, &client
.title
) &&
1124 !client
.title
.empty()) {
1125 xatom
->erase(client
.window
, otk::OBProperty::net_wm_visible_name
);
1128 //fall through to using WM_NAME
1129 if (xatom
->get(client
.window
, otk::OBProperty::wm_name
,
1130 otk::OBProperty::ascii
, &client
.title
)
1131 && !client
.title
.empty()) {
1132 xatom
->erase(client
.window
, otk::OBProperty::net_wm_visible_name
);
1135 // fall back to an internal default
1136 client
.title
= "Unnamed";
1137 xatom
->set(client
.window
, otk::OBProperty::net_wm_visible_name
,
1138 otk::OBProperty::utf8
, client
.title
);
1140 #ifdef DEBUG_WITH_ID
1141 // the 16 is the 8 chars of the debug text plus the number
1142 char *tmp
= new char[client
.title
.length() + 16];
1143 sprintf(tmp
, "%s; id: 0x%lx", client
.title
.c_str(), client
.window
);
1150 void BlackboxWindow::getWMIconName(void) {
1151 if (xatom
->get(client
.window
, otk::OBProperty::net_wm_icon_name
,
1152 otk::OBProperty::utf8
, &client
.icon_title
) &&
1153 !client
.icon_title
.empty()) {
1154 xatom
->erase(client
.window
, otk::OBProperty::net_wm_visible_icon_name
);
1157 //fall through to using WM_ICON_NAME
1158 if (xatom
->get(client
.window
, otk::OBProperty::wm_icon_name
,
1159 otk::OBProperty::ascii
,
1160 &client
.icon_title
) &&
1161 !client
.icon_title
.empty()) {
1162 xatom
->erase(client
.window
, otk::OBProperty::net_wm_visible_icon_name
);
1165 // fall back to using the main name
1166 client
.icon_title
= client
.title
;
1167 xatom
->set(client
.window
, otk::OBProperty::net_wm_visible_icon_name
,
1168 otk::OBProperty::utf8
,
1174 * Retrieve which WM Protocols are supported by the client window.
1175 * If the WM_DELETE_WINDOW protocol is supported, add the close button to the
1176 * window's decorations and allow the close behavior.
1177 * If the WM_TAKE_FOCUS protocol is supported, save a value that indicates
1180 void BlackboxWindow::getWMProtocols(void) {
1184 if (XGetWMProtocols(otk::OBDisplay::display
, client
.window
,
1185 &proto
, &num_return
)) {
1186 for (int i
= 0; i
< num_return
; ++i
) {
1187 if (proto
[i
] == xatom
->atom(otk::OBProperty::wm_delete_window
)) {
1188 decorations
|= Decor_Close
;
1189 functions
|= Func_Close
;
1190 } else if (proto
[i
] == xatom
->atom(otk::OBProperty::wm_take_focus
))
1191 flags
.send_focus_message
= True
;
1200 * Gets the value of the WM_HINTS property.
1201 * If the property is not set, then use a set of default values.
1203 void BlackboxWindow::getWMHints(void) {
1204 focus_mode
= F_Passive
;
1206 // remove from current window group
1207 if (client
.window_group
) {
1208 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1209 if (group
) group
->removeWindow(this);
1211 client
.window_group
= None
;
1213 XWMHints
*wmhint
= XGetWMHints(otk::OBDisplay::display
, client
.window
);
1218 if (wmhint
->flags
& InputHint
) {
1219 if (wmhint
->input
== True
) {
1220 if (flags
.send_focus_message
)
1221 focus_mode
= F_LocallyActive
;
1223 if (flags
.send_focus_message
)
1224 focus_mode
= F_GloballyActive
;
1226 focus_mode
= F_NoInput
;
1230 if (wmhint
->flags
& StateHint
)
1231 current_state
= wmhint
->initial_state
;
1233 if (wmhint
->flags
& WindowGroupHint
) {
1234 client
.window_group
= wmhint
->window_group
;
1236 // add window to the appropriate group
1237 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1238 if (! group
) { // no group found, create it!
1239 new BWindowGroup(blackbox
, client
.window_group
);
1240 group
= blackbox
->searchGroup(client
.window_group
);
1243 group
->addWindow(this);
1251 * Gets the value of the WM_NORMAL_HINTS property.
1252 * If the property is not set, then use a set of default values.
1254 void BlackboxWindow::getWMNormalHints(void) {
1256 XSizeHints sizehint
;
1258 client
.min_width
= client
.min_height
=
1259 client
.width_inc
= client
.height_inc
= 1;
1260 client
.base_width
= client
.base_height
= 0;
1261 client
.win_gravity
= NorthWestGravity
;
1263 client
.min_aspect_x
= client
.min_aspect_y
=
1264 client
.max_aspect_x
= client
.max_aspect_y
= 1;
1267 // don't limit the size of a window, the default max width is the biggest
1269 client
.max_width
= (unsigned) -1;
1270 client
.max_height
= (unsigned) -1;
1273 if (! XGetWMNormalHints(otk::OBDisplay::display
, client
.window
,
1274 &sizehint
, &icccm_mask
))
1277 client
.normal_hint_flags
= sizehint
.flags
;
1279 if (sizehint
.flags
& PMinSize
) {
1280 if (sizehint
.min_width
>= 0)
1281 client
.min_width
= sizehint
.min_width
;
1282 if (sizehint
.min_height
>= 0)
1283 client
.min_height
= sizehint
.min_height
;
1286 if (sizehint
.flags
& PMaxSize
) {
1287 if (sizehint
.max_width
> static_cast<signed>(client
.min_width
))
1288 client
.max_width
= sizehint
.max_width
;
1290 client
.max_width
= client
.min_width
;
1292 if (sizehint
.max_height
> static_cast<signed>(client
.min_height
))
1293 client
.max_height
= sizehint
.max_height
;
1295 client
.max_height
= client
.min_height
;
1298 if (sizehint
.flags
& PResizeInc
) {
1299 client
.width_inc
= sizehint
.width_inc
;
1300 client
.height_inc
= sizehint
.height_inc
;
1303 #if 0 // we do not support this at the moment
1304 if (sizehint
.flags
& PAspect
) {
1305 client
.min_aspect_x
= sizehint
.min_aspect
.x
;
1306 client
.min_aspect_y
= sizehint
.min_aspect
.y
;
1307 client
.max_aspect_x
= sizehint
.max_aspect
.x
;
1308 client
.max_aspect_y
= sizehint
.max_aspect
.y
;
1312 if (sizehint
.flags
& PBaseSize
) {
1313 client
.base_width
= sizehint
.base_width
;
1314 client
.base_height
= sizehint
.base_height
;
1317 if (sizehint
.flags
& PWinGravity
)
1318 client
.win_gravity
= sizehint
.win_gravity
;
1323 * Gets the NETWM hints for the class' contained window.
1325 void BlackboxWindow::getNetWMHints(void) {
1326 unsigned long workspace
;
1328 if (xatom
->get(client
.window
, otk::OBProperty::net_wm_desktop
,
1329 otk::OBProperty::Atom_Cardinal
,
1331 if (workspace
== 0xffffffff)
1334 blackbox_attrib
.workspace
= workspace
;
1337 unsigned long *state
;
1338 unsigned long num
= (unsigned) -1;
1339 if (xatom
->get(client
.window
, otk::OBProperty::net_wm_state
,
1340 otk::OBProperty::Atom_Atom
,
1344 for (unsigned long i
= 0; i
< num
; ++i
) {
1345 if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_modal
))
1347 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_shaded
))
1348 flags
.shaded
= True
;
1349 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_skip_taskbar
))
1350 flags
.skip_taskbar
= True
;
1351 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_skip_pager
))
1352 flags
.skip_pager
= True
;
1353 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_fullscreen
))
1354 flags
.fullscreen
= True
;
1355 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_hidden
))
1356 setState(IconicState
);
1357 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_maximized_vert
))
1359 else if (state
[i
] == xatom
->atom(otk::OBProperty::net_wm_state_maximized_horz
))
1363 flags
.maximized
= 1;
1365 flags
.maximized
= 2;
1367 flags
.maximized
= 3;
1375 * Gets the MWM hints for the class' contained window.
1376 * This is used while initializing the window to its first state, and not
1378 * Returns: true if the MWM hints are successfully retreived and applied;
1379 * false if they are not.
1381 void BlackboxWindow::getMWMHints(void) {
1385 num
= PropMwmHintsElements
;
1386 if (! xatom
->get(client
.window
, otk::OBProperty::motif_wm_hints
,
1387 otk::OBProperty::motif_wm_hints
, &num
,
1388 (unsigned long **)&mwm_hint
))
1390 if (num
< PropMwmHintsElements
) {
1395 if (mwm_hint
->flags
& MwmHintsDecorations
) {
1396 if (mwm_hint
->decorations
& MwmDecorAll
) {
1397 mwm_decorations
= Decor_Titlebar
| Decor_Handle
| Decor_Border
|
1398 Decor_Iconify
| Decor_Maximize
;
1400 mwm_decorations
= 0;
1402 if (mwm_hint
->decorations
& MwmDecorBorder
)
1403 mwm_decorations
|= Decor_Border
;
1404 if (mwm_hint
->decorations
& MwmDecorHandle
)
1405 mwm_decorations
|= Decor_Handle
;
1406 if (mwm_hint
->decorations
& MwmDecorTitle
)
1407 mwm_decorations
|= Decor_Titlebar
;
1408 if (mwm_hint
->decorations
& MwmDecorIconify
)
1409 mwm_decorations
|= Decor_Iconify
;
1410 if (mwm_hint
->decorations
& MwmDecorMaximize
)
1411 mwm_decorations
|= Decor_Maximize
;
1415 if (mwm_hint
->flags
& MwmHintsFunctions
) {
1416 if (mwm_hint
->functions
& MwmFuncAll
) {
1417 functions
= Func_Resize
| Func_Move
| Func_Iconify
| Func_Maximize
|
1422 if (mwm_hint
->functions
& MwmFuncResize
)
1423 functions
|= Func_Resize
;
1424 if (mwm_hint
->functions
& MwmFuncMove
)
1425 functions
|= Func_Move
;
1426 if (mwm_hint
->functions
& MwmFuncIconify
)
1427 functions
|= Func_Iconify
;
1428 if (mwm_hint
->functions
& MwmFuncMaximize
)
1429 functions
|= Func_Maximize
;
1430 if (mwm_hint
->functions
& MwmFuncClose
)
1431 functions
|= Func_Close
;
1439 * Gets the blackbox hints from the class' contained window.
1440 * This is used while initializing the window to its first state, and not
1442 * Returns: true if the hints are successfully retreived and applied; false if
1445 bool BlackboxWindow::getBlackboxHints(void) {
1447 BlackboxHints
*blackbox_hint
;
1449 num
= PropBlackboxHintsElements
;
1450 if (! xatom
->get(client
.window
, otk::OBProperty::blackbox_hints
,
1451 otk::OBProperty::blackbox_hints
, &num
,
1452 (unsigned long **)&blackbox_hint
))
1454 if (num
< PropBlackboxHintsElements
) {
1455 delete [] blackbox_hint
;
1459 if (blackbox_hint
->flags
& AttribShaded
)
1460 flags
.shaded
= (blackbox_hint
->attrib
& AttribShaded
);
1462 if ((blackbox_hint
->flags
& AttribMaxHoriz
) &&
1463 (blackbox_hint
->flags
& AttribMaxVert
))
1464 flags
.maximized
= (blackbox_hint
->attrib
&
1465 (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
1466 else if (blackbox_hint
->flags
& AttribMaxVert
)
1467 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxVert
) ? 2 : 0;
1468 else if (blackbox_hint
->flags
& AttribMaxHoriz
)
1469 flags
.maximized
= (blackbox_hint
->attrib
& AttribMaxHoriz
) ? 3 : 0;
1471 if (blackbox_hint
->flags
& AttribOmnipresent
)
1472 flags
.stuck
= (blackbox_hint
->attrib
& AttribOmnipresent
);
1474 if (blackbox_hint
->flags
& AttribWorkspace
)
1475 blackbox_attrib
.workspace
= blackbox_hint
->workspace
;
1477 // if (blackbox_hint->flags & AttribStack)
1478 // don't yet have always on top/bottom for blackbox yet... working
1481 if (blackbox_hint
->flags
& AttribDecoration
) {
1482 switch (blackbox_hint
->decoration
) {
1484 blackbox_attrib
.decoration
= DecorNone
;
1491 // blackbox_attrib.decoration defaults to DecorNormal
1496 delete [] blackbox_hint
;
1502 void BlackboxWindow::getTransientInfo(void) {
1503 if (client
.transient_for
&&
1504 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1505 // reset transient_for in preparation of looking for a new owner
1506 client
.transient_for
->client
.transientList
.remove(this);
1509 // we have no transient_for until we find a new one
1510 client
.transient_for
= (BlackboxWindow
*) 0;
1513 if (! XGetTransientForHint(otk::OBDisplay::display
, client
.window
,
1515 // transient_for hint not set
1519 if (trans_for
== client
.window
) {
1520 // wierd client... treat this window as a normal window
1524 if (trans_for
== None
|| trans_for
== screen
->getRootWindow()) {
1525 // this is an undocumented interpretation of the ICCCM. a transient
1526 // associated with None/Root/itself is assumed to be a modal root
1527 // transient. we don't support the concept of a global transient,
1528 // so we just associate this transient with nothing, and perhaps
1529 // we will add support later for global modality.
1530 client
.transient_for
= (BlackboxWindow
*) ~0ul;
1535 client
.transient_for
= blackbox
->searchWindow(trans_for
);
1536 if (! client
.transient_for
&&
1537 client
.window_group
&& trans_for
== client
.window_group
) {
1538 // no direct transient_for, perhaps this is a group transient?
1539 BWindowGroup
*group
= blackbox
->searchGroup(client
.window_group
);
1540 if (group
) client
.transient_for
= group
->find(screen
);
1543 if (! client
.transient_for
|| client
.transient_for
== this) {
1544 // no transient_for found, or we have a wierd client that wants to be
1545 // a transient for itself, so we treat this window as a normal window
1546 client
.transient_for
= (BlackboxWindow
*) 0;
1550 // Check for a circular transient state: this can lock up Blackbox
1551 // when it tries to find the non-transient window for a transient.
1552 BlackboxWindow
*w
= this;
1553 while(w
->client
.transient_for
&&
1554 w
->client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1555 if(w
->client
.transient_for
== this) {
1556 client
.transient_for
= (BlackboxWindow
*) 0;
1559 w
= w
->client
.transient_for
;
1562 if (client
.transient_for
&&
1563 client
.transient_for
!= (BlackboxWindow
*) ~0ul) {
1564 // register ourselves with our new transient_for
1565 client
.transient_for
->client
.transientList
.push_back(this);
1566 flags
.stuck
= client
.transient_for
->flags
.stuck
;
1571 BlackboxWindow
*BlackboxWindow::getTransientFor(void) const {
1572 if (client
.transient_for
&&
1573 client
.transient_for
!= (BlackboxWindow
*) ~0ul)
1574 return client
.transient_for
;
1580 * This function is responsible for updating both the client and the frame
1582 * According to the ICCCM a client message is not sent for a resize, only a
1585 void BlackboxWindow::configure(int dx
, int dy
,
1586 unsigned int dw
, unsigned int dh
) {
1587 bool send_event
= ((frame
.rect
.x() != dx
|| frame
.rect
.y() != dy
) &&
1590 if (dw
!= frame
.rect
.width() || dh
!= frame
.rect
.height()) {
1591 frame
.rect
.setRect(dx
, dy
, dw
, dh
);
1592 frame
.inside_w
= frame
.rect
.width() - (frame
.border_w
* 2);
1593 frame
.inside_h
= frame
.rect
.height() - (frame
.border_w
* 2);
1595 if (frame
.rect
.right() <= 0 || frame
.rect
.bottom() <= 0)
1596 frame
.rect
.setPos(0, 0);
1598 client
.rect
.setCoords(frame
.rect
.left() + frame
.margin
.left
,
1599 frame
.rect
.top() + frame
.margin
.top
,
1600 frame
.rect
.right() - frame
.margin
.right
,
1601 frame
.rect
.bottom() - frame
.margin
.bottom
);
1604 if (blackbox
->hasShapeExtensions() && flags
.shaped
) {
1611 redrawWindowFrame();
1613 frame
.rect
.setPos(dx
, dy
);
1615 XMoveWindow(otk::OBDisplay::display
, frame
.window
,
1616 frame
.rect
.x(), frame
.rect
.y());
1618 we may have been called just after an opaque window move, so even though
1619 the old coords match the new ones no ConfigureNotify has been sent yet.
1620 There are likely other times when this will be relevant as well.
1622 if (! flags
.moving
) send_event
= True
;
1626 // if moving, the update and event will occur when the move finishes
1627 client
.rect
.setPos(frame
.rect
.left() + frame
.margin
.left
,
1628 frame
.rect
.top() + frame
.margin
.top
);
1631 event
.type
= ConfigureNotify
;
1633 event
.xconfigure
.display
= otk::OBDisplay::display
;
1634 event
.xconfigure
.event
= client
.window
;
1635 event
.xconfigure
.window
= client
.window
;
1636 event
.xconfigure
.x
= client
.rect
.x();
1637 event
.xconfigure
.y
= client
.rect
.y();
1638 event
.xconfigure
.width
= client
.rect
.width();
1639 event
.xconfigure
.height
= client
.rect
.height();
1640 event
.xconfigure
.border_width
= client
.old_bw
;
1641 event
.xconfigure
.above
= frame
.window
;
1642 event
.xconfigure
.override_redirect
= False
;
1644 XSendEvent(otk::OBDisplay::display
, client
.window
, False
,
1645 StructureNotifyMask
, &event
);
1646 XFlush(otk::OBDisplay::display
);
1652 void BlackboxWindow::configureShape(void) {
1653 XShapeCombineShape(otk::OBDisplay::display
, frame
.window
, ShapeBounding
,
1654 frame
.margin
.left
- frame
.border_w
,
1655 frame
.margin
.top
- frame
.border_w
,
1656 client
.window
, ShapeBounding
, ShapeSet
);
1659 XRectangle xrect
[2];
1661 if (decorations
& Decor_Titlebar
) {
1662 xrect
[0].x
= xrect
[0].y
= -frame
.border_w
;
1663 xrect
[0].width
= frame
.rect
.width();
1664 xrect
[0].height
= frame
.title_h
+ (frame
.border_w
* 2);
1668 if (decorations
& Decor_Handle
) {
1669 xrect
[1].x
= -frame
.border_w
;
1670 xrect
[1].y
= frame
.rect
.height() - frame
.margin
.bottom
+
1671 frame
.mwm_border_w
- frame
.border_w
;
1672 xrect
[1].width
= frame
.rect
.width();
1673 xrect
[1].height
= frame
.handle_h
+ (frame
.border_w
* 2);
1677 XShapeCombineRectangles(otk::OBDisplay::display
, frame
.window
,
1678 ShapeBounding
, 0, 0, xrect
, num
,
1679 ShapeUnion
, Unsorted
);
1683 void BlackboxWindow::clearShape(void) {
1684 XShapeCombineMask(otk::OBDisplay::display
, frame
.window
, ShapeBounding
,
1685 frame
.margin
.left
- frame
.border_w
,
1686 frame
.margin
.top
- frame
.border_w
,
1692 bool BlackboxWindow::setInputFocus(void) {
1693 if (flags
.focused
) return True
;
1695 assert(flags
.stuck
|| // window must be on the current workspace or sticky
1696 blackbox_attrib
.workspace
== screen
->getCurrentWorkspaceID());
1699 We only do this check for normal windows and dialogs because other windows
1700 do this on purpose, such as kde's kicker, and we don't want to go moving
1703 if (window_type
== Type_Normal
|| window_type
== Type_Dialog
)
1704 if (! frame
.rect
.intersects(screen
->getRect())) {
1705 // client is outside the screen, move it to the center
1706 configure((screen
->getWidth() - frame
.rect
.width()) / 2,
1707 (screen
->getHeight() - frame
.rect
.height()) / 2,
1708 frame
.rect
.width(), frame
.rect
.height());
1711 if (client
.transientList
.size() > 0) {
1712 // transfer focus to any modal transients
1713 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1714 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1715 if ((*it
)->flags
.modal
) return (*it
)->setInputFocus();
1719 if (focus_mode
== F_LocallyActive
|| focus_mode
== F_Passive
) {
1720 XSetInputFocus(otk::OBDisplay::display
, client
.window
,
1721 RevertToPointerRoot
, CurrentTime
);
1723 /* we could set the focus to none, since the window doesn't accept focus,
1724 * but we shouldn't set focus to nothing since this would surely make
1730 if (flags
.send_focus_message
) {
1732 ce
.xclient
.type
= ClientMessage
;
1733 ce
.xclient
.message_type
= xatom
->atom(otk::OBProperty::wm_protocols
);
1734 ce
.xclient
.display
= otk::OBDisplay::display
;
1735 ce
.xclient
.window
= client
.window
;
1736 ce
.xclient
.format
= 32;
1737 ce
.xclient
.data
.l
[0] = xatom
->atom(otk::OBProperty::wm_take_focus
);
1738 ce
.xclient
.data
.l
[1] = blackbox
->getLastTime();
1739 ce
.xclient
.data
.l
[2] = 0l;
1740 ce
.xclient
.data
.l
[3] = 0l;
1741 ce
.xclient
.data
.l
[4] = 0l;
1742 XSendEvent(otk::OBDisplay::display
, client
.window
, False
,
1744 XFlush(otk::OBDisplay::display
);
1751 void BlackboxWindow::iconify(void) {
1752 if (flags
.iconic
|| ! (functions
& Func_Iconify
)) return;
1754 // We don't need to worry about resizing because resizing always grabs the X
1755 // server. This should only ever happen if using opaque moving.
1760 * we don't want this XUnmapWindow call to generate an UnmapNotify event, so
1761 * we need to clear the event mask on client.window for a split second.
1762 * HOWEVER, since X11 is asynchronous, the window could be destroyed in that
1763 * split second, leaving us with a ghost window... so, we need to do this
1764 * while the X server is grabbed
1766 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1767 StructureNotifyMask
;
1768 XGrabServer(otk::OBDisplay::display
);
1769 XSelectInput(otk::OBDisplay::display
, client
.window
,
1770 event_mask
& ~StructureNotifyMask
);
1771 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
1772 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
1773 XUngrabServer(otk::OBDisplay::display
);
1775 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
1776 flags
.visible
= False
;
1777 flags
.iconic
= True
;
1779 setState(IconicState
);
1781 screen
->getWorkspace(blackbox_attrib
.workspace
)->removeWindow(this);
1783 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
1784 if (i
!= blackbox_attrib
.workspace
)
1785 screen
->getWorkspace(i
)->removeWindow(this, True
);
1788 if (isTransient()) {
1789 if (client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
1790 ! client
.transient_for
->flags
.iconic
) {
1791 // iconify our transient_for
1792 client
.transient_for
->iconify();
1796 screen
->addIcon(this);
1798 if (client
.transientList
.size() > 0) {
1799 // iconify all transients
1800 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1801 for (it
= client
.transientList
.begin(); it
!= end
; ++it
) {
1802 if (! (*it
)->flags
.iconic
) (*it
)->iconify();
1805 screen
->updateStackingList();
1809 void BlackboxWindow::show(void) {
1810 flags
.visible
= True
;
1811 flags
.iconic
= False
;
1813 current_state
= (flags
.shaded
) ? IconicState
: NormalState
;
1814 setState(current_state
);
1816 XMapWindow(otk::OBDisplay::display
, client
.window
);
1817 XMapSubwindows(otk::OBDisplay::display
, frame
.window
);
1818 XMapWindow(otk::OBDisplay::display
, frame
.window
);
1823 XTranslateCoordinates(otk::OBDisplay::display
, client
.window
,
1824 screen
->getRootWindow(),
1825 0, 0, &real_x
, &real_y
, &child
);
1826 fprintf(stderr
, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(),
1827 client
.rect
.left(), client
.rect
.top(), real_x
, real_y
);
1828 assert(client
.rect
.left() == real_x
&& client
.rect
.top() == real_y
);
1833 void BlackboxWindow::deiconify(bool reassoc
, bool raise
) {
1834 if (flags
.iconic
|| reassoc
)
1835 screen
->reassociateWindow(this, otk::BSENTINEL
, False
);
1836 else if (blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID())
1841 // reassociate and deiconify all transients
1842 if (reassoc
&& client
.transientList
.size() > 0) {
1843 BlackboxWindowList::iterator it
, end
= client
.transientList
.end();
1844 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
1845 (*it
)->deiconify(True
, False
);
1849 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1853 void BlackboxWindow::close(void) {
1854 if (! (functions
& Func_Close
)) return;
1857 ce
.xclient
.type
= ClientMessage
;
1858 ce
.xclient
.message_type
= xatom
->atom(otk::OBProperty::wm_protocols
);
1859 ce
.xclient
.display
= otk::OBDisplay::display
;
1860 ce
.xclient
.window
= client
.window
;
1861 ce
.xclient
.format
= 32;
1862 ce
.xclient
.data
.l
[0] = xatom
->atom(otk::OBProperty::wm_delete_window
);
1863 ce
.xclient
.data
.l
[1] = CurrentTime
;
1864 ce
.xclient
.data
.l
[2] = 0l;
1865 ce
.xclient
.data
.l
[3] = 0l;
1866 ce
.xclient
.data
.l
[4] = 0l;
1867 XSendEvent(otk::OBDisplay::display
, client
.window
, False
, NoEventMask
, &ce
);
1868 XFlush(otk::OBDisplay::display
);
1872 void BlackboxWindow::withdraw(void) {
1873 // We don't need to worry about resizing because resizing always grabs the X
1874 // server. This should only ever happen if using opaque moving.
1878 flags
.visible
= False
;
1879 flags
.iconic
= False
;
1881 setState(current_state
);
1883 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
1885 XGrabServer(otk::OBDisplay::display
);
1887 unsigned long event_mask
= PropertyChangeMask
| FocusChangeMask
|
1888 StructureNotifyMask
;
1889 XSelectInput(otk::OBDisplay::display
, client
.window
,
1890 event_mask
& ~StructureNotifyMask
);
1891 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
1892 XSelectInput(otk::OBDisplay::display
, client
.window
, event_mask
);
1894 XUngrabServer(otk::OBDisplay::display
);
1898 void BlackboxWindow::maximize(unsigned int button
) {
1899 if (! (functions
& Func_Maximize
)) return;
1901 // We don't need to worry about resizing because resizing always grabs the X
1902 // server. This should only ever happen if using opaque moving.
1906 if (flags
.maximized
) {
1907 flags
.maximized
= 0;
1909 blackbox_attrib
.flags
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1910 blackbox_attrib
.attrib
&= ! (AttribMaxHoriz
| AttribMaxVert
);
1913 when a resize finishes, maximize(0) is called to clear any maximization
1914 flags currently set. Otherwise it still thinks it is maximized.
1915 so we do not need to call configure() because resizing will handle it
1917 if (! flags
.resizing
)
1918 configure(blackbox_attrib
.premax_x
, blackbox_attrib
.premax_y
,
1919 blackbox_attrib
.premax_w
, blackbox_attrib
.premax_h
);
1921 blackbox_attrib
.premax_x
= blackbox_attrib
.premax_y
= 0;
1922 blackbox_attrib
.premax_w
= blackbox_attrib
.premax_h
= 0;
1924 redrawAllButtons(); // in case it is not called in configure()
1925 setState(current_state
);
1929 blackbox_attrib
.premax_x
= frame
.rect
.x();
1930 blackbox_attrib
.premax_y
= frame
.rect
.y();
1931 blackbox_attrib
.premax_w
= frame
.rect
.width();
1932 // use client.rect so that clients can be restored even if shaded
1933 blackbox_attrib
.premax_h
=
1934 client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
;
1937 if (screen
->isXineramaActive() && blackbox
->doXineramaMaximizing()) {
1938 // find the area to use
1939 RectList availableAreas
= screen
->allAvailableAreas();
1940 RectList::iterator it
, end
= availableAreas
.end();
1942 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
1943 if (it
->intersects(frame
.rect
)) break;
1944 if (it
== end
) // the window isn't inside an area
1945 it
= availableAreas
.begin(); // so just default to the first one
1947 frame
.changing
= *it
;
1950 frame
.changing
= screen
->availableArea();
1954 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
1955 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
1959 blackbox_attrib
.flags
|= AttribMaxVert
;
1960 blackbox_attrib
.attrib
|= AttribMaxVert
;
1962 frame
.changing
.setX(frame
.rect
.x());
1963 frame
.changing
.setWidth(frame
.rect
.width());
1967 blackbox_attrib
.flags
|= AttribMaxHoriz
;
1968 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
1970 frame
.changing
.setY(frame
.rect
.y());
1971 frame
.changing
.setHeight(frame
.rect
.height());
1978 blackbox_attrib
.flags
^= AttribShaded
;
1979 blackbox_attrib
.attrib
^= AttribShaded
;
1980 flags
.shaded
= False
;
1983 flags
.maximized
= button
;
1985 configure(frame
.changing
.x(), frame
.changing
.y(),
1986 frame
.changing
.width(), frame
.changing
.height());
1988 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
1989 redrawAllButtons(); // in case it is not called in configure()
1990 setState(current_state
);
1994 // re-maximizes the window to take into account availableArea changes
1995 void BlackboxWindow::remaximize(void) {
1997 // we only update the window's attributes otherwise we lose the shade bit
1998 switch(flags
.maximized
) {
2000 blackbox_attrib
.flags
|= AttribMaxHoriz
| AttribMaxVert
;
2001 blackbox_attrib
.attrib
|= AttribMaxHoriz
| AttribMaxVert
;
2005 blackbox_attrib
.flags
|= AttribMaxVert
;
2006 blackbox_attrib
.attrib
|= AttribMaxVert
;
2010 blackbox_attrib
.flags
|= AttribMaxHoriz
;
2011 blackbox_attrib
.attrib
|= AttribMaxHoriz
;
2017 // save the original dimensions because maximize will wipe them out
2018 int premax_x
= blackbox_attrib
.premax_x
,
2019 premax_y
= blackbox_attrib
.premax_y
,
2020 premax_w
= blackbox_attrib
.premax_w
,
2021 premax_h
= blackbox_attrib
.premax_h
;
2023 unsigned int button
= flags
.maximized
;
2024 flags
.maximized
= 0; // trick maximize() into working
2027 // restore saved values
2028 blackbox_attrib
.premax_x
= premax_x
;
2029 blackbox_attrib
.premax_y
= premax_y
;
2030 blackbox_attrib
.premax_w
= premax_w
;
2031 blackbox_attrib
.premax_h
= premax_h
;
2035 void BlackboxWindow::setWorkspace(unsigned int n
) {
2036 blackbox_attrib
.flags
|= AttribWorkspace
;
2037 blackbox_attrib
.workspace
= n
;
2038 if (n
== otk::BSENTINEL
) { // iconified window
2040 we set the workspace to 'all workspaces' so that taskbars will show the
2041 window. otherwise, it made uniconifying a window imposible without the
2042 blackbox workspace menu
2046 xatom
->set(client
.window
, otk::OBProperty::net_wm_desktop
,
2047 otk::OBProperty::Atom_Cardinal
, n
);
2051 void BlackboxWindow::shade(void) {
2053 XResizeWindow(otk::OBDisplay::display
, frame
.window
,
2054 frame
.inside_w
, frame
.inside_h
);
2055 flags
.shaded
= False
;
2056 blackbox_attrib
.flags
^= AttribShaded
;
2057 blackbox_attrib
.attrib
^= AttribShaded
;
2059 setState(NormalState
);
2061 // set the frame rect to the normal size
2062 frame
.rect
.setHeight(client
.rect
.height() + frame
.margin
.top
+
2063 frame
.margin
.bottom
);
2065 if (! (decorations
& Decor_Titlebar
))
2066 return; // can't shade it without a titlebar!
2068 XResizeWindow(otk::OBDisplay::display
, frame
.window
,
2069 frame
.inside_w
, frame
.title_h
);
2070 flags
.shaded
= True
;
2071 blackbox_attrib
.flags
|= AttribShaded
;
2072 blackbox_attrib
.attrib
|= AttribShaded
;
2074 setState(IconicState
);
2076 // set the frame rect to the shaded size
2077 frame
.rect
.setHeight(frame
.title_h
+ (frame
.border_w
* 2));
2083 * (Un)Sticks a window and its relatives.
2085 void BlackboxWindow::stick(void) {
2087 blackbox_attrib
.flags
^= AttribOmnipresent
;
2088 blackbox_attrib
.attrib
^= AttribOmnipresent
;
2090 flags
.stuck
= False
;
2092 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2093 if (i
!= blackbox_attrib
.workspace
)
2094 screen
->getWorkspace(i
)->removeWindow(this, True
);
2097 screen
->reassociateWindow(this, otk::BSENTINEL
, True
);
2098 // temporary fix since sticky windows suck. set the hint to what we
2099 // actually hold in our data.
2100 xatom
->set(client
.window
, otk::OBProperty::net_wm_desktop
,
2101 otk::OBProperty::Atom_Cardinal
,
2102 blackbox_attrib
.workspace
);
2104 setState(current_state
);
2108 blackbox_attrib
.flags
|= AttribOmnipresent
;
2109 blackbox_attrib
.attrib
|= AttribOmnipresent
;
2111 // temporary fix since sticky windows suck. set the hint to a different
2112 // value than that contained in the class' data.
2113 xatom
->set(client
.window
, otk::OBProperty::net_wm_desktop
,
2114 otk::OBProperty::Atom_Cardinal
,
2117 for (unsigned int i
= 0; i
< screen
->getNumberOfWorkspaces(); ++i
)
2118 if (i
!= blackbox_attrib
.workspace
)
2119 screen
->getWorkspace(i
)->addWindow(this, False
, True
);
2121 setState(current_state
);
2127 if (isTransient() && client
.transient_for
!= (BlackboxWindow
*) ~0ul &&
2128 client
.transient_for
->isStuck() != flags
.stuck
)
2129 client
.transient_for
->stick();
2130 // go down the chain
2131 BlackboxWindowList::iterator it
;
2132 const BlackboxWindowList::iterator end
= client
.transientList
.end();
2133 for (it
= client
.transientList
.begin(); it
!= end
; ++it
)
2134 if ((*it
)->isStuck() != flags
.stuck
)
2139 void BlackboxWindow::redrawWindowFrame(void) const {
2140 if (decorations
& Decor_Titlebar
) {
2141 if (flags
.focused
) {
2143 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2144 frame
.title
, frame
.ftitle
);
2146 XSetWindowBackground(otk::OBDisplay::display
,
2147 frame
.title
, frame
.ftitle_pixel
);
2150 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2151 frame
.title
, frame
.utitle
);
2153 XSetWindowBackground(otk::OBDisplay::display
,
2154 frame
.title
, frame
.utitle_pixel
);
2156 XClearWindow(otk::OBDisplay::display
, frame
.title
);
2162 if (decorations
& Decor_Handle
) {
2163 if (flags
.focused
) {
2165 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2166 frame
.handle
, frame
.fhandle
);
2168 XSetWindowBackground(otk::OBDisplay::display
,
2169 frame
.handle
, frame
.fhandle_pixel
);
2172 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2173 frame
.left_grip
, frame
.fgrip
);
2174 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2175 frame
.right_grip
, frame
.fgrip
);
2177 XSetWindowBackground(otk::OBDisplay::display
,
2178 frame
.left_grip
, frame
.fgrip_pixel
);
2179 XSetWindowBackground(otk::OBDisplay::display
,
2180 frame
.right_grip
, frame
.fgrip_pixel
);
2184 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2185 frame
.handle
, frame
.uhandle
);
2187 XSetWindowBackground(otk::OBDisplay::display
,
2188 frame
.handle
, frame
.uhandle_pixel
);
2191 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2192 frame
.left_grip
, frame
.ugrip
);
2193 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2194 frame
.right_grip
, frame
.ugrip
);
2196 XSetWindowBackground(otk::OBDisplay::display
,
2197 frame
.left_grip
, frame
.ugrip_pixel
);
2198 XSetWindowBackground(otk::OBDisplay::display
,
2199 frame
.right_grip
, frame
.ugrip_pixel
);
2202 XClearWindow(otk::OBDisplay::display
, frame
.handle
);
2203 XClearWindow(otk::OBDisplay::display
, frame
.left_grip
);
2204 XClearWindow(otk::OBDisplay::display
, frame
.right_grip
);
2207 if (decorations
& Decor_Border
) {
2209 XSetWindowBorder(otk::OBDisplay::display
,
2210 frame
.plate
, frame
.fborder_pixel
);
2212 XSetWindowBorder(otk::OBDisplay::display
,
2213 frame
.plate
, frame
.uborder_pixel
);
2218 void BlackboxWindow::setFocusFlag(bool focus
) {
2219 // only focus a window if it is visible
2220 if (focus
&& ! flags
.visible
)
2223 flags
.focused
= focus
;
2225 redrawWindowFrame();
2228 blackbox
->setFocusedWindow(this);
2232 void BlackboxWindow::installColormap(bool install
) {
2233 int i
= 0, ncmap
= 0;
2234 Colormap
*cmaps
= XListInstalledColormaps(otk::OBDisplay::display
,
2235 client
.window
, &ncmap
);
2237 XWindowAttributes wattrib
;
2238 if (XGetWindowAttributes(otk::OBDisplay::display
,
2239 client
.window
, &wattrib
)) {
2241 // install the window's colormap
2242 for (i
= 0; i
< ncmap
; i
++) {
2243 if (*(cmaps
+ i
) == wattrib
.colormap
)
2244 // this window is using an installed color map... do not install
2247 // otherwise, install the window's colormap
2249 XInstallColormap(otk::OBDisplay::display
, wattrib
.colormap
);
2251 // uninstall the window's colormap
2252 for (i
= 0; i
< ncmap
; i
++) {
2253 if (*(cmaps
+ i
) == wattrib
.colormap
)
2254 // we found the colormap to uninstall
2255 XUninstallColormap(otk::OBDisplay::display
, wattrib
.colormap
);
2265 void BlackboxWindow::setAllowedActions(void) {
2269 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_shade
);
2270 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_change_desktop
);
2271 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_close
);
2273 if (functions
& Func_Move
)
2274 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_move
);
2275 if (functions
& Func_Resize
)
2276 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_resize
);
2277 if (functions
& Func_Maximize
) {
2278 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_maximize_horz
);
2279 actions
[num
++] = xatom
->atom(otk::OBProperty::net_wm_action_maximize_vert
);
2282 xatom
->set(client
.window
, otk::OBProperty::net_wm_allowed_actions
,
2283 otk::OBProperty::Atom_Atom
,
2288 void BlackboxWindow::setState(unsigned long new_state
) {
2289 current_state
= new_state
;
2291 unsigned long state
[2];
2292 state
[0] = current_state
;
2294 xatom
->set(client
.window
, otk::OBProperty::wm_state
, otk::OBProperty::wm_state
, state
, 2);
2296 xatom
->set(client
.window
, otk::OBProperty::blackbox_attributes
,
2297 otk::OBProperty::blackbox_attributes
, (unsigned long *)&blackbox_attrib
,
2298 PropBlackboxAttributesElements
);
2303 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_modal
);
2305 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_shaded
);
2307 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_hidden
);
2308 if (flags
.skip_taskbar
)
2309 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_skip_taskbar
);
2310 if (flags
.skip_pager
)
2311 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_skip_pager
);
2312 if (flags
.fullscreen
)
2313 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_fullscreen
);
2314 if (flags
.maximized
== 1 || flags
.maximized
== 2)
2315 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_maximized_vert
);
2316 if (flags
.maximized
== 1 || flags
.maximized
== 3)
2317 netstate
[num
++] = xatom
->atom(otk::OBProperty::net_wm_state_maximized_horz
);
2318 xatom
->set(client
.window
, otk::OBProperty::net_wm_state
,
2319 otk::OBProperty::Atom_Atom
,
2324 bool BlackboxWindow::getState(void) {
2325 bool ret
= xatom
->get(client
.window
, otk::OBProperty::wm_state
,
2326 otk::OBProperty::wm_state
, ¤t_state
);
2327 if (! ret
) current_state
= 0;
2332 void BlackboxWindow::restoreAttributes(void) {
2333 unsigned long num
= PropBlackboxAttributesElements
;
2334 BlackboxAttributes
*net
;
2335 if (! xatom
->get(client
.window
, otk::OBProperty::blackbox_attributes
,
2336 otk::OBProperty::blackbox_attributes
, &num
,
2337 (unsigned long **)&net
))
2339 if (num
< PropBlackboxAttributesElements
) {
2344 if (net
->flags
& AttribShaded
&& net
->attrib
& AttribShaded
) {
2345 flags
.shaded
= False
;
2346 unsigned long orig_state
= current_state
;
2350 At this point in the life of a window, current_state should only be set
2351 to IconicState if the window was an *icon*, not if it was shaded.
2353 if (orig_state
!= IconicState
)
2354 current_state
= WithdrawnState
;
2357 if (net
->workspace
!= screen
->getCurrentWorkspaceID() &&
2358 net
->workspace
< screen
->getWorkspaceCount())
2359 screen
->reassociateWindow(this, net
->workspace
, True
);
2361 if ((blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID()) &&
2362 (blackbox_attrib
.workspace
< screen
->getWorkspaceCount())) {
2363 // set to WithdrawnState so it will be mapped on the new workspace
2364 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2365 } else if (current_state
== WithdrawnState
) {
2366 // the window is on this workspace and is Withdrawn, so it is waiting to
2368 current_state
= NormalState
;
2371 if (net
->flags
& AttribOmnipresent
&& net
->attrib
& AttribOmnipresent
&&
2375 // if the window was on another workspace, it was going to be hidden. this
2376 // specifies that the window should be mapped since it is sticky.
2377 if (current_state
== WithdrawnState
) current_state
= NormalState
;
2380 if (net
->flags
& AttribMaxHoriz
|| net
->flags
& AttribMaxVert
) {
2381 int x
= net
->premax_x
, y
= net
->premax_y
;
2382 unsigned int w
= net
->premax_w
, h
= net
->premax_h
;
2383 flags
.maximized
= 0;
2386 if ((net
->flags
& AttribMaxHoriz
) &&
2387 (net
->flags
& AttribMaxVert
))
2388 m
= (net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0;
2389 else if (net
->flags
& AttribMaxVert
)
2390 m
= (net
->attrib
& AttribMaxVert
) ? 2 : 0;
2391 else if (net
->flags
& AttribMaxHoriz
)
2392 m
= (net
->attrib
& AttribMaxHoriz
) ? 3 : 0;
2396 blackbox_attrib
.premax_x
= x
;
2397 blackbox_attrib
.premax_y
= y
;
2398 blackbox_attrib
.premax_w
= w
;
2399 blackbox_attrib
.premax_h
= h
;
2402 if (net
->flags
& AttribDecoration
) {
2403 switch (net
->decoration
) {
2408 /* since tools only let you toggle this anyways, we'll just make that all
2409 it supports for now.
2420 // with the state set it will then be the map event's job to read the
2421 // window's state and behave accordingly
2428 * Positions the Rect r according the the client window position and
2431 void BlackboxWindow::applyGravity(otk::Rect
&r
) {
2432 // apply horizontal window gravity
2433 switch (client
.win_gravity
) {
2435 case NorthWestGravity
:
2436 case SouthWestGravity
:
2438 r
.setX(client
.rect
.x());
2444 r
.setX(client
.rect
.x() - (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2447 case NorthEastGravity
:
2448 case SouthEastGravity
:
2450 r
.setX(client
.rect
.x() - frame
.margin
.left
- frame
.margin
.right
+ 2);
2455 r
.setX(client
.rect
.x() - frame
.margin
.left
);
2459 // apply vertical window gravity
2460 switch (client
.win_gravity
) {
2462 case NorthWestGravity
:
2463 case NorthEastGravity
:
2465 r
.setY(client
.rect
.y());
2471 r
.setY(client
.rect
.y() - (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2474 case SouthWestGravity
:
2475 case SouthEastGravity
:
2477 r
.setY(client
.rect
.y() - frame
.margin
.top
- frame
.margin
.bottom
+ 2);
2482 r
.setY(client
.rect
.y() - frame
.margin
.top
);
2489 * The reverse of the applyGravity function.
2491 * Positions the Rect r according to the frame window position and
2494 void BlackboxWindow::restoreGravity(otk::Rect
&r
) {
2495 // restore horizontal window gravity
2496 switch (client
.win_gravity
) {
2498 case NorthWestGravity
:
2499 case SouthWestGravity
:
2501 r
.setX(frame
.rect
.x());
2507 r
.setX(frame
.rect
.x() + (frame
.margin
.left
+ frame
.margin
.right
) / 2);
2510 case NorthEastGravity
:
2511 case SouthEastGravity
:
2513 r
.setX(frame
.rect
.x() + frame
.margin
.left
+ frame
.margin
.right
- 2);
2518 r
.setX(frame
.rect
.x() + frame
.margin
.left
);
2522 // restore vertical window gravity
2523 switch (client
.win_gravity
) {
2525 case NorthWestGravity
:
2526 case NorthEastGravity
:
2528 r
.setY(frame
.rect
.y());
2534 r
.setY(frame
.rect
.y() + (frame
.margin
.top
+ frame
.margin
.bottom
) / 2);
2537 case SouthWestGravity
:
2538 case SouthEastGravity
:
2540 r
.setY(frame
.rect
.y() + frame
.margin
.top
+ frame
.margin
.bottom
- 2);
2545 r
.setY(frame
.rect
.y() + frame
.margin
.top
);
2551 void BlackboxWindow::redrawLabel(void) const {
2552 if (flags
.focused
) {
2554 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2555 frame
.label
, frame
.flabel
);
2557 XSetWindowBackground(otk::OBDisplay::display
,
2558 frame
.label
, frame
.flabel_pixel
);
2561 XSetWindowBackgroundPixmap(otk::OBDisplay::display
,
2562 frame
.label
, frame
.ulabel
);
2564 XSetWindowBackground(otk::OBDisplay::display
,
2565 frame
.label
, frame
.ulabel_pixel
);
2567 XClearWindow(otk::OBDisplay::display
, frame
.label
);
2569 otk::Style
*style
= screen
->getWindowStyle();
2571 int pos
= frame
.bevel_w
* 2;
2572 style
->doJustify(client
.title
.c_str(), pos
, frame
.label_w
, frame
.bevel_w
* 4);
2573 style
->font
->drawString(frame
.label
, pos
, 1,
2574 (flags
.focused
? style
->l_text_focus
:
2575 style
->l_text_unfocus
),
2580 void BlackboxWindow::redrawAllButtons(void) const {
2581 if (frame
.iconify_button
) redrawIconifyButton(False
);
2582 if (frame
.maximize_button
) redrawMaximizeButton(flags
.maximized
);
2583 if (frame
.close_button
) redrawCloseButton(False
);
2584 if (frame
.stick_button
) redrawStickyButton(flags
.stuck
);
2588 void BlackboxWindow::redrawButton(bool pressed
, Window win
,
2589 Pixmap fppix
, unsigned long fppixel
,
2590 Pixmap uppix
, unsigned long uppixel
,
2591 Pixmap fpix
, unsigned long fpixel
,
2592 Pixmap upix
, unsigned long upixel
) const {
2597 if (flags
.focused
) {
2605 if (flags
.focused
) {
2615 XSetWindowBackgroundPixmap(otk::OBDisplay::display
, win
, p
);
2617 XSetWindowBackground(otk::OBDisplay::display
, win
, pix
);
2621 void BlackboxWindow::redrawIconifyButton(bool pressed
) const {
2622 redrawButton(pressed
, frame
.iconify_button
,
2623 frame
.pfbutton
, frame
.pfbutton_pixel
,
2624 frame
.pubutton
, frame
.pubutton_pixel
,
2625 frame
.fbutton
, frame
.fbutton_pixel
,
2626 frame
.ubutton
, frame
.ubutton_pixel
);
2628 XClearWindow(otk::OBDisplay::display
, frame
.iconify_button
);
2629 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2630 screen
->getWindowStyle()->b_pic_unfocus
);
2632 otk::Style::PixmapMask pm
= screen
->getWindowStyle()->icon_button
;
2634 if (screen
->getWindowStyle()->icon_button
.mask
!= None
) {
2635 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2636 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2637 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2639 XFillRectangle(otk::OBDisplay::display
, frame
.iconify_button
, pen
.gc(),
2640 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2641 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2643 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), None
);
2644 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0);
2646 XDrawRectangle(otk::OBDisplay::display
, frame
.iconify_button
, pen
.gc(),
2647 2, (frame
.button_w
- 5), (frame
.button_w
- 5), 2);
2652 void BlackboxWindow::redrawMaximizeButton(bool pressed
) const {
2653 redrawButton(pressed
, frame
.maximize_button
,
2654 frame
.pfbutton
, frame
.pfbutton_pixel
,
2655 frame
.pubutton
, frame
.pubutton_pixel
,
2656 frame
.fbutton
, frame
.fbutton_pixel
,
2657 frame
.ubutton
, frame
.ubutton_pixel
);
2659 XClearWindow(otk::OBDisplay::display
, frame
.maximize_button
);
2661 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2662 screen
->getWindowStyle()->b_pic_unfocus
);
2664 otk::Style::PixmapMask pm
= screen
->getWindowStyle()->max_button
;
2666 if (pm
.mask
!= None
) {
2667 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2668 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2669 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2671 XFillRectangle(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2672 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2673 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2675 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2676 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2678 XDrawRectangle(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2679 2, 2, (frame
.button_w
- 5), (frame
.button_w
- 5));
2680 XDrawLine(otk::OBDisplay::display
, frame
.maximize_button
, pen
.gc(),
2681 2, 3, (frame
.button_w
- 3), 3);
2686 void BlackboxWindow::redrawCloseButton(bool pressed
) const {
2687 redrawButton(pressed
, frame
.close_button
,
2688 frame
.pfbutton
, frame
.pfbutton_pixel
,
2689 frame
.pubutton
, frame
.pubutton_pixel
,
2690 frame
.fbutton
, frame
.fbutton_pixel
,
2691 frame
.ubutton
, frame
.ubutton_pixel
);
2693 XClearWindow(otk::OBDisplay::display
, frame
.close_button
);
2695 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2696 screen
->getWindowStyle()->b_pic_unfocus
);
2698 otk::Style::PixmapMask pm
= screen
->getWindowStyle()->close_button
;
2700 if (pm
.mask
!= None
) {
2701 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2702 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2703 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2705 XFillRectangle(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2706 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2707 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2710 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2711 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2713 XDrawLine(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2714 2, 2, (frame
.button_w
- 3), (frame
.button_w
- 3));
2715 XDrawLine(otk::OBDisplay::display
, frame
.close_button
, pen
.gc(),
2716 2, (frame
.button_w
- 3), (frame
.button_w
- 3), 2);
2720 void BlackboxWindow::redrawStickyButton(bool pressed
) const {
2721 redrawButton(pressed
, frame
.stick_button
,
2722 frame
.pfbutton
, frame
.pfbutton_pixel
,
2723 frame
.pubutton
, frame
.pubutton_pixel
,
2724 frame
.fbutton
, frame
.fbutton_pixel
,
2725 frame
.ubutton
, frame
.ubutton_pixel
);
2727 XClearWindow(otk::OBDisplay::display
, frame
.stick_button
);
2729 otk::BPen
pen((flags
.focused
) ? screen
->getWindowStyle()->b_pic_focus
:
2730 screen
->getWindowStyle()->b_pic_unfocus
);
2732 otk::Style::PixmapMask pm
= screen
->getWindowStyle()->stick_button
;
2734 if (pm
.mask
!= None
) {
2735 XSetClipMask(otk::OBDisplay::display
, pen
.gc(), pm
.mask
);
2736 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(),
2737 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2);
2739 XFillRectangle(otk::OBDisplay::display
, frame
.stick_button
, pen
.gc(),
2740 (frame
.button_w
- pm
.w
)/2, (frame
.button_w
- pm
.h
)/2,
2741 (frame
.button_w
+ pm
.w
)/2, (frame
.button_w
+ pm
.h
)/2);
2744 XSetClipOrigin(otk::OBDisplay::display
, pen
.gc(), 0, 0 );
2745 XSetClipMask( otk::OBDisplay::display
, pen
.gc(), None
);
2747 XFillRectangle(otk::OBDisplay::display
, frame
.stick_button
, pen
.gc(),
2748 frame
.button_w
/2 - 1, frame
.button_w
/2 -1, 2, 2 );
2752 void BlackboxWindow::mapRequestEvent(const XMapRequestEvent
*re
) {
2753 if (re
->window
!= client
.window
)
2757 fprintf(stderr
, "BlackboxWindow::mapRequestEvent() for 0x%lx\n",
2762 Even though the window wants to be shown, if it is not on the current
2763 workspace, then it isn't going to be shown right now.
2765 if (! flags
.stuck
&&
2766 blackbox_attrib
.workspace
!= screen
->getCurrentWorkspaceID() &&
2767 blackbox_attrib
.workspace
< screen
->getWorkspaceCount())
2768 if (current_state
== NormalState
) current_state
= WithdrawnState
;
2770 switch (current_state
) {
2775 case WithdrawnState
:
2784 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
2786 if (blackbox
->state() != Openbox::State_Starting
) {
2787 XSync(otk::OBDisplay::display
, False
); // make sure the frame is mapped
2788 if (screen
->doFocusNew() || (isTransient() && getTransientFor() &&
2789 getTransientFor()->isFocused())) {
2792 if (screen
->getPlacementPolicy() == BScreen::ClickMousePlacement
) {
2796 XQueryPointer(otk::OBDisplay::display
, screen
->getRootWindow(),
2797 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
2807 void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent
*ue
) {
2808 if (ue
->window
!= client
.window
)
2812 fprintf(stderr
, "BlackboxWindow::unmapNotifyEvent() for 0x%lx\n",
2816 screen
->unmanageWindow(this, False
);
2820 void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent
*de
) {
2821 if (de
->window
!= client
.window
)
2825 fprintf(stderr
, "BlackboxWindow::destroyNotifyEvent() for 0x%lx\n",
2829 screen
->unmanageWindow(this, False
);
2833 void BlackboxWindow::reparentNotifyEvent(const XReparentEvent
*re
) {
2834 if (re
->window
!= client
.window
|| re
->parent
== frame
.plate
)
2838 fprintf(stderr
, "BlackboxWindow::reparentNotifyEvent(): reparent 0x%lx to "
2839 "0x%lx.\n", client
.window
, re
->parent
);
2844 XPutBackEvent(otk::OBDisplay::display
, &ev
);
2845 screen
->unmanageWindow(this, True
);
2849 void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent
*pe
) {
2850 if (pe
->state
== PropertyDelete
|| ! validateClient())
2854 fprintf(stderr
, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n",
2860 case XA_WM_CLIENT_MACHINE
:
2864 case XA_WM_TRANSIENT_FOR
: {
2865 bool s
= flags
.stuck
;
2867 // determine if this is a transient window
2870 if (flags
.stuck
!= s
) stick();
2872 // adjust the window decorations based on transience
2873 if (isTransient()) {
2874 functions
&= ~Func_Maximize
;
2875 setAllowedActions();
2887 case XA_WM_ICON_NAME
:
2889 if (flags
.iconic
) screen
->propagateWindowName(this);
2892 case otk::OBProperty::net_wm_name
:
2896 if (decorations
& Decor_Titlebar
)
2899 screen
->propagateWindowName(this);
2902 case XA_WM_NORMAL_HINTS
: {
2905 if ((client
.normal_hint_flags
& PMinSize
) &&
2906 (client
.normal_hint_flags
& PMaxSize
)) {
2907 // the window now can/can't resize itself, so the buttons need to be
2910 if (client
.max_width
<= client
.min_width
&&
2911 client
.max_height
<= client
.min_height
) {
2912 functions
&= ~(Func_Resize
| Func_Maximize
);
2914 if (! isTransient())
2915 functions
|= Func_Maximize
;
2916 functions
|= Func_Resize
;
2919 setAllowedActions();
2923 otk::Rect old_rect
= frame
.rect
;
2927 if (old_rect
!= frame
.rect
)
2934 if (pe
->atom
== xatom
->atom(otk::OBProperty::wm_protocols
)) {
2937 if ((decorations
& Decor_Close
) && (! frame
.close_button
)) {
2938 createCloseButton();
2939 if (decorations
& Decor_Titlebar
) {
2940 positionButtons(True
);
2941 XMapSubwindows(otk::OBDisplay::display
, frame
.title
);
2944 } else if (pe
->atom
== xatom
->atom(otk::OBProperty::net_wm_strut
)) {
2953 void BlackboxWindow::exposeEvent(const XExposeEvent
*ee
) {
2955 fprintf(stderr
, "BlackboxWindow::exposeEvent() for 0x%lx\n", client
.window
);
2958 if (frame
.label
== ee
->window
&& (decorations
& Decor_Titlebar
))
2960 else if (frame
.close_button
== ee
->window
)
2961 redrawCloseButton(False
);
2962 else if (frame
.maximize_button
== ee
->window
)
2963 redrawMaximizeButton(flags
.maximized
);
2964 else if (frame
.iconify_button
== ee
->window
)
2965 redrawIconifyButton(False
);
2966 else if (frame
.stick_button
== ee
->window
)
2967 redrawStickyButton(flags
.stuck
);
2971 void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent
*cr
) {
2972 if (cr
->window
!= client
.window
|| flags
.iconic
)
2975 if (cr
->value_mask
& CWBorderWidth
)
2976 client
.old_bw
= cr
->border_width
;
2978 if (cr
->value_mask
& (CWX
| CWY
| CWWidth
| CWHeight
)) {
2979 frame
.changing
= frame
.rect
;
2981 if (cr
->value_mask
& (CWX
| CWY
)) {
2982 if (cr
->value_mask
& CWX
)
2983 client
.rect
.setX(cr
->x
);
2984 if (cr
->value_mask
& CWY
)
2985 client
.rect
.setY(cr
->y
);
2987 applyGravity(frame
.changing
);
2990 if (cr
->value_mask
& (CWWidth
| CWHeight
)) {
2991 if (cr
->value_mask
& CWWidth
)
2992 frame
.changing
.setWidth(cr
->width
+
2993 frame
.margin
.left
+ frame
.margin
.right
);
2995 if (cr
->value_mask
& CWHeight
)
2996 frame
.changing
.setHeight(cr
->height
+
2997 frame
.margin
.top
+ frame
.margin
.bottom
);
3000 if a position change has been specified, then that position will be
3001 used instead of determining a position based on the window's gravity.
3003 if (! (cr
->value_mask
& (CWX
| CWY
))) {
3005 switch (client
.win_gravity
) {
3006 case NorthEastGravity
:
3010 case SouthWestGravity
:
3012 corner
= BottomLeft
;
3014 case SouthEastGravity
:
3015 corner
= BottomRight
;
3017 default: // NorthWest, Static, etc
3024 configure(frame
.changing
.x(), frame
.changing
.y(),
3025 frame
.changing
.width(), frame
.changing
.height());
3028 if (cr
->value_mask
& CWStackMode
&& !isDesktop()) {
3029 switch (cr
->detail
) {
3032 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3038 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3045 void BlackboxWindow::buttonPressEvent(const XButtonEvent
*be
) {
3047 fprintf(stderr
, "BlackboxWindow::buttonPressEvent() for 0x%lx\n",
3051 if (frame
.maximize_button
== be
->window
&& be
->button
<= 3) {
3052 redrawMaximizeButton(True
);
3053 } else if (be
->button
== 1 || (be
->button
== 3 && be
->state
== mod_mask
)) {
3054 if (! flags
.focused
)
3057 if (frame
.iconify_button
== be
->window
) {
3058 redrawIconifyButton(True
);
3059 } else if (frame
.close_button
== be
->window
) {
3060 redrawCloseButton(True
);
3061 } else if (frame
.stick_button
== be
->window
) {
3062 redrawStickyButton(True
);
3063 } else if (frame
.plate
== be
->window
) {
3064 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3066 XAllowEvents(otk::OBDisplay::display
, ReplayPointer
, be
->time
);
3068 if (frame
.title
== be
->window
|| frame
.label
== be
->window
) {
3069 if (((be
->time
- lastButtonPressTime
) <=
3070 blackbox
->getDoubleClickInterval()) ||
3071 (be
->state
== ControlMask
)) {
3072 lastButtonPressTime
= 0;
3075 lastButtonPressTime
= be
->time
;
3079 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3081 } else if (be
->button
== 2 && (be
->window
!= frame
.iconify_button
) &&
3082 (be
->window
!= frame
.close_button
) &&
3083 (be
->window
!= frame
.stick_button
)) {
3084 screen
->getWorkspace(blackbox_attrib
.workspace
)->lowerWindow(this);
3086 } else if (be
->button
== 4) {
3087 if ((be
->window
== frame
.label
||
3088 be
->window
== frame
.title
||
3089 be
->window
== frame
.maximize_button
||
3090 be
->window
== frame
.iconify_button
||
3091 be
->window
== frame
.close_button
||
3092 be
->window
== frame
.stick_button
) &&
3096 } else if (be
->button
== 5) {
3097 if ((be
->window
== frame
.label
||
3098 be
->window
== frame
.title
||
3099 be
->window
== frame
.maximize_button
||
3100 be
->window
== frame
.iconify_button
||
3101 be
->window
== frame
.close_button
||
3102 be
->window
== frame
.stick_button
) &&
3109 void BlackboxWindow::buttonReleaseEvent(const XButtonEvent
*re
) {
3111 fprintf(stderr
, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n",
3115 if (re
->window
== frame
.maximize_button
&&
3116 re
->button
>= 1 && re
->button
<= 3) {
3117 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3118 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3119 maximize(re
->button
);
3121 redrawMaximizeButton(flags
.maximized
);
3123 } else if (re
->window
== frame
.iconify_button
&& re
->button
== 1) {
3124 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3125 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3128 redrawIconifyButton(False
);
3130 } else if (re
->window
== frame
.stick_button
&& re
->button
== 1) {
3131 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3132 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
))) {
3135 redrawStickyButton(False
);
3137 } else if (re
->window
== frame
.close_button
& re
->button
== 1) {
3138 if ((re
->x
>= 0 && re
->x
<= static_cast<signed>(frame
.button_w
)) &&
3139 (re
->y
>= 0 && re
->y
<= static_cast<signed>(frame
.button_w
)))
3141 redrawCloseButton(False
);
3142 } else if (flags
.moving
) {
3144 } else if (flags
.resizing
) {
3146 } else if (re
->window
== frame
.window
) {
3147 if (re
->button
== 2 && re
->state
== mod_mask
)
3148 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3154 void BlackboxWindow::beginMove(int x_root
, int y_root
) {
3155 if (! (functions
& Func_Move
)) return;
3157 assert(! (flags
.resizing
|| flags
.moving
));
3160 Only one window can be moved/resized at a time. If another window is already
3161 being moved or resized, then stop it before whating to work with this one.
3163 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3164 if (changing
&& changing
!= this) {
3165 if (changing
->flags
.moving
)
3166 changing
->endMove();
3167 else // if (changing->flags.resizing)
3168 changing
->endResize();
3171 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3172 PointerMotionMask
| ButtonReleaseMask
,
3173 GrabModeAsync
, GrabModeAsync
,
3174 None
, blackbox
->getMoveCursor(), CurrentTime
);
3176 flags
.moving
= True
;
3177 blackbox
->setChangingWindow(this);
3179 if (! screen
->doOpaqueMove()) {
3180 XGrabServer(otk::OBDisplay::display
);
3182 frame
.changing
= frame
.rect
;
3183 screen
->showPosition(frame
.changing
.x(), frame
.changing
.y());
3185 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3189 frame
.changing
.width() - 1,
3190 frame
.changing
.height() - 1);
3193 frame
.grab_x
= x_root
- frame
.rect
.x() - frame
.border_w
;
3194 frame
.grab_y
= y_root
- frame
.rect
.y() - frame
.border_w
;
3198 void BlackboxWindow::doMove(int x_root
, int y_root
) {
3199 assert(flags
.moving
);
3200 assert(blackbox
->getChangingWindow() == this);
3202 int dx
= x_root
- frame
.grab_x
, dy
= y_root
- frame
.grab_y
;
3203 dx
-= frame
.border_w
;
3204 dy
-= frame
.border_w
;
3206 doWindowSnapping(dx
, dy
);
3208 if (screen
->doOpaqueMove()) {
3209 if (screen
->doWorkspaceWarping())
3210 doWorkspaceWarping(x_root
, y_root
, dx
);
3212 configure(dx
, dy
, frame
.rect
.width(), frame
.rect
.height());
3214 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3218 frame
.changing
.width() - 1,
3219 frame
.changing
.height() - 1);
3221 if (screen
->doWorkspaceWarping())
3222 doWorkspaceWarping(x_root
, y_root
, dx
);
3224 frame
.changing
.setPos(dx
, dy
);
3226 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3230 frame
.changing
.width() - 1,
3231 frame
.changing
.height() - 1);
3234 screen
->showPosition(dx
, dy
);
3238 void BlackboxWindow::doWorkspaceWarping(int x_root
, int y_root
, int &dx
) {
3239 // workspace warping
3241 unsigned int dest
= screen
->getCurrentWorkspaceID();
3245 if (dest
> 0) dest
--;
3246 else dest
= screen
->getNumberOfWorkspaces() - 1;
3248 } else if (x_root
>= screen
->getRect().right()) {
3251 if (dest
< screen
->getNumberOfWorkspaces() - 1) dest
++;
3257 bool focus
= flags
.focused
; // had focus while moving?
3259 int dest_x
= x_root
;
3261 dest_x
+= screen
->getRect().width() - 1;
3262 dx
+= screen
->getRect().width() - 1;
3264 dest_x
-= screen
->getRect().width() - 1;
3265 dx
-= screen
->getRect().width() - 1;
3269 screen
->reassociateWindow(this, dest
, False
);
3270 screen
->changeWorkspaceID(dest
);
3272 if (screen
->doOpaqueMove())
3273 XGrabServer(otk::OBDisplay::display
);
3275 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3276 XWarpPointer(otk::OBDisplay::display
, None
,
3277 screen
->getRootWindow(), 0, 0, 0, 0,
3279 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3280 PointerMotionMask
| ButtonReleaseMask
,
3281 GrabModeAsync
, GrabModeAsync
,
3282 None
, blackbox
->getMoveCursor(), CurrentTime
);
3284 if (screen
->doOpaqueMove())
3285 XUngrabServer(otk::OBDisplay::display
);
3293 void BlackboxWindow::doWindowSnapping(int &dx
, int &dy
) {
3294 // how much resistance to edges to provide
3295 const int resistance_size
= screen
->getResistanceSize();
3297 // how far away to snap
3298 const int snap_distance
= screen
->getSnapThreshold();
3300 // how to snap windows
3301 const int snap_to_windows
= screen
->getWindowToWindowSnap();
3302 const int snap_to_edges
= screen
->getWindowToEdgeSnap();
3303 // the amount of space away from the edge to provide resistance/snap
3304 const int snap_offset
= screen
->getSnapOffset();
3306 // find the geomeetery where the moving window currently is
3307 const otk::Rect
&moving
=
3308 screen
->doOpaqueMove() ? frame
.rect
: frame
.changing
;
3311 const int wleft
= dx
,
3312 wright
= dx
+ frame
.rect
.width() - 1,
3314 wbottom
= dy
+ frame
.rect
.height() - 1;
3316 if (snap_to_windows
) {
3317 otk::RectList rectlist
;
3319 Workspace
*w
= screen
->getWorkspace(getWorkspaceNumber());
3322 // add windows on the workspace to the rect list
3323 const BlackboxWindowList
& stack_list
= w
->getStackingList();
3324 BlackboxWindowList::const_iterator st_it
, st_end
= stack_list
.end();
3325 for (st_it
= stack_list
.begin(); st_it
!= st_end
; ++st_it
)
3326 if (*st_it
!= this) // don't snap to ourself
3327 rectlist
.push_back( (*st_it
)->frameRect() );
3329 otk::RectList::const_iterator it
, end
= rectlist
.end();
3330 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3331 bool snapped
= False
;
3332 const otk::Rect
&winrect
= *it
;
3333 otk::Rect offsetrect
;
3334 offsetrect
.setCoords(winrect
.left() - snap_offset
,
3335 winrect
.top() - snap_offset
,
3336 winrect
.right() + snap_offset
,
3337 winrect
.bottom() + snap_offset
);
3339 if (snap_to_windows
== BScreen::WindowResistance
)
3340 // if the window is already over top of this snap target, then
3341 // resistance is futile, so just ignore it
3342 if (winrect
.intersects(moving
))
3345 int dleft
, dright
, dtop
, dbottom
;
3347 // if the windows are in the same plane vertically
3348 if (wtop
>= (signed)(winrect
.y() - frame
.rect
.height() + 1) &&
3349 wtop
< (signed)(winrect
.y() + winrect
.height() - 1)) {
3351 if (snap_to_windows
== BScreen::WindowResistance
) {
3352 dleft
= wright
- offsetrect
.left();
3353 dright
= offsetrect
.right() - wleft
;
3355 // snap left of other window?
3356 if (dleft
>= 0 && dleft
< resistance_size
&&
3357 dleft
< (wright
- wleft
)) {
3358 dx
= offsetrect
.left() - frame
.rect
.width();
3361 // snap right of other window?
3362 else if (dright
>= 0 && dright
< resistance_size
&&
3363 dright
< (wright
- wleft
)) {
3364 dx
= offsetrect
.right() + 1;
3367 } else { // BScreen::WindowSnap
3368 dleft
= abs(wright
- offsetrect
.left());
3369 dright
= abs(wleft
- offsetrect
.right());
3371 // snap left of other window?
3372 if (dleft
< snap_distance
&& dleft
<= dright
) {
3373 dx
= offsetrect
.left() - frame
.rect
.width();
3376 // snap right of other window?
3377 else if (dright
< snap_distance
) {
3378 dx
= offsetrect
.right() + 1;
3384 if (screen
->getWindowCornerSnap()) {
3385 // try corner-snap to its other sides
3386 if (snap_to_windows
== BScreen::WindowResistance
) {
3387 dtop
= winrect
.top() - wtop
;
3388 dbottom
= wbottom
- winrect
.bottom();
3389 if (dtop
> 0 && dtop
< resistance_size
) {
3390 // if we're already past the top edge, then don't provide
3392 if (moving
.top() >= winrect
.top())
3394 } else if (dbottom
> 0 && dbottom
< resistance_size
) {
3395 // if we're already past the bottom edge, then don't provide
3397 if (moving
.bottom() <= winrect
.bottom())
3398 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3400 } else { // BScreen::WindowSnap
3401 dtop
= abs(wtop
- winrect
.top());
3402 dbottom
= abs(wbottom
- winrect
.bottom());
3403 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3405 else if (dbottom
< snap_distance
)
3406 dy
= winrect
.bottom() - frame
.rect
.height() + 1;
3414 // if the windows are on the same plane horizontally
3415 if (wleft
>= (signed)(winrect
.x() - frame
.rect
.width() + 1) &&
3416 wleft
< (signed)(winrect
.x() + winrect
.width() - 1)) {
3418 if (snap_to_windows
== BScreen::WindowResistance
) {
3419 dtop
= wbottom
- offsetrect
.top();
3420 dbottom
= offsetrect
.bottom() - wtop
;
3422 // snap top of other window?
3423 if (dtop
>= 0 && dtop
< resistance_size
&& dtop
< (wbottom
- wtop
)) {
3424 dy
= offsetrect
.top() - frame
.rect
.height();
3427 // snap bottom of other window?
3428 else if (dbottom
>= 0 && dbottom
< resistance_size
&&
3429 dbottom
< (wbottom
- wtop
)) {
3430 dy
= offsetrect
.bottom() + 1;
3433 } else { // BScreen::WindowSnap
3434 dtop
= abs(wbottom
- offsetrect
.top());
3435 dbottom
= abs(wtop
- offsetrect
.bottom());
3437 // snap top of other window?
3438 if (dtop
< snap_distance
&& dtop
<= dbottom
) {
3439 dy
= offsetrect
.top() - frame
.rect
.height();
3442 // snap bottom of other window?
3443 else if (dbottom
< snap_distance
) {
3444 dy
= offsetrect
.bottom() + 1;
3451 if (screen
->getWindowCornerSnap()) {
3452 // try corner-snap to its other sides
3453 if (snap_to_windows
== BScreen::WindowResistance
) {
3454 dleft
= winrect
.left() - wleft
;
3455 dright
= wright
- winrect
.right();
3456 if (dleft
> 0 && dleft
< resistance_size
) {
3457 // if we're already past the left edge, then don't provide
3459 if (moving
.left() >= winrect
.left())
3460 dx
= winrect
.left();
3461 } else if (dright
> 0 && dright
< resistance_size
) {
3462 // if we're already past the right edge, then don't provide
3464 if (moving
.right() <= winrect
.right())
3465 dx
= winrect
.right() - frame
.rect
.width() + 1;
3467 } else { // BScreen::WindowSnap
3468 dleft
= abs(wleft
- winrect
.left());
3469 dright
= abs(wright
- winrect
.right());
3470 if (dleft
< snap_distance
&& dleft
<= dright
)
3471 dx
= winrect
.left();
3472 else if (dright
< snap_distance
)
3473 dx
= winrect
.right() - frame
.rect
.width() + 1;
3483 if (snap_to_edges
) {
3484 otk::RectList rectlist
;
3486 // snap to the screen edges (and screen boundaries for xinerama)
3488 if (screen
->isXineramaActive() && blackbox
->doXineramaSnapping()) {
3489 rectlist
.insert(rectlist
.begin(),
3490 screen
->getXineramaAreas().begin(),
3491 screen
->getXineramaAreas().end());
3494 rectlist
.push_back(screen
->getRect());
3496 otk::RectList::const_iterator it
, end
= rectlist
.end();
3497 for (it
= rectlist
.begin(); it
!= end
; ++it
) {
3498 const otk::Rect
&srect
= *it
;
3499 otk::Rect offsetrect
;
3500 offsetrect
.setCoords(srect
.left() + snap_offset
,
3501 srect
.top() + snap_offset
,
3502 srect
.right() - snap_offset
,
3503 srect
.bottom() - snap_offset
);
3505 if (snap_to_edges
== BScreen::WindowResistance
) {
3506 // if we're not in the rectangle then don't snap to it.
3507 if (! srect
.contains(moving
))
3509 } else { // BScreen::WindowSnap
3510 // if we're not in the rectangle then don't snap to it.
3511 if (! srect
.intersects(otk::Rect(wleft
, wtop
, frame
.rect
.width(),
3512 frame
.rect
.height())))
3516 if (snap_to_edges
== BScreen::WindowResistance
) {
3517 int dleft
= offsetrect
.left() - wleft
,
3518 dright
= wright
- offsetrect
.right(),
3519 dtop
= offsetrect
.top() - wtop
,
3520 dbottom
= wbottom
- offsetrect
.bottom();
3523 if (dleft
> 0 && dleft
< resistance_size
)
3524 dx
= offsetrect
.left();
3526 else if (dright
> 0 && dright
< resistance_size
)
3527 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3530 if (dtop
> 0 && dtop
< resistance_size
)
3531 dy
= offsetrect
.top();
3533 else if (dbottom
> 0 && dbottom
< resistance_size
)
3534 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3535 } else { // BScreen::WindowSnap
3536 int dleft
= abs(wleft
- offsetrect
.left()),
3537 dright
= abs(wright
- offsetrect
.right()),
3538 dtop
= abs(wtop
- offsetrect
.top()),
3539 dbottom
= abs(wbottom
- offsetrect
.bottom());
3542 if (dleft
< snap_distance
&& dleft
<= dright
)
3543 dx
= offsetrect
.left();
3545 else if (dright
< snap_distance
)
3546 dx
= offsetrect
.right() - frame
.rect
.width() + 1;
3549 if (dtop
< snap_distance
&& dtop
<= dbottom
)
3550 dy
= offsetrect
.top();
3552 else if (dbottom
< snap_distance
)
3553 dy
= offsetrect
.bottom() - frame
.rect
.height() + 1;
3560 void BlackboxWindow::endMove(void) {
3561 assert(flags
.moving
);
3562 assert(blackbox
->getChangingWindow() == this);
3564 flags
.moving
= False
;
3565 blackbox
->setChangingWindow(0);
3567 if (! screen
->doOpaqueMove()) {
3568 /* when drawing the rubber band, we need to make sure we only draw inside
3569 * the frame... frame.changing_* contain the new coords for the window,
3570 * so we need to subtract 1 from changing_w/changing_h every where we
3571 * draw the rubber band (for both moving and resizing)
3573 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3574 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3575 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3576 XUngrabServer(otk::OBDisplay::display
);
3578 configure(frame
.changing
.x(), frame
.changing
.y(),
3579 frame
.changing
.width(), frame
.changing
.height());
3581 configure(frame
.rect
.x(), frame
.rect
.y(),
3582 frame
.rect
.width(), frame
.rect
.height());
3584 screen
->hideGeometry();
3586 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3588 // if there are any left over motions from the move, drop them now
3589 XSync(otk::OBDisplay::display
, false); // make sure we don't miss any
3591 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, frame
.window
,
3596 void BlackboxWindow::beginResize(int x_root
, int y_root
, Corner dir
) {
3597 if (! (functions
& Func_Resize
)) return;
3599 assert(! (flags
.resizing
|| flags
.moving
));
3602 Only one window can be moved/resized at a time. If another window is
3603 already being moved or resized, then stop it before whating to work with
3606 BlackboxWindow
*changing
= blackbox
->getChangingWindow();
3607 if (changing
&& changing
!= this) {
3608 if (changing
->flags
.moving
)
3609 changing
->endMove();
3610 else // if (changing->flags.resizing)
3611 changing
->endResize();
3619 switch (resize_dir
) {
3622 cursor
= blackbox
->getLowerLeftAngleCursor();
3627 cursor
= blackbox
->getLowerRightAngleCursor();
3631 anchor
= BottomRight
;
3632 cursor
= blackbox
->getUpperLeftAngleCursor();
3636 anchor
= BottomLeft
;
3637 cursor
= blackbox
->getUpperRightAngleCursor();
3641 assert(false); // unhandled Corner
3642 return; // unreachable, for the compiler
3645 XGrabServer(otk::OBDisplay::display
);
3646 XGrabPointer(otk::OBDisplay::display
, frame
.window
, False
,
3647 PointerMotionMask
| ButtonReleaseMask
,
3648 GrabModeAsync
, GrabModeAsync
, None
, cursor
, CurrentTime
);
3650 flags
.resizing
= True
;
3651 blackbox
->setChangingWindow(this);
3653 unsigned int gw
, gh
;
3654 frame
.changing
= frame
.rect
;
3656 constrain(anchor
, &gw
, &gh
);
3658 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3659 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3660 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3662 screen
->showGeometry(gw
, gh
);
3664 frame
.grab_x
= x_root
;
3665 frame
.grab_y
= y_root
;
3669 void BlackboxWindow::doResize(int x_root
, int y_root
) {
3670 assert(flags
.resizing
);
3671 assert(blackbox
->getChangingWindow() == this);
3673 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3674 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3675 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3677 unsigned int gw
, gh
;
3679 int dx
, dy
; // the amount of change in the size of the window
3681 switch (resize_dir
) {
3684 dx
= - (x_root
- frame
.grab_x
);
3685 dy
= + (y_root
- frame
.grab_y
);
3689 dx
= + (x_root
- frame
.grab_x
);
3690 dy
= + (y_root
- frame
.grab_y
);
3693 anchor
= BottomRight
;
3694 dx
= - (x_root
- frame
.grab_x
);
3695 dy
= - (y_root
- frame
.grab_y
);
3698 anchor
= BottomLeft
;
3699 dx
= + (x_root
- frame
.grab_x
);
3700 dy
= - (y_root
- frame
.grab_y
);
3704 assert(false); // unhandled Corner
3705 return; // unreachable, for the compiler
3708 // make sure the user cant resize the window smaller than 0, which makes it
3709 // wrap around and become huge
3710 if (dx
< -(signed)client
.rect
.width()) dx
= -(signed)client
.rect
.width();
3711 if (dy
< -(signed)client
.rect
.height()) dy
= -(signed)client
.rect
.height();
3713 frame
.changing
.setSize(frame
.rect
.width() + dx
, frame
.rect
.height() + dy
);
3715 constrain(anchor
, &gw
, &gh
);
3717 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3718 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3719 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3721 screen
->showGeometry(gw
, gh
);
3725 void BlackboxWindow::endResize(void) {
3726 assert(flags
.resizing
);
3727 assert(blackbox
->getChangingWindow() == this);
3729 XDrawRectangle(otk::OBDisplay::display
, screen
->getRootWindow(),
3730 screen
->getOpGC(), frame
.changing
.x(), frame
.changing
.y(),
3731 frame
.changing
.width() - 1, frame
.changing
.height() - 1);
3732 XUngrabServer(otk::OBDisplay::display
);
3734 // unset maximized state after resized when fully maximized
3735 if (flags
.maximized
== 1)
3738 flags
.resizing
= False
;
3739 blackbox
->setChangingWindow(0);
3741 configure(frame
.changing
.x(), frame
.changing
.y(),
3742 frame
.changing
.width(), frame
.changing
.height());
3743 screen
->hideGeometry();
3745 XUngrabPointer(otk::OBDisplay::display
, CurrentTime
);
3747 // if there are any left over motions from the resize, drop them now
3748 XSync(otk::OBDisplay::display
, false); // make sure we don't miss any
3750 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, frame
.window
,
3755 void BlackboxWindow::motionNotifyEvent(const XMotionEvent
*me
) {
3757 fprintf(stderr
, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n",
3762 doMove(me
->x_root
, me
->y_root
);
3763 } else if (flags
.resizing
) {
3764 doResize(me
->x_root
, me
->y_root
);
3766 if ((functions
& Func_Move
) &&
3767 (me
->state
& Button1Mask
) &&
3768 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3769 frame
.handle
== me
->window
|| frame
.window
== me
->window
)) {
3770 beginMove(me
->x_root
, me
->y_root
);
3771 } else if ((functions
& Func_Resize
) &&
3772 ((me
->state
& Button1Mask
) &&
3773 (me
->window
== frame
.right_grip
||
3774 me
->window
== frame
.left_grip
)) ||
3775 ((me
->state
& Button3Mask
) && (me
->state
& mod_mask
) &&
3776 (frame
.title
== me
->window
|| frame
.label
== me
->window
||
3777 frame
.handle
== me
->window
|| frame
.window
== me
->window
||
3778 frame
.right_grip
== me
->window
||
3779 frame
.left_grip
== me
->window
))) {
3780 unsigned int zones
= screen
->getResizeZones();
3783 if (me
->window
== frame
.left_grip
) {
3784 corner
= BottomLeft
;
3785 } else if (me
->window
== frame
.right_grip
|| zones
== 1) {
3786 corner
= BottomRight
;
3789 bool left
= (me
->x_root
- frame
.rect
.x() <=
3790 static_cast<signed>(frame
.rect
.width() / 2));
3793 else // (zones == 4)
3794 top
= (me
->y_root
- frame
.rect
.y() <=
3795 static_cast<signed>(frame
.rect
.height() / 2));
3796 corner
= (top
? (left
? TopLeft
: TopRight
) :
3797 (left
? BottomLeft
: BottomRight
));
3800 beginResize(me
->x_root
, me
->y_root
, corner
);
3806 void BlackboxWindow::enterNotifyEvent(const XCrossingEvent
* ce
) {
3807 if (! (screen
->isSloppyFocus() && isVisible() && isNormal()))
3811 bool leave
= False
, inferior
= False
;
3813 while (XCheckTypedWindowEvent(otk::OBDisplay::display
, ce
->window
,
3815 if (e
.type
== LeaveNotify
&& e
.xcrossing
.mode
== NotifyNormal
) {
3817 inferior
= (e
.xcrossing
.detail
== NotifyInferior
);
3821 if (! leave
|| inferior
) {
3822 if (! isFocused()) {
3823 bool success
= setInputFocus();
3824 if (success
) // if focus succeeded install the colormap
3825 installColormap(True
); // XXX: shouldnt we honour no install?
3828 We only auto-raise when the window wasn't focused because otherwise
3829 we run into problems with gtk+ drop-down lists. The window ends up
3830 raising over the list.
3832 if (screen
->doAutoRaise())
3839 void BlackboxWindow::leaveNotifyEvent(const XCrossingEvent
*) {
3840 if (! (screen
->isSloppyFocus() && screen
->doAutoRaise() && isNormal()))
3843 installColormap(False
);
3850 void BlackboxWindow::shapeEvent(XShapeEvent
*e
) {
3851 if (blackbox
->hasShapeExtensions()) {
3852 if (! e
->shaped
&& flags
.shaped
) {
3854 flags
.shaped
= False
;
3855 } else if (e
->shaped
) {
3857 flags
.shaped
= True
;
3864 bool BlackboxWindow::validateClient(void) const {
3865 XSync(otk::OBDisplay::display
, False
);
3868 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3869 DestroyNotify
, &e
) ||
3870 XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3872 XPutBackEvent(otk::OBDisplay::display
, &e
);
3881 void BlackboxWindow::restore(bool remap
) {
3882 XChangeSaveSet(otk::OBDisplay::display
, client
.window
, SetModeDelete
);
3883 XSelectInput(otk::OBDisplay::display
, client
.window
, NoEventMask
);
3884 XSelectInput(otk::OBDisplay::display
, frame
.plate
, NoEventMask
);
3886 // do not leave a shaded window as an icon unless it was an icon
3887 if (flags
.shaded
&& ! flags
.iconic
)
3888 setState(NormalState
);
3890 // erase the netwm stuff that we read when a window maps, so that it
3891 // doesn't persist between mappings.
3892 // (these are the ones read in getNetWMFlags().)
3893 xatom
->erase(client
.window
, otk::OBProperty::net_wm_desktop
);
3894 xatom
->erase(client
.window
, otk::OBProperty::net_wm_state
);
3896 restoreGravity(client
.rect
);
3898 XUnmapWindow(otk::OBDisplay::display
, frame
.window
);
3899 XUnmapWindow(otk::OBDisplay::display
, client
.window
);
3901 XSetWindowBorderWidth(otk::OBDisplay::display
, client
.window
, client
.old_bw
);
3904 if (XCheckTypedWindowEvent(otk::OBDisplay::display
, client
.window
,
3905 ReparentNotify
, &ev
)) {
3908 // according to the ICCCM - if the client doesn't reparent to
3909 // root, then we have to do it for them
3910 XReparentWindow(otk::OBDisplay::display
, client
.window
,
3911 screen
->getRootWindow(),
3912 client
.rect
.x(), client
.rect
.y());
3915 if (remap
) XMapWindow(otk::OBDisplay::display
, client
.window
);
3919 // timer for autoraise
3920 void BlackboxWindow::timeout(BlackboxWindow
*t
) {
3921 t
->screen
->getWorkspace(t
->blackbox_attrib
.workspace
)->raiseWindow(t
);
3922 printf("TIMED OUT YA YAY\n");
3926 void BlackboxWindow::changeBlackboxHints(const BlackboxHints
*net
) {
3927 if ((net
->flags
& AttribShaded
) &&
3928 ((blackbox_attrib
.attrib
& AttribShaded
) !=
3929 (net
->attrib
& AttribShaded
)))
3932 if (flags
.visible
&& // watch out for requests when we can not be seen
3933 (net
->flags
& (AttribMaxVert
| AttribMaxHoriz
)) &&
3934 ((blackbox_attrib
.attrib
& (AttribMaxVert
| AttribMaxHoriz
)) !=
3935 (net
->attrib
& (AttribMaxVert
| AttribMaxHoriz
)))) {
3936 if (flags
.maximized
) {
3941 if ((net
->flags
& AttribMaxHoriz
) && (net
->flags
& AttribMaxVert
))
3942 button
= ((net
->attrib
& (AttribMaxHoriz
| AttribMaxVert
)) ? 1 : 0);
3943 else if (net
->flags
& AttribMaxVert
)
3944 button
= ((net
->attrib
& AttribMaxVert
) ? 2 : 0);
3945 else if (net
->flags
& AttribMaxHoriz
)
3946 button
= ((net
->attrib
& AttribMaxHoriz
) ? 3 : 0);
3952 if ((net
->flags
& AttribOmnipresent
) &&
3953 ((blackbox_attrib
.attrib
& AttribOmnipresent
) !=
3954 (net
->attrib
& AttribOmnipresent
)))
3957 if ((net
->flags
& AttribWorkspace
) &&
3958 (blackbox_attrib
.workspace
!= net
->workspace
)) {
3959 screen
->reassociateWindow(this, net
->workspace
, True
);
3961 if (screen
->getCurrentWorkspaceID() != net
->workspace
) {
3965 screen
->getWorkspace(blackbox_attrib
.workspace
)->raiseWindow(this);
3969 if (net
->flags
& AttribDecoration
) {
3970 switch (net
->decoration
) {
3987 * Set the sizes of all components of the window frame
3988 * (the window decorations).
3989 * These values are based upon the current style settings and the client
3990 * window's dimensions.
3992 void BlackboxWindow::upsize(void) {
3993 frame
.bevel_w
= screen
->getWindowStyle()->getBevelWidth();
3995 if (decorations
& Decor_Border
) {
3996 frame
.border_w
= screen
->getWindowStyle()->getBorderWidth();
3997 if (! isTransient())
3998 frame
.mwm_border_w
= screen
->getWindowSty2le()->getFrameWidth();
4000 frame
.mwm_border_w
= 0;
4002 frame
.mwm_border_w
= frame
.border_w
= 0;
4005 if (decorations
& Decor_Titlebar
) {
4006 // the height of the titlebar is based upon the height of the font being
4007 // used to display the window's title
4008 otk::Style
*style
= screen
->getWindowStyle();
4009 frame
.title_h
= style
->font
->height() + (frame
.bevel_w
* 2) + 2;
4011 frame
.label_h
= frame
.title_h
- (frame
.bevel_w
* 2);
4012 frame
.button_w
= (frame
.label_h
- 2);
4014 // set the top frame margin
4015 frame
.margin
.top
= frame
.border_w
+ frame
.title_h
+
4016 frame
.border_w
+ frame
.mwm_border_w
;
4022 // set the top frame margin
4023 frame
.margin
.top
= frame
.border_w
+ frame
.mwm_border_w
;
4026 // set the left/right frame margin
4027 frame
.margin
.left
= frame
.margin
.right
= frame
.border_w
+ frame
.mwm_border_w
;
4029 if (decorations
& Decor_Handle
) {
4030 frame
.grip_w
= frame
.button_w
* 2;
4031 frame
.handle_h
= screen
->getWindowStyle()->getHandleWidth();
4033 // set the bottom frame margin
4034 frame
.margin
.bottom
= frame
.border_w
+ frame
.handle_h
+
4035 frame
.border_w
+ frame
.mwm_border_w
;
4040 // set the bottom frame margin
4041 frame
.margin
.bottom
= frame
.border_w
+ frame
.mwm_border_w
;
4045 We first get the normal dimensions and use this to define the inside_w/h
4046 then we modify the height if shading is in effect.
4047 If the shade state is not considered then frame.rect gets reset to the
4048 normal window size on a reconfigure() call resulting in improper
4049 dimensions appearing in move/resize and other events.
4052 height
= client
.rect
.height() + frame
.margin
.top
+ frame
.margin
.bottom
,
4053 width
= client
.rect
.width() + frame
.margin
.left
+ frame
.margin
.right
;
4055 frame
.inside_w
= width
- (frame
.border_w
* 2);
4056 frame
.inside_h
= height
- (frame
.border_w
* 2);
4059 height
= frame
.title_h
+ (frame
.border_w
* 2);
4060 frame
.rect
.setSize(width
, height
);
4065 * Calculate the size of the client window and constrain it to the
4066 * size specified by the size hints of the client window.
4068 * The logical width and height are placed into pw and ph, if they
4069 * are non-zero. Logical size refers to the users perception of
4070 * the window size (for example an xterm resizes in cells, not in pixels).
4071 * pw and ph are then used to display the geometry during window moves, resize,
4074 * The physical geometry is placed into frame.changing_{x,y,width,height}.
4075 * Physical geometry refers to the geometry of the window in pixels.
4077 void BlackboxWindow::constrain(Corner anchor
,
4078 unsigned int *pw
, unsigned int *ph
) {
4079 // frame.changing represents the requested frame size, we need to
4080 // strip the frame margin off and constrain the client size
4081 frame
.changing
.setCoords(frame
.changing
.left() + frame
.margin
.left
,
4082 frame
.changing
.top() + frame
.margin
.top
,
4083 frame
.changing
.right() - frame
.margin
.right
,
4084 frame
.changing
.bottom() - frame
.margin
.bottom
);
4086 unsigned int dw
= frame
.changing
.width(), dh
= frame
.changing
.height(),
4087 base_width
= (client
.base_width
) ? client
.base_width
: client
.min_width
,
4088 base_height
= (client
.base_height
) ? client
.base_height
:
4091 // constrain, but only if the min/max are being used. if they aren't, then
4092 // this resize is going to be from a ConfigureRequest because the window
4093 // isn't allowed to be resized by the user. And in that case, we don't want
4094 // to limit what the app can do
4095 if (client
.max_width
> client
.min_width
||
4096 client
.max_height
> client
.min_height
) {
4097 if (dw
< client
.min_width
) dw
= client
.min_width
;
4098 if (dh
< client
.min_height
) dh
= client
.min_height
;
4099 if (dw
> client
.max_width
) dw
= client
.max_width
;
4100 if (dh
> client
.max_height
) dh
= client
.max_height
;
4103 if (client
.width_inc
> 1) {
4105 dw
/= client
.width_inc
;
4107 if (client
.height_inc
> 1) {
4109 dh
/= client
.height_inc
;
4118 if (client
.width_inc
> 1) {
4119 dw
*= client
.width_inc
;
4122 if (client
.height_inc
> 1) {
4123 dh
*= client
.height_inc
;
4127 frame
.changing
.setSize(dw
, dh
);
4129 // add the frame margin back onto frame.changing
4130 frame
.changing
.setCoords(frame
.changing
.left() - frame
.margin
.left
,
4131 frame
.changing
.top() - frame
.margin
.top
,
4132 frame
.changing
.right() + frame
.margin
.right
,
4133 frame
.changing
.bottom() + frame
.margin
.bottom
);
4135 // move frame.changing to the specified anchor
4143 dx
= frame
.rect
.right() - frame
.changing
.right();
4147 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4151 dx
= frame
.rect
.right() - frame
.changing
.right();
4152 dy
= frame
.rect
.bottom() - frame
.changing
.bottom();
4156 assert(false); // unhandled corner
4158 frame
.changing
.setPos(frame
.changing
.x() + dx
, frame
.changing
.y() + dy
);
4162 BWindowGroup::BWindowGroup(Blackbox
*b
, Window _group
)
4163 : blackbox(b
), group(_group
) {
4164 XWindowAttributes wattrib
;
4165 if (! XGetWindowAttributes(otk::OBDisplay::display
, group
, &wattrib
)) {
4166 // group window doesn't seem to exist anymore
4171 XSelectInput(otk::OBDisplay::display
, group
,
4172 PropertyChangeMask
| FocusChangeMask
| StructureNotifyMask
);
4174 blackbox
->saveGroupSearch(group
, this);
4178 BWindowGroup::~BWindowGroup(void) {
4179 blackbox
->removeGroupSearch(group
);
4184 BWindowGroup::find(BScreen
*screen
, bool allow_transients
) const {
4185 BlackboxWindow
*ret
= blackbox
->getFocusedWindow();
4187 // does the focus window match (or any transient_fors)?
4188 for (; ret
; ret
= ret
->getTransientFor()) {
4189 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4190 (! ret
->isTransient() || allow_transients
))
4194 if (ret
) return ret
;
4196 // the focus window didn't match, look in the group's window list
4197 BlackboxWindowList::const_iterator it
, end
= windowList
.end();
4198 for (it
= windowList
.begin(); it
!= end
; ++it
) {
4200 if (ret
->getScreen() == screen
&& ret
->getGroupWindow() == group
&&
4201 (! ret
->isTransient() || allow_transients
))