This is an automated email from the git hooks/post-receive script. x2go pushed a commit to branch master in repository x2goclient. commit f399a0453487ac97eb113923f7503fd0f06e046d Author: Mihai Moldovan <ionic@ionic.de> Date: Wed Jan 13 06:03:55 2016 +0100 onmainwindow.{cpp,h}: don't use a hardcoded path to xmodmap on OS X and handle errors more gracefully. Fixes: #487. --- debian/changelog | 2 + src/onmainwindow.cpp | 169 +++++++++++++++++++++++++++++++++++++++++--------- src/onmainwindow.h | 1 + 3 files changed, 141 insertions(+), 31 deletions(-) diff --git a/debian/changelog b/debian/changelog index 5c5bef8..92a3d0e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -14,6 +14,8 @@ x2goclient (4.0.5.1-0x2go1) UNRELEASED; urgency=low - x2gosettings.cpp: let centralSettings () return false on Windows. - onmainwindow.cpp: be more precise in slotScDaemonError () regarding unknown and undefined errors. + - onmainwindow.{cpp,h}: don't use a hardcoded path to xmodmap on OS X and + handle errors more gracefully. Fixes: #487. [ Oleksandr Shneyder ] * New upstream release (4.0.5.1): diff --git a/src/onmainwindow.cpp b/src/onmainwindow.cpp index c574070..41de685 100644 --- a/src/onmainwindow.cpp +++ b/src/onmainwindow.cpp @@ -5555,47 +5555,154 @@ void ONMainWindow::slotSndTunnelFailed ( bool result, QString output, #ifdef Q_OS_DARWIN void ONMainWindow::slotSetModMap() { - if(!nxproxy) - { + if (!nxproxy) { return; } - if (kbMap.isEmpty ()) - { - QProcess pr(this); - pr.setProcessEnvironment(QProcessEnvironment::systemEnvironment()); - pr.start("/opt/X11/bin/xmodmap -pke"); - pr.waitForFinished(); - kbMap=pr.readAllStandardOutput(); - pr.start("/opt/X11/bin/xmodmap -pm"); - pr.waitForFinished(); - QString modifiers=pr.readAllStandardOutput(); - x2goDebug<<"modifiers: "<<modifiers; - kbMap+="clear shift\nclear lock\nclear control\nclear mod1\nclear mod2\nclear mod3\nclear mod4\nclear mod5\n"; - QStringList lines=modifiers.split("\n",QString::SkipEmptyParts); - for(int i=0; i<lines.count(); ++i) - { - QStringList parts=lines[i].split(" ",QString::SkipEmptyParts); - if(parts.count()<2) - { - continue; + if (kbMap.isEmpty ()) { + QProcess pr (this); + QProcessEnvironment tmp_env = QProcessEnvironment::systemEnvironment (); + QString path_val = tmp_env.value ("PATH"); + + /* Let's set a reasonable default value if none is provided. */ + if (path_val.isEmpty ()) { + /* Prefer the default MacPorts prefix. */ + path_val = "/opt/local/bin:/opt/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin:/usr/X11R6/bin:/opt/X11/bin"; + tmp_env.insert ("PATH", path_val); + } + + pr.setProcessEnvironment (tmp_env); + + QStringList key_map_fetch_args; + key_map_fetch_args << "-pke"; + pr.start ("xmodmap", key_map_fetch_args); + bool key_map_fetch_ret = pr.waitForStarted (); + + if (!key_map_fetch_ret) { + handle_xmodmap_error (pr); + } + else { + key_map_fetch_ret = pr.waitForFinished (); + + if (!key_map_fetch_ret) { + handle_xmodmap_error (pr); } - QString mod=parts[0]; - if(mod == "shift" || mod=="lock" || mod=="control" || mod=="mod1"|| mod=="mod2"|| mod=="mod3"|| mod=="mod4"|| mod=="mod5") - { - for(int j=1; j<parts.count(); ++j) - { - if(parts[j].indexOf("(")==-1) - { - kbMap+="add "+mod+" = "+parts[j]+"\n"; + + kbMap = pr.readAllStandardOutput (); + + QStringList mod_fetch_args; + mod_fetch_args << "-pm"; + pr.start ("xmodmap", mod_fetch_args); + bool mod_fetch_ret = pr.waitForStarted (); + + if (!mod_fetch_ret) { + handle_xmodmap_error (pr); + } + else { + mod_fetch_ret = pr.waitForFinished (); + + if (!mod_fetch_ret) { + handle_xmodmap_error (pr); + } + + QString modifiers = pr.readAllStandardOutput (); + x2goDebug << "modifiers: " << modifiers; + + /* Reset all modifiers first. */ + kbMap += "clear shift\nclear lock\nclear control\nclear mod1\nclear mod2\nclear mod3\nclear mod4\nclear mod5\n"; + + /* And set them back again. */ + QStringList lines = modifiers.split ("\n", QString::SkipEmptyParts); + for (int i = 0; i < lines.count (); ++i) { + QStringList parts = lines[i].split (" ", QString::SkipEmptyParts); + if (parts.count () < 2) { + continue; + } + + QString mod = parts[0]; + if ((mod == "shift") || (mod == "lock") || (mod == "control") || (mod == "mod1") || (mod == "mod2") || (mod == "mod3") || (mod == "mod4") || (mod == "mod5")) { + for (int j = 1; j < parts.count (); ++j) { + if (parts[j].indexOf ("(") == -1) { + kbMap += "add " + mod + " = " + parts[j] + "\n"; + } + } } } + + /* Send modified map to server. */ + QString cmd = "export DISPLAY=\":" + resumingSession.display + "\"; echo \"" + kbMap + "\" | xmodmap -"; + sshConnection->executeCommand (cmd); } } } +} - QString cmd = "export DISPLAY=\":" + resumingSession.display + "\"; echo \"" + kbMap + "\" | xmodmap -"; +void ONMainWindow::handle_xmodmap_error (QProcess &proc) { + QString main_text ("xmodmap "); + QString informative_text; - sshConnection->executeCommand (cmd); + QProcessEnvironment proc_env = QProcessEnvironment::systemEnvironment (); + + /* If the process has a special env, fetch it. */ + if (!(proc.processEnvironment ().isEmpty ())) { + proc_env = proc.processEnvironment (); + } + + switch (proc.error ()) { + case QProcess::FailedToStart: { + main_text += tr ("failed to start."); + informative_text += tr ("This likely means the binary is not available.\n" + "The current search path is: "); + + QString path_val = proc_env.value ("PATH", "unknown"); + + /* Add a newline every 100 characters. */ + for (std::size_t i = 100; i < static_cast<std::size_t> (path_val.size ()); i += 100) { + path_val.insert (i, "\n"); + } + + informative_text += path_val; + break; + } + case QProcess::Crashed: { + main_text += tr ("returned a non-zero exit code or crashed otherwise."); + informative_text += tr ("Execution failed, exit code was: "); + informative_text += QString::number (proc.exitCode ()); + break; + } + case QProcess::Timedout: { + main_text += tr ("didn't start up in time."); + informative_text = tr ("This error shouldn't come up."); + break; + } + case QProcess::WriteError: { + main_text += tr ("didn't accept a write operation."); + informative_text = tr ("It is probably not running correctly or crashed in-between."); + break; + } + case QProcess::ReadError: { + main_text = tr ("Unable to read from xmodmap."); + informative_text = tr ("It is probably not running correctly or crashed in-between."); + break; + } + case QProcess::UnknownError: { + main_text += tr ("encountered an unknown error during start up or execution."); + break; + } + default: { + main_text += tr ("experienced an undefined error."); + break; + } + } + + if (!informative_text.isEmpty ()) { + informative_text += "\n\n"; + } + + informative_text += tr ("X2Go Client will now terminate.\n\n" + "File a bug report as outlined on the <a href=\"http://wiki.x2go.org/doku.php/wiki:bugs\">bugs wiki page</a>."); + + show_RichText_ErrorMsgBox (main_text, informative_text); + trayQuit (); } #endif diff --git a/src/onmainwindow.h b/src/onmainwindow.h index 5674c2c..2ae1269 100644 --- a/src/onmainwindow.h +++ b/src/onmainwindow.h @@ -1148,6 +1148,7 @@ private slots: void slotStartNewBrokerSession (); #ifdef Q_OS_DARWIN void slotSetModMap(); + void handle_xmodmap_error (QProcess &proc); private: QTimer* modMapTimer; QString kbMap; -- Alioth's /srv/git/code.x2go.org/x2goclient.git//..//_hooks_/post-receive-email on /srv/git/code.x2go.org/x2goclient.git