handle map events with the Openbox class
[mikachu/openbox.git] / src / openbox.cc
1 // -*- mode: C++; indent-tabs-mode: nil; -*-
2
3 #ifdef HAVE_CONFIG_H
4 # include "../config.h"
5 #endif
6
7 #include "../version.h"
8 #include "openbox.hh"
9 #include "screen.hh"
10 #include "otk/property.hh"
11 #include "otk/display.hh"
12 #include "otk/assassin.hh"
13 #include "otk/util.hh" // TEMPORARY
14
15 extern "C" {
16 #include <X11/cursorfont.h>
17
18 #ifdef    HAVE_STDIO_H
19 #  include <stdio.h>
20 #endif // HAVE_STDIO_H
21
22 #ifdef    HAVE_STDLIB_H
23 #  include <stdlib.h>
24 #endif // HAVE_STDLIB_H
25
26 #ifdef    HAVE_SIGNAL_H
27 #  include <signal.h>
28 #endif // HAVE_SIGNAL_H
29
30 #ifdef    HAVE_FCNTL_H
31 #  include <fcntl.h>
32 #endif // HAVE_FCNTL_H
33
34 #ifdef    HAVE_UNISTD_H
35 #  include <sys/types.h>
36 #  include <unistd.h>
37 #endif // HAVE_UNISTD_H
38
39 #ifdef    HAVE_SYS_SELECT_H
40 #  include <sys/select.h>
41 #endif // HAVE_SYS_SELECT_H
42
43 #include "gettext.h"
44 #define _(str) gettext(str)
45 }
46
47 #include <algorithm>
48
49 namespace ob {
50
51 Openbox *Openbox::instance = (Openbox *) 0;
52
53
54 void Openbox::signalHandler(int signal)
55 {
56   switch (signal) {
57   case SIGHUP:
58     // XXX: Do something with HUP? Really shouldn't, we get this when X shuts
59     //      down and hangs-up on us.
60     
61   case SIGINT:
62   case SIGTERM:
63   case SIGPIPE:
64     printf("Caught signal %d. Exiting.\n", signal);
65     instance->shutdown();
66
67     break;
68   case SIGFPE:
69   case SIGSEGV:
70     printf("Caught signal %d. Aborting and dumping core.\n", signal);
71     abort();
72   }
73 }
74
75
76 Openbox::Openbox(int argc, char **argv)
77   : otk::OtkEventDispatcher(),
78     otk::OtkEventHandler()
79 {
80   struct sigaction action;
81
82   _state = State_Starting; // initializing everything
83
84   Openbox::instance = this;
85
86   _displayreq = (char*) 0;
87   _argv0 = argv[0];
88   _doshutdown = false;
89   _rcfilepath = otk::expandTilde("~/.openbox/rc3");
90
91   parseCommandLine(argc, argv);
92
93   // TEMPORARY: using the xrdb rc3
94   _config.setFile(_rcfilepath);
95   if (!_config.load()) {
96     printf("failed to load rc file %s\n", _config.file().c_str());
97     ::exit(2);
98   }
99   std::string s;
100   _config.getValue("session.styleFile", s);
101   _config.setFile(s);
102   if (!_config.load()) {
103     printf("failed to load style %s\n", _config.file().c_str());
104     ::exit(2);
105   }
106
107   // open the X display (and gets some info about it, and its screens)
108   otk::OBDisplay::initialize(_displayreq);
109   assert(otk::OBDisplay::display);
110     
111   // set up the signal handler
112   action.sa_handler = Openbox::signalHandler;
113   action.sa_mask = sigset_t();
114   action.sa_flags = SA_NOCLDSTOP | SA_NODEFER;
115   sigaction(SIGPIPE, &action, (struct sigaction *) 0);
116   sigaction(SIGSEGV, &action, (struct sigaction *) 0);
117   sigaction(SIGFPE, &action, (struct sigaction *) 0);
118   sigaction(SIGTERM, &action, (struct sigaction *) 0);
119   sigaction(SIGINT, &action, (struct sigaction *) 0);
120   sigaction(SIGHUP, &action, (struct sigaction *) 0);
121
122   _property = new otk::OBProperty();
123
124   // set this class as the fallback event handler (for map events)
125   setFallbackHandler(this);
126
127   // create the mouse cursors we'll use
128   _cursors.session = XCreateFontCursor(otk::OBDisplay::display, XC_left_ptr);
129   _cursors.move = XCreateFontCursor(otk::OBDisplay::display, XC_fleur);
130   _cursors.ll_angle = XCreateFontCursor(otk::OBDisplay::display, XC_ll_angle);
131   _cursors.lr_angle = XCreateFontCursor(otk::OBDisplay::display, XC_lr_angle);
132   _cursors.ul_angle = XCreateFontCursor(otk::OBDisplay::display, XC_ul_angle);
133   _cursors.ur_angle = XCreateFontCursor(otk::OBDisplay::display, XC_ur_angle);
134
135   // initialize all the screens
136   OBScreen *screen;
137   screen = new OBScreen(0, _config);
138   if (screen->managed()) {
139     _screens.push_back(screen);
140     _screens[0]->manageExisting();
141     // XXX: "change to" the first workspace on the screen to initialize stuff
142   } else
143     delete screen;
144
145   if (_screens.empty()) {
146     printf(_("No screens were found without a window manager. Exiting.\n"));
147     ::exit(1);
148   }
149   
150   _state = State_Normal; // done starting
151 }
152
153
154 Openbox::~Openbox()
155 {
156   _state = State_Exiting; // time to kill everything
157
158   std::for_each(_screens.begin(), _screens.end(), otk::PointerAssassin());
159   
160   // close the X display
161   otk::OBDisplay::destroy();
162 }
163
164
165 void Openbox::parseCommandLine(int argc, char **argv)
166 {
167   bool err = false;
168
169   for (int i = 1; i < argc; ++i) {
170     std::string arg(argv[i]);
171
172     if (arg == "-display") {
173       if (++i >= argc)
174         err = true;
175       else
176         _displayreq = argv[i];
177     } else if (arg == "-rc") {
178       if (++i >= argc)
179         err = true;
180       else
181         _rcfilepath = argv[i];
182     } else if (arg == "-menu") {
183       if (++i >= argc)
184         err = true;
185       else
186         _menufilepath = argv[i];
187     } else if (arg == "-version") {
188       showVersion();
189       ::exit(0);
190     } else if (arg == "-help") {
191       showHelp();
192       ::exit(0);
193     } else
194       err = true;
195
196     if (err) {
197       showHelp();
198       exit(1);
199     }
200   }
201 }
202
203
204 void Openbox::showVersion()
205 {
206   printf(_("Openbox - version %s\n"), OPENBOX_VERSION);
207   printf("    (c) 2002 - 2002 Ben Jansens\n\n");
208 }
209
210
211 void Openbox::showHelp()
212 {
213   showVersion(); // show the version string and copyright
214
215   // print program usage and command line options
216   printf(_("Usage: %s [OPTIONS...]\n\
217   Options:\n\
218   -display <string>  use display connection.\n\
219   -rc <string>       use alternate resource file.\n\
220   -menu <string>     use alternate menu file.\n\
221   -version           display version and exit.\n\
222   -help              display this help text and exit.\n\n"), _argv0);
223
224   printf(_("Compile time options:\n\
225   Debugging: %s\n\
226   Shape:     %s\n\
227   Xinerama:  %s\n"),
228 #ifdef    DEBUG
229          _("yes"),
230 #else // !DEBUG
231          _("no"),
232 #endif // DEBUG
233
234 #ifdef    SHAPE
235          _("yes"),
236 #else // !SHAPE
237          _("no"),
238 #endif // SHAPE
239
240 #ifdef    XINERAMA
241          _("yes")
242 #else // !XINERAMA
243          _("no")
244 #endif // XINERAMA
245     );
246 }
247
248
249 void Openbox::eventLoop()
250 {
251   while (!_doshutdown) {
252     dispatchEvents(); // from OtkEventDispatcher
253     _timermanager.fire();
254   }
255 }
256
257
258 void Openbox::addClient(Window window, OBClient *client)
259 {
260   _clients[window] = client;
261 }
262
263
264 void Openbox::removeClient(Window window)
265 {
266   ClientMap::iterator it = _clients.find(window);
267   if (it != _clients.end())
268     _clients.erase(it);
269 }
270
271
272 OBClient *Openbox::findClient(Window window)
273 {
274   /*
275     NOTE: we dont use _clients[] to find the value because that will insert
276     a new null into the hash, which really sucks when we want to clean up the
277     hash at shutdown!
278   */
279   ClientMap::iterator it = _clients.find(window);
280   if (it != _clients.end())
281     return it->second;
282   else
283     return (OBClient*) 0;
284 }
285
286
287 void Openbox::mapRequestHandler(const XMapRequestEvent &e)
288 {
289 #ifdef    DEBUG
290   printf("MapRequest for 0x%lx\n", e.window);
291 #endif // DEBUG
292
293   otk::OtkEventHandler::mapRequestHandler(e);
294
295   OBClient *client = findClient(e.window);
296
297   if (client) {
298     // XXX: uniconify and/or unshade the window
299   } else {
300     int screen = INT_MAX;
301
302     for (int i = 0; i < ScreenCount(otk::OBDisplay::display); ++i)
303       if (otk::OBDisplay::screenInfo(i)->getRootWindow() == e.parent) {
304         screen = i;
305         break;
306       }
307
308     if (screen >= ScreenCount(otk::OBDisplay::display)) {
309       /*
310         we got a map request for a window who's parent isn't root. this
311         can happen in only one circumstance:
312
313         a client window unmapped a managed window, and then remapped it
314         somewhere between unmapping the client window and reparenting it
315         to root.
316
317         regardless of how it happens, we need to find the screen that
318         the window is on
319       */
320       XWindowAttributes wattrib;
321       if (! XGetWindowAttributes(otk::OBDisplay::display, e.window,
322                                  &wattrib)) {
323         // failed to get the window attributes, perhaps the window has
324         // now been destroyed?
325         return;
326       }
327
328       for (int i = 0; i < ScreenCount(otk::OBDisplay::display); ++i)
329         if (otk::OBDisplay::screenInfo(i)->getRootWindow() == wattrib.root) {
330           screen = i;
331           break;
332         }
333     }
334
335     assert(screen < static_cast<int>(_screens.size()));
336     _screens[screen]->manageWindow(e.window);
337   }
338 }
339
340 }
341