]> Dogcows Code - chaz/openbox/blob - src/screen.cc
resizing works and whatnot
[chaz/openbox] / src / screen.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif
6
7 extern "C" {
8 #ifdef HAVE_STDIO_H
9 # include <stdio.h>
10 #endif // HAVE_STDIO_H
11
12 #ifdef HAVE_UNISTD_H
13 # include <sys/types.h>
14 # include <unistd.h>
15 #endif // HAVE_UNISTD_H
16
17 #include "gettext.h"
18 #define _(str) gettext(str)
19 }
20
21 #include "screen.hh"
22 #include "client.hh"
23 #include "openbox.hh"
24 #include "frame.hh"
25 #include "otk/display.hh"
26
27 static bool running;
28 static int anotherWMRunning(Display *display, XErrorEvent *) {
29 printf(_("Another window manager already running on display %s.\n"),
30 DisplayString(display));
31 running = true;
32 return -1;
33 }
34
35
36 namespace ob {
37
38
39 OBScreen::OBScreen(int screen, const otk::Configuration &config)
40 : _number(screen),
41 _root(screen)
42 {
43 assert(screen >= 0); assert(screen < ScreenCount(otk::OBDisplay::display));
44 _info = otk::OBDisplay::screenInfo(screen);
45
46 ::running = false;
47 XErrorHandler old = XSetErrorHandler(::anotherWMRunning);
48 XSelectInput(otk::OBDisplay::display, _info->getRootWindow(),
49 OBScreen::event_mask);
50 XSync(otk::OBDisplay::display, false);
51 XSetErrorHandler(old);
52
53 _managed = !::running;
54 if (! _managed) return; // was unable to manage the screen
55
56 printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
57 _number, XVisualIDFromVisual(_info->getVisual()), _info->getDepth());
58
59 Openbox::instance->property()->set(_info->getRootWindow(),
60 otk::OBProperty::openbox_pid,
61 otk::OBProperty::Atom_Cardinal,
62 (unsigned long) getpid());
63
64 // set the mouse cursor for the root window (the default cursor)
65 XDefineCursor(otk::OBDisplay::display, _info->getRootWindow(),
66 Openbox::instance->cursors().session);
67
68 // initialize the shit that is used for all drawing on the screen
69 _image_control = new otk::BImageControl(Openbox::instance->timerManager(),
70 _info, true);
71 _image_control->installRootColormap();
72 _root_cmap_installed = True;
73
74 // initialize the screen's style
75 _style.setImageControl(_image_control);
76 _style.load(config);
77
78
79 // Set the netwm atoms for geomtery and viewport
80 unsigned long geometry[] = { _info->getWidth(),
81 _info->getHeight() };
82 Openbox::instance->property()->set(_info->getRootWindow(),
83 otk::OBProperty::net_desktop_geometry,
84 otk::OBProperty::Atom_Cardinal,
85 geometry, 2);
86 unsigned long viewport[] = { 0, 0 };
87 Openbox::instance->property()->set(_info->getRootWindow(),
88 otk::OBProperty::net_desktop_viewport,
89 otk::OBProperty::Atom_Cardinal,
90 viewport, 2);
91
92 // these may be further updated if any pre-existing windows are found in
93 // the manageExising() function
94 setClientList(); // initialize the client lists, which will be empty
95 calcArea(); // initialize the available working area
96 }
97
98
99 OBScreen::~OBScreen()
100 {
101 if (! _managed) return;
102
103 // unmanage all windows
104 while (!_clients.empty())
105 unmanageWindow(_clients.front());
106
107 delete _image_control;
108 }
109
110
111 void OBScreen::manageExisting()
112 {
113 unsigned int i, j, nchild;
114 Window r, p, *children;
115 XQueryTree(otk::OBDisplay::display, _info->getRootWindow(), &r, &p,
116 &children, &nchild);
117
118 // preen the window list of all icon windows... for better dockapp support
119 for (i = 0; i < nchild; i++) {
120 if (children[i] == None) continue;
121
122 XWMHints *wmhints = XGetWMHints(otk::OBDisplay::display,
123 children[i]);
124
125 if (wmhints) {
126 if ((wmhints->flags & IconWindowHint) &&
127 (wmhints->icon_window != children[i])) {
128 for (j = 0; j < nchild; j++) {
129 if (children[j] == wmhints->icon_window) {
130 children[j] = None;
131 break;
132 }
133 }
134 }
135
136 XFree(wmhints);
137 }
138 }
139
140 // manage shown windows
141 for (i = 0; i < nchild; ++i) {
142 if (children[i] == None)
143 continue;
144
145 XWindowAttributes attrib;
146 if (XGetWindowAttributes(otk::OBDisplay::display, children[i], &attrib)) {
147 if (attrib.override_redirect) continue;
148
149 if (attrib.map_state != IsUnmapped) {
150 manageWindow(children[i]);
151 }
152 }
153 }
154
155 XFree(children);
156 }
157
158
159 //! Adds a window's strut to the screen's list of reserved spaces
160 void OBScreen::addStrut(otk::Strut *strut)
161 {
162 _struts.push_back(strut);
163 }
164
165
166 //! Removes a window's strut from the screen's list of reserved spaces
167 void OBScreen::removeStrut(otk::Strut *strut)
168 {
169 _struts.remove(strut);
170 }
171
172
173 void OBScreen::calcArea()
174 {
175 otk::Rect old_area = _area;
176
177 /*
178 #ifdef XINERAMA
179 // reset to the full areas
180 if (isXineramaActive())
181 xineramaUsableArea = getXineramaAreas();
182 #endif // XINERAMA
183 */
184
185 /* these values represent offsets from the screen edge
186 * we look for the biggest offset on each edge and then apply them
187 * all at once
188 * do not be confused by the similarity to the names of Rect's members
189 */
190 unsigned int current_left = 0, current_right = 0, current_top = 0,
191 current_bottom = 0;
192
193 StrutList::const_iterator it = _struts.begin(), end = _struts.end();
194
195 for(; it != end; ++it) {
196 otk::Strut *strut = *it;
197 if (strut->left > current_left)
198 current_left = strut->left;
199 if (strut->top > current_top)
200 current_top = strut->top;
201 if (strut->right > current_right)
202 current_right = strut->right;
203 if (strut->bottom > current_bottom)
204 current_bottom = strut->bottom;
205 }
206
207 _area.setRect(current_left, current_top,
208 _info->getWidth() - (current_left + current_right),
209 _info->getHeight() - (current_top + current_bottom));
210
211 /*
212 #ifdef XINERAMA
213 if (isXineramaActive()) {
214 // keep each of the ximerama-defined areas inside the strut
215 RectList::iterator xit, xend = xineramaUsableArea.end();
216 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
217 if (xit->x() < usableArea.x()) {
218 xit->setX(usableArea.x());
219 xit->setWidth(xit->width() - usableArea.x());
220 }
221 if (xit->y() < usableArea.y()) {
222 xit->setY(usableArea.y());
223 xit->setHeight(xit->height() - usableArea.y());
224 }
225 if (xit->x() + xit->width() > usableArea.width())
226 xit->setWidth(usableArea.width() - xit->x());
227 if (xit->y() + xit->height() > usableArea.height())
228 xit->setHeight(usableArea.height() - xit->y());
229 }
230 }
231 #endif // XINERAMA
232 */
233
234 if (old_area != _area)
235 // XXX: re-maximize windows
236
237 setWorkArea();
238 }
239
240
241 void OBScreen::setClientList()
242 {
243 Window *windows;
244
245 // create an array of the window ids
246 if (_clients.size() > 0) {
247 Window *win_it;
248
249 windows = new Window[_clients.size()];
250 win_it = windows;
251 ClientList::const_iterator it = _clients.begin();
252 const ClientList::const_iterator end = _clients.end();
253 for (; it != end; ++it, ++win_it)
254 *win_it = (*it)->window();
255 } else
256 windows = (Window*) 0;
257
258 Openbox::instance->property()->set(_info->getRootWindow(),
259 otk::OBProperty::net_client_list,
260 otk::OBProperty::Atom_Window,
261 windows, _clients.size());
262
263 if (_clients.size())
264 delete [] windows;
265
266 setStackingList();
267 }
268
269
270 void OBScreen::setStackingList()
271 {
272 // The below comment is wrong now hopefully :> but ill keep it here for
273 // reference anyways
274 /*
275 Get the stacking order from all of the workspaces.
276 We start with the current workspace so that the sticky windows will be
277 in the right order on the current workspace.
278 */
279 /*
280 Openbox::instance->property()->set(_info->getRootWindow(),
281 otk::OBProperty::net_client_list_stacking,
282 otk::OBProperty::Atom_Window,
283 _stacking, _stacking.size());
284 */
285 }
286
287
288 void OBScreen::setWorkArea() {
289 unsigned long area[] = { _area.x(), _area.y(),
290 _area.width(), _area.height() };
291 Openbox::instance->property()->set(_info->getRootWindow(),
292 otk::OBProperty::net_workarea,
293 otk::OBProperty::Atom_Cardinal,
294 area, 4);
295 /*
296 if (workspacesList.size() > 0) {
297 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
298 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
299 // XXX: this could be different for each workspace
300 const otk::Rect &area = availableArea();
301 dims[(i * 4) + 0] = area.x();
302 dims[(i * 4) + 1] = area.y();
303 dims[(i * 4) + 2] = area.width();
304 dims[(i * 4) + 3] = area.height();
305 }
306 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
307 otk::OBProperty::Atom_Cardinal,
308 dims, 4 * workspacesList.size());
309 delete [] dims;
310 } else
311 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
312 otk::OBProperty::Atom_Cardinal, 0, 0);
313 */
314 }
315
316
317 void OBScreen::loadStyle(const otk::Configuration &config)
318 {
319 _style.load(config);
320
321 // XXX: make stuff redraw!
322 }
323
324
325 void OBScreen::manageWindow(Window window)
326 {
327 OBClient *client = 0;
328 XWMHints *wmhint;
329 XSetWindowAttributes attrib_set;
330
331 // is the window a docking app
332 if ((wmhint = XGetWMHints(otk::OBDisplay::display, window))) {
333 if ((wmhint->flags & StateHint) &&
334 wmhint->initial_state == WithdrawnState) {
335 //slit->addClient(w); // XXX: make dock apps work!
336 XFree(wmhint);
337 return;
338 }
339 XFree(wmhint);
340 }
341
342 otk::OBDisplay::grab();
343
344 // choose the events we want to receive on the CLIENT window
345 attrib_set.event_mask = OBClient::event_mask;
346 attrib_set.do_not_propagate_mask = OBClient::no_propagate_mask;
347 XChangeWindowAttributes(otk::OBDisplay::display, window,
348 CWEventMask|CWDontPropagate, &attrib_set);
349
350 // create the OBClient class, which gets all of the hints on the window
351 client = new OBClient(_number, window);
352 // register for events
353 Openbox::instance->registerHandler(window, client);
354 // add to the wm's map
355 Openbox::instance->addClient(window, client);
356
357 // we dont want a border on the client
358 client->toggleClientBorder(false);
359
360 // specify that if we exit, the window should not be destroyed and should be
361 // reparented back to root automatically
362 XChangeSaveSet(otk::OBDisplay::display, window, SetModeInsert);
363
364 if (!client->positionRequested()) {
365 // XXX: position the window intelligenty
366 }
367
368 // create the decoration frame for the client window
369 client->frame = new OBFrame(client, &_style);
370
371 // add to the wm's map
372 Openbox::instance->addClient(client->frame->getWindow(), client);
373 Openbox::instance->addClient(client->frame->plate(), client);
374 Openbox::instance->addClient(client->frame->titlebar(), client);
375 Openbox::instance->addClient(client->frame->label(), client);
376 Openbox::instance->addClient(client->frame->button_max(), client);
377 Openbox::instance->addClient(client->frame->button_iconify(), client);
378 Openbox::instance->addClient(client->frame->button_stick(), client);
379 Openbox::instance->addClient(client->frame->button_close(), client);
380 Openbox::instance->addClient(client->frame->handle(), client);
381 Openbox::instance->addClient(client->frame->grip_left(), client);
382 Openbox::instance->addClient(client->frame->grip_right(), client);
383
384 // XXX: if on the current desktop..
385 client->frame->show();
386
387 // XXX: handle any requested states such as shaded/maximized
388
389 otk::OBDisplay::ungrab();
390
391 // add to the screen's list
392 _clients.push_back(client);
393 // update the root properties
394 setClientList();
395 }
396
397
398 void OBScreen::unmanageWindow(OBClient *client)
399 {
400 OBFrame *frame = client->frame;
401
402 // XXX: pass around focus if this window was focused
403
404 // remove from the wm's map
405 Openbox::instance->removeClient(client->window());
406 Openbox::instance->removeClient(frame->getWindow());
407 Openbox::instance->removeClient(frame->plate());
408 Openbox::instance->removeClient(frame->titlebar());
409 Openbox::instance->removeClient(frame->label());
410 Openbox::instance->removeClient(frame->button_max());
411 Openbox::instance->removeClient(frame->button_iconify());
412 Openbox::instance->removeClient(frame->button_stick());
413 Openbox::instance->removeClient(frame->button_close());
414 Openbox::instance->removeClient(frame->handle());
415 Openbox::instance->removeClient(frame->grip_left());
416 Openbox::instance->removeClient(frame->grip_right());
417 // unregister for handling events
418 Openbox::instance->clearHandler(client->window());
419
420 // remove the window from our save set
421 XChangeSaveSet(otk::OBDisplay::display, client->window(), SetModeDelete);
422
423 // we dont want events no more
424 XSelectInput(otk::OBDisplay::display, client->window(), NoEventMask);
425
426 frame->hide();
427
428 // give the client its border back
429 client->toggleClientBorder(true);
430
431 delete client->frame;
432 client->frame = 0;
433
434 // remove from the screen's list
435 _clients.remove(client);
436 delete client;
437
438 // update the root properties
439 setClientList();
440 }
441
442 }
This page took 0.058112 seconds and 4 git commands to generate.