00001
00002
00003
00004
00005
00006 extern "C" {
00007 #include <assert.h>
00008 #include <stdlib.h>
00009 #include <unistd.h>
00010 #include <X11/Xlib.h>
00011 #include <X11/Xatom.h>
00012 #include <X11/Xutil.h>
00013 }
00014
00015 #include <sstream>
00016
00017 #include "kernel.h"
00018
00019 #include "action.h"
00020 #include "actions.h"
00021 #include "atoms.h"
00022 #include "binder.h"
00023 #include "box.h"
00024 #include "client.h"
00025 #include "clientbar.h"
00026 #include "cursors.h"
00027 #include "container.h"
00028 #include "draw.h"
00029 #include "expander.h"
00030 #include "float.h"
00031 #include "frame.h"
00032 #include "inputbar.h"
00033 #include "launcher.h"
00034 #include "loader.h"
00035 #include "logger.h"
00036 #include "menu.h"
00037 #include "monitor.h"
00038 #include "prompt.h"
00039 #include "shortcut.h"
00040 #include "slot.h"
00041 #include "split.h"
00042 #include "statusbar.h"
00043 #include "thing.h"
00044 #include "util.h"
00045 #include "validators.h"
00046 #include "workspace.h"
00047 #include "xcore.h"
00048
00049 Kernel::Kernel() {
00050 }
00051
00052 void Kernel::initMonitors() {
00053
00054 unsigned int monitorCount = ScreenCount(display_);
00055
00056 for (unsigned int i = 0; i < monitorCount; i++) {
00057 Monitor *monitor = new Monitor(display_, i);
00058 monitors_->attach(monitor);
00059 }
00060 }
00061
00062 int Kernel::start(char *argv[], Display *display, MSettings *themeSettings,
00063 MSettings *commonSettings, MSettings *actionSettings,
00064 MSettings *sessionSettings, bool isFirstRun)
00065 {
00066
00067 runlevel_ = START;
00068
00069
00070 display_ = display;
00071 monitors_ = new CMonitor(this);
00072 themeSettings_ = themeSettings;
00073 commonSettings_ = commonSettings;
00074 actionSettings_ = actionSettings;
00075 sessionSettings_ = sessionSettings;
00076 actionBindings_ = new MBindings();
00077 isRecording_ = false;
00078 isMenuMode_ = false;
00079 isSloppyMode_ = true;
00080 isStackedTabbing_ = Util::get(commonSettings_, "cycle.mode") != "default";
00081 borderWidth_ = Util::strToUInt(Util::get(commonSettings_, "border.width"));
00082
00083 LOGDEBUG("--- begin of new NCWM session ---");
00084 XSetErrorHandler(XCore::handleErrors);
00085 LOGDEBUG("error handler installed");
00086 XCORE->setDisplay(display_);
00087 LOGDEBUG("xcore initialized");
00088 Atoms::initAtoms();
00089 LOGDEBUG("atoms initialized");
00090 Cursors::initCursors();
00091 LOGDEBUG("cursors initialized");
00092 Actions::instance()->initInternActions(actionBindings_);
00093 LOGDEBUG("intern actions initialized");
00094 initActionBindings();
00095 LOGDEBUG("action bindings initialized");
00096 initMonitors();
00097 LOGDEBUG("monitors initialized");
00098 initKeys();
00099 LOGDEBUG("keys initialized");
00100 Launcher::instance()->exec(
00101 Util::get(themeSettings_, "exec"));
00102 if (isFirstRun) {
00103 Actions::instance()->executeTerm(0, "man ncwm");
00104 }
00105
00106
00107 XCORE->sync();
00108 initWindows();
00109 LOGDEBUG("windows initialized");
00110
00111 defaultPrompt_ = new Prompt(": ", &Binder::queryActionKeysForPattern);
00112
00113 Action* startupAction = new Action("startup", &Actions::sequence,
00114 &Validators::isAlwaysPossible,
00115 Action::SEQUENCE,
00116 strdup(Util::get(commonSettings_,
00117 "startup.chain").c_str()));
00118 startupAction->perform();
00119 delete startupAction;
00120 Expander::instance();
00121
00122
00123 runlevel_ = RUN;
00124 int result = run();
00125
00126 serialize();
00127 LOGDEBUG("current state serialized");
00128 LOGDEBUG("--- end of NCWM session ---");
00129
00130 cleanup();
00131
00132 if (runlevel_ == RESTART) {
00133 saveSettings();
00134 execvp(argv[0], argv);
00135 LOGERROR("restart failed", false);
00136 exit(1);
00137 }
00138
00139 return result;
00140 }
00141
00142 Kernel::~Kernel() {
00143 }
00144
00145 Prompt *Kernel::defaultPrompt() const {
00146 return defaultPrompt_;
00147 }
00148
00149 Window Kernel::defaultRootWindow() {
00150 return DefaultRootWindow(display_);
00151 }
00152
00153 Window Kernel::rootWindow() {
00154 return focusedMonitor()->rootWindow();
00155 }
00156
00157 Client *Kernel::focusedClient() {
00158
00159 assert(focusedMonitor() != 0);
00160 Workspace *focusedWorkspace = focusedMonitor()->focused();
00161 assert(focusedWorkspace != 0);
00162
00163 return focusedWorkspace->topClient();
00164 }
00165
00166 void Kernel::killClient(Client *client) {
00167 if (client) {
00168 XCORE->kill(client->clientWindow(), client->protocols());
00169 }
00170 }
00171
00172 void Kernel::updateBars() {
00173
00174 for (LMonitor::iterator it = monitors_->begin();
00175 it != monitors_->end(); it++)
00176 {
00177 Monitor *monitor = (Monitor *)*it;
00178 monitor->statusBar()->illuminate();
00179 monitor->clientBar()->illuminate();
00180 }
00181 }
00182
00183 void Kernel::initWindows() {
00184
00185 for (LMonitor::iterator it = monitors_->begin();
00186 it != monitors_->end(); it++)
00187 {
00188 Monitor *monitor = (Monitor *)*it;
00189 monitor->scanWindows();
00190 }
00191 }
00192
00193 void Kernel::initKeys() {
00194
00195 XCORE->ungrabKeyboard();
00196 Binder *bm = Binder::instance();
00197
00198 for (LMonitor::iterator it = monitors_->begin();
00199 it != monitors_->end(); it++)
00200 {
00201 Monitor *monitor = (Monitor *)*it;
00202 bm->initKeys(monitor->rootWindow());
00203 }
00204 }
00205
00206 void Kernel::initActionBindings() {
00207
00208 Action::Type type = Action::UNKNOWN;
00209
00210 string settingsKey, bind, postfix, spec, keys;
00211 spec = "";
00212 Action *action = 0;
00213
00214
00215 for (MSettings::iterator it = actionSettings_->begin();
00216 it != actionSettings_->end(); it++)
00217 {
00218 settingsKey = (*it).first;
00219 if (settingsKey.substr(0, 6) == "extern") {
00220 type = Action::EXTERN;
00221 }
00222 else if (settingsKey.substr(0, 5) == "chain") {
00223 type = Action::SEQUENCE;
00224 }
00225 else {
00226 type = Action::UNKNOWN;
00227 }
00228
00229 if (type != Action::UNKNOWN) {
00230 bind = Util::nthToken(settingsKey, '.', 2);
00231 LOGDEBUG("found " + bind);
00232 postfix = Util::nthToken(settingsKey, '.', 3);
00233
00234 if ((type == Action::EXTERN) && (postfix == "cmd")) {
00235 spec = (*it).second;
00236 }
00237 else if ((type == Action::SEQUENCE) && (postfix == "seq")) {
00238 spec = (*it).second;
00239 }
00240
00241 if (spec != "") {
00242
00243 if (type == Action::EXTERN) {
00244 action = new Action(bind, &Actions::execute,
00245 &Validators::isWorkspaceFocused, type,
00246 (char *)spec.c_str());
00247 }
00248 else if (type == Action::SEQUENCE) {
00249
00250
00251
00252
00253
00254 string firstActionKey = Util::nthToken(spec, ',', 1);
00255 IsValid isValid = 0;
00256 Action *firstAction =
00257 Util::get(actionBindings_, firstActionKey);
00258 if (firstAction) {
00259 isValid = firstAction->getIsValid();
00260 }
00261 else {
00262 isValid = &Validators::isAlwaysPossible;
00263 }
00264 action = new Action(bind, &Actions::sequence,
00265 isValid, type, (char *)spec.c_str());
00266 }
00267 }
00268
00269 if (action != 0) {
00270
00271 LOGDEBUG("creating action: " + bind);
00272 (*actionBindings_)[bind] = action;
00273 action = 0;
00274 spec = "";
00275 }
00276 }
00277 }
00278
00279
00280 for (MSettings::iterator it = actionSettings_->begin();
00281 it != actionSettings_->end(); it++)
00282 {
00283 settingsKey = (*it).first;
00284 if (settingsKey.substr(0, 6) == "extern") {
00285 type = Action::EXTERN;
00286 }
00287 else if (settingsKey.substr(0, 6) == "intern") {
00288 type = Action::INTERN;
00289 }
00290 else if (settingsKey.substr(0, 5) == "chain") {
00291 type = Action::SEQUENCE;
00292 }
00293 else {
00294 type = Action::UNKNOWN;
00295 }
00296
00297 if (type != Action::UNKNOWN) {
00298
00299 bind = Util::nthToken(settingsKey, '.', 2);
00300 LOGDEBUG("found " + bind);
00301 postfix = Util::nthToken(settingsKey, '.', 3);
00302
00303
00304 if (postfix == "keys") {
00305 keys = (*it).second;
00306
00307 if (keys != "") {
00308
00309
00310 action = Util::get(actionBindings_, bind);
00311 if (action) {
00312 action->setShortcut(Shortcut::shortcut(keys));
00313 }
00314
00315 keys = "";
00316 }
00317 }
00318 }
00319 }
00320 }
00321
00322 bool Kernel::isNCWMWindow(Window window) {
00323
00324 return isRootWindow(window) ||
00325 #ifdef SLOT_SUPPORT
00326 slotWindow(window) ||
00327 #endif // SLOT_SUPPORT
00328 menuWindow(window) ||
00329 barWindow(window) ||
00330 boxWindow(window) ||
00331 thingWindow(window);
00332 }
00333
00334 bool Kernel::isRootWindow(Window window) {
00335
00336 for (LMonitor::iterator it = monitors_->begin();
00337 it != monitors_->end(); it++)
00338 {
00339 Monitor *monitor = (Monitor *)*it;
00340 if (monitor->rootWindow() == window) {
00341 monitors_->focus(monitor);
00342 return true;
00343 }
00344 }
00345
00346 return false;
00347 }
00348
00349 Menu *Kernel::menuWindow(Window window) {
00350
00351 for (LMonitor::iterator it = monitors_->begin();
00352 it != monitors_->end(); it++)
00353 {
00354 Monitor *monitor = (Monitor *)*it;
00355 Menu *menu = monitor->menuWindow(window);
00356 if (menu) {
00357 monitors_->focus(monitor);
00358 return menu;
00359 }
00360 }
00361
00362 return 0;
00363 }
00364
00365 #ifdef SLOT_SUPPORT
00366 Slot *Kernel::slotWindow(Window window) {
00367
00368 for (LMonitor::iterator it = monitors_->begin();
00369 it != monitors_->end(); it++)
00370 {
00371 Monitor *monitor = (Monitor *)*it;
00372 Slot *slot = monitor->slotWindow(window);
00373 if (slot) {
00374 monitors_->focus(monitor);
00375 return slot;
00376 }
00377 }
00378
00379 return 0;
00380 }
00381 #endif // SLOT_SUPPORT
00382
00383 Thing *Kernel::thingWindow(Window window) {
00384
00385 for (LMonitor::iterator it = monitors_->begin();
00386 it != monitors_->end(); it++)
00387 {
00388 Monitor *monitor = (Monitor *)*it;
00389 Thing *thing = monitor->thingWindow(window);
00390 if (thing) {
00391 monitors_->focus(monitor);
00392 return thing;
00393 }
00394 }
00395
00396 return 0;
00397 }
00398
00399 Box *Kernel::boxWindow(Window window) {
00400
00401 for (LMonitor::iterator it = monitors_->begin();
00402 it != monitors_->end(); it++)
00403 {
00404 Monitor *monitor = (Monitor *)*it;
00405 Box *box = monitor->box();
00406 if (box->window() == window) {
00407 return box;
00408 }
00409 }
00410 return 0;
00411 }
00412
00413 Bar *Kernel::barWindow(Window window) {
00414
00415 for (LMonitor::iterator it = monitors_->begin();
00416 it != monitors_->end(); it++)
00417 {
00418 Monitor *monitor = (Monitor *)*it;
00419 Bar *bar = monitor->barWindow(window);
00420 if (bar) {
00421 monitors_->focus(monitor);
00422 return bar;
00423 }
00424 }
00425
00426 return 0;
00427 }
00428
00429 Client *Kernel::clientForWindow(Window window) {
00430
00431 for (LMonitor::iterator it = monitors_->begin();
00432 it != monitors_->end(); it++)
00433 {
00434 Monitor *monitor = (Monitor *)*it;
00435 Client *client = monitor->clientForWindow(window);
00436 if (client != 0) {
00437 monitors_->focus(monitor);
00438 return client;
00439 }
00440 }
00441 return 0;
00442 }
00443
00444 bool Kernel::isInputMode() {
00445 return focusedMonitor()->inputBar()->isVisible();
00446 }
00447
00448 void Kernel::ungrabShortcutOnAllMonitors(Shortcut *shortcut) {
00449
00450 Binder *bm = Binder::instance();
00451
00452 for (LMonitor::iterator it = monitors_->begin();
00453 it != monitors_->end(); it++)
00454 {
00455 Monitor *monitor = (Monitor *)*it;
00456 bm->ungrabShortcut(shortcut, monitor->rootWindow());
00457 }
00458 }
00459
00460 void Kernel::grabShortcutOnAllMonitors(Shortcut *shortcut) {
00461
00462 Binder *bm = Binder::instance();
00463
00464 for (LMonitor::iterator it = monitors_->begin();
00465 it != monitors_->end(); it++)
00466 {
00467 Monitor *monitor = (Monitor *)*it;
00468 bm->grabShortcut(shortcut, monitor->rootWindow());
00469 }
00470 }
00471
00472 void Kernel::toggleShortcuts() {
00473
00474 static bool isGrabbed = false;
00475
00476 isGrabbed = !isGrabbed;
00477 for (MBindings::iterator it = actionBindings_->begin();
00478 it != actionBindings_->end(); it++)
00479 {
00480 Action *action = (*it).second;
00481 Shortcut *shortcut = action->listenOn();
00482 if (shortcut
00483 && (action->getToPerform() != &Actions::inputMode)
00484 && (action->getToPerform() != &Actions::toggleShortcuts))
00485 {
00486 if (isGrabbed) {
00487 ungrabShortcutOnAllMonitors(shortcut);
00488 }
00489 else {
00490 grabShortcutOnAllMonitors(shortcut);
00491 }
00492 }
00493 }
00494 }
00495
00496 void Kernel::bindShortcut(string argument) {
00497
00498 unsigned int argDelim = argument.find_first_of('+');
00499 if (argDelim == string::npos) {
00500 return;
00501 }
00502 string bind = argument.substr(0, argDelim);
00503 string keys = argument.substr(argDelim + 1);
00504
00505 Action *action = Util::get(actionBindings_, bind);
00506
00507 if (action) {
00508 Shortcut *oldShortcut = action->shortcut();
00509 if (oldShortcut) {
00510 bool doUngrab = true;
00511 for (MBindings::iterator it = actionBindings_->begin();
00512 it != actionBindings_->end(); it++)
00513 {
00514 Action *action = (*it).second;
00515 Shortcut *s = action->listenOn();
00516 if (s &&
00517 (s->modMask() == oldShortcut->modMask()) &&
00518 (s->keyCode() == oldShortcut->keyCode()) &&
00519 (s->button() == oldShortcut->button()))
00520 {
00521 doUngrab = false;
00522 break;
00523 }
00524 }
00525 if (doUngrab) {
00526 ungrabShortcutOnAllMonitors(oldShortcut);
00527 }
00528 delete oldShortcut;
00529 }
00530
00531 string prefix;
00532 switch (action->type()) {
00533 case Action::INTERN:
00534 prefix = "intern.";
00535 break;
00536 case Action::EXTERN:
00537 prefix = "extern.";
00538 break;
00539 case Action::SEQUENCE:
00540 prefix = "chain.";
00541 break;
00542 case Action::UNKNOWN:
00543 prefix = "unknown.";
00544 break;
00545 }
00546
00547 if (keys == "") {
00548 Util::remove(actionSettings_, prefix + bind + ".keys");
00549 return;
00550 }
00551 action->setShortcut(Shortcut::shortcut(keys));
00552
00553 (*actionSettings_)[prefix + bind + ".keys"] = keys;
00554 if (action->listenOn()) {
00555 grabShortcutOnAllMonitors(action->listenOn());
00556 }
00557 }
00558 }
00559
00560 void Kernel::serialize() {
00561
00562 for (LMonitor::iterator it = monitors_->begin();
00563 it != monitors_->end(); it++)
00564 {
00565 Monitor *monitor = *it;
00566 monitor->serialize();
00567 }
00568 }
00569
00570 void Kernel::installCursor(Cursor cursor, Window window) {
00571 XSetWindowAttributes attr;
00572 attr.cursor = cursor;
00573 XCORE->setWindowAttributes(window, CWCursor, &attr);
00574 }
00575
00576
00577 void Kernel::addClient(Client *client) {
00578
00579 focusedMonitor()->addClient(client);
00580 }
00581
00582 void Kernel::saveSettings() {
00583
00584
00585
00586 const char *home = getenv("HOME");
00587
00588 Loader::saveSettings(actionSettings_, (string)home +
00589 "/.ncwm/actions.session");
00590 Loader::saveSettings(sessionSettings_, (string)home +
00591 "/.ncwm/ncwm.session");
00592 }
00593
00594 void Kernel::cleanup() {
00595
00596 for (LMonitor::iterator it = monitors_->begin();
00597 it != monitors_->end(); it++)
00598 {
00599 Monitor *monitor = *it;
00600 monitor->cleanup();
00601 }
00602 XCORE->setInputFocus(PointerRoot);
00603 Cursors::cleanup();
00604 delete monitors_;
00605
00606 XCloseDisplay(display_);
00607 }
00608
00610
00611 void Kernel::handleButtonRelease(XButtonEvent *event) {
00612
00613 event->state &= Binder::instance()->validModMask();
00614
00615 Bar *bar = barWindow(event->window);
00616 if (bar) {
00617 bar->handleButtonRelease(event);
00618 return;
00619 }
00620
00621 Thing *thing = thingWindow(event->window);
00622 if (thing) {
00623 thing->handleButtonRelease(event);
00624 }
00625 }
00626
00627 void Kernel::handleButtonPress(XButtonEvent *event) {
00628
00629 event->state &= Binder::instance()->validModMask();
00630
00631 if (event->state != 0) {
00632
00633 Binder::instance()->handleButton(event->root, event);
00634 return;
00635 }
00636
00637 Menu *menu = menuWindow(event->window);
00638 if (menu) {
00639 menu->handleButtonPress(event);
00640 return;
00641 }
00642
00643 Bar *bar = barWindow(event->window);
00644 if (bar) {
00645 bar->handleButtonPress(event);
00646 return;
00647 }
00648
00649 #ifdef SLOT_SUPPORT
00650 Slot *slot = slotWindow(event->window);
00651 if (slot) {
00652 slot->handleButtonPress(event);
00653 return;
00654 }
00655 #endif
00656
00657 Thing *thing = thingWindow(event->window);
00658
00659 if (thing) {
00660 thing->handleButtonPress(event);
00661 }
00662
00663 Client *client = clientForWindow(event->window);
00664 if (client) {
00665 client->handleButtonPress(event);
00666 }
00667 }
00668
00669 void Kernel::handleConfigureRequest(XConfigureRequestEvent *event) {
00670
00671 Client *client = clientForWindow(event->window);
00672
00673 if (client) {
00674 client->handleConfigureRequest(event);
00675 }
00676 else {
00677 XWindowChanges wc;
00678
00679 wc.x = event->x;
00680 wc.y = event->y;
00681 wc.width = event->width;
00682 wc.height = event->height;
00683 wc.border_width = 0;
00684 wc.sibling = None;
00685 wc.stack_mode = Above;
00686 event->value_mask &= ~CWStackMode;
00687 event->value_mask |= CWBorderWidth;
00688
00689 XCORE->configureWindow(event->window, event->value_mask, &wc);
00690 }
00691 }
00692
00693 void Kernel::handleDestroyNotify(XDestroyWindowEvent *event) {
00694
00695 Client *client = clientForWindow(event->window);
00696
00697 if (client) {
00698 if (event->window == client->clientWindow()) {
00699 client->setDestroyed(true);
00700 client->monitor()->removeClient(client);
00701 delete client;
00702 }
00703 }
00704 }
00705
00706 void Kernel::handleExpose(XExposeEvent *event) {
00707
00708 Bar *bar = barWindow(event->window);
00709 if (bar) {
00710 bar->illuminate();
00711 return;
00712 }
00713
00714 #ifdef SLOT_SUPPORT
00715 Slot *slot = slotWindow(event->window);
00716 if (slot) {
00717 slot->illuminate();
00718 return;
00719 }
00720 #endif // SLOT_SUPPORT
00721
00722 Thing *thing = thingWindow(event->window);
00723 if (thing) {
00724 thing->illuminate();
00725 }
00726 }
00727
00728 void Kernel::handleKeyPress(XKeyEvent *event) {
00729
00730 event->state &= Binder::instance()->validModMask();
00731
00732 if (isInputMode()) {
00733 focusedMonitor()->inputBar()->handleInput(event);
00734 }
00735 else {
00736 Binder::instance()->handleKey(event->root, event);
00737 updateBars();
00738 }
00739 }
00740
00741 void Kernel::handleMapRequest(XMapRequestEvent *event) {
00742
00743 if (isNCWMWindow(event->window)) {
00744 return;
00745 }
00746
00747 XWindowAttributes attr;
00748 XCORE->windowAttributes(event->window, &attr);
00749
00750 if (attr.override_redirect) {
00751 LOGDEBUG("override redirect!");
00752 return;
00753 }
00754
00755 Client *client = clientForWindow(event->window);
00756
00757 if (!client) {
00758 client = new Client(focusedMonitor(), event->window, &attr);
00759 focusedMonitor()->addClient(client);
00760 LOGDEBUG("client created");
00761 }
00762 else if (client->attached()) {
00763 client->setRequestsFocus(true);
00764 client->attached()->setRequestsFocus(true);
00765 return;
00766 }
00767
00768 ostringstream oss;
00769 oss << "client dims: " << client->x() << "," <<
00770 client->y() << "," << client->width() << "," <<
00771 client->height();
00772 LOGDEBUG(oss.str());
00773
00775 focusedMonitor()->attachClient(client);
00776 }
00777
00778 void Kernel::handleMotionNotify(XMotionEvent *event) {
00779
00780 Menu *menu = menuWindow(event->window);
00781 if (menu) {
00782 menu->handleMotionNotify(event);
00783 }
00784
00785 Bar *bar = barWindow(event->window);
00786 if (bar) {
00787 bar->handleMotionNotify(event);
00788 return;
00789 }
00790
00791 Thing *thing = thingWindow(event->window);
00792 if (thing) {
00793 if (!thing->isFocused() && isSloppyMode_) {
00794 Workspace *workspace = focusedMonitor()->focused();
00795 workspace->focus(thing, false);
00796 }
00797 thing->handleMotionNotify(event);
00798 }
00799
00800
00801 isRootWindow(event->root);
00802 }
00803
00804 void Kernel::handlePropertyNotify(XPropertyEvent *event) {
00805
00806 if (!isRootWindow(event->window)) {
00807
00808 Client *client = clientForWindow(event->window);
00809 ostringstream oss;
00810 oss << "property atom: " << XCORE->atomName(event->atom);
00811 LOGDEBUG(oss.str());
00812
00813 if (client) {
00814 client->handlePropertyNotify(event);
00815 }
00816 return;
00817 }
00818
00819
00820 if (event->atom == Atoms::NCWM_STATUSTEXT ||
00821 event->atom == Atoms::NCWM_METERTEXT)
00822 {
00823 focusedMonitor()->updateBars();
00824 return;
00825 }
00826 else if (event->atom == Atoms::NCWM_ACTIONCMD) {
00827
00828
00829
00830 string actionCmd;
00831 if (XCORE->textProperty(defaultRootWindow(),
00832 Atoms::NCWM_ACTIONCMD, &actionCmd))
00833 {
00834 string bind, arg;
00835 unsigned int pos = actionCmd.find_first_of('+');
00836 if (pos != string::npos) {
00837 bind = actionCmd.substr(0, pos);
00838 arg = actionCmd.substr(pos + 1);
00839 }
00840 else {
00841 bind = actionCmd;
00842 }
00843
00844
00845 Action *action = Util::get(actionBindings_, bind);
00846 if (action && pos != string::npos) {
00847 action->setArgument((char *)arg.c_str());
00848 }
00849
00850 if (action) {
00851 if ((action->promptsCount() > 0) && !action->argument()) {
00852 focusedMonitor()->inputBar()->runArgument(action);
00853
00854 }
00855 else {
00856 action->perform();
00857 }
00858 }
00859
00860 }
00861 return;
00862 }
00863 else if (event->atom == Atoms::NCWM_PRETTYPRINT_REQUEST) {
00864
00865 XTextProperty property;
00866 XCORE->stringListToTextProperty(
00867 Binder::instance()->prettyPrintKeyBindings(), &property);
00868 XCORE->setTextProperty(display_, defaultRootWindow(),
00869 &property, Atoms::NCWM_PRETTYPRINT_RESPONSE);
00870 }
00871 }
00872
00873 void Kernel::handleUnmapNotify(XUnmapEvent *event) {
00874 LOGDEBUG("handle unmap notify");
00875 Client *client = clientForWindow(event->window);
00876
00877 if (client) {
00878 LOGDEBUG("got unmap client");
00879 client->handleUnmapNotify(event);
00880 }
00881 }
00882
00883 void Kernel::handleClientMessage(XClientMessageEvent *event) {
00884
00885 LOGDEBUG("handle client message");
00886 if (event->message_type == Atoms::WM_CHANGE_STATE) {
00887 Client *client = clientForWindow(event->window);
00888
00889 if (client && client->monitor()
00890 && (event->format == 32)
00891 && (event->data.l[0] == IconicState))
00892 {
00893 client->monitor()->detachClient(client);
00894 }
00895 }
00896 }
00897
00898 int Kernel::run() {
00899 XEvent event;
00900
00901 LOGDEBUG("main event loop launched");
00902 ostringstream oss;
00903 while (runlevel_ == Kernel::RUN) {
00904
00905 XCORE->nextEvent(&event);
00906 switch (event.type) {
00907 case ButtonPress:
00908 LOGDEBUG("button press event");
00909 handleButtonPress(&event.xbutton);
00910 break;
00911 case ButtonRelease:
00912 LOGDEBUG("button release event");
00913 handleButtonRelease(&event.xbutton);
00914 break;
00915 case ClientMessage:
00916 LOGDEBUG("client message event");
00917 handleClientMessage(&event.xclient);
00918 break;
00919 case ConfigureRequest:
00920 LOGDEBUG("configure request event");
00921 handleConfigureRequest(&event.xconfigurerequest);
00922 break;
00923 case DestroyNotify:
00924 LOGDEBUG("destroy window event");
00925 handleDestroyNotify(&event.xdestroywindow);
00926 break;
00927 case Expose:
00928 LOGDEBUG("expose event");
00929 handleExpose(&event.xexpose);
00930 break;
00931 case KeyPress:
00932 LOGDEBUG("keypress event");
00933 handleKeyPress(&event.xkey);
00934 break;
00935 case MapRequest:
00936 LOGDEBUG("map request event");
00937 handleMapRequest(&event.xmaprequest);
00938 break;
00939 case MotionNotify:
00940 LOGDEBUG("motion event");
00941 handleMotionNotify(&event.xmotion);
00942 break;
00943 case PropertyNotify:
00944 LOGDEBUG("property event");
00945 handlePropertyNotify(&event.xproperty);
00946 break;
00947 case UnmapNotify:
00948 LOGDEBUG("unmap event");
00949 handleUnmapNotify(&event.xunmap);
00950 break;
00951 }
00952
00953 }
00954 return 0;
00955 }
00956
00957 void Kernel::runResizeMode(Thing *thing, XButtonEvent *buttonEvent,
00958 Direction dir, bool resize)
00959 {
00960 Window window = thing->window();
00961 if (!window) {
00962 return;
00963 }
00964
00965 Monitor *monitor = thing->monitor();
00966 Window rootWindow = monitor->rootWindow();
00967 Thing::Type type = thing->type();
00968 Workspace *workspace = (type == Thing::CLIENT) ?
00969 ((Client *)thing)->attached() : ((Frame *)thing)->attached();
00970
00971 if (!workspace) {
00972 return;
00973 }
00974
00975 int origX, origY, lastX, lastY, newX, newY, dx, dy;
00976 Rectangle rect(*thing);
00977
00978 XCORE->translateCoordinates(window, rootWindow,
00979 buttonEvent->x, buttonEvent->y,
00980 &lastX, &lastY);
00981 newX = newY = 0;
00982 origX = lastX;
00983 origY = lastY;
00984
00985 XCORE->grabPointer(window,
00986 ButtonMotionMask | ButtonReleaseMask,
00987 buttonEvent->time);
00988
00989 XEvent event;
00990 bool done = false, found = false, firstMotion = true;
00991
00992 XCORE->grabServer();
00993 while (!done) {
00994 found = false;
00995
00996 while (XCORE->checkMaskEvent(
00997 ButtonReleaseMask | ButtonMotionMask, &event))
00998 {
00999 found = true;
01000
01001 if (event.type != MotionNotify) {
01002 break;
01003 }
01004 }
01005
01006 if (!found) {
01007 usleep(20000);
01008 continue;
01009 }
01010
01011 switch (event.type) {
01012 case ButtonRelease:
01013 if (!firstMotion) {
01014 monitor->illuminateTransRect(&rect, thing->titleBarHeight());
01015
01016 dx = newX - origX;
01017 dy = newY - origY;
01018
01019 if ((dir == LEFT) || (dir == UP)) {
01020
01021 dx *= -1;
01022 dy *= -1;
01023 }
01024
01025 if (type == Thing::FRAME) {
01026 Split::resize(workspace->root(),
01027 ((Frame *)thing)->tree(),
01028 dir, dx, dy);
01029 }
01030 else {
01031 thing->copy(&rect);
01032 thing->resize();
01033 thing->illuminate();
01034 }
01035 XCORE->sync();
01036 }
01037 XCORE->ungrabPointer(event.xbutton.time);
01038 XCORE->ungrabServer();
01039 done = true;
01040 break;
01041 case MotionNotify:
01042 XCORE->translateCoordinates(event.xmotion.window,
01043 rootWindow, event.xmotion.x, event.xmotion.y,
01044 &newX, &newY);
01045
01046 dx = newX - lastX;
01047 dy = newY - lastY;
01048
01049 lastX = newX;
01050 lastY = newY;
01051
01052 if (firstMotion) {
01053 firstMotion = false;
01054 }
01055 else {
01056 monitor->illuminateTransRect(&rect, thing->titleBarHeight());
01057 }
01058
01059 if (type == Thing::FRAME) {
01060 switch (dir) {
01061 case LEFT:
01062 rect.setX(rect.x() + dx);
01063 rect.setWidth(rect.width() - dx);
01064 break;
01065 case RIGHT:
01066 rect.setWidth(rect.width() + dx);
01067 break;
01068 case UP:
01069 rect.setY(rect.y() + dy);
01070 rect.setHeight(rect.height() - dy);
01071 break;
01072 case DOWN:
01073 rect.setHeight(rect.height() + dy);
01074 break;
01075 default:
01076 break;
01077 }
01078 }
01079 else {
01080
01081 if (resize) {
01082 Float::resize(&rect, dir, dx, dy);
01083 }
01084 else {
01085 Float::move(&rect, dx, dy);
01086 }
01087 }
01088 monitor->illuminateTransRect(&rect, thing->titleBarHeight());
01089 break;
01090 }
01091 }
01092 }
01093
01094 void Kernel::beginRecording() {
01095 isRecording_ = true;
01096 assert(recordedActions_.size() == 0);
01097 }
01098
01099 void Kernel::endChainRecording(string name) {
01100 isRecording_ = false;
01101 if (recordedActions_.size() == 0) {
01102 return;
01103 }
01104
01105 string chain = "";
01106 Action *firstAction = 0;
01107 for (LAction::iterator it = recordedActions_.begin();
01108 it != recordedActions_.end(); )
01109 {
01110 Action *action = *it;
01111
01112 it++;
01113 if (action->argument()) {
01114 chain += action->id() + "+" + action->argument();
01115 }
01116 else {
01117 chain += action->id();
01118 }
01119 if (it != recordedActions_.end()) {
01120 chain += ",";
01121 }
01122
01123 if (it == recordedActions_.begin()) {
01124 firstAction = action;
01125 }
01126 else {
01127 delete action;
01128 }
01129 }
01130
01131 recordedActions_.clear();
01132
01133 IsValid isValid = 0;
01134 if (firstAction) {
01135 isValid = firstAction->getIsValid();
01136 }
01137 else {
01138 isValid = &Validators::isAlwaysPossible;
01139 }
01140 delete firstAction;
01141
01142 (*actionSettings_)["chain." + name + ".seq"] = chain;
01143 Action *action = new Action(name, &Actions::sequence, isValid,
01144 Action::SEQUENCE, (char *)chain.c_str());
01145 (*actionBindings_)[name] = action;
01146 }
01147
01148 void Kernel::cancelRecording() {
01149 isRecording_ = false;
01150 if (recordedActions_.size() == 0) {
01151 return;
01152 }
01153
01154 recordedActions_.clear();
01155 }
01156
01157
01158 void Kernel::endScriptRecording(string name) {
01159 isRecording_ = false;
01160 if (recordedActions_.size() == 0) {
01161 return;
01162 }
01163
01164 string script = "#!/bin/sh\n";
01165 for (LAction::iterator it = recordedActions_.begin();
01166 it != recordedActions_.end(); )
01167 {
01168 Action *action = *it;
01169
01170 it++;
01171 script += "ncwmremote -a \"";
01172 if (action->argument()) {
01173 script += action->id() + "+" + action->argument();
01174 }
01175 else {
01176 script += action->id();
01177 }
01178 script += "\"\n";
01179
01180 delete action;
01181 }
01182
01183 recordedActions_.clear();
01184
01185
01186 Loader::saveFile(name, script);
01187 }
01188
01189
01190 MSettings *Kernel::themeSettings() {
01191 return themeSettings_;
01192 }
01193
01194 MSettings *Kernel::commonSettings() {
01195 return commonSettings_;
01196 }
01197
01198 MSettings *Kernel::actionSettings() {
01199 return actionSettings_;
01200 }
01201
01202 MSettings *Kernel::sessionSettings() {
01203 return sessionSettings_;
01204 }
01205
01206 Display *Kernel::display() const {
01207 return display_;
01208 }
01209
01210 Monitor *Kernel::focusedMonitor() const {
01211 return monitors_->focused();
01212 }
01213
01214 Kernel::Runlevel Kernel::runlevel() const {
01215 return runlevel_;
01216 }
01217
01218 void Kernel::restart() {
01219 runlevel_ = RESTART;
01220 }
01221
01222 void Kernel::stop() {
01223 runlevel_ = STOP;
01224 }
01225
01226 MBindings *Kernel::actionBindings() const {
01227 return actionBindings_;
01228 }
01229
01230
01231 bool Kernel::isRecording() const {
01232 return isRecording_;
01233 }
01234
01235 LAction *Kernel::recordedActions() {
01236 return &recordedActions_;
01237 }
01238
01239 unsigned int Kernel::borderWidth() const {
01240 return borderWidth_;
01241 }
01242
01243 void Kernel::setMenuMode(bool isMenuMode) {
01244 isMenuMode_ = isMenuMode;
01245 }
01246
01247 void Kernel::toggleSloppyMode() {
01248 isSloppyMode_ = !isSloppyMode_;
01249 }
01250
01251 bool Kernel::isStackedTabbing() const {
01252 return isStackedTabbing_;
01253 }
01254
01255 CMonitor *Kernel::monitors() const {
01256 return monitors_;
01257 }
01258
01259 void Kernel::selectMonitor(string displayString) {
01260
01261 for (LMonitor::iterator it = monitors_->begin();
01262 it != monitors_->end(); it++)
01263 {
01264 Monitor *monitor = *it;
01265 if (monitor->displayString() == displayString) {
01266 if (monitors_->focused() != monitor) {
01267 XCORE->warpPointer(monitor->rootWindow(),
01268 monitor->width() / 2,
01269 monitor->height() / 2);
01270 monitors_->focus(monitor);
01271 Workspace *ws = monitor->focused();
01272 ws->focus(ws->topClient());
01273 }
01274 return;
01275 }
01276 }
01277 }
01278
01279 void Kernel::grabMove() {
01280
01281 Client *client = focusedClient();
01282 if (!client || client->frame()) {
01283 return;
01284 }
01285 XCORE->warpPointer(client->window(),
01286 client->width() / 2,
01287 client->height() / 2);
01288 XButtonEvent event;
01289 event.x = client->width() / 2;
01290 event.y = client->height() / 2;
01291 event.time = CurrentTime;
01292 runResizeMode(client, &event, LEFT, false);
01293 }