r370 - trunk

DONOTREPLY at icculus.org DONOTREPLY at icculus.org
Wed Nov 21 02:32:54 EST 2007


Author: icculus
Date: 2007-11-21 02:32:54 -0500 (Wed, 21 Nov 2007)
New Revision: 370

Modified:
   trunk/gui.c
   trunk/gui.h
   trunk/gui_gtkplus2.c
   trunk/gui_macosx.c
   trunk/gui_ncurses.c
   trunk/gui_stdio.c
   trunk/gui_www.c
   trunk/mojosetup.c
   trunk/platform.h
   trunk/platform_unix.c
   trunk/platform_windows.c
Log:
Spawn a terminal if we aren't using one and found no functioning GUI plugins.
 This might let the ncurses or stdio targets work, whereas before they would
 fail (or worse, block on interaction that would never happen). Panic if that
 still doesn't work out.

Initial work on this came from Gerry JJ. Thanks!



Modified: trunk/gui.c
===================================================================
--- trunk/gui.c	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/gui.c	2007-11-21 07:32:54 UTC (rev 370)
@@ -46,7 +46,7 @@
 {
     MojoGuiPluginPriority retval;
 
-    retval = gui->priority();
+    retval = gui->priority(MojoPlatform_istty());
 
     // If the plugin isn't saying "don't try me at all" then see if the
     //  user explicitly wants this one.

Modified: trunk/gui.h
===================================================================
--- trunk/gui.h	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/gui.h	2007-11-21 07:32:54 UTC (rev 370)
@@ -59,12 +59,12 @@
 #define MOJOGUI_ENTRY_POINT_STR DEFINE_TO_STR(MOJOGUI_ENTRY_POINT)
 
 // Increment this value when MojoGui's structure changes.
-#define MOJOGUI_INTERFACE_REVISION 1
+#define MOJOGUI_INTERFACE_REVISION 2
 
 typedef struct MojoGui MojoGui;
 struct MojoGui
 {
-    uint8 (*priority)(void);
+    uint8 (*priority)(boolean istty);
     const char* (*name)(void);
     boolean (*init)(void);
     void (*deinit)(void);
@@ -104,7 +104,7 @@
  */
 #define MOJOGUI_PLUGIN(module) \
 static const MojoSetupEntryPoints *entry = NULL; \
-static uint8 MojoGui_##module##_priority(void); \
+static uint8 MojoGui_##module##_priority(boolean istty); \
 static const char* MojoGui_##module##_name(void) { return #module; } \
 static boolean MojoGui_##module##_init(void); \
 static void MojoGui_##module##_deinit(void); \

Modified: trunk/gui_gtkplus2.c
===================================================================
--- trunk/gui_gtkplus2.c	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/gui_gtkplus2.c	2007-11-21 07:32:54 UTC (rev 370)
@@ -187,7 +187,7 @@
 }
 
 
-static uint8 MojoGui_gtkplus2_priority(void)
+static uint8 MojoGui_gtkplus2_priority(boolean istty)
 {
     // gnome-session exports this environment variable since 2002.
     if (getenv("GNOME_DESKTOP_SESSION_ID") != NULL)

Modified: trunk/gui_macosx.c
===================================================================
--- trunk/gui_macosx.c	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/gui_macosx.c	2007-11-21 07:32:54 UTC (rev 370)
@@ -25,7 +25,7 @@
 
 // (A lot of this is stolen from MojoPatch: http://icculus.org/mojopatch/ ...)
 
-static uint8 MojoGui_macosx_priority(void)
+static uint8 MojoGui_macosx_priority(boolean istty)
 {
     // obviously this is the thing you want on Mac OS X.
     return MOJOGUI_PRIORITY_TRY_FIRST;

Modified: trunk/gui_ncurses.c
===================================================================
--- trunk/gui_ncurses.c	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/gui_ncurses.c	2007-11-21 07:32:54 UTC (rev 370)
@@ -560,9 +560,11 @@
 } // upkeepBox
 
 
-static uint8 MojoGui_ncurses_priority(void)
+static uint8 MojoGui_ncurses_priority(boolean istty)
 {
-    if (getenv("DISPLAY") != NULL)
+    if (!istty)
+        return MOJOGUI_PRIORITY_NEVER_TRY;  // need a terminal for this!
+    else if (getenv("DISPLAY") != NULL)
         return MOJOGUI_PRIORITY_TRY_LAST;  // let graphical stuff go first.
     return MOJOGUI_PRIORITY_TRY_NORMAL;
 } // MojoGui_ncurses_priority
@@ -570,18 +572,6 @@
 
 static boolean MojoGui_ncurses_init(void)
 {
-    const char *badtty = NULL;
-    if (!isatty(0))
-        badtty = "stdin";
-    else if (!isatty(1))
-        badtty = "stdout";
-
-    if (badtty != NULL)
-    {
-        entry->logInfo("ncurses: %s is not a tty, use another UI.", badtty);
-        return false;  // stdin or stdout redirected, or maybe no xterm...
-    } // if
-
     if (initscr() == NULL)
     {
         entry->logInfo("ncurses: initscr() failed, use another UI.");

Modified: trunk/gui_stdio.c
===================================================================
--- trunk/gui_stdio.c	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/gui_stdio.c	2007-11-21 07:32:54 UTC (rev 370)
@@ -74,8 +74,16 @@
 } // print_prompt
 
 
-static uint8 MojoGui_stdio_priority(void)
+static uint8 MojoGui_stdio_priority(boolean istty)
 {
+    // if not a tty and no other GUI plugins worked out, let the base
+    //  application try to spawn a terminal and try again. If it can't do so,
+    //  it will panic() and thus end the process, so we don't end up blocking
+    //  on some prompt the user can't see.
+
+    if (!istty)
+        return MOJOGUI_PRIORITY_NEVER_TRY;
+
     return MOJOGUI_PRIORITY_TRY_ABSOLUTELY_LAST;  // always a last resort.
 } // MojoGui_stdio_priority
 
@@ -83,7 +91,7 @@
 static boolean MojoGui_stdio_init(void)
 {
     percentTicks = 0;
-    return true;   // always succeeds.
+    return true;  // always succeeds.
 } // MojoGui_stdio_init
 
 

Modified: trunk/gui_www.c
===================================================================
--- trunk/gui_www.c	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/gui_www.c	2007-11-21 07:32:54 UTC (rev 370)
@@ -130,7 +130,7 @@
 static SOCKET clientSocket = INVALID_SOCKET;
 
 
-static uint8 MojoGui_www_priority(void)
+static uint8 MojoGui_www_priority(boolean istty)
 {
     return MOJOGUI_PRIORITY_TRY_LAST;
 } // MojoGui_www_priority

Modified: trunk/mojosetup.c
===================================================================
--- trunk/mojosetup.c	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/mojosetup.c	2007-11-21 07:32:54 UTC (rev 370)
@@ -110,6 +110,20 @@
 #endif
 
 
+static void trySpawnTerminal(void)
+{
+    if (cmdlinestr("notermspawn", "MOJOSETUP_NOTERMSPAWN", NULL) != NULL)
+        return;  // we already spawned or the user is preventing it.
+
+    if (MojoPlatform_istty())  // maybe we can spawn a terminal for stdio?
+        return;  // We're a terminal already, no need to spawn one.
+
+    logInfo("No usable GUI found. Trying to spawn a terminal...");
+    MojoPlatform_spawnTerminal();  // no return on success.
+    logError("...Terminal spawning failed.");
+} // trySpawnTerminal
+
+
 static boolean initEverything(void)
 {
     MojoLog_initLogging();
@@ -128,10 +142,15 @@
     trySwitchBinaries();  // may not return.
 
     if (!MojoGui_initGuiPlugin())
+    {
+        trySpawnTerminal();  // may not return.
         panic("Initial GUI setup failed. Cannot continue.");
+    } // if
 
     else if (!MojoLua_initLua())
+    {
         panic("Initial Lua setup failed. Cannot continue.");
+    } // else if
 
     crashedmsg = xstrdup(_("The installer has crashed due to a bug."));
     termedmsg = xstrdup(_("The installer has been stopped by the system."));

Modified: trunk/platform.h
===================================================================
--- trunk/platform.h	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/platform.h	2007-11-21 07:32:54 UTC (rev 370)
@@ -90,6 +90,9 @@
 //  otherwise (including if (fname) doesn't exist). Don't follow symlinks.
 boolean MojoPlatform_issymlink(const char *fname);
 
+// Returns true if stdin and stdout are connected to a tty.
+boolean MojoPlatform_istty(void);
+
 // Returns true if (fname) is a regular file in the physical filesystem, false
 //  otherwise (including if (fname) doesn't exist). Don't follow symlinks.
 boolean MojoPlatform_isfile(const char *fname);
@@ -222,6 +225,10 @@
 void MojoPlatform_switchBin(const uint8 *img, size_t len);
 #endif
 
+// Try to spawn a terminal, and relaunch MojoSetup within it.
+//  Does not return on success (process replaces itself).
+void MojoPlatform_spawnTerminal(void);
+
 // Put the calling process to sleep for at least (ticks) milliseconds.
 //  This is meant to yield the CPU while spinning in a loop that is polling
 //  for input, etc. Pumping the GUI event queue happens elsewhere, not here.

Modified: trunk/platform_unix.c
===================================================================
--- trunk/platform_unix.c	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/platform_unix.c	2007-11-21 07:32:54 UTC (rev 370)
@@ -58,6 +58,20 @@
 
 static struct timeval startup_time;
 
+boolean MojoPlatform_istty(void)
+{
+    static boolean already_checked = false;  // this never changes in a run.
+    static boolean retval = false;
+    if (!already_checked)
+    {
+        retval = isatty(0) && isatty(1) ? true : false;
+        already_checked = true;
+    } // if
+
+    return retval;
+} // MojoPlatform_istty
+
+
 char *MojoPlatform_currentWorkingDir(void)
 {
     char *retval = NULL;
@@ -933,6 +947,76 @@
 #endif
 
 
+void MojoPlatform_spawnTerminal(void)
+{
+#if PLATFORM_BEOS
+    #error write me.
+    // "/boot/apps/Terminal"
+#elif PLATFORM_MACOSX
+    #error write me.
+    // "/Applications/Utilities/Terminal.app"
+#else
+
+    // urgh
+    static const char *terms[] = {
+        "gnome-terminal", "konsole", "kvt", "xterm", "rxvt",
+        "dtterm", "eterm", "Eterm", "aterm"
+    };
+
+    const char *tryfirst = NULL;
+    const int max_added_args = 5;
+    const unsigned int argc = GArgc + max_added_args;
+    const char **argv = NULL;
+    int i = 0;
+    int startarg = 0;
+
+    if (getenv("DISPLAY") == NULL)
+        return;  // don't bother if we don't have X.
+
+    else if (getenv("GNOME_DESKTOP_SESSION_ID") != NULL)  // this is gnome?
+        tryfirst = "gnome-terminal";
+
+    else if (getenv("KDE_FULL_SESSION") != NULL)  // this KDE >= 3.2?
+        tryfirst = "konsole";
+
+    argv = xmalloc((argc + 1) * sizeof(char *));
+
+    for (i = -1; i < ((int) STATICARRAYLEN(terms)); i++)
+    {
+        int is_gnome_term = false;
+        int argi = 0;
+        const char *trythis = (i == -1) ? tryfirst : terms[i];
+        if (trythis == NULL)
+            continue;
+
+        // !!! FIXME: hack. I'm sure other terminal emulators have needs, too.
+        is_gnome_term = (strcmp(trythis, "gnome-terminal") == 0);
+
+        argv[argi++] = trythis;
+        argv[argi++] = is_gnome_term ? "--title" : "-title";
+        argv[argi++] = "MojoSetup";
+        argv[argi++] = is_gnome_term ? "-x" : "-e";
+        argv[argi++] = GArgv[0];
+        argv[argi++] = "-notermspawn=1";
+        assert(argi-1 <= max_added_args);
+
+        for (startarg = argi-1; argi <= argc; argi++)  // include ending NULL.
+        {
+            argv[argi] = GArgv[argi - startarg];
+            if (argv[argi] == NULL)
+                break;
+        } // for
+
+        execvp(trythis, (char * const *) argv);
+    } // for
+
+    // Still here? We failed. Mankind is wiped out in the Robot Wars.
+
+    free(argv);
+#endif
+} // MojoPlatform_spawnTerminal
+
+
 static void signal_catcher(int sig)
 {
     static boolean first_shot = true;

Modified: trunk/platform_windows.c
===================================================================
--- trunk/platform_windows.c	2007-11-21 04:29:33 UTC (rev 369)
+++ trunk/platform_windows.c	2007-11-21 07:32:54 UTC (rev 370)
@@ -627,6 +627,20 @@
 
 // ok, now the actual platform layer implementation...
 
+boolean MojoPlatform_istty(void)
+{
+    // !!! FIXME: this will prevent the stdio plugin from working over
+    // !!! FIXME:  ssh, etc. Check if we're really in a console somehow...
+    return false;  // never a terminal on Windows, always a GUI app.
+} // MojoPlatform_istty
+
+
+void MojoPlatform_spawnTerminal(void)
+{
+    // unsupported.
+} // MojoPlatform_spawnTerminal
+
+
 char *MojoPlatform_currentWorkingDir(void)
 {
     char *retval = NULL;




More information about the mojosetup-commits mailing list