1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // window.cc for Epistrophy - a key handler for NETWM/EWMH window managers.
3 // Copyright (c) 2002 - 2002 Ben Jansens <ben at orodu.net>
5 // Modified for use and inclusion in bbkeys by Jason 'vanRijn' Kasper
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the "Software"),
9 // to deal in the Software without restriction, including without limitation
10 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 // and/or sell copies of the Software, and to permit persons to whom the
12 // Software is furnished to do so, subject to the following conditions:
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 // DEALINGS IN THE SOFTWARE.
32 // defined by black/openbox
33 const unsigned long XWindow::PropBlackboxAttributesElements
;
34 const unsigned long XWindow::AttribDecoration
;
35 const unsigned long XWindow::DecorNone
;
36 const unsigned long XWindow::DecorNormal
;
39 XWindow::XWindow(Window window
, Netclient
* netclient
,
40 const bt::ScreenInfo
& screenInfo
, bt::Application
& app
)
41 : _window(window
), _netclient(netclient
), _screenInfo(screenInfo
),
46 _display
=_screenInfo
.display().XDisplay();
47 _root
= _screenInfo
.rootWindow();
49 XSelectInput(_display
, _window
,
50 PropertyChangeMask
| StructureNotifyMask
);
52 // add an event handler for our window
53 _app
.insertEventHandler(_window
, this);
55 updateBlackboxAttributes();
69 XSelectInput(_display
, _window
, None
);
71 // tell our main app about our death
72 _app
.removeEventHandler( _window
);
75 // Window configure (size, position, stacking, etc.).
76 void XWindow::configureNotifyEvent(const XConfigureEvent
* const e
) {
80 // Window property changed/added/deleted.
81 void XWindow::propertyNotifyEvent(const XPropertyEvent
* const e
) {
83 if (e
->atom
== XA_WM_NORMAL_HINTS
)
85 else if (e
->atom
== XA_WM_HINTS
)
87 else if (e
->atom
== _netclient
->xaBlackboxAttributes())
88 updateBlackboxAttributes();
89 else if (e
->atom
== _netclient
->wmState() )
91 else if (e
->atom
== _netclient
->wmDesktop() )
93 else if (e
->atom
== _netclient
->wmName() ||
94 e
->atom
== _netclient
->xaWmName() )
96 else if (e
->atom
== _netclient
->xaWmClass() )
101 void XWindow::unmapNotifyEvent(const XUnmapEvent
* const e
) {
106 void XWindow::destroyNotifyEvent(const XDestroyWindowEvent
* const e
) {
110 void XWindow::updateDimensions(const XConfigureEvent
* const e
) {
111 _rect
.setRect(e
->x
, e
->y
, e
->width
, e
->height
);
114 void XWindow::updateDimensions() {
116 XWindowAttributes win_attributes
;
120 _rect
.setRect(0,0,1,1);
122 if (! XGetWindowAttributes(_display
, _window
, &win_attributes
)) {
123 std::cerr
<< BBTOOL
<< ": " << "updateDimensions. couldn't get what I needed, so setting to ridiculously wrong values.\n";
127 XTranslateCoordinates (_display
, _window
, win_attributes
.root
,
128 -win_attributes
.border_width
,
129 -win_attributes
.border_width
,
131 _rect
.setRect(rx
, ry
, win_attributes
.width
, win_attributes
.height
);
135 void XWindow::updateBlackboxAttributes() {
137 unsigned long num
= PropBlackboxAttributesElements
;
141 if (_netclient
->getValue(_window
,
142 _netclient
->xaBlackboxAttributes(),
143 _netclient
->xaBlackboxAttributes(),
145 if (num
== PropBlackboxAttributesElements
)
146 if (data
[0] & AttribDecoration
)
147 _decorated
= (data
[4] != DecorNone
);
152 void XWindow::updateNormalHints() {
157 _gravity
= NorthWestGravity
;
159 _base_x
= _base_y
= 0;
161 if (XGetWMNormalHints(_display
, _window
, &size
, &ret
)) {
162 if (size
.flags
& PWinGravity
)
163 _gravity
= size
.win_gravity
;
164 if (size
.flags
& PBaseSize
) {
165 _base_x
= size
.base_width
;
166 _base_y
= size
.base_height
;
168 if (size
.flags
& PResizeInc
) {
169 _inc_x
= size
.width_inc
;
170 _inc_y
= size
.height_inc
;
176 void XWindow::updateWMHints() {
179 // assume a window takes input if it doesnt specify
182 if ((hints
= XGetWMHints(_display
, _window
)) != NULL
) {
183 if (hints
->flags
& InputHint
)
184 _can_focus
= hints
->input
;
190 void XWindow::updateState() {
192 _shaded
= _skip_pager
= _iconic
= _max_vert
= _max_horz
= false;
194 unsigned long num
= (unsigned) -1;
196 if (! _netclient
->getValue(_window
, _netclient
->wmState(), XA_ATOM
,
199 for (unsigned long i
= 0; i
< num
; ++i
) {
200 if (state
[i
] == _netclient
->wmStateMaximizedVert())
202 if (state
[i
] == _netclient
->wmStateMaximizedHorz())
204 if (state
[i
] == _netclient
->wmStateShaded())
206 if (state
[i
] == _netclient
->wmStateHidden())
208 if (state
[i
] == _netclient
->wmStateSkipPager())
216 void XWindow::updateDesktop() {
217 unsigned long d
= 0ul;
218 if (! _netclient
->getValue(_window
, _netclient
->wmDesktop(), XA_CARDINAL
, d
))
221 _desktop
= static_cast<unsigned int>(d
);
226 void XWindow::updateTitle() {
230 if (! _netclient
->getValue(_window
, _netclient
->wmName(),
231 Netclient::utf8
, _title
)) {
233 _netclient
->getValue(_window
, XA_WM_NAME
, Netclient::ansi
, _title
);
242 void XWindow::updateClass() {
244 _app_name
= _app_class
= "";
246 Netclient::StringVect v
;
247 unsigned long num
= 2;
249 if (! _netclient
->getValue(_window
, XA_WM_CLASS
, Netclient::ansi
, num
, v
))
252 if (num
> 0) _app_name
= v
[0];
253 if (num
> 1) _app_class
= v
[1];
258 void XWindow::shade(const bool sh
) const {
259 _netclient
->sendClientMessage(_root
, _netclient
->wmState(),
260 _window
, (sh
? 1 : 0),
261 _netclient
->wmStateShaded());
264 void XWindow::close() const {
265 _netclient
->sendClientMessage(_root
, _netclient
->closeWindow(),
270 void XWindow::raise() const {
271 XRaiseWindow(_display
, _window
);
274 void XWindow::lower() const {
275 XLowerWindow(_display
, _window
);
278 void XWindow::iconify() const {
279 _netclient
->sendClientMessage(_root
, _netclient
->xaWmChangeState(),
280 _window
, IconicState
);
283 void XWindow::focus(bool raise
) const {
284 // this will cause the window to be uniconified also
287 _netclient
->sendClientMessage(_root
, _netclient
->activeWindow(),
290 XSetInputFocus(_display
, _window
, None
, CurrentTime
);
294 void XWindow::decorate(bool d
) const {
295 _netclient
->sendClientMessage(_root
,
296 _netclient
->xaBlackboxChangeAttributes(),
297 _window
, AttribDecoration
,
298 0, 0, 0, (d
? DecorNormal
: DecorNone
));
301 void XWindow::sendTo(unsigned int dest
) const {
302 _netclient
->sendClientMessage(_root
, _netclient
->wmDesktop(),
307 void XWindow::move(int x
, int y
) const {
309 XWindowAttributes win_attributes
;
314 if (! XGetWindowAttributes(_display
, _window
, &win_attributes
)) {
315 std::cerr
<< BBTOOL
<< ": " << "move: couldn't get what I needed. not able to move, sorry.\n";
319 XTranslateCoordinates (_display
, _window
, win_attributes
.root
,
320 -win_attributes
.border_width
,
321 -win_attributes
.border_width
,
326 int dw
= _screenInfo
.width(), dh
= _screenInfo
.height();
329 /* find our window manager frame, if any */
330 Window wmframe
= _window
;
337 status
= XQueryTree(_display
, wmframe
, &root
, &parent
, &childlist
, &ujunk
);
338 if (parent
== root
|| !parent
|| !status
)
341 if (status
&& childlist
)
342 XFree((char *)childlist
);
345 if (wmframe
!= _window
) {
346 /* WM reparented, so find edges of the frame */
347 /* Only works for ICCCM-compliant WMs, and then only if the
348 window has corner gravity. We would need to know the original width
349 of the window to correctly handle the other gravities. */
351 XWindowAttributes frame_attr
;
353 if (!XGetWindowAttributes(_display
, wmframe
, &frame_attr
)) {
354 std::cerr
<< BBTOOL
<< ": " << "updateDimensions. error. can't get frame attributes.\n";
358 case NorthWestGravity
: case SouthWestGravity
:
359 case NorthEastGravity
: case SouthEastGravity
:
364 case NorthWestGravity
: case SouthWestGravity
:
365 case NorthEastGravity
: case SouthEastGravity
:
367 xright
= dw
- frame_attr
.x
- frame_attr
.width
-
368 2*frame_attr
.border_width
;
371 case NorthWestGravity
: case SouthWestGravity
:
372 case NorthEastGravity
: case SouthEastGravity
:
377 case NorthWestGravity
: case SouthWestGravity
:
378 case NorthEastGravity
: case SouthEastGravity
:
380 ybelow
= dh
- frame_attr
.y
- frame_attr
.height
-
381 2*frame_attr
.border_width
;
385 int destx
= rx
+x
, desty
= ry
+y
;
387 XMoveWindow(_display
, _window
, destx
, desty
);
392 void XWindow::resizeRel(int dwidth
, int dheight
) const {
393 // resize in increments if requested by the window
394 unsigned int width
= _rect
.width(), height
= _rect
.height();
396 unsigned int wdest
= width
+ (dwidth
* _inc_x
) / _inc_x
* _inc_x
+ _base_x
;
397 unsigned int hdest
= height
+ (dheight
* _inc_y
) / _inc_y
* _inc_y
+ _base_y
;
399 XResizeWindow(_display
, _window
, wdest
, hdest
);
403 void XWindow::resizeAbs(unsigned int width
, unsigned int height
) const {
404 // resize in increments if requested by the window
406 unsigned int wdest
= width
/ _inc_x
* _inc_x
+ _base_x
;
407 unsigned int hdest
= height
/ _inc_y
* _inc_y
+ _base_y
;
410 while (width
> wdest
)
413 while (width
< wdest
)
416 if (height
> hdest
) {
417 while (height
> hdest
)
420 while (height
< hdest
)
424 XResizeWindow(_display
, _window
, wdest
, hdest
);
428 void XWindow::toggleMaximize(Max max
) const {
432 sendClientMessage(_root
, _netclient
->wmState(),
433 _window
, (_max_vert
== _max_horz
? 2 : 1),
434 _netclient
->wmStateMaximizedHorz(),
435 _netclient
->wmStateMaximizedVert());
440 sendClientMessage(_root
, _netclient
->wmState(),
442 _netclient
->wmStateMaximizedHorz());
447 sendClientMessage(_root
, _netclient
->wmState(),
449 _netclient
->wmStateMaximizedVert());
453 assert(false); // you should not do this. it is pointless and probly a bug
459 void XWindow::maximize(Max max
) const {
463 sendClientMessage(_root
, _netclient
->wmState(),
465 _netclient
->wmStateMaximizedHorz(),
466 _netclient
->wmStateMaximizedVert());
471 sendClientMessage(_root
, _netclient
->wmState(),
473 _netclient
->wmStateMaximizedHorz(),
474 _netclient
->wmStateMaximizedVert());
479 sendClientMessage(_root
, _netclient
->wmState(),
481 _netclient
->wmStateMaximizedHorz());
486 sendClientMessage(_root
, _netclient
->wmState(),
488 _netclient
->wmStateMaximizedVert());