"Fossies" - the Fresh Open Source Software Archive

Member "mozplugger-2.1.6/mozplugger-controller.c" (17 Apr 2014, 21491 Bytes) of package /linux/www/old/mozplugger-2.1.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /**
    2  * This file is part of mozplugger a fork of plugger, for list of developers
    3  * see the README file.
    4  *
    5  * This program is free software; you can redistribute it and/or modify
    6  * it under the terms of the GNU General Public License as published by
    7  * the Free Software Foundation; either version 2 of the License, or
    8  * (at your option) any later version.
    9  *
   10  * This program is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13  * GNU General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU General Public License
   16  * along with this program; if not, write to the Free Software
   17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
   18  */
   19 
   20 #ifdef HAVE_CONFIG_H
   21 #include "config.h"
   22 #endif
   23 
   24 #include <stdlib.h>
   25 #include <stdint.h>
   26 #include <unistd.h>
   27 #include <string.h>
   28 #include <stdio.h>
   29 #include <sysexits.h>
   30 #include <signal.h>
   31 #include <sys/stat.h>
   32 #include <fcntl.h>
   33 #include <sys/wait.h>
   34 #include <errno.h>
   35 #include <X11/X.h>
   36 #include <X11/Xutil.h>
   37 
   38 #include "cmd_flags.h"
   39 #include "child.h"
   40 #include "debug.h"
   41 #include "pipe_msg.h"
   42 #include "widgets.h"
   43 
   44 
   45 #define WINDOW_BORDER_WIDTH 1
   46 
   47 struct SigGlobals_s
   48 {
   49     pid_t childPid;
   50 };
   51 
   52 typedef struct SigGlobals_s SigGlobals_t;
   53 
   54 struct AppData_s
   55 {
   56      unsigned long cmd_flags;
   57      char * command;
   58      int repeats;
   59      int dlProgress;
   60      int paused;
   61 };
   62 
   63 typedef struct AppData_s AppData_t;
   64 
   65 
   66 
   67 static SigGlobals_t sig_globals;
   68 static GC gc_white;
   69 static GC gc_black;
   70 static GC gc_onColor;
   71 static GC gc_offColor;
   72 
   73 /**
   74  * Redraw the three control buttons
   75  *
   76  * @param[in] dpy
   77  * @param[in] win
   78  * @param[in] mouseClickPos, where mouse was clicked
   79  *
   80  * @return Which button is down
   81  */
   82 static int redraw(Display * dpy, Window win, int mouseClickPos,
   83                                                            AppData_t * appData)
   84 {
   85      static int old_buttonsize = -1;
   86 
   87      int buttonsize;
   88      XWindowAttributes attr;
   89      XPoint base;
   90      int buttonDown = -1;
   91 
   92      XGetWindowAttributes(dpy, win, &attr);
   93      buttonsize = attr.width / 3;
   94      if(attr.height < buttonsize)
   95      {
   96           buttonsize = attr.height;
   97      }
   98 
   99      if(old_buttonsize != buttonsize)
  100      {
  101           old_buttonsize = buttonsize;
  102           XFillRectangle(dpy, win, gc_white,
  103                              0, 0, (unsigned)attr.width, (unsigned)attr.height);
  104      }
  105 
  106 
  107      base.x = (attr.width - buttonsize * 3)/2;
  108      base.y = (attr.height - buttonsize)/2;
  109 
  110      if(mouseClickPos > 0)
  111      {
  112          buttonDown = (mouseClickPos - base.x) / buttonsize;
  113      }
  114 
  115      /***** play ******/
  116 
  117      drawPlayButton(dpy, win, &base, buttonsize,
  118             ((sig_globals.childPid > 0) && (!appData->paused)) ? gc_onColor : gc_offColor,
  119                                            gc_black, gc_white, buttonDown == 0);
  120 #if 0
  121      drawProgressBar(dpy, win, &base, buttonsize, gc_onColor, gc_black, gc_white, appData->dlProgress);
  122 #endif
  123 
  124      /***** pause *****/
  125      base.x += buttonsize;
  126      drawPauseButton(dpy, win, &base, buttonsize,
  127              ((sig_globals.childPid > 0) && appData->paused) ? gc_onColor : gc_offColor,
  128                                            gc_black, gc_white, buttonDown == 1);
  129 
  130      /***** stop *****/
  131      base.x += buttonsize;
  132      drawStopButton(dpy, win, &base, buttonsize,
  133              (sig_globals.childPid > 0) ? gc_onColor : gc_offColor, gc_black, gc_white,
  134                                                                buttonDown == 2);
  135      return buttonDown;
  136 }
  137 
  138 /**
  139  * Get the value of environment variable 'var' and convert to an integer value
  140  * - use 'def' if enviroment variable does not exist
  141  *
  142  * @param[in] var The name of the variable
  143  * @param[in] def The default value to use
  144  *
  145  * @return The integer value
  146  */
  147 static int igetenv(char *var, int def)
  148 {
  149      char *tmp=getenv(var);
  150      if(!tmp)
  151      {
  152           return def;
  153      }
  154      return atoi(tmp);
  155 }
  156 
  157 /**
  158  * Called when the user clicks on the play button
  159  *
  160  * @param[in] data Data associated with the application to execute
  161  * @param[in] maxFd The maximum open file descriptor
  162  */
  163 static void my_play(AppData_t * appData)
  164 {
  165      appData->paused = 0;
  166      if(sig_globals.childPid > 0)
  167      {
  168           if(!kill(-sig_globals.childPid, SIGCONT))
  169           {
  170                return;
  171           }
  172      }
  173 
  174      sig_globals.childPid = spawn_app(appData->command, appData->cmd_flags);
  175 }
  176 
  177 /**
  178  * Called when the user clicks on the pause button
  179  *
  180  * @param[in] appData Pointer to the App data structure
  181  */
  182 static void my_pause(AppData_t * appData)
  183 {
  184      if(sig_globals.childPid > 0)
  185      {
  186           if(!kill(-sig_globals.childPid, SIGSTOP))
  187           {
  188                appData->paused = 1;
  189           }
  190      }
  191 }
  192 
  193 /**
  194  * Terminate the controller application
  195  */
  196 static void low_die(void)
  197 {
  198      if(sig_globals.childPid > 0)
  199      {
  200           kill_app(sig_globals.childPid);
  201      }
  202      _exit(0);
  203 }
  204 
  205 /**
  206  * Called when the user clicks on the stop button
  207  *
  208  * @param[in] appData Pointer to the App data structure
  209  */
  210 static void my_stop(AppData_t * appData)
  211 {
  212      if(sig_globals.childPid > 0)
  213      {
  214           if(appData->paused)
  215           {
  216                kill(-sig_globals.childPid, SIGCONT);
  217                appData->paused = 0;
  218           }
  219           kill_app(sig_globals.childPid);
  220           sig_globals.childPid = -1;
  221      }
  222 }
  223 
  224 /**
  225  * Terminate, called from signal handler or when SHUTDOWN_MSG received
  226  */
  227 static void terminate(pid_t pid, Display * dpy)
  228 {
  229      if(pid >= 0)
  230      {
  231           kill_app(pid);
  232      }
  233 
  234      if(dpy)
  235      {
  236           XCloseDisplay(dpy);
  237      }
  238 }
  239 
  240 
  241 /**
  242  * Callback function passed to X for when error occurs. This terminates the
  243  * controlled application
  244  *
  245  * @param[in] dpy The display pointer (not used)
  246  * @param[in] ev The X event (not used)
  247  *
  248  * @return Always returns zero
  249  */
  250 static int die(Display *dpy, XErrorEvent *ev)
  251 {
  252      low_die();
  253      return 0;
  254 }
  255 
  256 /**
  257  * Callback function passed to X for when error occurs. This terminates the
  258  * controlled application
  259  *
  260  * @param[in] dpy The display pointer (not used)
  261  *
  262  * @return Always returns zero
  263  */
  264 static int die2(Display *dpy)
  265 {
  266      low_die();
  267      return 0;
  268 }
  269 
  270 /**
  271  * Callback function attached as a signal handler. This terminates the
  272  * controlled application
  273  *
  274  * @param[in] sig The signal (not used)
  275  */
  276 static void sigdie(int sig)
  277 {
  278      low_die();
  279 }
  280 
  281 /**
  282  * Force the repaint to happen
  283  *
  284  * @param[in] dpy The display pointer
  285  * @param[in] win The window ID
  286  */
  287 static void forceRepaint(Display * dpy, Window win)
  288 {
  289      XEvent event;
  290 
  291      event.type = Expose;
  292      event.xexpose.display = dpy;
  293      event.xexpose.window = win;
  294      event.xexpose.count = 0;
  295 
  296      XSendEvent(dpy, win, False, ExposureMask, &event);
  297 }
  298 
  299 /**
  300  * Checks for X events and processes them. Returns when no more events left
  301  * to process.
  302  *
  303  * @param[in] dpy
  304  * @param[in] win
  305  *
  306  * @return nothing
  307  */
  308 static void check_x_events(Display * dpy, Window win, AppData_t * appData)
  309 {
  310      int numEvents = XPending(dpy);
  311      static int mouseClickPos = -1;
  312 
  313      while(numEvents > 0)
  314      {
  315           XEvent ev;
  316 
  317           XNextEvent(dpy, &ev);
  318 
  319           switch(ev.type)
  320           {
  321           case ButtonPress:
  322                if(ev.xbutton.button == 1)
  323                {
  324                     int buttonDown;
  325                     mouseClickPos = ev.xbutton.x;
  326                     buttonDown = redraw(dpy, win, mouseClickPos, appData); /* do first gives quicker visual feedback */
  327                     XSync(dpy, False);
  328 
  329                     switch(buttonDown)
  330                     {
  331                     case 0: /* play */
  332                          my_play(appData);
  333                          break;
  334                     case 1: /* pause*/
  335                          my_pause(appData);
  336                          break;
  337                     case 2: /* stop */
  338                          my_stop(appData);
  339                          break;
  340                     }
  341 
  342                     redraw(dpy, win, mouseClickPos, appData);
  343                }
  344                break;
  345 
  346           case ButtonRelease:
  347                if(mouseClickPos != -1)
  348                {
  349                     mouseClickPos = -1;
  350                     redraw(dpy, win, mouseClickPos, appData);
  351                }
  352                break;
  353 
  354           case Expose:
  355                if(ev.xexpose.count)
  356                {
  357                     break;
  358                }
  359           case ResizeRequest:
  360           case MapNotify:
  361                redraw(dpy, win, mouseClickPos, appData);
  362                break;
  363 
  364           default:
  365                D("Unknown event %d\n",ev.type);
  366                break;
  367           }
  368 
  369           /* If this is the last of this batch, check that more havent
  370            * been added in the meantime as a result of an action */
  371           numEvents--;
  372           if(numEvents == 0)
  373           {
  374                numEvents = XPending(dpy);
  375           }
  376      }
  377 }
  378 
  379 /**
  380  * Given initial width & height of the window containing the buttons
  381  * limit the width and aspect ratio and place in the center of the
  382  * window (calculate x & y)
  383  *
  384  * @param[in,out] width The width before and after
  385  * @param[in,out] height The height before and after
  386  * @param[in,out] x The x co-ordinate before and after
  387  * @param[in,out] y The y co-ordinate before and after
  388  * @param[in] flags The Flags as read from mozpluggerrc
  389  */
  390 static void normalise_window_coords(unsigned * width, unsigned * height,
  391                                     int * x, int * y, unsigned long flags)
  392 {
  393      unsigned w = *width;
  394      unsigned h = *height;
  395      const unsigned target_aspect = 3;
  396 
  397      if(flags & H_SMALL_CNTRLS)
  398      {
  399           *y = *x = 0;
  400           *width = 3 * MIN_BUTTON_SIZE;
  401           *height = MIN_BUTTON_SIZE;
  402           return;
  403      }
  404 
  405      if(w > 3 * MAX_BUTTON_SIZE)
  406      {
  407           w = 3 * MAX_BUTTON_SIZE;
  408      }
  409 
  410      /* Keep the controls as close to default ratio as possible */
  411      if(h > w / target_aspect)
  412      {
  413           h = w / target_aspect;
  414      }
  415 
  416      *x = (int) (*width - w)/2;
  417      *y = (int) (*height - h)/2;
  418 
  419      *height = h;
  420      *width = w;
  421 }
  422 
  423 /**
  424  * Check to see if new window size information has arrived from plugin and if
  425  * so resize the controls accordingly.
  426  *
  427  * @param[in] dpy The display
  428  * @param[in] win The window
  429  * @param[in] appData Pointer to the application data structure
  430  * @param[in] pipeFd The Fd of the pipe
  431  */
  432 static void check_pipe_fd_events(Display * dpy, Window win,
  433                                     AppData_t * appData, int pipe_fd)
  434 {
  435      struct PipeMsg_s msg;
  436      int n;
  437 
  438      D("Got pipe_fd data, pipe_fd=%d\n", pipe_fd);
  439 
  440      n = read(pipe_fd, ((char *) &msg),  sizeof(msg));
  441      if((n == 0) || ((n < 0) && (errno != EINTR)))
  442      {
  443           D("Pipe returned n=%i\n", n);
  444           terminate(sig_globals.childPid, dpy);
  445           exit(EX_UNAVAILABLE);
  446      }
  447 
  448      if(n != sizeof(msg))
  449      {
  450           if(n > 0)
  451           {
  452               D("Pipe msg too short, size = %i\n", n);
  453           }
  454           return;
  455      }
  456 
  457      switch(msg.msgType)
  458      {
  459           case WINDOW_MSG:
  460           {
  461                int x, y;
  462                /* Adjust the width & height to compensate for the window border width */
  463                unsigned w = (unsigned) msg.window_msg.width - 2 * WINDOW_BORDER_WIDTH;
  464                unsigned h = (unsigned) msg.window_msg.height - 2 * WINDOW_BORDER_WIDTH;
  465 
  466                normalise_window_coords(&w, &h, &x, &y, appData->cmd_flags);
  467 
  468                D("Controller window: x=%i, y=%i, w=%u, h=%u\n", x, y, w, h);
  469 
  470                XMoveResizeWindow(dpy, win, x, y, w, h);
  471           }
  472           break;
  473 
  474           case PROGRESS_MSG:
  475           {
  476                if(msg.progress_msg.done)
  477                {
  478                     appData->dlProgress = -1;
  479                }
  480                else
  481                {
  482                     appData->dlProgress++;
  483                }
  484                forceRepaint(dpy, win);
  485           }
  486           break;
  487 
  488           case STATE_CHG_MSG:
  489           {
  490                switch(msg.stateChg_msg.stateChgReq)
  491                {
  492                     case STOP_REQ:
  493                           my_stop(appData);
  494                           break;
  495 
  496                     case PLAY_REQ:
  497                           my_play(appData);
  498                           break;
  499 
  500                     case PAUSE_REQ:
  501                           my_pause(appData);
  502                           break;
  503                }
  504                forceRepaint(dpy, win);
  505           }
  506           break;
  507      }
  508 }
  509 
  510 /**
  511  * Called if we exit main() early because of invalid passed argument into
  512  * the main function. print to both debug and stderr (just in case someone
  513  * called mozplugger-controller directly)
  514  */
  515 static void exitEarly(void)
  516 {
  517      D("Invalid parameters passed to Controller - controller exiting\n");
  518 
  519      fprintf(stderr,"MozPlugger version " VERSION
  520                     " controller application.\n"
  521                     "Please see 'man mozplugger' for details.\n");
  522      exit(EXIT_FAILURE);
  523 }
  524 
  525 /**
  526  * mozplugger-controller takes two arguments. The first is a shell command line
  527  * to run when the 'play' button is pressed (or if autostart is set). The second
  528  * parameter is optional and is the ID of the parent window into which to draw
  529  * the controls.
  530  *
  531  * If the command line contains the string "$window", then no controls are
  532  * drawn.
  533  *
  534  * @param[in]  argc The number of arguments
  535  * @param[in]  argv Array of the arguments
  536  * @param[out] pWidth Width of window
  537  * @param[out] pHeight Height of window
  538  * @param[out] pWindow The Window ID
  539  * @param[out] command The command line
  540  *
  541  * @return True if all Ok
  542  */
  543 static int readCommandLine(int argc, char **argv, unsigned int * pWidth,
  544                                                    unsigned int * pHeight,
  545                                                    Window * pWindow,
  546                                                    AppData_t * appData,
  547                                                    int * pPipeFd)
  548 {
  549      unsigned long temp = 0;
  550      int i;
  551      char * fileName;
  552 
  553      D("Controller started.....\n");
  554 
  555      if (argc < 3)
  556      {
  557           return 0;
  558      }
  559 
  560      i = sscanf(argv[1],"%lu,%d,%d,%lu,%d,%d",
  561             &appData->cmd_flags,
  562             &appData->repeats,
  563             pPipeFd,
  564             &temp,
  565             (int *)pWidth,
  566             (int *)pHeight);
  567 
  568      if(i < 6)
  569      {
  570           return 0;
  571      }
  572 
  573      *pWindow = (Window)temp;
  574      appData->command = argv[2];
  575 
  576      fileName = getenv("file");
  577 
  578      D("CONTROLLER: %s %s %s %s\n",
  579        argv[0],
  580        argv[1],
  581        fileName ? fileName : "NULL",
  582        argv[2]);
  583 
  584      /* The application will use the $repeat variable */
  585      if (appData->cmd_flags & H_REPEATCOUNT)
  586      {
  587           appData->repeats = 1;
  588      }
  589 
  590       /* If the command contains a reference to window it is likely that that
  591       * application also wants to draw into the same window as the controls
  592       * so lets use small controls in top left corner */
  593      if(strstr(appData->command,"$window") || strstr(appData->command,"$hexwindow"))
  594      {
  595           appData->cmd_flags |= H_SMALL_CNTRLS;
  596      }
  597      appData->paused = 0;
  598      appData->dlProgress = 0;
  599      return 1;
  600 }
  601 
  602 /**
  603  * Create the on color
  604  *
  605  * @param[in] dpy Display handle
  606  * @param[in] window The window handle
  607  */
  608 static void createOnColor(Display * dpy, Window window)
  609 {
  610      XColor colour;
  611 
  612      gc_onColor = XCreateGC(dpy, window, 0, 0);
  613      colour.red = 0x0000;
  614      colour.green = 0xa000;
  615      colour.blue = 0x0000;
  616      colour.pixel = 0;
  617      colour.flags=0;
  618 
  619      XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &colour);
  620      XSetForeground(dpy, gc_onColor, colour.pixel);
  621 }
  622 
  623 /**
  624  * Create the off color
  625  *
  626  * @param[in] dpy Display handle
  627  * @param[in] window The window handle
  628  */
  629 static void createOffColor(Display * dpy, Window window)
  630 {
  631      XColor colour;
  632 
  633      gc_offColor = XCreateGC(dpy, window, 0, 0);
  634      colour.red = 0x8000;
  635      colour.green = 0x8000;
  636      colour.blue = 0x8000;
  637      colour.pixel = 0;
  638      colour.flags = 0;
  639 
  640      XAllocColor(dpy, DefaultColormap(dpy, DefaultScreen(dpy)), &colour);
  641      XSetForeground(dpy, gc_offColor, colour.pixel);
  642 }
  643 
  644 
  645 /**
  646  * mozplugger-controller main()
  647  *
  648  * If the command line contains the string "$window", then no controls are
  649  * drawn.
  650  *
  651  * @param[in] argc The number of arguments
  652  * @param[in] argv Array of the arguments
  653  *
  654  * @return Never returns unless the application exits
  655  */
  656 int main(int argc, char **argv)
  657 {
  658      /* Set defaults, may be changed later */
  659      unsigned int width =  3 * DEFAULT_BUTTON_SIZE;
  660      unsigned int height = DEFAULT_BUTTON_SIZE;
  661      int x, y;
  662 
  663      Window parentWid = 0;
  664      AppData_t appData;
  665 
  666      XSetWindowAttributes attr;
  667      Display * dpy = 0;
  668      Window topLevel;
  669      int pipe_fd;
  670      int repeatsLeft;
  671      int sig_chld_fd;
  672 
  673      if(!readCommandLine(argc, argv, &width,
  674                                  &height,
  675                                  &parentWid,
  676                                  &appData,
  677                                  &pipe_fd))
  678      {
  679          exitEarly();
  680      }
  681 
  682 
  683      repeatsLeft = appData.repeats;
  684 
  685      if(!(dpy = XOpenDisplay(getenv("DISPLAY"))))
  686      {
  687           D("%s: unable to open display %s\n",
  688                    argv[0], XDisplayName(getenv("DISPLAY")));
  689           exitEarly();
  690      }
  691 
  692      /* Adjust the width & height to compensate for the window border
  693       * width */
  694      width -= 2 * WINDOW_BORDER_WIDTH;
  695      height -= 2 * WINDOW_BORDER_WIDTH;
  696 
  697      /* x, y co-ords of the parent is of no interest, we need to know
  698       * the x, y relative to the parent. */
  699      normalise_window_coords(&width, &height, &x, &y, appData.cmd_flags);
  700 
  701      D("Controller window: x=%i, y=%i, w=%u, h=%u\n", x, y, width, height);
  702 
  703      attr.border_pixel = 0;
  704      attr.background_pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(dpy));
  705      attr.event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask;
  706      attr.override_redirect=0;
  707 
  708      topLevel = XCreateWindow(dpy,
  709                               parentWid,
  710                               x, y,
  711                               width, height,
  712                               WINDOW_BORDER_WIDTH,
  713                               CopyFromParent,
  714                               InputOutput, (Visual *) CopyFromParent,
  715                               (unsigned long)(CWBorderPixel|
  716                               CWEventMask|
  717                               CWOverrideRedirect|
  718                               CWBackPixel),
  719                               &attr);
  720 
  721      setWindowClassHint(dpy, topLevel, "mozplugger-controller");
  722 
  723      gc_black=XCreateGC(dpy,topLevel,0,0);
  724      XSetForeground(dpy,gc_black,BlackPixel(dpy,DefaultScreen(dpy)));
  725 
  726      gc_white=XCreateGC(dpy,topLevel,0,0);
  727      XSetForeground(dpy,gc_white,WhitePixel(dpy,DefaultScreen(dpy)));
  728 
  729      createOnColor(dpy, topLevel);
  730 
  731      createOffColor(dpy, topLevel);
  732 
  733      setWindowHints(dpy, topLevel, 3);
  734 
  735      /* Map the window, if the parent has asked for redirect this does nothing
  736       * (i.e. if swallow has been used in mozplugger.c) */
  737      XMapWindow(dpy, topLevel);
  738 
  739      XSetIOErrorHandler(die2);
  740      XSetErrorHandler(die);
  741 
  742 
  743      sig_globals.childPid = -1;
  744      signal(SIGHUP, sigdie);
  745      signal(SIGINT, sigdie);
  746      signal(SIGTERM, sigdie);
  747 
  748      if(igetenv("autostart",1))
  749      {
  750           my_play(&appData);
  751      }
  752 
  753      sig_chld_fd = redirect_SIGCHLD_to_fd();
  754 
  755      while(1)
  756      {
  757           fd_set fds;
  758           int maxFd;
  759           int rd_chld_fd = get_chld_out_fd();
  760 
  761           check_x_events(dpy, topLevel, &appData);
  762 
  763           FD_ZERO(&fds);
  764 
  765           maxFd = ConnectionNumber(dpy);
  766           FD_SET(ConnectionNumber(dpy), &fds);
  767 
  768           maxFd = pipe_fd > maxFd ? pipe_fd : maxFd;
  769           FD_SET(pipe_fd, &fds);
  770 
  771           if(sig_chld_fd >= 0)
  772           {
  773                maxFd = sig_chld_fd > maxFd ? sig_chld_fd : maxFd;
  774                FD_SET(sig_chld_fd, &fds);
  775           }
  776           if(rd_chld_fd >= 0)
  777           {
  778                FD_SET(rd_chld_fd, &fds);
  779                maxFd = rd_chld_fd > maxFd ? rd_chld_fd : maxFd;
  780           }
  781 
  782 
  783           D("SELECT IN maxFd = %i\n", maxFd);
  784           if( select(maxFd + 1, &fds, NULL, NULL, 0) > 0)
  785           {
  786                if (FD_ISSET(pipe_fd, &fds))
  787                {
  788                     check_pipe_fd_events(dpy, topLevel, &appData, pipe_fd);
  789                }
  790                if(FD_ISSET(sig_chld_fd, &fds))
  791                {
  792                     handle_SIGCHLD_event();
  793                }
  794                if( FD_ISSET(rd_chld_fd, &fds))
  795                {
  796                     handle_chld_out_event(rd_chld_fd);
  797                }
  798           }
  799           D("SELECT OUT\n");
  800 
  801           if(sig_globals.childPid > 0)
  802           {
  803                int status;
  804                if(waitpid(sig_globals.childPid, &status, WNOHANG) > 0)
  805                {
  806                     appData.paused = 0;
  807                     sig_globals.childPid = -1;
  808                     if(appData.repeats != INF_LOOPS)
  809                     {
  810                          repeatsLeft--;
  811                     }
  812                     if(repeatsLeft > 0)
  813                     {
  814                          my_play(&appData);
  815                          rd_chld_fd = get_chld_out_fd();
  816                     }
  817                     forceRepaint(dpy, topLevel);
  818                }
  819           }
  820           else
  821           {
  822                repeatsLeft = appData.repeats;
  823           }
  824      }
  825 }
  826