]> Dogcows Code - chaz/openbox/blob - src/openbox.cc
linear focus cycling
[chaz/openbox] / src / openbox.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 #include "openbox.hh"
8 #include "client.hh"
9 #include "screen.hh"
10 #include "actions.hh"
11 #include "bindings.hh"
12 #include "python.hh"
13 #include "otk/property.hh"
14 #include "otk/assassin.hh"
15 #include "otk/property.hh"
16 #include "otk/util.hh"
17 #include "otk/rendercolor.hh"
18
19 extern "C" {
20 #include <X11/cursorfont.h>
21
22 #ifdef HAVE_STDIO_H
23 # include <stdio.h>
24 #endif // HAVE_STDIO_H
25
26 #ifdef HAVE_STDLIB_H
27 # include <stdlib.h>
28 #endif // HAVE_STDLIB_H
29
30 #ifdef HAVE_SIGNAL_H
31 # include <signal.h>
32 #endif // HAVE_SIGNAL_H
33
34 #ifdef HAVE_FCNTL_H
35 # include <fcntl.h>
36 #endif // HAVE_FCNTL_H
37
38 #ifdef HAVE_UNISTD_H
39 # include <sys/types.h>
40 # include <unistd.h>
41 #endif // HAVE_UNISTD_H
42
43 #ifdef HAVE_SYS_SELECT_H
44 # include <sys/select.h>
45 #endif // HAVE_SYS_SELECT_H
46
47 #ifdef HAVE_SYS_WAIT_H
48 # include <sys/wait.h>
49 #endif // HAVE_SYS_WAIT_H
50
51 #include "gettext.h"
52 #define _(str) gettext(str)
53 }
54
55 #include <algorithm>
56
57 namespace ob {
58
59 Openbox *openbox = (Openbox *) 0;
60
61
62 void Openbox::signalHandler(int signal)
63 {
64 switch (signal) {
65 case SIGUSR1:
66 printf("Caught SIGUSR1 signal. Restarting.\n");
67 openbox->restart();
68 break;
69
70 case SIGCHLD:
71 wait(NULL);
72 break;
73
74 case SIGHUP:
75 case SIGINT:
76 case SIGTERM:
77 case SIGPIPE:
78 printf("Caught signal %d. Exiting.\n", signal);
79 openbox->shutdown();
80 break;
81
82 case SIGFPE:
83 case SIGSEGV:
84 printf("Caught signal %d. Aborting and dumping core.\n", signal);
85 abort();
86 }
87 }
88
89
90 Openbox::Openbox(int argc, char **argv)
91 : otk::EventDispatcher(),
92 otk::EventHandler(),
93 _display()
94 {
95 struct sigaction action;
96
97 _state = State_Starting; // initializing everything
98
99 openbox = this;
100
101 _displayreq = (char*) 0;
102 _argv = argv;
103 _shutdown = false;
104 _restart = false;
105 _rcfilepath = otk::expandTilde("~/.openbox/rc3");
106 _scriptfilepath = otk::expandTilde("~/.openbox/user.py");
107 _focused_client = 0;
108 _sync = false;
109
110 parseCommandLine(argc, argv);
111
112 XSynchronize(**otk::display, _sync);
113
114 // set up the signal handler
115 action.sa_handler = Openbox::signalHandler;
116 action.sa_mask = sigset_t();
117 action.sa_flags = SA_NOCLDSTOP | SA_NODEFER;
118 sigaction(SIGUSR1, &action, (struct sigaction *) 0);
119 sigaction(SIGPIPE, &action, (struct sigaction *) 0);
120 sigaction(SIGSEGV, &action, (struct sigaction *) 0);
121 sigaction(SIGFPE, &action, (struct sigaction *) 0);
122 sigaction(SIGTERM, &action, (struct sigaction *) 0);
123 sigaction(SIGINT, &action, (struct sigaction *) 0);
124 sigaction(SIGHUP, &action, (struct sigaction *) 0);
125 sigaction(SIGCHLD, &action, (struct sigaction *) 0);
126
127 // anything that died while we were restarting won't give us a SIGCHLD
128 while (waitpid(-1, NULL, WNOHANG) > 0);
129
130 otk::RenderColor::initialize();
131 otk::Timer::initialize();
132 otk::Property::initialize();
133 _actions = new Actions();
134 _bindings = new Bindings();
135
136 setMasterHandler(_actions); // set as the master event handler
137
138 // create the mouse cursors we'll use
139 _cursors.session = XCreateFontCursor(**otk::display, XC_left_ptr);
140 _cursors.move = XCreateFontCursor(**otk::display, XC_fleur);
141 _cursors.ll_angle = XCreateFontCursor(**otk::display, XC_ll_angle);
142 _cursors.lr_angle = XCreateFontCursor(**otk::display, XC_lr_angle);
143 _cursors.ul_angle = XCreateFontCursor(**otk::display, XC_ul_angle);
144 _cursors.ur_angle = XCreateFontCursor(**otk::display, XC_ur_angle);
145
146 // initialize scripting
147 python_init(argv[0]);
148
149 // load config values
150 python_exec(SCRIPTDIR"/config.py"); // load openbox config values
151 // run all of the python scripts
152 python_exec(SCRIPTDIR"/builtins.py"); // builtin callbacks
153 python_exec(SCRIPTDIR"/focus.py"); // focus helpers
154 // run the user's script or the system defaults if that fails
155 if (!python_exec(_scriptfilepath.c_str()))
156 python_exec(SCRIPTDIR"/defaults.py"); // system default bahaviors
157
158 // initialize all the screens
159 Screen *screen;
160 int i = _single ? DefaultScreen(**otk::display) : 0;
161 int max = _single ? i + 1 : ScreenCount(**otk::display);
162 for (; i < max; ++i) {
163 screen = new Screen(i);
164 if (screen->managed())
165 _screens.push_back(screen);
166 else
167 delete screen;
168 }
169
170 if (_screens.empty()) {
171 printf(_("No screens were found without a window manager. Exiting.\n"));
172 ::exit(1);
173 }
174
175 ScreenList::iterator it, end = _screens.end();
176 for (it = _screens.begin(); it != end; ++it) {
177 (*it)->manageExisting();
178 }
179
180 // grab any keys set up before the screens existed
181 _bindings->grabKeys(true);
182
183 // set up input focus
184 _focused_screen = _screens[0];
185 setFocusedClient(0);
186
187 _state = State_Normal; // done starting
188 }
189
190
191 Openbox::~Openbox()
192 {
193 _state = State_Exiting; // time to kill everything
194
195 int first_screen = _screens.front()->number();
196
197 std::for_each(_screens.begin(), _screens.end(), otk::PointerAssassin());
198
199 delete _bindings;
200 delete _actions;
201
202 python_destroy();
203
204 XSetInputFocus(**otk::display, PointerRoot, RevertToNone,
205 CurrentTime);
206 XSync(**otk::display, false);
207
208 // this tends to block.. i honestly am not sure why. causing an x error in
209 // the shutdown process unblocks it. blackbox simply did a ::exit(0), so
210 // all im gunna do is the same.
211 //otk::display->destroy();
212
213 otk::Timer::destroy();
214 otk::RenderColor::destroy();
215
216 if (_restart) {
217 if (!_restart_prog.empty()) {
218 otk::putenv(otk::display->screenInfo(first_screen)->displayString());
219 execl("/bin/sh", "/bin/sh", "-c", _restart_prog.c_str(), NULL);
220 perror(_restart_prog.c_str());
221 }
222
223 // fall back in case the above execlp doesn't work
224 execvp(_argv[0], _argv);
225 execvp(otk::basename(_argv[0]).c_str(), _argv);
226 }
227 }
228
229
230 void Openbox::parseCommandLine(int argc, char **argv)
231 {
232 bool err = false;
233
234 for (int i = 1; i < argc; ++i) {
235 std::string arg(argv[i]);
236
237 if (arg == "-display") {
238 if (++i >= argc)
239 err = true;
240 else
241 _displayreq = argv[i];
242 } else if (arg == "-rc") {
243 if (++i >= argc)
244 err = true;
245 else
246 _rcfilepath = argv[i];
247 } else if (arg == "-menu") {
248 if (++i >= argc)
249 err = true;
250 else
251 _menufilepath = argv[i];
252 } else if (arg == "-script") {
253 if (++i >= argc)
254 err = true;
255 else
256 _scriptfilepath = argv[i];
257 } else if (arg == "-sync") {
258 _sync = true;
259 } else if (arg == "-single") {
260 _single = true;
261 } else if (arg == "-version") {
262 showVersion();
263 ::exit(0);
264 } else if (arg == "-help") {
265 showHelp();
266 ::exit(0);
267 } else
268 err = true;
269
270 if (err) {
271 showHelp();
272 exit(1);
273 }
274 }
275 }
276
277
278 void Openbox::showVersion()
279 {
280 printf(_("Openbox - version %s\n"), VERSION);
281 printf(" (c) 2002 - 2002 Ben Jansens\n\n");
282 }
283
284
285 void Openbox::showHelp()
286 {
287 showVersion(); // show the version string and copyright
288
289 // print program usage and command line options
290 printf(_("Usage: %s [OPTIONS...]\n\
291 Options:\n\
292 -display <string> use display connection.\n\
293 -single run on a single screen (default is to run every one).\n\
294 -rc <string> use alternate resource file.\n\
295 -menu <string> use alternate menu file.\n\
296 -script <string> use alternate startup script file.\n\
297 -sync run in synchronous mode (for debugging).\n\
298 -version display version and exit.\n\
299 -help display this help text and exit.\n\n"), _argv[0]);
300
301 printf(_("Compile time options:\n\
302 Debugging: %s\n\
303 Shape: %s\n\
304 Xinerama: %s\n\
305 Xkb: %s\n"),
306 #ifdef DEBUG
307 _("yes"),
308 #else // !DEBUG
309 _("no"),
310 #endif // DEBUG
311
312 #ifdef SHAPE
313 _("yes"),
314 #else // !SHAPE
315 _("no"),
316 #endif // SHAPE
317
318 #ifdef XINERAMA
319 _("yes"),
320 #else // !XINERAMA
321 _("no"),
322 #endif // XINERAMA
323
324 #ifdef XKB
325 _("yes")
326 #else // !XKB
327 _("no")
328 #endif // XKB
329 );
330 }
331
332
333 void Openbox::eventLoop()
334 {
335 while (true) {
336 dispatchEvents(); // from otk::EventDispatcher
337 XFlush(**otk::display); // flush here before we go wait for timers
338 // don't wait if we're to shutdown
339 if (_shutdown) break;
340 otk::Timer::dispatchTimers(!_sync); // wait if not in sync mode
341 }
342 }
343
344
345 void Openbox::addClient(Window window, Client *client)
346 {
347 _clients[window] = client;
348 }
349
350
351 void Openbox::removeClient(Window window)
352 {
353 _clients.erase(window);
354 }
355
356
357 Client *Openbox::findClient(Window window)
358 {
359 /*
360 NOTE: we dont use _clients[] to find the value because that will insert
361 a new null into the hash, which really sucks when we want to clean up the
362 hash at shutdown!
363 */
364 ClientMap::iterator it = _clients.find(window);
365 if (it != _clients.end())
366 return it->second;
367 else
368 return (Client*) 0;
369 }
370
371
372 void Openbox::setFocusedClient(Client *c)
373 {
374 _focused_client = c;
375 if (c) {
376 _focused_screen = _screens[c->screen()];
377 } else {
378 assert(_focused_screen);
379 XSetInputFocus(**otk::display, _focused_screen->focuswindow(),
380 RevertToNone, CurrentTime);
381 }
382 // set the NET_ACTIVE_WINDOW hint for all screens
383 ScreenList::iterator it, end = _screens.end();
384 for (it = _screens.begin(); it != end; ++it) {
385 int num = (*it)->number();
386 Window root = otk::display->screenInfo(num)->rootWindow();
387 otk::Property::set(root, otk::Property::atoms.net_active_window,
388 otk::Property::atoms.window,
389 (c && _focused_screen == *it) ? c->window() : None);
390 }
391
392 // call the python Focus callbacks
393 EventData data(_focused_screen->number(), c, EventFocus, 0);
394 _bindings->fireEvent(&data);
395 }
396
397 void Openbox::execute(int screen, const std::string &bin)
398 {
399 if (screen >= ScreenCount(**otk::display))
400 screen = 0;
401 otk::bexec(bin, otk::display->screenInfo(screen)->displayString());
402 }
403
404 }
405
This page took 0.051033 seconds and 5 git commands to generate.