1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
4 # include "../config.h"
10 #endif // HAVE_STDIO_H
13 # include <sys/types.h>
15 #endif // HAVE_UNISTD_H
18 #define _(str) gettext(str)
25 #include "bindings.hh"
27 #include "otk/display.hh"
32 static int anotherWMRunning(Display
*display
, XErrorEvent
*) {
33 printf(_("Another window manager already running on display %s.\n"),
34 DisplayString(display
));
43 OBScreen::OBScreen(int screen
)
47 assert(screen
>= 0); assert(screen
< ScreenCount(otk::OBDisplay::display
));
48 _info
= otk::OBDisplay::screenInfo(screen
);
51 XErrorHandler old
= XSetErrorHandler(::anotherWMRunning
);
52 XSelectInput(otk::OBDisplay::display
, _info
->rootWindow(),
53 OBScreen::event_mask
);
54 XSync(otk::OBDisplay::display
, false);
55 XSetErrorHandler(old
);
57 _managed
= !::running
;
58 if (! _managed
) return; // was unable to manage the screen
60 printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
61 _number
, XVisualIDFromVisual(_info
->visual()), _info
->depth());
63 Openbox::instance
->property()->set(_info
->rootWindow(),
64 otk::OBProperty::openbox_pid
,
65 otk::OBProperty::Atom_Cardinal
,
66 (unsigned long) getpid());
68 // set the mouse cursor for the root window (the default cursor)
69 XDefineCursor(otk::OBDisplay::display
, _info
->rootWindow(),
70 Openbox::instance
->cursors().session
);
72 // initialize the shit that is used for all drawing on the screen
73 _image_control
= new otk::BImageControl(Openbox::instance
->timerManager(),
75 _image_control
->installRootColormap();
76 _root_cmap_installed
= True
;
78 // initialize the screen's style
79 _style
.setImageControl(_image_control
);
80 std::string stylepath
;
81 python_get_string("theme", &stylepath
);
82 otk::Configuration
sconfig(false);
83 sconfig
.setFile(otk::expandTilde(stylepath
));
84 if (!sconfig
.load()) {
85 sconfig
.setFile(otk::expandTilde(DEFAULTSTYLE
));
86 if (!sconfig
.load()) {
87 printf(_("Unable to load default style: %s. Aborting.\n"), DEFAULTSTYLE
);
93 // Set the netwm atoms for geomtery and viewport
94 unsigned long geometry
[] = { _info
->width(),
96 Openbox::instance
->property()->set(_info
->rootWindow(),
97 otk::OBProperty::net_desktop_geometry
,
98 otk::OBProperty::Atom_Cardinal
,
100 unsigned long viewport
[] = { 0, 0 };
101 Openbox::instance
->property()->set(_info
->rootWindow(),
102 otk::OBProperty::net_desktop_viewport
,
103 otk::OBProperty::Atom_Cardinal
,
106 // create the window which gets focus when no clients get it
107 XSetWindowAttributes attr
;
108 attr
.override_redirect
= true;
109 _focuswindow
= XCreateWindow(otk::OBDisplay::display
, _info
->rootWindow(),
110 -100, -100, 1, 1, 0, 0, InputOnly
,
111 _info
->visual(), CWOverrideRedirect
, &attr
);
112 XMapWindow(otk::OBDisplay::display
, _focuswindow
);
114 // these may be further updated if any pre-existing windows are found in
115 // the manageExising() function
116 setClientList(); // initialize the client lists, which will be empty
117 calcArea(); // initialize the available working area
121 OBScreen::~OBScreen()
123 if (! _managed
) return;
125 // unmanage all windows
126 while (!clients
.empty())
127 unmanageWindow(clients
.front());
129 delete _image_control
;
133 void OBScreen::manageExisting()
135 unsigned int i
, j
, nchild
;
136 Window r
, p
, *children
;
137 XQueryTree(otk::OBDisplay::display
, _info
->rootWindow(), &r
, &p
,
140 // preen the window list of all icon windows... for better dockapp support
141 for (i
= 0; i
< nchild
; i
++) {
142 if (children
[i
] == None
) continue;
144 XWMHints
*wmhints
= XGetWMHints(otk::OBDisplay::display
,
148 if ((wmhints
->flags
& IconWindowHint
) &&
149 (wmhints
->icon_window
!= children
[i
])) {
150 for (j
= 0; j
< nchild
; j
++) {
151 if (children
[j
] == wmhints
->icon_window
) {
162 // manage shown windows
163 for (i
= 0; i
< nchild
; ++i
) {
164 if (children
[i
] == None
)
167 XWindowAttributes attrib
;
168 if (XGetWindowAttributes(otk::OBDisplay::display
, children
[i
], &attrib
)) {
169 if (attrib
.override_redirect
) continue;
171 if (attrib
.map_state
!= IsUnmapped
) {
172 manageWindow(children
[i
]);
181 //! Adds a window's strut to the screen's list of reserved spaces
182 void OBScreen::addStrut(otk::Strut
*strut
)
184 _struts
.push_back(strut
);
188 //! Removes a window's strut from the screen's list of reserved spaces
189 void OBScreen::removeStrut(otk::Strut
*strut
)
191 _struts
.remove(strut
);
195 void OBScreen::calcArea()
197 otk::Rect old_area
= _area
;
201 // reset to the full areas
202 if (isXineramaActive())
203 xineramaUsableArea = getXineramaAreas();
207 /* these values represent offsets from the screen edge
208 * we look for the biggest offset on each edge and then apply them
210 * do not be confused by the similarity to the names of Rect's members
212 unsigned int current_left
= 0, current_right
= 0, current_top
= 0,
215 StrutList::const_iterator it
= _struts
.begin(), end
= _struts
.end();
217 for(; it
!= end
; ++it
) {
218 otk::Strut
*strut
= *it
;
219 if (strut
->left
> current_left
)
220 current_left
= strut
->left
;
221 if (strut
->top
> current_top
)
222 current_top
= strut
->top
;
223 if (strut
->right
> current_right
)
224 current_right
= strut
->right
;
225 if (strut
->bottom
> current_bottom
)
226 current_bottom
= strut
->bottom
;
229 _area
.setRect(current_left
, current_top
,
230 _info
->width() - (current_left
+ current_right
),
231 _info
->height() - (current_top
+ current_bottom
));
235 if (isXineramaActive()) {
236 // keep each of the ximerama-defined areas inside the strut
237 RectList::iterator xit, xend = xineramaUsableArea.end();
238 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
239 if (xit->x() < usableArea.x()) {
240 xit->setX(usableArea.x());
241 xit->setWidth(xit->width() - usableArea.x());
243 if (xit->y() < usableArea.y()) {
244 xit->setY(usableArea.y());
245 xit->setHeight(xit->height() - usableArea.y());
247 if (xit->x() + xit->width() > usableArea.width())
248 xit->setWidth(usableArea.width() - xit->x());
249 if (xit->y() + xit->height() > usableArea.height())
250 xit->setHeight(usableArea.height() - xit->y());
256 if (old_area
!= _area
)
257 // XXX: re-maximize windows
263 void OBScreen::setClientList()
267 // create an array of the window ids
268 if (clients
.size() > 0) {
271 windows
= new Window
[clients
.size()];
273 ClientList::const_iterator it
= clients
.begin();
274 const ClientList::const_iterator end
= clients
.end();
275 for (; it
!= end
; ++it
, ++win_it
)
276 *win_it
= (*it
)->window();
278 windows
= (Window
*) 0;
280 Openbox::instance
->property()->set(_info
->rootWindow(),
281 otk::OBProperty::net_client_list
,
282 otk::OBProperty::Atom_Window
,
283 windows
, clients
.size());
292 void OBScreen::setStackingList()
294 // The below comment is wrong now hopefully :> but ill keep it here for
297 Get the stacking order from all of the workspaces.
298 We start with the current workspace so that the sticky windows will be
299 in the right order on the current workspace.
302 Openbox::instance->property()->set(_info->getRootWindow(),
303 otk::OBProperty::net_client_list_stacking,
304 otk::OBProperty::Atom_Window,
305 _stacking, _stacking.size());
310 void OBScreen::setWorkArea() {
311 unsigned long area
[] = { _area
.x(), _area
.y(),
312 _area
.width(), _area
.height() };
313 Openbox::instance
->property()->set(_info
->rootWindow(),
314 otk::OBProperty::net_workarea
,
315 otk::OBProperty::Atom_Cardinal
,
318 if (workspacesList.size() > 0) {
319 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
320 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
321 // XXX: this could be different for each workspace
322 const otk::Rect &area = availableArea();
323 dims[(i * 4) + 0] = area.x();
324 dims[(i * 4) + 1] = area.y();
325 dims[(i * 4) + 2] = area.width();
326 dims[(i * 4) + 3] = area.height();
328 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
329 otk::OBProperty::Atom_Cardinal,
330 dims, 4 * workspacesList.size());
333 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
334 otk::OBProperty::Atom_Cardinal, 0, 0);
339 void OBScreen::manageWindow(Window window
)
341 OBClient
*client
= 0;
343 XSetWindowAttributes attrib_set
;
345 // is the window a docking app
346 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
347 if ((wmhint
->flags
& StateHint
) &&
348 wmhint
->initial_state
== WithdrawnState
) {
349 //slit->addClient(w); // XXX: make dock apps work!
356 otk::OBDisplay::grab();
358 // choose the events we want to receive on the CLIENT window
359 attrib_set
.event_mask
= OBClient::event_mask
;
360 attrib_set
.do_not_propagate_mask
= OBClient::no_propagate_mask
;
361 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
362 CWEventMask
|CWDontPropagate
, &attrib_set
);
364 // create the OBClient class, which gets all of the hints on the window
365 client
= new OBClient(_number
, window
);
366 // register for events
367 Openbox::instance
->registerHandler(window
, client
);
368 // add to the wm's map
369 Openbox::instance
->addClient(window
, client
);
371 // we dont want a border on the client
372 client
->toggleClientBorder(false);
374 // specify that if we exit, the window should not be destroyed and should be
375 // reparented back to root automatically
376 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
378 if (!client
->positionRequested()) {
379 // XXX: position the window intelligenty
382 // create the decoration frame for the client window
383 client
->frame
= new OBFrame(client
, &_style
);
385 // add to the wm's map
386 Openbox::instance
->addClient(client
->frame
->window(), client
);
387 Openbox::instance
->addClient(client
->frame
->plate(), client
);
388 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
389 Openbox::instance
->addClient(client
->frame
->label(), client
);
390 Openbox::instance
->addClient(client
->frame
->button_max(), client
);
391 Openbox::instance
->addClient(client
->frame
->button_iconify(), client
);
392 Openbox::instance
->addClient(client
->frame
->button_stick(), client
);
393 Openbox::instance
->addClient(client
->frame
->button_close(), client
);
394 Openbox::instance
->addClient(client
->frame
->handle(), client
);
395 Openbox::instance
->addClient(client
->frame
->grip_left(), client
);
396 Openbox::instance
->addClient(client
->frame
->grip_right(), client
);
398 // XXX: if on the current desktop..
399 client
->frame
->show();
401 // XXX: handle any requested states such as shaded/maximized
403 otk::OBDisplay::ungrab();
405 // add to the screen's list
406 clients
.push_back(client
);
407 // this puts into the stacking order, then raises it
408 _stacking
.push_back(client
);
409 restack(true, client
);
410 // update the root properties
413 Openbox::instance
->bindings()->grabButtons(true, client
);
417 void OBScreen::unmanageWindow(OBClient
*client
)
419 OBFrame
*frame
= client
->frame
;
421 Openbox::instance
->bindings()->grabButtons(false, client
);
423 // XXX: pass around focus if this window was focused
425 // remove from the wm's map
426 Openbox::instance
->removeClient(client
->window());
427 Openbox::instance
->removeClient(frame
->window());
428 Openbox::instance
->removeClient(frame
->plate());
429 Openbox::instance
->removeClient(frame
->titlebar());
430 Openbox::instance
->removeClient(frame
->label());
431 Openbox::instance
->removeClient(frame
->button_max());
432 Openbox::instance
->removeClient(frame
->button_iconify());
433 Openbox::instance
->removeClient(frame
->button_stick());
434 Openbox::instance
->removeClient(frame
->button_close());
435 Openbox::instance
->removeClient(frame
->handle());
436 Openbox::instance
->removeClient(frame
->grip_left());
437 Openbox::instance
->removeClient(frame
->grip_right());
438 // unregister for handling events
439 Openbox::instance
->clearHandler(client
->window());
441 // remove the window from our save set
442 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
444 // we dont want events no more
445 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
449 // give the client its border back
450 client
->toggleClientBorder(true);
452 delete client
->frame
;
455 // remove from the screen's lists
456 _stacking
.remove(client
);
457 clients
.remove(client
);
460 // update the root properties
464 void OBScreen::restack(bool raise
, OBClient
*client
)
466 const int layer
= client
->layer();
467 std::vector
<Window
> wins
;
469 _stacking
.remove(client
);
471 // the stacking list is from highest to lowest
473 ClientList::iterator it
= _stacking
.begin(), end
= _stacking
.end();
474 // insert the windows above this window
475 for (; it
!= end
; ++it
) {
476 if ((*it
)->layer() < layer
|| (raise
&& (*it
)->layer() == layer
))
478 wins
.push_back((*it
)->frame
->window());
481 wins
.push_back(client
->frame
->window());
482 _stacking
.insert(it
, client
);
483 // insert the remaining below this window
484 for (; it
!= end
; ++it
)
485 wins
.push_back((*it
)->frame
->window());
487 XRestackWindows(otk::OBDisplay::display
, &wins
[0], wins
.size());