gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash ChangeLog gui/Makefile.am gui/gnash.cpp


From: Sandro Santilli
Subject: [Gnash-commit] gnash ChangeLog gui/Makefile.am gui/gnash.cpp
Date: Sat, 23 Sep 2006 15:13:09 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Sandro Santilli <strk>  06/09/23 15:13:09

Modified files:
        .              : ChangeLog 
        gui            : Makefile.am gnash.cpp 

Log message:
                * gui/Makefile.am, gui/gnash.cpp: build libgnashplayer, have 
gnash
                  executable use the new class.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.903&r2=1.904
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/Makefile.am?cvsroot=gnash&r1=1.17&r2=1.18
http://cvs.savannah.gnu.org/viewcvs/gnash/gui/gnash.cpp?cvsroot=gnash&r1=1.39&r2=1.40

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.903
retrieving revision 1.904
diff -u -b -r1.903 -r1.904
--- ChangeLog   23 Sep 2006 15:06:52 -0000      1.903
+++ ChangeLog   23 Sep 2006 15:13:09 -0000      1.904
@@ -1,5 +1,7 @@
 2006-09-23 Sandro Santilli  <address@hidden>
 
+       * gui/Makefile.am, gui/gnash.cpp: build libgnashplayer, have gnash
+         executable use the new class.
        * gui/gtk.cpp, gui/gtksup.h, gui/gui.h, gui/sdl.cpp, gui/sdlsup.h:
          const-corrected createWindow() function.
        * gui/Player.{h,cpp}: new class to simplify player startup.

Index: gui/Makefile.am
===================================================================
RCS file: /sources/gnash/gnash/gui/Makefile.am,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -b -r1.17 -r1.18
--- gui/Makefile.am     17 Sep 2006 19:45:59 -0000      1.17
+++ gui/Makefile.am     23 Sep 2006 15:13:09 -0000      1.18
@@ -146,7 +146,7 @@
 #      $(all_libraries) \
 #      $(KDE_RPATH)
 
-lib_LTLIBRARIES = libgnashgui.la
+lib_LTLIBRARIES = libgnashgui.la libgnashplayer.la
 libgnashgui_la_SOURCES = \
        $(SDL_SRCS) \
        $(FLTK_SRCS) \
@@ -177,16 +177,19 @@
        ../libgeometry/libgnashgeo.la \
        ../libbase/libgnashbase.la
 
-gnash_SOURCES = gnash.cpp # $(libgnashgui_la_SOURCES)
-if USE_GUI_GTK
-gnash_CPPFLAGS = -DUSE_GTK
-endif
-if USE_GUI_SDL
-gnash_CPPFLAGS = -DUSE_SDL
-endif
+libgnashplayer_la_SOURCES = \
+       Player.cpp Player.h
+
+libgnashplayer_la_LIBADD = \
+       ../server/libgnashserver.la \
+       ../backend/libgnashbackend.la \
+       $(AM_LDFLAGS) 
+
+gnash_SOURCES = gnash.cpp 
 gnash_LDFLAGS = -module -avoid-version -no-undefined
 gnash_LDADD = \
-       $(GNASH_LIBS)
+       $(GNASH_LIBS) \
+       libgnashplayer.la
 
 klash_SOURCES = gnash.cpp
 klash_CPPFLAGS = -DUSE_KDE

Index: gui/gnash.cpp
===================================================================
RCS file: /sources/gnash/gnash/gui/gnash.cpp,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -b -r1.39 -r1.40
--- gui/gnash.cpp       23 Sep 2006 11:33:37 -0000      1.39
+++ gui/gnash.cpp       23 Sep 2006 15:13:09 -0000      1.40
@@ -40,95 +40,90 @@
 #include "config.h"
 #endif
 
-#ifndef USE_KDE
-# ifdef GUI_GTK
-#  include "gtksup.h"
-#  define GUI_CLASS GtkGui
-# elif defined(GUI_SDL)
-#  include "sdlsup.h"
-#  define GUI_CLASS SDLGui
-# endif
-#else
-# ifdef HAVE_KDE
-#  include "kdesup.h"
-#  include <qapplication.h>
-#  define GUI_CLASS KdeGui
-# else
-#  error "KDE development packages not installed!"
-# endif
-#endif
-
-
-#if defined(_WIN32) || defined(WIN32)
-# include "getopt.c"
-#endif
-
-#include "NullGui.h"
-
-#include "gnash.h"
-#include "movie_definition.h"
-#include "sprite_instance.h" // for setting FlashVars
-
-#include "URL.h"
-#include "rc.h"
-#include "GnashException.h"
+#include "Player.h"
+#include "log.h" // for dbglogfile (I hate this)
 
-#include "log.h"
 #include <iostream>
 
-using namespace std;
-using namespace gnash;
 
-static void usage ();
-static void version_and_copyright();
+using namespace gnash; // for dbglogfile
 
-// we don't need to register a file opener anymore, the
-// default gnash::globals::streamProvider is good enough
-#if 0
-static tu_file*
-file_opener(const char* url)
-// Callback function.  This opens files for the library.
-{
-//    GNASH_REPORT_FUNCTION;
+using namespace std;
 
-    if (strcmp(url, "-") == 0) {
-        FILE *newin = fdopen(dup(0),"rb");
-        return new tu_file(newin, false);
-    } else {
-        return new tu_file(url, "rb");
-    }
-}
-#endif
+char* infile = NULL;
+char* url = NULL;
 
 static void
-fs_callback(gnash::movie_interface* movie, const char* command, const char* 
args)
-// For handling notification callbacks from ActionScript.
+usage()
 {
-    log_msg("fs_callback(%p): %s %s'", (void*)movie, command, args);
+    printf(
+        "usage: gnash [options] movie_file.swf\n"
+        "\n"
+        "Plays a SWF (Shockwave Flash) movie\n"
+        "options:\n"
+        "\n"
+        "  -h, --help  Print this info.\n"
+        "  -s <factor> Scale the movie up/down by the specified factor\n"
+        "  -c          Produce a core file instead of letting SDL trap it\n"
+        "  -d num      Number of milliseconds to delay in main loop\n"
+        "  -v          Be verbose; i.e. print log messages to stdout\n"
+#if VERBOSE_ACTION
+        "  -va         Be verbose about movie Actions\n"
+#endif
+#if VERBOSE_PARSE
+        "  -vp         Be verbose about parsing the movie\n"
+#endif
+        "  -m <bias>   Specify the texture LOD bias (float, default is -1.0)\n"
+#if 0
+        "  -f          Run full speed (no sleep) and log frame rate\n"
+        "  -e          Use SDL Event thread\n"
+#endif
+        "  -x <ID>     X11 Window ID for display\n"
+        "  -w          Produce the disk based debug log\n"
+        "  -1          Play once; exit when/if movie reaches the last frame\n"
+        "  -r <0|1|2|3>\n"
+       "              0 disables both rendering & sound (good for batch 
tests)\n"
+        "              1 enables rendering & disables sound (default)\n"
+        "              2 enables sound & disables rendering\n"
+        "              3 enables both rendering & sound\n"
+        "  -t <sec>    Timeout and exit after the specified number of 
seconds\n"
+        "  -b <bits>   Bit depth of output window (16 or 32, default is 16)\n"
+        "  -u <url>    Set \"real\" url of the movie\n"
+       "              (useful for downloaded movies)\n"
+        "  -P <param>  Set parameter (ie. \"FlashVars=A=1&b=2\")\n"
+        "  --version   Print gnash's version number and exit\n"
+        "\n"
+        "keys:\n"
+        "  CTRL-Q, CTRL-W, ESC   Quit/Exit\n"
+        "  CTRL-P          Toggle Pause\n"
+        "  CTRL-R          Restart the movie\n"
+        "  CTRL-[ or kp-   Step back one frame\n"
+        "  CTRL-] or kp+   Step forward one frame\n"
+#if 0
+        "  CTRL-A          Toggle antialiasing (doesn't work)\n"
+        "  CTRL-T          Debug.  Test the set_variable() function\n"
+        "  CTRL-G          Debug.  Test the get_variable() function\n"
+        "  CTRL-M          Debug.  Test the call_method() function\n"
+#endif
+        "  CTRL-B          Toggle background color\n"
+        );
 }
 
-void
-setFlashVars(gnash::movie_interface& m, const string& varstr)
+static void version_and_copyright()
 {
-       gnash::sprite_instance* si = m.get_root_movie();
-       assert(si);
-
-       typedef map<string, string> maptype;
+    printf (
+"Gnash " VERSION "\n"
+"Copyright (C) 2006 Free Software Foundation, Inc.\n"
+"Gnash comes with NO WARRANTY, to the extent permitted by law.\n"
+"You may redistribute copies of Gnash under the terms of the GNU General\n"
+"Public License.  For more information, see the file named COPYING.\n"
+       );
+}
 
-       maptype vars;
-       URL::parse_querystring(varstr, vars);
 
-       for (maptype::const_iterator it=vars.begin(), itEnd=vars.end();
-               it != itEnd; ++it)
-       {
-               const string& name = it->first;
-               const string& val = it->second;
-               si->set_variable(name.c_str(), val.c_str());
-       }
-}
 
-int
-main(int argc, char *argv[])
+static void
+parseCommandLine(int argc, char* argv[], gnash::Player& player)
 {
     int c = 0;
     // scan for the two main long GNU options
@@ -138,123 +133,60 @@
             printf("\n");
             usage();
             dbglogfile.removeLog();
-            exit(0);
+           exit(EXIT_SUCCESS);
         }
         if (strcmp("--version", argv[c]) == 0) {
             version_and_copyright();
            dbglogfile.removeLog();
-            exit(0);
+           exit(EXIT_SUCCESS);
         }
     }
     
-    char* infile = NULL;
-    char* url = NULL;
-    int render_arg;
-
-    // Parameters (for -P)
-    map<string, string> params;
-    
-    unsigned long windowid = 0;
-    bool do_render = true, do_sound = false, background = true, do_loop = true;
-    unsigned int  delay = 0;
-    float scale = 1.0f, exit_timeout = 0;
-    long int width = 0, height = 0;
-#ifdef USE_KDE
-    QApplication *app = new QApplication(argc, argv);
-#else
-    void *app=NULL;
-#endif
-#if defined(RENDERER_CAIRO)
-    unsigned int bit_depth = 32;
-#else
-    unsigned int bit_depth = 16;
-#endif
-
-    assert(tu_types_validate());
-   
-
-    dbglogfile.setWriteDisk(false);
-    rcfile.loadFiles();
-//    rcfile.dump();
-
-    if (rcfile.useWriteLog()) {
-        dbglogfile.setWriteDisk(true);
-    }
-    
-    if (rcfile.verbosityLevel() > 0) {
-        dbglogfile.setVerbosity(rcfile.verbosityLevel());
-    }
-    
-    if (rcfile.useActionDump()) {
-        dbglogfile.setActionDump(true);
-        dbglogfile.setVerbosity();
-    }
-    
-    if (rcfile.useParserDump()) {
-        dbglogfile.setParserDump(true);
-        dbglogfile.setVerbosity();
-    }
-    
-    if (rcfile.getTimerDelay() > 0) {
-        delay = rcfile.getTimerDelay();
-        dbglogfile << "Timer delay set to " << delay << "milliseconds" << endl;
-    }    
-
-    while ((c = getopt (argc, argv, "hvaps:cfd:x:r:t:b:1ewj:k:u:P:")) != -1) {
+    while ((c = getopt (argc, argv, "hvaps:cfd:x:r:t:b:1ewj:k:u:P:")) != -1)
+    {
        switch (c) {
          case 'h':
              usage ();
           exit(0);
          case 'v':
               dbglogfile.setVerbosity();
-             dbglogfile << "Verbose output turned on" << endl;
+             dbglogfile << "Verbose output turned on" << std::endl;
              break;
          case 'w':
               dbglogfile.setWriteDisk(true);
-             dbglogfile << "Logging to disk enabled." << endl;
+             dbglogfile << "Logging to disk enabled." << std::endl;
              break;
          case 'a':
 #if VERBOSE_ACTION
              dbglogfile.setActionDump(true); //gnash::set_verbose_action(true);
 #else
-              dbglogfile << "Verbose actions disabled at compile time" << endl;
+              dbglogfile << "Verbose actions disabled at compile time" << 
std::endl;
 #endif
              break;
          case 'p':
 #if VERBOSE_PARSE
              dbglogfile.setParserDump(true); // gnash::set_verbose_parse(true);
 #else
-              dbglogfile << "Verbose parsing disabled at compile time" << endl;
+              dbglogfile << "Verbose parsing disabled at compile time" << 
std::endl;
 #endif
              break;
-#if 0
-          case 'f':
-              s_measure_performance = true;
-              break;
-#endif
           case 's':
-              scale = fclamp((float) atof(optarg), 0.01f, 100.f);
-              break;
-#if 0
-          // This option is parsed in SDLGui::init().
-          case 'c':
-              sdl_abort = false;
+              player.setScale( fclamp((float) atof(optarg), 0.01f, 100.f) );
               break;
-#endif
           case 'd':
-              delay = strtol(optarg, NULL, 0);
+              player.setDelay( strtol(optarg, NULL, 0) );
               break;
           case 'u':
               url = optarg;
-              dbglogfile << "Setting root URL to: " << url << endl;
+              dbglogfile << "Setting root URL to: " << url << std::endl;
               break;
           case 'j':
-              width = strtol(optarg, NULL, 0);
-              dbglogfile << "Setting width to: " << width << endl;
+              player.setWidth ( strtol(optarg, NULL, 0) );
+              dbglogfile << "Setting width to: " << player.getWidth() << 
std::endl;
               break;
           case 'k':
-              height = strtol(optarg, NULL, 0);
-              dbglogfile << "Setting height to: " << height << endl;
+              player.setHeight ( strtol(optarg, NULL, 0) );
+              dbglogfile << "Setting height to: " << player.getHeight() << 
std::endl;
               break;
 #if 0
           case 'e':
@@ -262,53 +194,53 @@
               break;
 #endif
           case 'x':
-              windowid = strtol(optarg, NULL, 0);
-              break;
-#if 0
-          // This option is parsed in GtkGlExtGlue::init().
-          case 'm':
-              tex_lod_bias = (float) atof(optarg);
+              player.setWindowId(strtol(optarg, NULL, 0));
               break;
-#endif
           case '1':
-              do_loop = false;
+              player.setDoLoop(false);
               break;
           case 'r':
-              render_arg = strtol(optarg, NULL, 0);
+       {
+              long int render_arg = strtol(optarg, NULL, 0);
               switch (render_arg) {
                 case 0:
                     // Disable both
-                    do_render = false;
-                    do_sound = false;
+                    player.setDoRender(false);
+                    player.setDoSound(false);
                     break;
                 case 1:
                     // Enable rendering, disable sound
-                    do_render = true;
-                    do_sound = false;
+                    player.setDoRender(true);
+                    player.setDoSound(false);
                     break;
                 case 2:
                     // Enable sound, disable rendering
-                    do_render = false;
-                    do_sound = true;
+                    player.setDoRender(false);
+                    player.setDoSound(true);
                     break;
                 case 3:
                     // Enable render & sound
-                    do_render = true;
-                    do_sound = true;
+                    player.setDoRender(true);
+                    player.setDoSound(true);
                     break;
                 default:
                     cerr << "-r must be followed by 0, 1, 2 or 3 (" << 
-                        render_arg << ") is invalid" << endl;
+                        render_arg << ") is invalid" << std::endl;
                     break;
               };
               break;
+       }
           case 't':
-              exit_timeout = (float) atof(optarg);
+              player.setExitTimeout( (float) atof(optarg) );
               break;
           case 'b':
+          {
+               int bit_depth;
               bit_depth = atoi(optarg);
               assert (!bit_depth || bit_depth == 16 || bit_depth == 32);
+               player.setBitDepth(bit_depth);
               break;
+          }
           case 'P':
                string param = optarg;
                size_t eq = param.find("=");
@@ -320,8 +252,9 @@
                        name = param.substr(0, eq);
                        value = param.substr(eq+1);
                }
-               //cerr << "Param name = "<<name<<" val="<<value<<endl;
-               params[name] = value;
+               //cerr << "Param name = "<<name<<" val="<<value<<std::endl;
+               player.setParam(name, value);
+               //params[name] = value;
                break;
        }
     }
@@ -332,7 +265,7 @@
 #if 0 // Options setting variables should use the getopt style!
       // Some options set variables, like ip=127.0.0.1
       if (argc > 2 && strchr(argv[optind], '=')) {
-         dbglogfile << "Got variable option on command line!" << endl;
+         dbglogfile << "Got variable option on command line!" << std::endl;
       } else {
 #endif
          infile = argv[optind];
@@ -342,209 +275,24 @@
 #endif
       optind++;
     }
+}
 
-    // Remove the logfile that's created by default, since leaving a short
-    // file is confusing.
-    if (dbglogfile.getWriteDisk() == false) {
-        dbglogfile.removeLog();
-    }
+
+int
+main(int argc, char *argv[])
+{
+       gnash::Player player;
+
+       parseCommandLine(argc, argv, player);
 
     // No file name was supplied
     if (!infile) {
-       std::cerr << "Error: no input file was specified." << endl << endl;
+               std::cerr << "Error: no input file was specified."
+                       << endl << endl;
        usage();
        return EXIT_FAILURE;
     }
 
-// we don't need to register a file opener anymore, the
-// default gnash::globals::streamProvider is good enough
-#if 0
-    // strk removed this function..
-    gnash::register_file_opener_callback(file_opener);
-#endif
-    gnash::register_fscommand_callback(fs_callback);
-
-    std::auto_ptr<gnash::sound_handler>  sound;
-
-    if (do_sound) {
-#ifdef SOUND_SDL
-      sound = std::auto_ptr<gnash::sound_handler>
-        (gnash::create_sound_handler_sdl());
-      gnash::set_sound_handler(sound.get());
-#endif
-#ifdef SOUND_GST
-      sound = std::auto_ptr<gnash::sound_handler>
-        (gnash::create_sound_handler_gst());
-      gnash::set_sound_handler(sound.get());
-#endif
-    }
-
-    // Get info about the width & height of the movie.
-    int        movie_version = 0, movie_width = 0, movie_height = 0;
-    float movie_fps = 30.0f;
-
-    try {
-        gnash::get_movie_info(URL(infile), &movie_version, &movie_width,
-            &movie_height, &movie_fps, NULL, NULL);
-    } catch (const GnashException& er) {
-        fprintf(stderr, "%s\n", er.what());
-        movie_version = 0;
-    }
-
-    if (movie_version == 0) {
-      std::cerr << "Error: can't get info about " << infile << "." << endl;
-      return EXIT_FAILURE;
-    }
-
-    if (!width) {
-      width = int(movie_width * scale);
-    }
-    if (!height) {
-      height = int(movie_height * scale);
-    }
-
-    std::auto_ptr<Gui> gui_ptr;
-    if ( do_render )
-    {
-       gui_ptr.reset(new GUI_CLASS(windowid, scale, do_loop, bit_depth));
-
-#ifdef GUI_SDL
-       SDLGui* sdlgui=dynamic_cast<SDLGui*>(gui_ptr.get());
-       if ( sdlgui && !sdl_abort ) {
-         sdlgui->disableCoreTrap();
-       }
-#endif
-
-    }
-    else
-    {
-       gui_ptr.reset(new NullGui);
-    }
-    Gui& gui = *gui_ptr;
-
-    gui.init(argc, &argv);
-
-    gui.createWindow(infile, width, height);
-
-    // Load the actual movie.
-    gnash::movie_definition *md;
- 
-    try {
-      md = gnash::create_library_movie(URL(infile), url);
-    } catch (const GnashException& er) {
-      fprintf(stderr, "%s\n", er.what());
-      md = NULL;
-    }
-
-    gnash::movie_interface *m = create_library_movie_inst(md);
-    assert(m);
-
-    // Parse parameters
-    for ( map<string,string>::const_iterator it=params.begin(),
-               itEnd=params.end(); it != itEnd; ++it)
-    {
-       // todo: use a case-insensitive string type
-       if ( it->first == "flashvars" || it->first == "FlashVars" )
-       {
-               setFlashVars(*m, it->second);
-               continue;
-       }
-
-       // too much noise...
-        //log_warning("Unused parameter %s = %s",
-       //      it->first.c_str(), it->second.c_str());
-    }
-
-
-    gnash::set_current_root(m);
-
-    m->set_display_viewport(0, 0, width, height);
-    m->set_background_alpha(background ? 1.0f : 0.05f);
-
-    if (!delay) {
-      //delay = (unsigned int) (300 / movie_fps) ; // milliseconds per frame
-      delay = (unsigned int) (1000 / movie_fps) ; // milliseconds per frame
-    }
-    gui.setCallback(delay);
-
-    if (exit_timeout) {
-      gui.setTimeout((unsigned int)(exit_timeout * 1000));
-    }
-
-    // @@ is it ok for 'app' to be NULL ?
-    // (this would be the case when USE_KDE is not defined)
-    gui.run(app);
-
-    // Clean up as much as possible, so valgrind will help find actual leaks.
-    gnash::clear();
-
-    return EXIT_SUCCESS;
+       return player.run(argc, argv, infile, url);
 }
 
-void
-version_and_copyright()
-{
-    printf (
-"Gnash " VERSION "\n"
-"Copyright (C) 2006 Free Software Foundation, Inc.\n"
-"Gnash comes with NO WARRANTY, to the extent permitted by law.\n"
-"You may redistribute copies of Gnash under the terms of the GNU General\n"
-"Public License.  For more information, see the file named COPYING.\n"
-       );
-}
-
-void
-usage()
-{
-    printf(
-        "usage: gnash [options] movie_file.swf\n"
-        "\n"
-        "Plays a SWF (Shockwave Flash) movie\n"
-        "options:\n"
-        "\n"
-        "  -h, --help  Print this info.\n"
-        "  -s <factor> Scale the movie up/down by the specified factor\n"
-        "  -c          Produce a core file instead of letting SDL trap it\n"
-        "  -d num      Number of milliseconds to delay in main loop\n"
-        "  -v          Be verbose; i.e. print log messages to stdout\n"
-#if VERBOSE_ACTION
-        "  -va         Be verbose about movie Actions\n"
-#endif
-#if VERBOSE_PARSE
-        "  -vp         Be verbose about parsing the movie\n"
-#endif
-        "  -m <bias>   Specify the texture LOD bias (float, default is -1.0)\n"
-#if 0
-        "  -f          Run full speed (no sleep) and log frame rate\n"
-        "  -e          Use SDL Event thread\n"
-#endif
-        "  -x <ID>     X11 Window ID for display\n"
-        "  -w          Produce the disk based debug log\n"
-        "  -1          Play once; exit when/if movie reaches the last frame\n"
-        "  -r <0|1|2|3>\n"
-       "              0 disables both rendering & sound (good for batch 
tests)\n"
-        "              1 enables rendering & disables sound (default)\n"
-        "              2 enables sound & disables rendering\n"
-        "              3 enables both rendering & sound\n"
-        "  -t <sec>    Timeout and exit after the specified number of 
seconds\n"
-        "  -b <bits>   Bit depth of output window (16 or 32, default is 16)\n"
-        "  -u <url>    Set \"real\" url of the movie\n"
-       "              (useful for downloaded movies)\n"
-        "  -P <param>  Set parameter (ie. \"FlashVars=A=1&b=2\")\n"
-        "  --version   Print gnash's version number and exit\n"
-        "\n"
-        "keys:\n"
-        "  CTRL-Q, CTRL-W, ESC   Quit/Exit\n"
-        "  CTRL-P          Toggle Pause\n"
-        "  CTRL-R          Restart the movie\n"
-        "  CTRL-[ or kp-   Step back one frame\n"
-        "  CTRL-] or kp+   Step forward one frame\n"
-#if 0
-        "  CTRL-A          Toggle antialiasing (doesn't work)\n"
-        "  CTRL-T          Debug.  Test the set_variable() function\n"
-        "  CTRL-G          Debug.  Test the get_variable() function\n"
-        "  CTRL-M          Debug.  Test the call_method() function\n"
-#endif
-        "  CTRL-B          Toggle background color\n"
-        );
-}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]