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 "otk/display.hh"
28 static int anotherWMRunning(Display
*display
, XErrorEvent
*) {
29 printf(_("Another window manager already running on display %s.\n"),
30 DisplayString(display
));
39 OBScreen::OBScreen(int screen
, const otk::Configuration
&config
)
42 assert(screen
>= 0); assert(screen
< ScreenCount(otk::OBDisplay::display
));
43 _info
= otk::OBDisplay::screenInfo(screen
);
46 XErrorHandler old
= XSetErrorHandler(::anotherWMRunning
);
47 XSelectInput(otk::OBDisplay::display
, _info
->getRootWindow(),
48 OBScreen::event_mask
);
49 XSync(otk::OBDisplay::display
, false);
50 XSetErrorHandler(old
);
52 _managed
= !::running
;
53 if (! _managed
) return; // was unable to manage the screen
55 printf(_("Managing screen %d: visual 0x%lx, depth %d\n"),
56 _number
, XVisualIDFromVisual(_info
->getVisual()), _info
->getDepth());
58 Openbox::instance
->property()->set(_info
->getRootWindow(),
59 otk::OBProperty::openbox_pid
,
60 otk::OBProperty::Atom_Cardinal
,
61 (unsigned long) getpid());
63 // set the mouse cursor for the root window (the default cursor)
64 XDefineCursor(otk::OBDisplay::display
, _info
->getRootWindow(),
65 Openbox::instance
->cursors().session
);
67 // initialize the shit that is used for all drawing on the screen
68 _image_control
= new otk::BImageControl(Openbox::instance
->timerManager(),
70 _image_control
->installRootColormap();
71 _root_cmap_installed
= True
;
73 // initialize the screen's style
74 _style
.setImageControl(_image_control
);
78 // Set the netwm atoms for geomtery and viewport
79 unsigned long geometry
[] = { _size
.x(),
81 Openbox::instance
->property()->set(_info
->getRootWindow(),
82 otk::OBProperty::net_desktop_geometry
,
83 otk::OBProperty::Atom_Cardinal
,
85 unsigned long viewport
[] = { 0, 0 };
86 Openbox::instance
->property()->set(_info
->getRootWindow(),
87 otk::OBProperty::net_desktop_viewport
,
88 otk::OBProperty::Atom_Cardinal
,
91 // these may be further updated if any pre-existing windows are found in
92 // the manageExising() function
93 setClientList(); // initialize the client lists, which will be empty
94 calcArea(); // initialize the available working area
100 if (! _managed
) return;
102 // unmanage all windows
103 while (!_clients
.empty())
104 unmanageWindow(_clients
[0]);
106 delete _image_control
;
110 void OBScreen::manageExisting()
112 unsigned int i
, j
, nchild
;
113 Window r
, p
, *children
;
114 XQueryTree(otk::OBDisplay::display
, _info
->getRootWindow(), &r
, &p
,
117 // preen the window list of all icon windows... for better dockapp support
118 for (i
= 0; i
< nchild
; i
++) {
119 if (children
[i
] == None
) continue;
121 XWMHints
*wmhints
= XGetWMHints(otk::OBDisplay::display
,
125 if ((wmhints
->flags
& IconWindowHint
) &&
126 (wmhints
->icon_window
!= children
[i
])) {
127 for (j
= 0; j
< nchild
; j
++) {
128 if (children
[j
] == wmhints
->icon_window
) {
139 // manage shown windows
140 for (i
= 0; i
< nchild
; ++i
) {
141 if (children
[i
] == None
)
144 XWindowAttributes attrib
;
145 if (XGetWindowAttributes(otk::OBDisplay::display
, children
[i
], &attrib
)) {
146 if (attrib
.override_redirect
) continue;
148 if (attrib
.map_state
!= IsUnmapped
) {
149 manageWindow(children
[i
]);
158 //! Adds a window's strut to the screen's list of reserved spaces
159 void OBScreen::addStrut(otk::Strut
*strut
)
161 _struts
.push_back(strut
);
165 //! Removes a window's strut from the screen's list of reserved spaces
166 void OBScreen::removeStrut(otk::Strut
*strut
)
168 _struts
.remove(strut
);
172 void OBScreen::calcArea()
174 otk::Rect old_area
= _area
;
178 // reset to the full areas
179 if (isXineramaActive())
180 xineramaUsableArea = getXineramaAreas();
184 /* these values represent offsets from the screen edge
185 * we look for the biggest offset on each edge and then apply them
187 * do not be confused by the similarity to the names of Rect's members
189 unsigned int current_left
= 0, current_right
= 0, current_top
= 0,
192 StrutList::const_iterator it
= _struts
.begin(), end
= _struts
.end();
194 for(; it
!= end
; ++it
) {
195 otk::Strut
*strut
= *it
;
196 if (strut
->left
> current_left
)
197 current_left
= strut
->left
;
198 if (strut
->top
> current_top
)
199 current_top
= strut
->top
;
200 if (strut
->right
> current_right
)
201 current_right
= strut
->right
;
202 if (strut
->bottom
> current_bottom
)
203 current_bottom
= strut
->bottom
;
206 _area
.setRect(current_left
, current_top
,
207 _info
->getWidth() - (current_left
+ current_right
),
208 _info
->getHeight() - (current_top
+ current_bottom
));
212 if (isXineramaActive()) {
213 // keep each of the ximerama-defined areas inside the strut
214 RectList::iterator xit, xend = xineramaUsableArea.end();
215 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
216 if (xit->x() < usableArea.x()) {
217 xit->setX(usableArea.x());
218 xit->setWidth(xit->width() - usableArea.x());
220 if (xit->y() < usableArea.y()) {
221 xit->setY(usableArea.y());
222 xit->setHeight(xit->height() - usableArea.y());
224 if (xit->x() + xit->width() > usableArea.width())
225 xit->setWidth(usableArea.width() - xit->x());
226 if (xit->y() + xit->height() > usableArea.height())
227 xit->setHeight(usableArea.height() - xit->y());
233 if (old_area
!= _area
)
234 // XXX: re-maximize windows
240 void OBScreen::setClientList()
244 // create an array of the window ids
245 if (_clients
.size() > 0) {
248 windows
= new Window
[_clients
.size()];
250 ClientList::const_iterator it
= _clients
.begin();
251 const ClientList::const_iterator end
= _clients
.end();
252 for (; it
!= end
; ++it
, ++win_it
)
253 *win_it
= (*it
)->window();
255 windows
= (Window
*) 0;
257 Openbox::instance
->property()->set(_info
->getRootWindow(),
258 otk::OBProperty::net_client_list
,
259 otk::OBProperty::Atom_Window
,
260 windows
, _clients
.size());
269 void OBScreen::setStackingList()
271 // The below comment is wrong now hopefully :> but ill keep it here for
274 Get the stacking order from all of the workspaces.
275 We start with the current workspace so that the sticky windows will be
276 in the right order on the current workspace.
279 Openbox::instance->property()->set(_info->getRootWindow(),
280 otk::OBProperty::net_client_list_stacking,
281 otk::OBProperty::Atom_Window,
282 _stacking, _stacking.size());
287 void OBScreen::setWorkArea() {
288 unsigned long area
[] = { _area
.x(), _area
.y(),
289 _area
.width(), _area
.height() };
290 Openbox::instance
->property()->set(_info
->getRootWindow(),
291 otk::OBProperty::net_workarea
,
292 otk::OBProperty::Atom_Cardinal
,
295 if (workspacesList.size() > 0) {
296 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
297 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
298 // XXX: this could be different for each workspace
299 const otk::Rect &area = availableArea();
300 dims[(i * 4) + 0] = area.x();
301 dims[(i * 4) + 1] = area.y();
302 dims[(i * 4) + 2] = area.width();
303 dims[(i * 4) + 3] = area.height();
305 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
306 otk::OBProperty::Atom_Cardinal,
307 dims, 4 * workspacesList.size());
310 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
311 otk::OBProperty::Atom_Cardinal, 0, 0);
316 void OBScreen::loadStyle(const otk::Configuration
&config
)
320 // XXX: make stuff redraw!
324 void OBScreen::manageWindow(Window window
)
326 OBClient
*client
= 0;
328 XSetWindowAttributes attrib_set
;
330 // is the window a docking app
331 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
332 if ((wmhint
->flags
& StateHint
) &&
333 wmhint
->initial_state
== WithdrawnState
) {
334 //slit->addClient(w); // XXX: make dock apps work!
341 // choose the events we want to receive on the CLIENT window
342 attrib_set
.event_mask
= OBClient::event_mask
;
343 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
345 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
346 CWEventMask
|CWDontPropagate
, &attrib_set
);
348 // create the OBClient class, which gets all of the hints on the window
349 Openbox::instance
->addClient(window
, client
= new OBClient(_number
, window
));
351 // we dont want a border on the client
352 XSetWindowBorderWidth(otk::OBDisplay::display
, window
, 0);
354 // specify that if we exit, the window should not be destroyed and should be
355 // reparented back to root automatically
356 XChangeSaveSet(otk::OBDisplay::display
, window
, SetModeInsert
);
358 if (!client
->positionRequested()) {
359 // XXX: position the window intelligenty
362 // create the decoration frame for the client window
363 client
->frame
= new OBFrame(client
, &_style
);
365 // add all the client's decoration windows as event handlers for the client
366 Openbox::instance
->addClient(client
->frame
->window(), client
);
367 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
368 Openbox::instance
->addClient(client
->frame
->buttonIconify(), client
);
369 Openbox::instance
->addClient(client
->frame
->buttonMax(), client
);
370 Openbox::instance
->addClient(client
->frame
->buttonStick(), client
);
371 Openbox::instance
->addClient(client
->frame
->buttonClose(), client
);
372 Openbox::instance
->addClient(client
->frame
->label(), client
);
373 Openbox::instance
->addClient(client
->frame
->handle(), client
);
374 Openbox::instance
->addClient(client
->frame
->gripLeft(), client
);
375 Openbox::instance
->addClient(client
->frame
->gripRight(), client
);
377 // XXX: if on the current desktop..
378 XMapWindow(otk::OBDisplay::display
, client
->frame
->window());
380 // XXX: handle any requested states such as shaded/maximized
383 _clients
.push_back(client
);
388 void OBScreen::unmanageWindow(OBClient
*client
)
390 OBFrame
*frame
= client
->frame
;
392 // XXX: pass around focus if this window was focused
394 // remove the window from our save set
395 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
397 // we dont want events no more
398 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
400 XUnmapWindow(otk::OBDisplay::display
, frame
->window());
402 // we dont want a border on the client
403 XSetWindowBorderWidth(otk::OBDisplay::display
, client
->window(),
404 client
->borderWidth());
406 // remove the client class from the search list
407 Openbox::instance
->removeClient(client
->window());
408 // remove the frame's decor elements as event handlers for the client
409 Openbox::instance
->removeClient(frame
->window());
410 Openbox::instance
->removeClient(frame
->titlebar());
411 Openbox::instance
->removeClient(frame
->buttonIconify());
412 Openbox::instance
->removeClient(frame
->buttonMax());
413 Openbox::instance
->removeClient(frame
->buttonStick());
414 Openbox::instance
->removeClient(frame
->buttonClose());
415 Openbox::instance
->removeClient(frame
->label());
416 Openbox::instance
->removeClient(frame
->handle());
417 Openbox::instance
->removeClient(frame
->gripLeft());
418 Openbox::instance
->removeClient(frame
->gripRight());
420 delete client
->frame
;
423 ClientList::iterator it
= _clients
.begin(), end
= _clients
.end();
424 for (; it
!= end
; ++it
)