Go to the documentation of this file.00001 #include <ros/ros.h>
00002 #include <sys/select.h>
00003 #include <stdio.h>
00004 #include <dirent.h>
00005 #include <stdlib.h>
00006 #include <vector>
00007 #include <string>
00008 #include <sstream>
00009 using namespace std;
00010
00011 enum MODE
00012 {
00013 MODE_SCREEN,
00014 MODE_X,
00015 };
00016
00017 enum MODE g_mode = MODE_SCREEN;
00018 string g_screen_cmd = "screen";
00019
00020 struct Params
00021 {
00022 std::string keyNewTab;
00023 double sleepNewTab;
00024 std::string keyTabTitle;
00025 double sleepTabTitle;
00026 double sleepCommand;
00027
00028 bool load() {
00029 ros::NodeHandle nhPriv("~");
00030 nhPriv.param("key_new_tab", keyNewTab, std::string("ctrl+shift+t"));
00031 nhPriv.param("sleep_new_tab", sleepNewTab, 2.0);
00032 nhPriv.param("key_tab_title", keyTabTitle, std::string(""));
00033 nhPriv.param("sleep_tab_title", sleepTabTitle, 1.0);
00034 nhPriv.param("sleep_command", sleepCommand, 1.0);
00035 if(keyNewTab.empty()) {
00036 ROS_FATAL("~key_new_tab param was empty.");
00037 return false;
00038 }
00039 return true;
00040 }
00041 };
00042 Params g_params;
00043
00044 bool executeCmd(const string & cmd)
00045 {
00046 int ret = system(cmd.c_str());
00047 if(ret != 0) {
00048 perror("executeCmd");
00049 ROS_ERROR("Command \"%s\" returned %d", cmd.c_str(), ret);
00050 return false;
00051 }
00052 return true;
00053 }
00054
00055 bool queryCmd(const string & cmd, string & result)
00056 {
00057 FILE* p = popen(cmd.c_str(), "r");
00058 if(!p)
00059 return false;
00060
00061 char buf[1024];
00062 char* rr = fgets(buf, 1023, p);
00063 if(rr == NULL) {
00064 ROS_ERROR("Comamnd \"%s\" read from pipe failed.", cmd.c_str());
00065 return false;
00066 }
00067 result = buf;
00068 if(!result.empty()) {
00069 if(result[result.size() - 1] == '\n') {
00070 result = result.substr(0, result.size() - 1);
00071 }
00072 }
00073
00074 int ret = pclose(p);
00075 if(ret != 0) {
00076 perror("queryCmd");
00077 ROS_ERROR("Command \"%s\" returned %d", cmd.c_str(), ret);
00078 return false;
00079 }
00080 return true;
00081 }
00082
00083 class ProgramEntry
00084 {
00085 public:
00086 string name;
00087 vector<string> commands;
00088
00089 void pushToScreen() {
00090 ROS_INFO("Creating screen window for \"%s\"", name.c_str());
00091 if(!executeCmd(g_screen_cmd + " -S ros -X screen -t '" + name + "'"))
00092 return;
00093 for(vector<string>::iterator it = commands.begin(); it != commands.end(); it++) {
00094 ROS_INFO("Pushing command: \"%s\"", it->c_str());
00095 if(!executeCmd(g_screen_cmd + " -p '" + name + "' -S ros -X eval 'stuff \"" + *it + "\"'"))
00096 return;
00097 }
00098 }
00099
00102
00106 bool filterCmdReturn(std::string & cmd) {
00107 if(cmd.length() < 4)
00108 return false;
00109 if(cmd.substr(cmd.length() - 4) == "\\015") {
00110 cmd = cmd.substr(0, cmd.length() - 4);
00111 return true;
00112 }
00113 return false;
00114 }
00115
00116 std::string toString(double d) {
00117 std::stringstream ss;
00118 ss << d;
00119 return ss.str();
00120 }
00121
00122 void pushToXWindow(const std::string & wid) {
00123 ROS_INFO("Creating window/tab for \"%s\"", name.c_str());
00124 string cmd = "xdotool ";
00125 if(!executeCmd(cmd + "windowfocus " + wid))
00126 return;
00127
00128 if(!executeCmd(cmd + "key --clearmodifiers " + g_params.keyNewTab))
00129 return;
00130 if(!executeCmd(cmd + "sleep " + toString(g_params.sleepNewTab)))
00131 return;
00132
00133 if(!g_params.keyTabTitle.empty()) {
00134 if(!executeCmd(cmd + "key " + g_params.keyTabTitle))
00135 return;
00136 if(!executeCmd(cmd + "type " + name))
00137 return;
00138 if(!executeCmd(cmd + "key Return"))
00139 return;
00140 if(!executeCmd(cmd + "sleep " + toString(g_params.sleepTabTitle)))
00141 return;
00142 }
00143
00144 for(vector<string>::iterator it = commands.begin(); it != commands.end(); it++) {
00145 std::string pushCmd = *it;
00146 bool doReturn = filterCmdReturn(pushCmd);
00147 ROS_INFO("Pushing command: \"%s\"", pushCmd.c_str());
00148 if(!executeCmd(cmd + "type --delay 1 --clearmodifiers \"" + pushCmd.c_str() + "\""))
00149 return;
00150 if(doReturn)
00151 executeCmd(cmd + "key Return");
00152 if(!executeCmd(cmd + "sleep " + toString(g_params.sleepCommand)))
00153 return;
00154 }
00155
00156 cmd = "wmctrl ";
00157 if(!executeCmd(cmd + "-i -a " + wid))
00158 return;
00159 }
00160 };
00161
00162 vector<ProgramEntry> programs;
00163
00164 bool load()
00165 {
00166 ros::NodeHandle nh("~");
00167
00168 XmlRpc::XmlRpcValue xmlRpc;
00169 if(!nh.getParam("programs", xmlRpc)) {
00170 ROS_FATAL("No programs defined.");
00171 return false;
00172 }
00173
00174 if(xmlRpc.getType() != XmlRpc::XmlRpcValue::TypeArray) {
00175 ROS_FATAL("programs param should be a list.");
00176 return false;
00177 }
00178 if(xmlRpc.size() == 0) {
00179 ROS_FATAL("programs list is empty.");
00180 return false;
00181 }
00182
00183 for(int i = 0; i < xmlRpc.size(); i++) {
00184 ProgramEntry pe;
00185
00186 if(xmlRpc[i].getType() != XmlRpc::XmlRpcValue::TypeStruct) {
00187 ROS_FATAL("programs entry %d is not of type string.", i);
00188 return false;
00189 }
00190 pe.name = (string)xmlRpc[i]["name"];
00191 XmlRpc::XmlRpcValue cmds = xmlRpc[i]["commands"];
00192 if(cmds.getType() != XmlRpc::XmlRpcValue::TypeArray) {
00193 ROS_FATAL("commands for %s is not a list (type %d)", pe.name.c_str(), cmds.getType());
00194 return false;
00195 }
00196 for(int j = 0; j < cmds.size(); j++) {
00197 pe.commands.push_back((string)cmds[j]);
00198 }
00199
00200 programs.push_back(pe);
00201 }
00202
00203 return true;
00204 }
00205
00206 string getScreenPath()
00207 {
00208 char* user = getenv("USER");
00209 if(!user)
00210 return "";
00211
00212 return string("/var/run/screen/S-") + user;
00213 }
00214
00215 bool screenRunning()
00216 {
00217 string sp = getScreenPath();
00218 if(sp.empty())
00219 return false;
00220
00221 DIR* dir = opendir(sp.c_str());
00222 if(!dir)
00223 return false;
00224 struct dirent* entry;
00225 while( (entry = readdir(dir)) ) {
00226 string dname = entry->d_name;
00227 if(dname.find("ros") != string::npos)
00228 return true;
00229 }
00230 return false;
00231 }
00232
00233 bool command_exists(const std::string & cmd)
00234 {
00235 std::string query = std::string("which ") + cmd + " > /dev/null";
00236 int ret = system(query.c_str());
00237 return ret == 0;
00238 }
00239
00240 int main(int argc, char** argv)
00241 {
00242 ros::init(argc, argv, "screenrun");
00243
00244 if(argc > 1) {
00245 if(strcmp(argv[1], "b") == 0) {
00246 if(!command_exists("byobu")) {
00247 ROS_ERROR("Requested byobu for screen, but cannot find byobu executable. Install byobu for this. Falling back to screen for now.");
00248 } else {
00249 ROS_INFO("Using byobu for screen.");
00250 g_screen_cmd = "byobu";
00251 }
00252 } else if(strcmp(argv[1], "x") == 0) {
00253 if(!command_exists("xdotool") || !command_exists("wmctrl")) {
00254 ROS_FATAL("X Mode requested, but either 'xdotool' or 'wmctrl' are not installed.");
00255 return 1;
00256 }
00257 g_mode = MODE_X;
00258 }
00259 }
00260
00261 ros::NodeHandle nh;
00262
00263 if(!load())
00264 return 1;
00265
00266 std::string wid;
00267 if(g_mode == MODE_SCREEN) {
00268 if(screenRunning()) {
00269 ROS_WARN("Screen \"ros\" already running, reusing this session");
00270 } else {
00271 ROS_INFO("Creating screen \"ros\"");
00272 if(!executeCmd(g_screen_cmd + " -S ros -d -m")) {
00273 ROS_FATAL("failed");
00274 return 1;
00275 }
00276 }
00277 } else if(g_mode == MODE_X) {
00278
00279 std::string cmd = "xprop -root | grep \"_NET_ACTIVE_WINDOW(WINDOW)\"| awk '{print $5}'";
00280 if(!queryCmd(cmd, wid)) {
00281 ROS_FATAL("wid query failed.");
00282 return 1;
00283 }
00284 printf("%s\n", wid.c_str());
00285 if(!g_params.load())
00286 return 1;
00287 }
00288
00289 for(vector<ProgramEntry>::iterator it = programs.begin(); it != programs.end(); it++) {
00290 if(g_mode == MODE_SCREEN)
00291 it->pushToScreen();
00292 else if(g_mode == MODE_X)
00293 it->pushToXWindow(wid);
00294 }
00295
00296 return 0;
00297 }
00298