// FbCommandFactory.cc for Fluxbox Window manager // Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org) // and Simon Bowden (rathnor at users.sourceforge.net) // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // $Id$ #include "FbCommandFactory.hh" #include "CurrentWindowCmd.hh" #include "FbCommands.hh" #include "Window.hh" #include "WorkspaceCmd.hh" #include "fluxbox.hh" #include "SimpleCommand.hh" #include "Screen.hh" #include "FbTk/StringUtil.hh" #include "FbTk/MacroCommand.hh" #include "FbTk/stringstream.hh" #include #ifdef HAVE_CSTDIO #include #else #include #endif using std::string; using std::vector; using std::cerr; using std::endl; // autoregister this module to command parser FbCommandFactory FbCommandFactory::s_autoreg; namespace { static int getint(const char *str, int defaultvalue) { sscanf(str, "%d", &defaultvalue); return defaultvalue; } void parseNextWindowArgs(const string &in, int &opts, string &pat) { string options; int err = FbTk::StringUtil::getStringBetween(options, in.c_str(), '{', '}'); // the rest of the string is a ClientPattern pat = in.c_str() + err; // now parse the options vector args; FbTk::StringUtil::stringtok(args, options); vector::iterator it = args.begin(), it_end = args.end(); opts = 0; for (; it != it_end; ++it) { if (strcasecmp((*it).c_str(), "static") == 0) opts |= FocusControl::CYCLELINEAR; else if (strcasecmp((*it).c_str(), "groups") == 0) opts |= FocusControl::CYCLEGROUPS; } } }; // end anonymous namespace FbCommandFactory::FbCommandFactory() { // setup commands that we can handle const char* commands[] = { "arrangewindows", "bindkey", "close", "closeallwindows", "commanddialog", "custommenu", "deiconify", "detachclient", "export", "exec", "execcommand", "execute", "exit", "focusup", "focusdown", "focusleft", "focusright", "fullscreen", "gotowindow", "hidemenus", "iconify", "keymode", "killwindow", "leftworkspace", "lower", "lowerlayer", "macrocmd", "maximize", "maximizehorizontal", "maximizevertical", "maximizewindow", "minimize", "minimizewindow", "moveto", "move", "movedown", "moveleft", "moveright", "movetableft", "movetabright", "moveup", "nextgroup", "nexttab", "nextwindow", "nextworkspace", "prevgroup", "prevtab", "prevwindow", "prevworkspace", "quit", "raise", "raiselayer", "reconfig", "reconfigure", "reloadstyle", "resizeto", "resize", "resizehorizontal", "resizevertical", "restart", "rightworkspace", "rootmenu", "saverc", "sendtoworkspace", "sendtonextworkspace", "sendtoprevworkspace", "setalpha", "setenv", "sethead", "setmodkey", "setstyle", "setworkspacename", "setworkspacenamedialog", "setresourcevalue", "setresourcevaluedialog", "shade", "shadewindow", "showdesktop", "stick", "stickwindow", "tab", "taketoworkspace", "taketonextworkspace", "taketoprevworkspace", "togglecmd", "toggledecor", "typeaheadfocus", "windowmenu", "workspace", /* NOTE: The following are DEPRECATED and subject to removal */ "workspace1", "workspace2", "workspace3", "workspace4", "workspace5", "workspace6", "workspace7", "workspace8", "workspace9", "workspace10", "workspace11", "workspace12", /* end note */ "workspacemenu", 0 }; for (int i=0; commands[i]; ++i) addCommand(commands[i]); } FbTk::Command *FbCommandFactory::stringToCommand(const std::string &command, const std::string &arguments) { using namespace FbCommands; // // WM commands // if (command == "restart") return new RestartFluxboxCmd(arguments); else if (command == "reconfigure" || command == "reconfig") return new ReconfigureFluxboxCmd(); else if (command == "setstyle") return new SetStyleCmd(arguments); else if (command == "reloadstyle") return new ReloadStyleCmd(); else if (command == "keymode") return new KeyModeCmd(arguments); else if (command == "saverc") return new SaveResources(); else if (command == "execcommand" || command == "execute" || command == "exec") return new ExecuteCmd(arguments); // execute command on key screen else if (command == "exit" || command == "quit") return new ExitFluxboxCmd(); else if (command == "setenv" || command == "export") { string name = arguments; FbTk::StringUtil::removeFirstWhitespace(name); FbTk::StringUtil::removeTrailingWhitespace(name); size_t pos = name.find_first_of(command == "setenv" ? " \t" : "="); if (pos == string::npos || pos == name.size()) return 0; string value = name.substr(pos + 1); name = name.substr(0, pos); return new ExportCmd(name, value); } else if (command == "setmodkey") { string modkey(arguments); FbTk::StringUtil::removeFirstWhitespace(modkey); FbTk::StringUtil::removeTrailingWhitespace(modkey); return new SetModKeyCmd(modkey); } else if (command == "commanddialog") // run specified fluxbox command return new CommandDialogCmd(); else if (command == "bindkey") return new BindKeyCmd(arguments); else if (command == "setresourcevalue") { // we need to parse arguments as: // string name = arguments; FbTk::StringUtil::removeFirstWhitespace(name); size_t pos = name.find_first_of(" \t"); // we need an argument to resource name if (pos == std::string::npos || pos == name.size()) return 0; // +1 so we only remove the first whitespace // i.e so users can set space before workspace name and so on string value = name.substr(pos + 1); name = name.substr(0, pos); return new SetResourceValueCmd(name, value); } else if (command == "setresourcevaluedialog") return new SetResourceValueDialogCmd(); // // Current focused window commands // else if (command == "fullscreen") return new FullscreenCmd(); else if (command == "minimizewindow" || command == "minimize" || command == "iconify") { string cmd; if (FbTk::StringUtil::getStringBetween(cmd, arguments.c_str() + 0, '(', ')', " \t\n", true) && cmd == "layer") return new MinimizeLayerCmd(); else return new CurrentWindowCmd(&FluxboxWindow::iconify); } else if (command == "maximizewindow" || command == "maximize") return new CurrentWindowCmd(&FluxboxWindow::maximizeFull); else if (command == "maximizevertical") return new CurrentWindowCmd(&FluxboxWindow::maximizeVertical); else if (command == "maximizehorizontal") return new CurrentWindowCmd(&FluxboxWindow::maximizeHorizontal); else if (command == "setalpha") { typedef vector StringTokens; StringTokens tokens; FbTk::StringUtil::stringtok(tokens, arguments); int focused, unfocused; bool relative, un_rel; if (tokens.empty()) { // set default alpha focused = unfocused = 256; relative = un_rel = false; } else { relative = un_rel = (tokens[0][0] == '+' || tokens[0][0] == '-'); focused = unfocused = atoi(tokens[0].c_str()); } if (tokens.size() > 1) { // set different unfocused alpha un_rel = (tokens[1][0] == '+' || tokens[1][0] == '-'); unfocused = atoi(tokens[1].c_str()); } return new SetAlphaCmd(focused, relative, unfocused, un_rel); } else if (command == "resize") { FbTk_istringstream is(arguments.c_str()); int dx = 0, dy = 0; is >> dx >> dy; return new ResizeCmd(dx, dy); } else if (command == "resizeto") { FbTk_istringstream is(arguments.c_str()); int dx = 0, dy = 0; is >> dx >> dy; return new ResizeToCmd(dx, dy); } else if (command == "resizehorizontal") return new ResizeCmd(atoi(arguments.c_str()),0); else if (command == "resizevertical") return new ResizeCmd(0,atoi(arguments.c_str())); else if (command == "moveto") { typedef vector StringTokens; StringTokens tokens; FbTk::StringUtil::stringtok(tokens, arguments); if (tokens.size() < 2) { cerr<<"*** WARNING: missing arguments for MoveTo\n"; return NULL; } unsigned int refc = MoveToCmd::UPPER|MoveToCmd::LEFT; int dx = 0; int dy = 0; if (tokens[0][0] == '*') refc |= MoveToCmd::IGNORE_X; else dx = atoi(tokens[0].c_str()); if (tokens[1][0] == '*' && ! (refc & MoveToCmd::IGNORE_X)) refc |= MoveToCmd::IGNORE_Y; else dy = atoi(tokens[1].c_str()); if (tokens.size() >= 3) { tokens[2] = FbTk::StringUtil::toLower(tokens[2]); if (tokens[2] == "left" || tokens[2] == "upperleft" || tokens[2] == "lowerleft") { refc |= MoveToCmd::LEFT; refc &= ~MoveToCmd::RIGHT; } else if (tokens[2] == "right" || tokens[2] == "upperright" || tokens[2] == "lowerright") { refc |= MoveToCmd::RIGHT; refc &= ~MoveToCmd::LEFT; } if (tokens[2] == "upper" || tokens[2] == "upperleft" || tokens[2] == "upperright") { refc |= MoveToCmd::UPPER; refc &= ~MoveToCmd::LOWER; } else if (tokens[2] == "lower" || tokens[2] == "lowerleft" || tokens[2] == "lowerright") { refc |= MoveToCmd::LOWER; refc &= ~MoveToCmd::UPPER; } } return new MoveToCmd(dx, dy, refc); } else if (command == "move") { FbTk_istringstream is(arguments.c_str()); int dx = 0, dy = 0; is >> dx >> dy; return new MoveCmd(dx, dy); } else if (command == "moveright") return new MoveCmd(atoi(arguments.c_str()),0); else if (command == "moveleft") return new MoveCmd(-atoi(arguments.c_str()),0); else if (command == "moveup") return new MoveCmd(0,-atoi(arguments.c_str())); else if (command == "movedown") return new MoveCmd(0,atoi(arguments.c_str())); else if (command == "raise") return new CurrentWindowCmd(&FluxboxWindow::raise); else if (command == "raiselayer") return new CurrentWindowCmd(&FluxboxWindow::raiseLayer); else if (command == "lower") return new CurrentWindowCmd(&FluxboxWindow::lower); else if (command == "lowerlayer") return new CurrentWindowCmd(&FluxboxWindow::lowerLayer); else if (command == "close") return new CurrentWindowCmd(&FluxboxWindow::close); else if (command == "closeallwindows") return new CloseAllWindowsCmd(); else if (command == "shade" || command == "shadewindow") return new CurrentWindowCmd(&FluxboxWindow::shade); else if (command == "stick" || command == "stickwindow") return new CurrentWindowCmd(&FluxboxWindow::stick); else if (command == "toggledecor") return new CurrentWindowCmd(&FluxboxWindow::toggleDecoration); else if (command == "sethead") return new SetHeadCmd(atoi(arguments.c_str())); else if (command == "sendtoworkspace") // workspaces appear 1-indexed to the user, hence the minus 1 return new SendToWorkspaceCmd(getint(arguments.c_str(), 1) - 1); else if (command == "sendtonextworkspace") return new SendToNextWorkspaceCmd(getint(arguments.c_str(), 1)); else if (command == "sendtoprevworkspace") return new SendToPrevWorkspaceCmd(getint(arguments.c_str(), 1)); else if (command == "taketoworkspace") // workspaces appear 1-indexed to the user, hence the minus 1 return new TakeToWorkspaceCmd(getint(arguments.c_str(), 1) - 1); else if (command == "taketonextworkspace") return new TakeToNextWorkspaceCmd(getint(arguments.c_str(), 1)); else if (command == "taketoprevworkspace") return new TakeToPrevWorkspaceCmd(getint(arguments.c_str(), 1)); else if (command == "killwindow" || command == "kill") return new KillWindowCmd(); else if (command == "tab") return new GoToTabCmd(getint(arguments.c_str(), 1)); else if (command == "nexttab") return new CurrentWindowCmd(&FluxboxWindow::nextClient); else if (command == "prevtab") return new CurrentWindowCmd(&FluxboxWindow::prevClient); else if (command == "movetableft") return new CurrentWindowCmd(&FluxboxWindow::moveClientLeft); else if (command == "movetabright") return new CurrentWindowCmd(&FluxboxWindow::moveClientRight); else if (command == "detachclient") return new CurrentWindowCmd(&FluxboxWindow::detachCurrentClient); else if (command == "windowmenu") return new CurrentWindowCmd(&FluxboxWindow::popupMenu); // // Workspace commands // else if (command == "nextworkspace") return new NextWorkspaceCmd(getint(arguments.c_str(), 1)); else if (command == "prevworkspace") return new PrevWorkspaceCmd(getint(arguments.c_str(), 1)); else if (command == "rightworkspace") return new RightWorkspaceCmd(getint(arguments.c_str(), 1)); else if (command == "leftworkspace") return new LeftWorkspaceCmd(getint(arguments.c_str(), 1)); else if (command == "workspace") // workspaces appear 1-indexed to the user, hence the minus 1 return new JumpToWorkspaceCmd(getint(arguments.c_str(), 1) - 1); else if (command.substr(0, 9) == "workspace" && command[9] >= '0' && command[9] <= '9') { cerr<<"*** WARNING: 'Workspace' actions are deprecated! Use 'Workspace ' instead"<> num; string::size_type pos = arguments.find_first_of("({"); if (pos != string::npos && pos != arguments.size()) args = arguments.c_str() + pos; std::cerr << "GoToWindow args: " << args << std::endl; parseNextWindowArgs(args, opts, pat); return new GoToWindowCmd(num, opts, pat); } else if (command == "focusup") return new DirFocusCmd(FocusControl::FOCUSUP); else if (command == "focusdown") return new DirFocusCmd(FocusControl::FOCUSDOWN); else if (command == "focusleft") return new DirFocusCmd(FocusControl::FOCUSLEFT); else if (command == "focusright") return new DirFocusCmd(FocusControl::FOCUSRIGHT); else if (command == "arrangewindows") return new ArrangeWindowsCmd(); else if (command == "showdesktop") return new ShowDesktopCmd(); else if (command == "hidemenus") return new HideMenuCmd(); else if (command == "rootmenu") return new ShowRootMenuCmd(); else if (command == "custommenu") return new ShowCustomMenuCmd(arguments.c_str()); else if (command == "workspacemenu") return new ShowWorkspaceMenuCmd(); else if (command == "setworkspacename") { if (arguments.empty()) return new SetWorkspaceNameCmd("empty"); else return new SetWorkspaceNameCmd(arguments); } else if (command == "setworkspacenamedialog") return new WorkspaceNameDialogCmd(); // // special commands // else if (command == "deiconify") { FbTk_istringstream iss(arguments.c_str()); string mode; string d; DeiconifyCmd::Destination dest; iss >> mode; if (iss.fail()) mode="lastworkspace"; mode= FbTk::StringUtil::toLower(mode); iss >> d; if (iss.fail()) d="current"; d= FbTk::StringUtil::toLower(d); if (d == "origin" ) dest= DeiconifyCmd::ORIGIN; else if (d == "originquiet") dest= DeiconifyCmd::ORIGINQUIET; else dest= DeiconifyCmd::CURRENT; if ( mode == "all" ) return new DeiconifyCmd(DeiconifyCmd::ALL, dest); else if ( mode == "allworkspace" ) return new DeiconifyCmd(DeiconifyCmd::ALLWORKSPACE, dest); else if ( mode == "last" ) return new DeiconifyCmd(DeiconifyCmd::LAST, dest); else // lastworkspace, default return new DeiconifyCmd(DeiconifyCmd::LASTWORKSPACE, dest); } else if (command == "macrocmd") { string cmd; int err= 0; int parse_pos= 0; FbTk::MacroCommand* macro= new FbTk::MacroCommand(); while (true) { parse_pos+= err; err= FbTk::StringUtil::getStringBetween(cmd, arguments.c_str() + parse_pos, '{', '}', " \t\n", true); if ( err > 0 ) { string c, a; string::size_type first_pos = FbTk::StringUtil::removeFirstWhitespace(cmd); string::size_type second_pos = cmd.find_first_of(" \t", first_pos); if (second_pos != string::npos) { a= cmd.substr(second_pos); FbTk::StringUtil::removeFirstWhitespace(a); cmd.erase(second_pos); } c= FbTk::StringUtil::toLower(cmd); FbTk::Command* fbcmd= stringToCommand(c,a); if (fbcmd) { FbTk::RefCount rfbcmd(fbcmd); macro->add(rfbcmd); } } else break; } if ( macro->size() > 0 ) return macro; delete macro; } else if (command == "togglecmd") { string cmd; int err= 0; int parse_pos= 0; FbTk::ToggleCommand* macro= new FbTk::ToggleCommand(); while (true) { parse_pos+= err; err= FbTk::StringUtil::getStringBetween(cmd, arguments.c_str() + parse_pos, '{', '}', " \t\n", true); if ( err > 0 ) { string c, a; string::size_type first_pos = FbTk::StringUtil::removeFirstWhitespace(cmd); string::size_type second_pos= cmd.find_first_of(" \t", first_pos); if (second_pos != string::npos) { a= cmd.substr(second_pos); FbTk::StringUtil::removeFirstWhitespace(a); cmd.erase(second_pos); } c= FbTk::StringUtil::toLower(cmd); FbTk::Command* fbcmd= stringToCommand(c,a); if (fbcmd) { FbTk::RefCount rfbcmd(fbcmd); macro->add(rfbcmd); } } else break; } if ( macro->size() > 0 ) return macro; delete macro; } return 0; }