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
98 // XXX: "change to" the first workspace to initialize stuff
102 OBScreen::~OBScreen()
104 if (! _managed
) return;
106 // unmanage all windows
107 while (!_clients
.empty())
108 unmanageWindow(_clients
[0]);
110 delete _image_control
;
114 void OBScreen::manageExisting()
116 unsigned int i
, j
, nchild
;
117 Window r
, p
, *children
;
118 XQueryTree(otk::OBDisplay::display
, _info
->getRootWindow(), &r
, &p
,
121 // preen the window list of all icon windows... for better dockapp support
122 for (i
= 0; i
< nchild
; i
++) {
123 if (children
[i
] == None
) continue;
125 XWMHints
*wmhints
= XGetWMHints(otk::OBDisplay::display
,
129 if ((wmhints
->flags
& IconWindowHint
) &&
130 (wmhints
->icon_window
!= children
[i
])) {
131 for (j
= 0; j
< nchild
; j
++) {
132 if (children
[j
] == wmhints
->icon_window
) {
143 // manage shown windows
144 for (i
= 0; i
< nchild
; ++i
) {
145 if (children
[i
] == None
)
148 XWindowAttributes attrib
;
149 if (XGetWindowAttributes(otk::OBDisplay::display
, children
[i
], &attrib
)) {
150 if (attrib
.override_redirect
) continue;
152 if (attrib
.map_state
!= IsUnmapped
) {
153 manageWindow(children
[i
]);
162 //! Adds a window's strut to the screen's list of reserved spaces
163 void OBScreen::addStrut(otk::Strut
*strut
)
165 _struts
.push_back(strut
);
169 //! Removes a window's strut from the screen's list of reserved spaces
170 void OBScreen::removeStrut(otk::Strut
*strut
)
172 _struts
.remove(strut
);
176 void OBScreen::calcArea()
178 otk::Rect old_area
= _area
;
182 // reset to the full areas
183 if (isXineramaActive())
184 xineramaUsableArea = getXineramaAreas();
188 /* these values represent offsets from the screen edge
189 * we look for the biggest offset on each edge and then apply them
191 * do not be confused by the similarity to the names of Rect's members
193 unsigned int current_left
= 0, current_right
= 0, current_top
= 0,
196 StrutList::const_iterator it
= _struts
.begin(), end
= _struts
.end();
198 for(; it
!= end
; ++it
) {
199 otk::Strut
*strut
= *it
;
200 if (strut
->left
> current_left
)
201 current_left
= strut
->left
;
202 if (strut
->top
> current_top
)
203 current_top
= strut
->top
;
204 if (strut
->right
> current_right
)
205 current_right
= strut
->right
;
206 if (strut
->bottom
> current_bottom
)
207 current_bottom
= strut
->bottom
;
210 _area
.setRect(current_left
, current_top
,
211 _info
->getWidth() - (current_left
+ current_right
),
212 _info
->getHeight() - (current_top
+ current_bottom
));
216 if (isXineramaActive()) {
217 // keep each of the ximerama-defined areas inside the strut
218 RectList::iterator xit, xend = xineramaUsableArea.end();
219 for (xit = xineramaUsableArea.begin(); xit != xend; ++xit) {
220 if (xit->x() < usableArea.x()) {
221 xit->setX(usableArea.x());
222 xit->setWidth(xit->width() - usableArea.x());
224 if (xit->y() < usableArea.y()) {
225 xit->setY(usableArea.y());
226 xit->setHeight(xit->height() - usableArea.y());
228 if (xit->x() + xit->width() > usableArea.width())
229 xit->setWidth(usableArea.width() - xit->x());
230 if (xit->y() + xit->height() > usableArea.height())
231 xit->setHeight(usableArea.height() - xit->y());
237 if (old_area
!= _area
)
238 // XXX: re-maximize windows
244 void OBScreen::setClientList()
248 // create an array of the window ids
249 if (_clients
.size() > 0) {
252 windows
= new Window
[_clients
.size()];
254 ClientList::const_iterator it
= _clients
.begin();
255 const ClientList::const_iterator end
= _clients
.end();
256 for (; it
!= end
; ++it
, ++win_it
)
257 *win_it
= (*it
)->window();
259 windows
= (Window
*) 0;
261 Openbox::instance
->property()->set(_info
->getRootWindow(),
262 otk::OBProperty::net_client_list
,
263 otk::OBProperty::Atom_Window
,
264 windows
, _clients
.size());
273 void OBScreen::setStackingList()
275 // The below comment is wrong now hopefully :> but ill keep it here for
278 Get the stacking order from all of the workspaces.
279 We start with the current workspace so that the sticky windows will be
280 in the right order on the current workspace.
283 Openbox::instance->property()->set(_info->getRootWindow(),
284 otk::OBProperty::net_client_list_stacking,
285 otk::OBProperty::Atom_Window,
286 _stacking, _stacking.size());
291 void OBScreen::setWorkArea() {
292 unsigned long area
[] = { _area
.x(), _area
.y(),
293 _area
.width(), _area
.height() };
294 Openbox::instance
->property()->set(_info
->getRootWindow(),
295 otk::OBProperty::net_workarea
,
296 otk::OBProperty::Atom_Cardinal
,
299 if (workspacesList.size() > 0) {
300 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
301 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
302 // XXX: this could be different for each workspace
303 const otk::Rect &area = availableArea();
304 dims[(i * 4) + 0] = area.x();
305 dims[(i * 4) + 1] = area.y();
306 dims[(i * 4) + 2] = area.width();
307 dims[(i * 4) + 3] = area.height();
309 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
310 otk::OBProperty::Atom_Cardinal,
311 dims, 4 * workspacesList.size());
314 xatom->set(getRootWindow(), otk::OBProperty::net_workarea,
315 otk::OBProperty::Atom_Cardinal, 0, 0);
320 void OBScreen::loadStyle(const otk::Configuration
&config
)
324 // XXX: make stuff redraw!
328 void OBScreen::manageWindow(Window window
)
330 OBClient
*client
= 0;
332 XSetWindowAttributes attrib_set
;
334 // XXX: manage the window, i.e. grab events n shit
336 // is the window a docking app
337 if ((wmhint
= XGetWMHints(otk::OBDisplay::display
, window
))) {
338 if ((wmhint
->flags
& StateHint
) &&
339 wmhint
->initial_state
== WithdrawnState
) {
340 //slit->addClient(w); // XXX: make dock apps work!
347 // choose the events we want to receive on the CLIENT window
348 attrib_set
.event_mask
= OBClient::event_mask
;
349 attrib_set
.do_not_propagate_mask
= ButtonPressMask
| ButtonReleaseMask
|
351 XChangeWindowAttributes(otk::OBDisplay::display
, window
,
352 CWEventMask
|CWDontPropagate
, &attrib_set
);
354 // create the OBClient class, which gets all of the hints on the window
355 Openbox::instance
->addClient(window
, client
= new OBClient(_number
, window
));
357 // we dont want a border on the client
358 XSetWindowBorderWidth(otk::OBDisplay::display
, window
, 0);
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
);
364 if (!client
->positionRequested()) {
365 // XXX: position the window intelligenty
368 // create the decoration frame for the client window
369 client
->frame
= new OBFrame(client
, &_style
);
371 // add all the client's decoration windows as event handlers for the client
372 Openbox::instance
->addClient(client
->frame
->window(), client
);
373 Openbox::instance
->addClient(client
->frame
->titlebar(), client
);
374 Openbox::instance
->addClient(client
->frame
->buttonIconify(), client
);
375 Openbox::instance
->addClient(client
->frame
->buttonMax(), client
);
376 Openbox::instance
->addClient(client
->frame
->buttonStick(), client
);
377 Openbox::instance
->addClient(client
->frame
->buttonClose(), client
);
378 Openbox::instance
->addClient(client
->frame
->label(), client
);
379 Openbox::instance
->addClient(client
->frame
->handle(), client
);
380 Openbox::instance
->addClient(client
->frame
->gripLeft(), client
);
381 Openbox::instance
->addClient(client
->frame
->gripRight(), client
);
383 // XXX: if on the current desktop..
384 XMapWindow(otk::OBDisplay::display
, client
->frame
->window());
386 // XXX: handle any requested states such as shaded/maximized
389 _clients
.push_back(client
);
394 void OBScreen::unmanageWindow(OBClient
*client
)
396 OBFrame
*frame
= client
->frame
;
398 // XXX: pass around focus if this window was focused
400 // remove the window from our save set
401 XChangeSaveSet(otk::OBDisplay::display
, client
->window(), SetModeDelete
);
403 // we dont want events no more
404 XSelectInput(otk::OBDisplay::display
, client
->window(), NoEventMask
);
406 XUnmapWindow(otk::OBDisplay::display
, frame
->window());
408 // we dont want a border on the client
409 XSetWindowBorderWidth(otk::OBDisplay::display
, client
->window(),
410 client
->borderWidth());
412 // remove the client class from the search list
413 Openbox::instance
->removeClient(client
->window());
414 // remove the frame's decor elements as event handlers for the client
415 Openbox::instance
->removeClient(frame
->window());
416 Openbox::instance
->removeClient(frame
->titlebar());
417 Openbox::instance
->removeClient(frame
->buttonIconify());
418 Openbox::instance
->removeClient(frame
->buttonMax());
419 Openbox::instance
->removeClient(frame
->buttonStick());
420 Openbox::instance
->removeClient(frame
->buttonClose());
421 Openbox::instance
->removeClient(frame
->label());
422 Openbox::instance
->removeClient(frame
->handle());
423 Openbox::instance
->removeClient(frame
->gripLeft());
424 Openbox::instance
->removeClient(frame
->gripRight());
426 delete client
->frame
;
429 ClientList::iterator it
= _clients
.begin(), end
= _clients
.end();
430 for (; it
!= end
; ++it
)