adding program name to all logging
[bbkeys.git] / src / window.cc
blobf1a9d03a1d988fb33d3c350f431cf509aa1e7cd2
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 << BBTOOL << ": " << "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);
135 void XWindow::updateBlackboxAttributes() {
136 unsigned long *data;
137 unsigned long num = PropBlackboxAttributesElements;
139 _decorated = true;
141 if (_netclient->getValue(_window,
142 _netclient->xaBlackboxAttributes(),
143 _netclient->xaBlackboxAttributes(),
144 num, &data)) {
145 if (num == PropBlackboxAttributesElements)
146 if (data[0] & AttribDecoration)
147 _decorated = (data[4] != DecorNone);
148 delete data;
152 void XWindow::updateNormalHints() {
153 XSizeHints size;
154 long ret;
156 // defaults
157 _gravity = NorthWestGravity;
158 _inc_x = _inc_y = 1;
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() {
177 XWMHints *hints;
179 // assume a window takes input if it doesnt specify
180 _can_focus = True;
182 if ((hints = XGetWMHints(_display, _window)) != NULL) {
183 if (hints->flags & InputHint)
184 _can_focus = hints->input;
185 XFree(hints);
190 void XWindow::updateState() {
191 // set the defaults
192 _shaded = _skip_pager = _iconic = _max_vert = _max_horz = false;
194 unsigned long num = (unsigned) -1;
195 Atom *state;
196 if (! _netclient->getValue(_window, _netclient->wmState(), XA_ATOM,
197 num, &state))
198 return;
199 for (unsigned long i = 0; i < num; ++i) {
200 if (state[i] == _netclient->wmStateMaximizedVert())
201 _max_vert = true;
202 if (state[i] == _netclient->wmStateMaximizedHorz())
203 _max_horz = true;
204 if (state[i] == _netclient->wmStateShaded())
205 _shaded = true;
206 if (state[i] == _netclient->wmStateHidden())
207 _iconic = true;
208 if (state[i] == _netclient->wmStateSkipPager())
209 _skip_pager = true;
212 delete [] state;
216 void XWindow::updateDesktop() {
217 unsigned long d = 0ul;
218 if (! _netclient->getValue(_window, _netclient->wmDesktop(), XA_CARDINAL, d))
219 d = 0ul;
221 _desktop = static_cast<unsigned int>(d);
226 void XWindow::updateTitle() {
227 _title = "";
229 // try netwm
230 if (! _netclient->getValue(_window, _netclient->wmName(),
231 Netclient::utf8, _title)) {
232 // try old x stuff
233 _netclient->getValue(_window, XA_WM_NAME, Netclient::ansi, _title);
236 if (_title.empty())
237 _title = "Unnamed";
242 void XWindow::updateClass() {
243 // set the defaults
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))
250 return;
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(),
266 _window);
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
286 if (raise) {
287 _netclient->sendClientMessage(_root, _netclient->activeWindow(),
288 _window);
289 } else {
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(),
303 _window, dest);
307 void XWindow::move(int x, int y) const {
309 XWindowAttributes win_attributes;
310 Window junkwin;
311 int rx, ry;
314 if (! XGetWindowAttributes(_display, _window, &win_attributes)) {
315 std::cerr << BBTOOL << ": " << "move: couldn't get what I needed. not able to move, sorry.\n";
316 return;
319 XTranslateCoordinates (_display, _window, win_attributes.root,
320 -win_attributes.border_width,
321 -win_attributes.border_width,
322 &rx, &ry, &junkwin);
324 Status status;
325 int xright, ybelow;
326 int dw = _screenInfo.width(), dh = _screenInfo.height();
329 /* find our window manager frame, if any */
330 Window wmframe = _window;
332 while (True) {
333 Window root, parent;
334 Window *childlist;
335 unsigned int ujunk;
337 status = XQueryTree(_display, wmframe, &root, &parent, &childlist, &ujunk);
338 if (parent == root || !parent || !status)
339 break;
340 wmframe = parent;
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";
357 switch (_gravity) {
358 case NorthWestGravity: case SouthWestGravity:
359 case NorthEastGravity: case SouthEastGravity:
360 case WestGravity:
361 rx = frame_attr.x;
363 switch (_gravity) {
364 case NorthWestGravity: case SouthWestGravity:
365 case NorthEastGravity: case SouthEastGravity:
366 case EastGravity:
367 xright = dw - frame_attr.x - frame_attr.width -
368 2*frame_attr.border_width;
370 switch (_gravity) {
371 case NorthWestGravity: case SouthWestGravity:
372 case NorthEastGravity: case SouthEastGravity:
373 case NorthGravity:
374 ry = frame_attr.y;
376 switch (_gravity) {
377 case NorthWestGravity: case SouthWestGravity:
378 case NorthEastGravity: case SouthEastGravity:
379 case SouthGravity:
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;
409 if (width > wdest) {
410 while (width > wdest)
411 wdest += _inc_x;
412 } else {
413 while (width < wdest)
414 wdest -= _inc_x;
416 if (height > hdest) {
417 while (height > hdest)
418 hdest += _inc_y;
419 } else {
420 while (height < hdest)
421 hdest -= _inc_y;
424 XResizeWindow(_display, _window, wdest, hdest);
428 void XWindow::toggleMaximize(Max max) const {
429 switch (max) {
430 case Max_Full:
431 _netclient->
432 sendClientMessage(_root, _netclient->wmState(),
433 _window, (_max_vert == _max_horz ? 2 : 1),
434 _netclient->wmStateMaximizedHorz(),
435 _netclient->wmStateMaximizedVert());
436 break;
438 case Max_Horz:
439 _netclient->
440 sendClientMessage(_root, _netclient->wmState(),
441 _window, 2,
442 _netclient->wmStateMaximizedHorz());
443 break;
445 case Max_Vert:
446 _netclient->
447 sendClientMessage(_root, _netclient->wmState(),
448 _window, 2,
449 _netclient->wmStateMaximizedVert());
450 break;
452 case Max_None:
453 assert(false); // you should not do this. it is pointless and probly a bug
454 break;
459 void XWindow::maximize(Max max) const {
460 switch (max) {
461 case Max_None:
462 _netclient->
463 sendClientMessage(_root, _netclient->wmState(),
464 _window, 0,
465 _netclient->wmStateMaximizedHorz(),
466 _netclient->wmStateMaximizedVert());
467 break;
469 case Max_Full:
470 _netclient->
471 sendClientMessage(_root, _netclient->wmState(),
472 _window, 1,
473 _netclient->wmStateMaximizedHorz(),
474 _netclient->wmStateMaximizedVert());
475 break;
477 case Max_Horz:
478 _netclient->
479 sendClientMessage(_root, _netclient->wmState(),
480 _window, 1,
481 _netclient->wmStateMaximizedHorz());
482 break;
484 case Max_Vert:
485 _netclient->
486 sendClientMessage(_root, _netclient->wmState(),
487 _window, 1,
488 _netclient->wmStateMaximizedVert());
489 break;