news download themes documentation links










Remember.cc

00001 // Remember.cc for Fluxbox Window Manager
00002 // Copyright (c) 2002 Xavier Brouckaert
00003 // Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net)
00004 //                and Simon Bowden    (rathnor at users.sourceforge.net)
00005 //
00006 // Permission is hereby granted, free of charge, to any person obtaining a
00007 // copy of this software and associated documentation files (the "Software"),
00008 // to deal in the Software without restriction, including without limitation
00009 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
00010 // and/or sell copies of the Software, and to permit persons to whom the
00011 // Software is furnished to do so, subject to the following conditions:
00012 //
00013 // The above copyright notice and this permission notice shall be included in
00014 // all copies or substantial portions of the Software.
00015 //
00016 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00017 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00018 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00019 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00020 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00021 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00022 // DEALINGS IN THE SOFTWARE.
00023 
00024 // $Id: Remember.cc,v 1.33 2003/12/19 00:48:41 fluxgen Exp $
00025 
00026 #include "Remember.hh"
00027 #include "ClientPattern.hh"
00028 #include "Screen.hh"
00029 #include "Window.hh"
00030 #include "WinClient.hh"
00031 #include "FbMenu.hh"
00032 #include "FbCommands.hh"
00033 #include "fluxbox.hh"
00034 
00035 #include "FbTk/StringUtil.hh"
00036 #include "FbTk/MenuItem.hh"
00037 #include "FbTk/App.hh"
00038 
00039 
00040 #include <X11/Xlib.h>
00041 
00042 //use GNU extensions
00043 #ifndef  _GNU_SOURCE
00044 #define  _GNU_SOURCE
00045 #endif // _GNU_SOURCE
00046 
00047 
00048 #include <iostream>
00049 #include <fstream>
00050 #include <string>
00051 #include <memory>
00052 #include <set>
00053 
00054 #ifdef HAVE_CONFIG_H
00055 #include "config.h"
00056 #endif // HAVE_CONFIG_H
00057 
00058 #ifdef HAVE_SSTREAM
00059 #include <sstream>
00060 #define FB_istringstream istringstream
00061 #elif HAVE_STRSTREAM 
00062 #include <strstream>
00063 #define FB_istringstream istrstream
00064 #else
00065 #error "You dont have sstream or strstream headers!"
00066 #endif // HAVE_STRSTREAM
00067 
00068 using namespace std;
00069 
00070 #ifndef    MAXPATHLEN
00071 #define    MAXPATHLEN 255
00072 #endif // MAXPATHLEN
00073 
00074 namespace {
00075 
00076 class RememberMenuItem : public FbTk::MenuItem {
00077 public:
00078     RememberMenuItem(const char *label, Remember &remember,
00079                      FluxboxWindow &fbwin,
00080                      Remember::Attribute attrib) :
00081         FbTk::MenuItem(label), m_remember(remember), 
00082         m_win(fbwin), m_attrib(attrib) {}
00083 
00084     bool isSelected() const {
00085         return m_remember.isRemembered(m_win.winClient(), m_attrib);
00086     }
00087 
00088     bool isEnabled() const {
00089         if (m_attrib != Remember::REM_JUMPWORKSPACE) 
00090             return true;
00091         else 
00092             return (m_remember.isRemembered(m_win.winClient(), Remember::REM_WORKSPACE));
00093     }
00094 
00095     void click(int button, int time) {
00096         if (isSelected()) {
00097             m_remember.forgetAttrib(m_win.winClient(), m_attrib);
00098         } else {
00099             m_remember.rememberAttrib(m_win.winClient(), m_attrib);
00100         }
00101         m_remember.save();
00102         FbTk::MenuItem::click(button, time);
00103     }
00104 
00105 private:
00106     // my remember manager
00107     Remember &m_remember;
00108     FluxboxWindow &m_win;
00109     Remember::Attribute m_attrib;
00110 };
00111 
00112 FbTk::Menu *createRememberMenu(Remember &remember, FluxboxWindow &win, bool enabled) {
00113     // each fluxboxwindow has its own windowmenu
00114     // so we also create a remember menu just for it...
00115     FbTk::Menu *menu = win.screen().createMenu("");
00116 
00117     // if enabled, then we want this to be a unavailable menu
00118     if (!enabled) {
00119         FbTk::MenuItem *item = new FbTk::MenuItem("unavailable");
00120         item->setEnabled(false);
00121         menu->insert(item);
00122         menu->update();
00123         return menu;
00124     }
00125     
00126     // TODO: nls
00127     menu->insert(new RememberMenuItem("Workspace", remember, win,
00128                                       Remember::REM_WORKSPACE));
00129     menu->insert(new RememberMenuItem("Jump to workspace", remember, win,
00130                                       Remember::REM_JUMPWORKSPACE));
00131     menu->insert(new RememberMenuItem("Dimensions", remember, win,
00132                                       Remember::REM_DIMENSIONS));
00133     menu->insert(new RememberMenuItem("Position", remember, win,
00134                                       Remember::REM_POSITION));
00135     menu->insert(new RememberMenuItem("Sticky", remember, win,
00136                                       Remember::REM_STUCKSTATE));
00137     menu->insert(new RememberMenuItem("Decorations", remember, win,
00138                                       Remember::REM_DECOSTATE));
00139     menu->insert(new RememberMenuItem("Shaded", remember, win,
00140                                       Remember::REM_SHADEDSTATE));
00141     menu->insert(new RememberMenuItem("Layer", remember, win,
00142                                       Remember::REM_LAYER));
00143     menu->insert(new RememberMenuItem("Save on close", remember, win,
00144                                       Remember::REM_SAVEONCLOSE));
00145 
00146     menu->update();
00147     return menu;
00148 };
00149 
00150 // offset is the offset in the string that we start looking from
00151 // return true if all ok, false on error
00152 bool handleStartupItem(const string &line, int offset) {
00153     int next = 0;
00154     string str;
00155     int screen = 0;
00156 
00157     // accept some options, for now only "screen=NN"
00158     // these option are given in parentheses before the command
00159     next = FbTk::StringUtil::getStringBetween(str, 
00160                                               line.c_str() + offset, 
00161                                               '(', ')');
00162     if (next > 0) {
00163         // there are some options
00164         string option;
00165         int pos = str.find('=');
00166         bool error = false;
00167         if (pos > 0) {
00168             option = str.substr(0, pos);
00169             if (option == "screen") {
00170                 FB_istringstream iss(str.c_str() + pos + 1);
00171                 iss >> screen;
00172             } else {
00173                 error = true;
00174             }
00175         } else {
00176             error = true;
00177         }
00178         if (error) {
00179             cerr<<"Error parsing startup options."<<endl;
00180             return false;
00181         }
00182     } else {
00183         next = 0;
00184     }
00185 
00186     next = FbTk::StringUtil::getStringBetween(str, 
00187                                               line.c_str() + offset + next, 
00188                                               '{', '}');
00189 
00190     if (next <= 0) {
00191         cerr<<"Error parsing [startup] at column "<<offset<<" - expecting {command}."<<endl;
00192         return false;
00193     } else {
00194         FbCommands::ExecuteCmd *tmp_exec_cmd = new FbCommands::ExecuteCmd(str, screen);
00195 #ifdef DEBUG
00196         cerr<<"Executing startup command '"<<str<<"' on screen "<<screen<<endl;
00197 #endif // DEBUG
00198         tmp_exec_cmd->execute();
00199         delete tmp_exec_cmd;
00200         return true;
00201     }
00202 };
00203 
00204 }; // end anonymous namespace
00205 
00206 
00207 Application::Application(bool grouped)
00208     : is_grouped(grouped),
00209       group(0)
00210 {
00211     workspace_remember =
00212     dimensions_remember =
00213     position_remember =
00214     stuckstate_remember =
00215     decostate_remember =
00216     shadedstate_remember =
00217     tabstate_remember =
00218     jumpworkspace_remember =
00219         layer_remember =
00220     save_on_close_remember = false;
00221 }
00222 
00223 /********************************************************
00224  * Remember *
00225  ************/
00226 
00227 Remember::Remember() {
00228     enableUpdate();
00229     load();
00230 }
00231 
00232 Remember::~Remember() {
00233     // free our resources
00234 
00235     // the patterns free the "Application"s
00236     // the client mapping shouldn't need cleaning
00237     Patterns::iterator it;
00238     std::set<Application *> all_apps; // no duplicates
00239     while (!m_pats.empty()) {
00240         it = m_pats.begin();
00241         delete it->first; // ClientPattern
00242         all_apps.insert(it->second); // Application, not necessarily unique
00243         m_pats.erase(it);
00244     }
00245 
00246     std::set<Application *>::iterator ait = all_apps.begin(); // no duplicates
00247     while (ait != all_apps.end()) {
00248         delete (*ait);
00249         ++ait;
00250     }
00251 }
00252 
00253 Application* Remember::find(WinClient &winclient) {
00254     // if it is already associated with a application, return that one
00255     // otherwise, check it against every pattern that we've got
00256     Clients::iterator wc_it = m_clients.find(&winclient);
00257     if (wc_it != m_clients.end())
00258         return wc_it->second;
00259     else {
00260         Patterns::iterator it = m_pats.begin();
00261         for (; it != m_pats.end(); it++) 
00262             if (it->first->match(winclient)) {
00263                 it->first->addMatch();
00264                 m_clients[&winclient] = it->second;
00265                 return it->second;
00266             }
00267     }
00268     // oh well, no matches
00269     return 0;
00270 }
00271 
00272 Application * Remember::add(WinClient &winclient) {
00273     ClientPattern *p = new ClientPattern();
00274     Application *app = new Application(false);
00275     // by default, we match against the WMClass of a window.
00276     p->addTerm(p->getProperty(ClientPattern::NAME, winclient), ClientPattern::NAME);
00277     m_clients[&winclient] = app;
00278     p->addMatch();
00279     m_pats.push_back(make_pair(p, app));
00280     return app;
00281 }
00282 
00283 int Remember::parseApp(ifstream &file, Application &app, string *first_line) {
00284     string line;
00285     int row = 0;
00286     while (! file.eof()) {
00287         if (first_line || getline(file, line)) {
00288             if (first_line) {
00289                 line = *first_line;
00290                 first_line = 0;
00291             }
00292 
00293             row++;
00294             if (line[0] == '#')
00295                 continue;  //the line is commented
00296             int parse_pos = 0, err = 0;
00297             string str_key, str_option, str_label;
00298             err = FbTk::StringUtil::getStringBetween(str_key, 
00299                                                      line.c_str(), 
00300                                                      '[', ']');
00301             if (err > 0) {
00302                 int tmp;
00303                 tmp= FbTk::StringUtil::getStringBetween(str_option,
00304                                                         line.c_str() + err,
00305                                                         '(', ')');
00306                 if (tmp>0)
00307                   err += tmp;
00308             }
00309             if (err > 0 ) {
00310                 parse_pos += err;
00311                 err = FbTk::StringUtil::getStringBetween(str_label, 
00312                                                          line.c_str() + parse_pos, 
00313                                                          '{', '}');
00314                 if (err>0) {
00315                     parse_pos += err;
00316                 }
00317             } else
00318                 continue; //read next line
00319 
00320             if (!str_key.size())
00321                 continue; //read next line
00322             if (str_key == "Workspace") {
00323                 unsigned int w;
00324                 FB_istringstream iss(str_label.c_str());
00325                 iss >> w;
00326                 app.rememberWorkspace(w);
00327             } else if (str_key == "Layer") {
00328                 unsigned int l;
00329                 FB_istringstream iss(str_label.c_str());
00330                 iss >> l;
00331                 app.rememberLayer(l);
00332             } else if (str_key == "Dimensions") {
00333                 unsigned int h,w;
00334                 FB_istringstream iss(str_label.c_str());
00335                 iss >> w >> h;
00336                 app.rememberDimensions(w,h);
00337             } else if (str_key == "Position") {
00338                 FB_istringstream iss;
00339                 unsigned int r= 0;
00340                 unsigned int x= 0;
00341                 unsigned int y= 0;
00342                 // more info about the parameter
00343                 // in ::rememberPosition
00344                 
00345                 if ( str_option.length() )
00346                 {
00347                   if      ( str_option == "UPPERLEFT"  ) r= POS_UPPERLEFT;
00348                   else if ( str_option == "UPPERRIGHT" ) r= POS_UPPERRIGHT;
00349                   else if ( str_option == "LOWERLEFT"  ) r= POS_LOWERLEFT;
00350                   else if ( str_option == "LOWERRIGHT" ) r= POS_LOWERRIGHT;
00351                   else if ( str_option == "CENTER" )     r= POS_CENTER;
00352                   else if ( str_option == "WINCENTER" )  r= POS_WINCENTER;
00353                   else {
00354                       iss.str(str_option);
00355                       iss >> r;
00356                   }
00357                 }
00358 
00359                 iss.str(str_label.c_str());
00360                 iss >> x >> y;
00361                 app.rememberPosition(x, y, r);
00362             } else if (str_key == "Shaded") {
00363                 app.rememberShadedstate((str_label=="yes"));
00364             } else if (str_key == "Tab") {
00365                 app.rememberTabstate((str_label=="yes"));
00366             } else if (str_key == "Deco") {
00367                 if (str_label == "NONE") {
00368                     app.rememberDecostate((unsigned int) 0);
00369                 } else if (str_label == "NORMAL") {
00370                     app.rememberDecostate((unsigned int) 0xfffffff);
00371                 } else if (str_label == "TINY") {
00372                     app.rememberDecostate((unsigned int)
00373                                           FluxboxWindow::DECORM_TITLEBAR 
00374                                           | FluxboxWindow::DECORM_ICONIFY
00375                                           | FluxboxWindow::DECORM_MENU
00376                         );
00377                 } else if (str_label == "TOOL") {
00378                     app.rememberDecostate((unsigned int)
00379                                           FluxboxWindow::DECORM_TITLEBAR
00380                                           | FluxboxWindow::DECORM_MENU
00381                         );
00382                 } else if (str_label == "BORDER") {
00383                     app.rememberDecostate((unsigned int)
00384                                           FluxboxWindow::DECORM_BORDER
00385                                           | FluxboxWindow::DECORM_MENU
00386                         );
00387                 } else {
00388                     unsigned int mask;
00389                     const char * str = str_label.c_str();
00390                     // it'll have at least one char and \0, so this is safe
00391                     FB_istringstream iss(str);
00392                     // check for hex
00393                     if (str[0] == '0' && str[1] == 'x') {
00394                         iss.seekg(2);
00395                         iss >> hex;
00396                     }
00397                     iss >> mask ;
00398                     app.rememberDecostate(mask);
00399                 }
00400             } else if (str_key == "Sticky") {
00401                 app.rememberStuckstate((str_label=="yes"));
00402             } else if (str_key == "Jump") {
00403                 app.rememberJumpworkspace((str_label=="yes"));
00404             } else if (str_key == "Close") {
00405                 app.rememberSaveOnClose((str_label=="yes"));
00406             } else if (str_key == "end") {
00407                 return row;
00408             } else {
00409                 cerr << "Unsupported apps key = " << str_key << endl;
00410             }
00411         }
00412     }
00413     return row;
00414 }
00415 
00416 void Remember::load() {
00417 
00418     string apps_string;
00419     Fluxbox::instance()->getDefaultDataFilename("apps", apps_string);
00420 
00421 #ifdef DEBUG
00422     cerr<<__FILE__<<"("<<__FUNCTION__<<"): Loading apps file ["<<apps_string<<"]"<<endl;
00423 #endif // DEBUG
00424     ifstream apps_file(apps_string.c_str());
00425 
00426     if (!apps_file.fail()) {
00427         if (!apps_file.eof()) {
00428             string line;
00429             int row = 0;
00430             bool in_group = false;
00431             std::list<ClientPattern *> grouped_pats;
00432             while (getline(apps_file, line) && ! apps_file.eof()) {
00433                 row++;
00434                 if (line[0] == '#')
00435                     continue;
00436                 string key;
00437                 int err=0;
00438                 int pos = FbTk::StringUtil::getStringBetween(key, 
00439                                                              line.c_str(), 
00440                                                              '[', ']');
00441 
00442                 if (pos > 0 && key == "app") {
00443                     ClientPattern *pat = new ClientPattern(line.c_str() + pos);
00444                     if (!in_group) {
00445                         if ((err = pat->error()) == 0) {
00446                             Application *app = new Application(false);
00447                             m_pats.push_back(make_pair(pat, app));
00448                             row += parseApp(apps_file, *app);
00449                         } else {
00450                             cerr<<"Error reading apps file at line "<<row<<", column "<<(err+pos)<<"."<<endl;
00451                             delete pat; // since it didn't work
00452                         }
00453                     } else {
00454                         grouped_pats.push_back(pat);
00455                     }
00456                 } else if (pos > 0 && key == "startup") {
00457                     if (!handleStartupItem(line, pos)) {
00458                         cerr<<"Error reading apps file at line "<<row<<"."<<endl;
00459                     }
00460                     // save the item even if it was bad (aren't we nice)
00461                     m_startups.push_back(line.substr(pos));
00462                 } else if (pos > 0 && key == "group") {
00463                     in_group = true;
00464                 } else if (in_group) {
00465                     // otherwise assume that it is the start of the attributes
00466                     Application *app = new Application(true);
00467                     while (!grouped_pats.empty()) {
00468                         // associate all the patterns with this app
00469                         m_pats.push_back(make_pair(grouped_pats.front(), app));
00470                         grouped_pats.pop_front();
00471                     }
00472                     
00473                     // we hit end... probably don't have attribs for the group
00474                     // so finish it off with an empty application
00475                     // otherwise parse the app
00476                     if (!(pos>0 && key == "end")) {
00477                         row += parseApp(apps_file, *app, &line);
00478                     }
00479                     in_group = false;
00480                 } else
00481                     cerr<<"Error in apps file on line "<<row<<"."<<endl;
00482                 
00483             }
00484         } else {
00485 #ifdef DEBUG
00486             cerr<<__FILE__<<"("<<__FUNCTION__<< ") Empty apps file" << endl;
00487 #endif
00488         }
00489     } else {
00490         cerr << "apps file failure" << endl;
00491     }
00492 }
00493 
00494 void Remember::save() {
00495 #ifdef DEBUG
00496     cerr<<__FILE__<<"("<<__FUNCTION__<<"): Saving apps file..."<<endl;
00497 #endif // DEBUG
00498     string apps_string;
00499     Fluxbox::instance()->getDefaultDataFilename("apps", apps_string);
00500     ofstream apps_file(apps_string.c_str());
00501 
00502     // first of all we output all the startup commands
00503     Startups::iterator sit = m_startups.begin();
00504     Startups::iterator sit_end = m_startups.end();
00505     for (; sit != sit_end; ++sit) {
00506         apps_file<<"[startup] "<<(*sit)<<endl;
00507     }
00508 
00509     Patterns::iterator it = m_pats.begin();
00510     Patterns::iterator it_end = m_pats.end();
00511 
00512     std::set<Application *> grouped_apps; // no duplicates
00513 
00514     for (; it != it_end; ++it) {
00515         Application &a = *it->second;
00516         if (a.is_grouped) {
00517             // if already processed
00518             if (grouped_apps.find(&a) != grouped_apps.end())
00519                 continue;
00520             grouped_apps.insert(&a);
00521             // otherwise output this whole group
00522             apps_file << "[group]" << endl;
00523             Patterns::iterator git = m_pats.begin();
00524             Patterns::iterator git_end = m_pats.end();
00525             for (; git != git_end; git++) {
00526                 if (git->second == &a) {
00527                     apps_file << " [app]"<<git->first->toString()<<endl;
00528                 }
00529             }
00530         } else {
00531             apps_file << "[app]"<<it->first->toString()<<endl;
00532         }
00533         if (a.workspace_remember) {
00534             apps_file << "  [Workspace]\t{" << a.workspace << "}" << endl;
00535         }
00536         if (a.dimensions_remember) {
00537             apps_file << "  [Dimensions]\t{" << a.w << " " << a.h << "}" << endl;
00538         }
00539         if (a.position_remember) {
00540             apps_file << "  [Position]\t{" << a.x << " " << a.y << "}" << endl;
00541         }
00542         if (a.shadedstate_remember) {
00543             apps_file << "  [Shaded]\t{" << ((a.shadedstate)?"yes":"no") << "}" << endl;
00544         }
00545         if (a.tabstate_remember) {
00546             apps_file << "  [Tab]\t\t{" << ((a.tabstate)?"yes":"no") << "}" << endl;
00547         }
00548         if (a.decostate_remember) {
00549             switch (a.decostate) {
00550             case (0) :
00551                 apps_file << "  [Deco]\t{NONE}" << endl; 
00552                 break;
00553             case (0xffffffff):
00554             case (FluxboxWindow::DECORM_LAST - 1):
00555                 apps_file << "  [Deco]\t{NORMAL}" << endl;
00556                 break;
00557             case (FluxboxWindow::DECORM_TITLEBAR 
00558                   | FluxboxWindow::DECORM_ICONIFY
00559                   | FluxboxWindow::DECORM_MENU):
00560                 apps_file << "  [Deco]\t{TOOL}" << endl;
00561                 break;
00562             case (FluxboxWindow::DECORM_TITLEBAR 
00563                   | FluxboxWindow::DECORM_MENU):
00564                 apps_file << "  [Deco]\t{TINY}" << endl;
00565                 break;
00566             case (FluxboxWindow::DECORM_BORDER 
00567                   | FluxboxWindow::DECORM_MENU):
00568                 apps_file << "  [Deco]\t{BORDER}" << endl;
00569                 break;
00570             default:
00571                 apps_file << "  [Deco]\t{0x"<<hex<<a.decostate<<dec<<"}"<<endl;
00572                 break;
00573             }
00574         }
00575         if (a.stuckstate_remember) {
00576             apps_file << "  [Sticky]\t{" << ((a.stuckstate)?"yes":"no") << "}" << endl;
00577         }
00578         if (a.jumpworkspace_remember) {
00579             apps_file << "  [Jump]\t{" << ((a.jumpworkspace)?"yes":"no") << "}" << endl;
00580         }
00581         if (a.layer_remember) {
00582             apps_file << "  [Layer]\t{" << a.layer << "}" << endl;
00583         }
00584         if (a.save_on_close_remember) {
00585             apps_file << "  [Close]\t{" << ((a.save_on_close)?"yes":"no") << "}" << endl;
00586         }
00587         apps_file << "[end]" << endl;
00588     }
00589 }
00590 
00591 bool Remember::isRemembered(WinClient &winclient, Attribute attrib) {
00592     Application *app = find(winclient);
00593     if (!app) return false;
00594     switch (attrib) {
00595     case REM_WORKSPACE:
00596         return app->workspace_remember;
00597         break;
00598     case REM_DIMENSIONS:
00599         return app->dimensions_remember;
00600         break;
00601     case REM_POSITION:
00602         return app->position_remember;
00603         break;
00604     case REM_STUCKSTATE:
00605         return app->stuckstate_remember;
00606         break;
00607     case REM_DECOSTATE:
00608         return app->decostate_remember;
00609         break;
00610     case REM_SHADEDSTATE:
00611         return app->shadedstate_remember;
00612         break;
00613         //    case REM_TABSTATE:
00614         //        return app->tabstate_remember;
00615         //        break;
00616     case REM_JUMPWORKSPACE:
00617         return app->jumpworkspace_remember;
00618         break;
00619     case REM_LAYER:
00620         return app->layer_remember;
00621         break;
00622     case REM_SAVEONCLOSE:
00623         return app->save_on_close_remember;
00624         break;
00625     case REM_LASTATTRIB:
00626     default:
00627         return false; // should never get here
00628     }
00629 }
00630 
00631 void Remember::rememberAttrib(WinClient &winclient, Attribute attrib) {
00632     FluxboxWindow *win = winclient.fbwindow();
00633     if (!win) return;
00634     Application *app = find(winclient);
00635     if (!app) {
00636         app = add(winclient);
00637         if (!app) return;
00638     }
00639     switch (attrib) {
00640     case REM_WORKSPACE:
00641         app->rememberWorkspace(win->workspaceNumber());
00642         break;
00643     case REM_DIMENSIONS:
00644         app->rememberDimensions(win->width(), win->height());
00645         break;
00646     case REM_POSITION:
00647         app->rememberPosition(win->x(), win->y());
00648         break;
00649     case REM_SHADEDSTATE:
00650         app->rememberShadedstate(win->isShaded());
00651         break;
00652     case REM_DECOSTATE:
00653         app->rememberDecostate(win->decorationMask());
00654         break;
00655     case REM_STUCKSTATE:
00656         app->rememberStuckstate(win->isStuck());
00657         break;
00658         //    case REM_TABSTATE:
00659         //        break;
00660     case REM_JUMPWORKSPACE:
00661         app->rememberJumpworkspace(true);
00662         break;
00663     case REM_LAYER:
00664         app->rememberLayer(win->layerNum());
00665         break;
00666     case REM_SAVEONCLOSE:
00667         app->rememberSaveOnClose(true);
00668         break;
00669     case REM_LASTATTRIB:
00670     default:
00671         // nothing
00672         break;
00673     }
00674 }
00675 
00676 void Remember::forgetAttrib(WinClient &winclient, Attribute attrib) {
00677     FluxboxWindow *win = winclient.fbwindow();
00678     if (!win) return;
00679     Application *app = find(winclient);
00680     if (!app) {
00681         app = add(winclient);
00682         if (!app) return;
00683     }
00684     switch (attrib) {
00685     case REM_WORKSPACE:
00686         app->forgetWorkspace();
00687         break;
00688     case REM_DIMENSIONS:
00689         app->forgetDimensions();
00690         break;
00691     case REM_POSITION:
00692         app->forgetPosition();
00693         break;
00694     case REM_STUCKSTATE:
00695         app->forgetStuckstate();
00696         break;
00697     case REM_DECOSTATE:
00698         app->forgetDecostate();
00699         break;
00700     case REM_SHADEDSTATE:
00701         app->forgetShadedstate();
00702         break;
00703 //    case REM_TABSTATE:
00704 //        break;
00705     case REM_JUMPWORKSPACE:
00706         app->forgetJumpworkspace();
00707         break;
00708     case REM_LAYER:
00709         app->forgetLayer();
00710         break;
00711     case REM_SAVEONCLOSE:
00712         app->forgetSaveOnClose();
00713         break;
00714     case REM_LASTATTRIB:
00715     default:
00716         // nothing
00717         break;
00718     }
00719 }
00720 
00721 void Remember::setupFrame(FluxboxWindow &win) {
00722     WinClient &winclient = win.winClient();
00723 
00724     // we don't touch the window if it is a transient
00725     // of something else
00726 
00727     // All windows get the remember menu.
00728     // TODO: nls
00729     win.addExtraMenu("Remember...", createRememberMenu(*this, win, (winclient.transientFor() == 0)));
00730 
00731     if (winclient.transientFor()) 
00732         return;
00733 
00734     Application *app = find(winclient);
00735     if (app == 0) 
00736         return; // nothing to do
00737 
00738     if (app->is_grouped && app->group == 0)
00739         app->group = &win;
00740 
00741     BScreen &screen = winclient.screen();
00742 
00743     if (app->workspace_remember) {
00744         // TODO: fix placement to initialise properly
00745         screen.reassociateWindow(&win, app->workspace, true); 
00746         if (app->jumpworkspace_remember)
00747             screen.changeWorkspaceID(app->workspace);
00748     }
00749 
00750     if (app->dimensions_remember)
00751         win.resize(app->w, app->h);
00752     
00753     if (app->position_remember) {
00754         switch (app->refc) {
00755           default:
00756           case POS_UPPERLEFT: // upperleft corner
00757         win.move(app->x, app->y);
00758               break;
00759           case POS_UPPERRIGHT: // upperright corner
00760               win.move(screen.width() - win.width() - app->x, app->y);
00761               break;
00762           case POS_LOWERLEFT: // lowerleft corner
00763               win.move(app->x, screen.height() - win.height() - app->y);
00764               break;
00765           case POS_LOWERRIGHT: // lowerright corner
00766               win.move(screen.width() - win.width() - app->x,
00767                        screen.height() - win.height() - app->y);
00768               break;
00769           case POS_CENTER: // center of the screen, windows topleft corner is on the center
00770                 win.move((screen.width() / 2) + app->x,
00771                          (screen.height() / 2) + app->y);
00772               break;
00773           case POS_WINCENTER: // the window is centered REALLY upon the center
00774                 win.move((screen.width() / 2) - ( win.width() / 2 ) + app->x,
00775                          (screen.height() / 2) - ( win.height() / 2 ) + app->y);
00776               break;
00777         };
00778     }
00779 
00780     if (app->shadedstate_remember)
00781         // if inconsistent...
00782         if (win.isShaded() && !app->shadedstate ||
00783             !win.isShaded() && app->shadedstate)
00784             win.shade(); // toggles
00785 
00786     // external tabs aren't available atm...
00787     //if (app->tabstate_remember) ...
00788 
00789     if (app->decostate_remember)
00790         win.setDecorationMask(app->decostate);
00791 
00792     if (app->stuckstate_remember)
00793         // if inconsistent...
00794         if (win.isStuck() && !app->stuckstate ||
00795             !win.isStuck() && app->stuckstate)
00796             win.stick(); // toggles
00797 
00798     if (app->layer_remember)
00799         win.moveToLayer(app->layer);
00800 
00801 }
00802 
00803 void Remember::setupClient(WinClient &winclient) {
00804 
00805     Application *app = find(winclient);
00806     if (app == 0) 
00807         return; // nothing to do
00808 
00809     if (winclient.fbwindow() == 0 && app->is_grouped && app->group) {
00810         app->group->attachClient(winclient);
00811     }
00812 }
00813 
00814 void Remember::updateClientClose(WinClient &winclient) {
00815     Application *app = find(winclient);
00816 
00817     if (app && (app->save_on_close_remember && app->save_on_close)) {
00818 
00819         for (int attrib = 0; attrib <= REM_LASTATTRIB; attrib++) {
00820             if (isRemembered(winclient, (Attribute) attrib)) {
00821                 rememberAttrib(winclient, (Attribute) attrib);
00822             }
00823         }
00824 
00825         save();
00826     }
00827 
00828     // we need to get rid of references to this client
00829     Clients::iterator wc_it = m_clients.find(&winclient);
00830 
00831     if (wc_it != m_clients.end()) {
00832         m_clients.erase(wc_it);
00833     }
00834 
00835 }
00836 
00837 void Remember::updateFrameClose(FluxboxWindow &win) {
00838     // scan all applications and remove this fbw if it is a recorded group
00839     Patterns::iterator it = m_pats.begin();
00840     while (it != m_pats.end()) {
00841         if (&win == it->second->group)
00842             it->second->group = 0;
00843         ++it;
00844     }
00845 }

Fluxbox CVS-Jan-2003




      



Got comments about the page? Send them to webmaster.
If you have general Fluxbox related questions ask them on our irc channel or mailing lists.

Show Source








Designed by aLEczapKA