src/kernel.cpp

Go to the documentation of this file.
00001 // Copyright (c) 2003 - 2004 Anselm R. Garbe <anselmg at t-online.de>
00002 // See ../LICENSE.txt for license details.
00003 //
00004 // $Id: kernel.cpp 7 2007-05-24 11:03:53Z eg1981 $
00005 
00006 extern "C" {
00007 #include <assert.h>
00008 #include <stdlib.h> // getenv stuff
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     // init, order is very important
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     // Sync all X buffers and wait until all events has been
00106     // processed
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(); // rehash expander
00121 
00122     // Launch main event loop
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); // always, while running
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     // extract all extern actions and chain sequences
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) { // settingsKey has a valid action prefix
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                     // We determine the first sequential action and use
00251                     // its possibility method (or if it's user defined we
00252                     // allow sequential performing under all
00253                     // circumstances).
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     // extract all key bindings, if they're defined
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             // settingsKey has a valid action prefix
00304             if (postfix == "keys") {
00305                 keys = (*it).second;
00306 
00307                 if (keys != "") {
00308 
00309                     // fetch action
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     // actions and session will be safed under any circumstances saved
00585     // comments will be lost in these files
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     // TODO: theme, etc.
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         // no AnyModifier, so this seems to be shortcut
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; // we ignore Map Requests from those clients
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     // focusses the monitor if multihead
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     // check if status text has been changed
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         // TODO
00829         // action[+arg1[...]]
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             // query action
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                     // action will be performed by argument processing
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                     // normalization
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; // ButtonRelease
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; // MotionNotify
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     // clean up
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     // clean up
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     // clean up
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 }

Generated on Thu May 24 15:19:32 2007 for ncwm by  doxygen 1.5.1