passing move increments now, not position. also bringing in code from xwininfo for...
[bbkeys.git] / src / window.cc
blob3c14e00dfe72a9e0363f951d1249c630e0281723
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>
4 //
5 // Modified for use and inclusion in bbkeys by Jason 'vanRijn' Kasper
6 //
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.
25 #include <iostream>
27 using std::cout;
28 using std::endl;
30 #include "window.hh"
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),
42 _app(app) {
44 _unmapped = false;
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();
56 updateNormalHints();
57 updateWMHints();
58 updateDimensions();
59 updateState();
60 updateDesktop();
61 updateTitle();
62 updateClass();
67 XWindow::~XWindow() {
68 if (! _unmapped)
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) {
77 updateDimensions();
80 // Window property changed/added/deleted.
81 void XWindow::propertyNotifyEvent(const XPropertyEvent * const e) {
83 if (e->atom == XA_WM_NORMAL_HINTS)
84 updateNormalHints();
85 else if (e->atom == XA_WM_HINTS)
86 updateWMHints();
87 else if (e->atom == _netclient->xaBlackboxAttributes())
88 updateBlackboxAttributes();
89 else if (e->atom == _netclient->wmState() )
90 updateState();
91 else if (e->atom == _netclient->wmDesktop() )
92 updateDesktop();
93 else if (e->atom == _netclient->wmName() ||
94 e->atom == _netclient->xaWmName() )
95 updateTitle();
96 else if (e->atom == _netclient->xaWmClass() )
97 updateClass();
100 // Window hidden.
101 void XWindow::unmapNotifyEvent(const XUnmapEvent * const e) {
102 _unmapped = true;
105 // Window destroyed.
106 void XWindow::destroyNotifyEvent(const XDestroyWindowEvent * const e) {
107 _unmapped = true;
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;
117 Window junkwin;
118 int rx, ry;
120 _rect.setRect(0,0,1,1);
122 if (! XGetWindowAttributes(_display, _window, &win_attributes)) {
123 std::cerr << "updateDimensions. couldn't get what I needed, so setting to ridiculously wrong values.\n";
124 return;
127 XTranslateCoordinates (_display, _window, win_attributes.root,
128 -win_attributes.border_width,
129 -win_attributes.border_width,
130 &rx, &ry, &junkwin);
131 _rect.setRect(rx, ry, win_attributes.width, win_attributes.height);
133 #if DEBUG
134 std::cout << endl <<
135 "absolute upper-left x: " << rx << endl <<
136 "absolute upper-left y: " << ry << endl <<
137 "relative upper-left x: " << win_attributes.x << endl <<
138 "relative upper-left y: " << win_attributes.y << endl;
139 #endif
143 void XWindow::updateBlackboxAttributes() {
144 unsigned long *data;
145 unsigned long num = PropBlackboxAttributesElements;
147 _decorated = true;
149 if (_netclient->getValue(_window,
150 _netclient->xaBlackboxAttributes(),
151 _netclient->xaBlackboxAttributes(),
152 num, &data)) {
153 if (num == PropBlackboxAttributesElements)
154 if (data[0] & AttribDecoration)
155 _decorated = (data[4] != DecorNone);
156 delete data;
160 void XWindow::updateNormalHints() {
161 XSizeHints size;
162 long ret;
164 // defaults
165 _gravity = NorthWestGravity;
166 _inc_x = _inc_y = 1;
167 _base_x = _base_y = 0;
169 if (XGetWMNormalHints(_display, _window, &size, &ret)) {
170 if (size.flags & PWinGravity)
171 _gravity = size.win_gravity;
172 if (size.flags & PBaseSize) {
173 _base_x = size.base_width;
174 _base_y = size.base_height;
176 if (size.flags & PResizeInc) {
177 _inc_x = size.width_inc;
178 _inc_y = size.height_inc;
184 void XWindow::updateWMHints() {
185 XWMHints *hints;
187 // assume a window takes input if it doesnt specify
188 _can_focus = True;
190 if ((hints = XGetWMHints(_display, _window)) != NULL) {
191 if (hints->flags & InputHint)
192 _can_focus = hints->input;
193 XFree(hints);
198 void XWindow::updateState() {
199 // set the defaults
200 _shaded = _iconic = _max_vert = _max_horz = false;
202 unsigned long num = (unsigned) -1;
203 Atom *state;
204 if (! _netclient->getValue(_window, _netclient->wmState(), XA_ATOM,
205 num, &state))
206 return;
207 for (unsigned long i = 0; i < num; ++i) {
208 if (state[i] == _netclient->wmStateMaximizedVert())
209 _max_vert = true;
210 if (state[i] == _netclient->wmStateMaximizedHorz())
211 _max_horz = true;
212 if (state[i] == _netclient->wmStateShaded())
213 _shaded = true;
214 if (state[i] == _netclient->wmStateHidden())
215 _iconic = true;
218 delete [] state;
222 void XWindow::updateDesktop() {
223 unsigned long d = 0ul;
224 if (! _netclient->getValue(_window, _netclient->wmDesktop(), XA_CARDINAL, d))
225 d = 0ul;
227 _desktop = static_cast<unsigned int>(d);
231 void XWindow::updateTitle() {
232 _title = "";
234 // try netwm
235 if (! _netclient->getValue(_window, _netclient->wmName(),
236 Netclient::utf8, _title)) {
237 // try old x stuff
238 _netclient->getValue(_window, XA_WM_NAME, Netclient::ansi, _title);
241 if (_title.empty())
242 _title = "Unnamed";
247 void XWindow::updateClass() {
248 // set the defaults
249 _app_name = _app_class = "";
251 Netclient::StringVect v;
252 unsigned long num = 2;
254 if (! _netclient->getValue(_window, XA_WM_CLASS, Netclient::ansi, num, v))
255 return;
257 if (num > 0) _app_name = v[0];
258 if (num > 1) _app_class = v[1];
263 void XWindow::shade(const bool sh) const {
264 _netclient->sendClientMessage(_root, _netclient->wmState(),
265 _window, (sh ? 1 : 0),
266 _netclient->wmStateShaded());
269 void XWindow::close() const {
270 _netclient->sendClientMessage(_root, _netclient->closeWindow(),
271 _window);
275 void XWindow::raise() const {
276 XRaiseWindow(_display, _window);
279 void XWindow::lower() const {
280 XLowerWindow(_display, _window);
283 void XWindow::iconify() const {
284 _netclient->sendClientMessage(_root, _netclient->xaWmChangeState(),
285 _window, IconicState);
288 void XWindow::focus(bool raise) const {
289 // this will cause the window to be uniconified also
291 if (raise) {
292 _netclient->sendClientMessage(_root, _netclient->activeWindow(),
293 _window);
294 } else {
295 XSetInputFocus(_display, _window, None, CurrentTime);
299 void XWindow::decorate(bool d) const {
300 _netclient->sendClientMessage(_root,
301 _netclient->xaBlackboxChangeAttributes(),
302 _window, AttribDecoration,
303 0, 0, 0, (d ? DecorNormal : DecorNone));
306 void XWindow::sendTo(unsigned int dest) const {
307 _netclient->sendClientMessage(_root, _netclient->wmDesktop(),
308 _window, dest);
312 void XWindow::move(int x, int y) const {
314 XWindowAttributes win_attributes;
315 Window junkwin;
316 int rx, ry;
319 if (! XGetWindowAttributes(_display, _window, &win_attributes)) {
320 std::cerr << "move: couldn't get what I needed. not able to move, sorry.\n";
321 return;
324 XTranslateCoordinates (_display, _window, win_attributes.root,
325 -win_attributes.border_width,
326 -win_attributes.border_width,
327 &rx, &ry, &junkwin);
329 Status status;
330 int xright, ybelow;
331 int dw = _screenInfo.width(), dh = _screenInfo.height();
334 /* find our window manager frame, if any */
335 Window wmframe = _window;
337 while (True) {
338 Window root, parent;
339 Window *childlist;
340 unsigned int ujunk;
342 status = XQueryTree(_display, wmframe, &root, &parent, &childlist, &ujunk);
343 if (parent == root || !parent || !status)
344 break;
345 wmframe = parent;
346 if (status && childlist)
347 XFree((char *)childlist);
350 if (wmframe != _window) {
351 /* WM reparented, so find edges of the frame */
352 /* Only works for ICCCM-compliant WMs, and then only if the
353 window has corner gravity. We would need to know the original width
354 of the window to correctly handle the other gravities. */
356 XWindowAttributes frame_attr;
358 if (!XGetWindowAttributes(_display, wmframe, &frame_attr)) {
359 std::cerr << "updateDimensions. error. can't get frame attributes.\n";
362 switch (_gravity) {
363 case NorthWestGravity: case SouthWestGravity:
364 case NorthEastGravity: case SouthEastGravity:
365 case WestGravity:
366 rx = frame_attr.x;
368 switch (_gravity) {
369 case NorthWestGravity: case SouthWestGravity:
370 case NorthEastGravity: case SouthEastGravity:
371 case EastGravity:
372 xright = dw - frame_attr.x - frame_attr.width -
373 2*frame_attr.border_width;
375 switch (_gravity) {
376 case NorthWestGravity: case SouthWestGravity:
377 case NorthEastGravity: case SouthEastGravity:
378 case NorthGravity:
379 ry = frame_attr.y;
381 switch (_gravity) {
382 case NorthWestGravity: case SouthWestGravity:
383 case NorthEastGravity: case SouthEastGravity:
384 case SouthGravity:
385 ybelow = dh - frame_attr.y - frame_attr.height -
386 2*frame_attr.border_width;
390 int destx = rx +x, desty = ry +y;
392 #if DEBUG
393 std::cout<< "moving window to: +" << destx << "+" << desty << endl;
394 #endif
396 XMoveWindow(_display, _window, destx, desty);
401 void XWindow::resizeRel(int dwidth, int dheight) const {
402 // resize in increments if requested by the window
403 unsigned int width = _rect.width(), height = _rect.height();
405 unsigned int wdest = width + (dwidth * _inc_x) / _inc_x * _inc_x + _base_x;
406 unsigned int hdest = height + (dheight * _inc_y) / _inc_y * _inc_y + _base_y;
408 XResizeWindow(_display, _window, wdest, hdest);
412 void XWindow::resizeAbs(unsigned int width, unsigned int height) const {
413 // resize in increments if requested by the window
415 unsigned int wdest = width / _inc_x * _inc_x + _base_x;
416 unsigned int hdest = height / _inc_y * _inc_y + _base_y;
418 if (width > wdest) {
419 while (width > wdest)
420 wdest += _inc_x;
421 } else {
422 while (width < wdest)
423 wdest -= _inc_x;
425 if (height > hdest) {
426 while (height > hdest)
427 hdest += _inc_y;
428 } else {
429 while (height < hdest)
430 hdest -= _inc_y;
433 XResizeWindow(_display, _window, wdest, hdest);
437 void XWindow::toggleMaximize(Max max) const {
438 switch (max) {
439 case Max_Full:
440 _netclient->
441 sendClientMessage(_root, _netclient->wmState(),
442 _window, (_max_vert == _max_horz ? 2 : 1),
443 _netclient->wmStateMaximizedHorz(),
444 _netclient->wmStateMaximizedVert());
445 break;
447 case Max_Horz:
448 _netclient->
449 sendClientMessage(_root, _netclient->wmState(),
450 _window, 2,
451 _netclient->wmStateMaximizedHorz());
452 break;
454 case Max_Vert:
455 _netclient->
456 sendClientMessage(_root, _netclient->wmState(),
457 _window, 2,
458 _netclient->wmStateMaximizedVert());
459 break;
461 case Max_None:
462 assert(false); // you should not do this. it is pointless and probly a bug
463 break;
468 void XWindow::maximize(Max max) const {
469 switch (max) {
470 case Max_None:
471 _netclient->
472 sendClientMessage(_root, _netclient->wmState(),
473 _window, 0,
474 _netclient->wmStateMaximizedHorz(),
475 _netclient->wmStateMaximizedVert());
476 break;
478 case Max_Full:
479 _netclient->
480 sendClientMessage(_root, _netclient->wmState(),
481 _window, 1,
482 _netclient->wmStateMaximizedHorz(),
483 _netclient->wmStateMaximizedVert());
484 break;
486 case Max_Horz:
487 _netclient->
488 sendClientMessage(_root, _netclient->wmState(),
489 _window, 1,
490 _netclient->wmStateMaximizedHorz());
491 break;
493 case Max_Vert:
494 _netclient->
495 sendClientMessage(_root, _netclient->wmState(),
496 _window, 1,
497 _netclient->wmStateMaximizedVert());
498 break;