1 /*
2  * Copyright (c) 1995 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation for any purpose, without fee, and without written agreement is
7  * hereby granted, provided that the above copyright notice and the following
8  * two paragraphs appear in all copies of this software.
9  *
10  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
11  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
12  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
13  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
16  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
18  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
19  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
20 
21  contributed by (but no rights held by):
22 
23  Michael J. Donahue
24  National Institute of Standards and Technology
25  Gaithersburg MD USA
26  donahue@ulexite.nist.gov
27 
28  */
29 
30 /*
31  * Portions of this software Copyright (c) 1995 Brown University.
32  * All rights reserved.
33  *
34  * Permission to use, copy, modify, and distribute this software and its
35  * documentation for any purpose, without fee, and without written agreement
36  * is hereby granted, provided that the above copyright notice and the
37  * following two paragraphs appear in all copies of this software.
38  *
39  * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR
40  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
41  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN
42  * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43  *
44  * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
45  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
46  * PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
47  * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
48  * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
49  */
50 
51 /*
52     Changes to make the code reentrant:
53        If using ANSI C, do prototyping for static functions
54        display not a global, must be passed to functions
55        display window now not a global, must be passed to functions via xinfo
56           struct
57        FILMState removed - now uses vid_stream->film_has_ended instead
58        use totNumFrames from vid_stream, not global
59        must pass vid_stream (EOF_flag, seekValue, etc. no longer global)
60        CONTROLS version now can deal with >1 movie
61      Additional changes:
62        Do prototyping for static functions
63      - lsh@cs.brown.edu (Loring Holden)
64  */
65 
66 #ifndef NOCONTROLS
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include "dither.h"
71 #include "video.h"
72 #include "ctrlbar.h"
73 #include "proto.h"
74 
75 #ifndef MIPS
76 #include <sys/time.h>
77 #else
78 #include <sys/types.h>
79 #include <sys/system.h>
80 #endif
81 
82 /* Default is to play asap.  If you want it to start paused, change to
83    CTRL_PAUSE
84  */
85 #define INITIAL_STATE CTRL_PLAY
86 
87 /* Global variable definitions */
88 int ControlShow     = CTRLBAR_ON;         /* ON => Show (display) control bar */
89 int ControlState    = CTRL_UNDEFINED;     /* Current control state */
90 int ControlMotion   = CTRLMOTION_OFF;     /* Pause mode */
91 long TotalFrameCount= 0; /* Total number of frames processed, including loops */
92 
93 /* File statics */
94 static int CtrlBarWidth;
95 static int CtrlBarHeight =  31;
96 static int CtrlBarBorder =   4;
97 static int ChildBorder   =   2;
98 static int ChildMargin   =   6;
99 
100 static Window ctrlwindow = 0;
101 static int screen = -1;
102 static XFontStruct* ctrlfont = NULL;
103 static int fontheight, fontwidth;
104 static unsigned long fgcolor, bgcolor;
105 
106 static int ctrl_init = 0;  /* 1 => Control windows have been initialized */
107 
108 /* Support for WM_DELETE_WINDOW */
109 static Atom protocol_atom = (Atom)None;
110 static Atom delete_atom   = (Atom)None;
111 
112 /* Child windows */
113 static int ChildCount    =   7;
114 static Window frametotalwin;
115 static int ftw_width, ftw_height;
116 static Window rewindwin;
117 static int rww_width, rww_height;
118 static Window pausewin;
119 static int psw_width, psw_height;
120 static Window playwin;
121 static int plw_width, plw_height;
122 static Window stepwin;
123 static int stw_width, stw_height;
124 static Window exitwin;
125 static int exw_width, exw_height;
126 static Window loopwin;
127 static int lpw_width, lpw_height;
128 
129 
130 /*
131  *--------------------------------------------------------------
132  *
133  * StopWatch --
134  *
135  *        On/off timing routine (in real elapsed time).
136  *
137  * Results:
138  *        If import is:
139  *                STOPWATCH_START ---- Starts timing, returns 0.0.
140  *                STOPWATCH_STOP  ---- Stops timing,  returns elapsed
141  *                                    time in seconds.
142  *                STOPWATCH_RESET ---- Resets timing, returns 0.0.
143  *                STOPWATCH_READ  ---- Returns elapsed time in seconds.
144  *
145  * Side effects:
146  *      None.
147  *
148  *--------------------------------------------------------------
149  */
150 
151 double
StopWatch(action)152 StopWatch(action)
153 int action;
154 {
155   static struct timeval start,current;  /* Working times */
156   static struct timeval elapsed;        /* Previously accumulated time */
157   static int state = STOPWATCH_STOP;
158   double dtemp = 0.0;
159   long ltemp;
160 
161   if (action == state) {
162     if (state == STOPWATCH_START) {
163       return 0.0;
164     }
165     else return elapsed.tv_sec + elapsed.tv_usec/1000000.0;
166   }
167   switch(action) {
168   case STOPWATCH_START:
169     state = STOPWATCH_START;
170     gettimeofday(&start, (struct timezone *)NULL);
171     break;
172   case STOPWATCH_STOP:
173     gettimeofday(&current, (struct timezone *)NULL);
174     state = STOPWATCH_STOP;
175     ltemp = elapsed.tv_usec + current.tv_usec - start.tv_usec;
176     elapsed.tv_sec += current.tv_sec-start.tv_sec + ltemp/1000000;
177     elapsed.tv_usec = ltemp % 1000000;
178     /* And fall through to STOPWATCH_READ */
179   case STOPWATCH_READ:
180     if (state == STOPWATCH_START) { /* Stopwatch is running */
181       gettimeofday(&current,(struct timezone *)NULL);
182       dtemp = (current.tv_sec-start.tv_sec + elapsed.tv_sec)
183         + (current.tv_usec-start.tv_usec + elapsed.tv_usec) / 1000000.0;
184     }
185     else dtemp = elapsed.tv_sec + elapsed.tv_usec/1000000.0;
186     break;
187   case STOPWATCH_RESET:
188     state = STOPWATCH_STOP;
189     elapsed.tv_sec = elapsed.tv_usec = 0;
190     break;
191   default:
192     fprintf(stderr,"Illegal action (%d) requested of StopWatch()",action);
193     exit(1);
194   }
195   return dtemp;
196 }
197 
198 
199 /*
200  *--------------------------------------------------------------
201  *
202  * GetWindowOrigins --
203  *
204  *        Determines window coordinates with respect to root window.
205  *
206  * Results:
207  *        Sets (xwhole,ywhole) to root coordinates of upper lefthand corner
208  *        of the specified window (including decorations), and (xclient,yclient)
209  *        to the root coordinates of the client region.
210  *
211  * Side effects:
212  *      None.
213  *
214  *--------------------------------------------------------------
215  */
216 
217 #ifdef __STDC__
GetWindowOrigins(XInfo * xinfo,int * xclient,int * yclient,int * xwhole,int * ywhole)218 static void GetWindowOrigins(XInfo *xinfo, int *xclient,
219 			     int *yclient, int *xwhole, int *ywhole)
220 #else
221 static void GetWindowOrigins(xinfo,xclient,yclient,xwhole,ywhole)
222 XInfo *xinfo;
223 int *xclient;
224 int *yclient;
225 int *xwhole;
226 int *ywhole;
227 #endif
228 {
229   Window dummy_window;
230   Window win=xinfo->window;
231   Display *display=xinfo->display;
232 
233   /* First get coordinates for client "sub"-window */
234   XTranslateCoordinates(display,win,DefaultRootWindow(display),
235                         0,0,xclient,yclient,&dummy_window);
236   if (dummy_window == None) { /* Shouldn't happen, but if so, then punt */
237     *xwhole = *xclient;
238     *ywhole = *yclient;
239     return;
240   }
241 
242   /* Now dummy_window should be a direct child of root, so find */
243   /* its base coordinates.                                      */
244   XTranslateCoordinates(display,dummy_window,DefaultRootWindow(display),
245                         0,0,xwhole,ywhole,&dummy_window);
246 
247   /* And finally, subtract 1 for good luck ;-) */
248   if ((*xwhole) > 0) {
249     (*xwhole)--;
250   }
251   if ((*ywhole) > 0) {
252     (*ywhole)--;
253   }
254 }
255 
256 
257 
258 /*
259  *--------------------------------------------------------------
260  *
261  * WindowMapped --
262  *
263  *        Check event to see if window is mapped.  A procedure
264  *        intended to be passed to XIfEvent().
265  *
266  * Results:
267  *        Read the code.
268  *
269  * Side effects:
270  *      None.
271  *
272  *--------------------------------------------------------------
273  */
274 
WindowMapped(dsp,xev,window)275 Bool WindowMapped(dsp,xev,window)
276 Display *dsp;
277 XEvent *xev;
278 char *window;
279 {
280   if (xev->type == MapNotify && xev->xmap.event == *((Window *)window))
281     return TRUE;
282   return FALSE;
283 }
284 
285 /*
286  *--------------------------------------------------------------
287  *
288  * IfEventType --
289  *
290  *        Check event type.  A procedure intended to be passed to XIfEvent().
291  *
292  * Results:
293  *        Read the code.
294  *
295  * Side effects:
296  *      None.
297  *
298  *--------------------------------------------------------------
299  */
300 
IfEventType(dsp,xev,type)301 Bool IfEventType(dsp,xev,type)
302 Display *dsp;
303 XEvent *xev;
304 char *type;
305 {
306   if (xev->type == *((int *)type)) {
307     return TRUE;
308   }
309   return FALSE;
310 }
311 
312 
313 
314 /*
315  *--------------------------------------------------------------
316  * ShowHideControls---
317  *
318  *        Maps or unmaps control bar as dictated by the value of the
319  *        global variable ControlShow.
320  *
321  * Results:
322  *        None.
323  *
324  * Side effects:
325  *      None.
326  *
327  *--------------------------------------------------------------
328  */
329 #ifdef __STDC__
ShowHideControls(XInfo * xinfo)330 static void ShowHideControls(XInfo *xinfo)
331 #else
332 static void ShowHideControls(xinfo)
333 XInfo *xinfo;
334 #endif
335 {
336   if (ControlShow == CTRLBAR_ON) {
337     XEvent event;
338     XMapRaised(xinfo->display, ctrlwindow);
339     XIfEvent(xinfo->display, &event, WindowMapped, (char *)(&ctrlwindow));
340                                                /* Wait for map. */
341   }
342   else {
343     XUnmapWindow(xinfo->display, ctrlwindow);
344   }
345 }
346 
347 
348 
349 /*
350  *--------------------------------------------------------------
351  *
352  * MakeControlBar --
353  *
354  *        Creates and (possibly) displays Control Bar in root window
355  *      at position (x,y) relative to video output window.
356  *
357  * Results:
358  *        Sets ctrlwindow.
359  *
360  * Side effects:
361  *        Sets ctrl_init to 1 if successful.
362  *
363  *--------------------------------------------------------------
364  */
MakeControlBar(xinfo)365 void MakeControlBar(xinfo)
366   XInfo *xinfo;
367 {
368   char *ctrlname = "MPEG Player Controls";
369   XSizeHints hint;
370   int xpos, ypos;
371   Display *display=xinfo->display;
372 
373   if (ctrl_init) {
374     fprintf(stderr,
375             "Warning from MakeControlBar(): Controls already initialized\n");
376     return;
377   }
378   if (xinfo->ditherType == NO_DITHER) return;
379   if (display == (Display*)NULL) {
380     fprintf(stderr,
381       "Fatal error in MakeControlBar(): Display pointer not initialized\n");
382     exit(1);
383   }
384 
385   /* Get font (used in window sizing) */
386   if ((ctrlfont = XLoadQueryFont(display, "fixed")) == NULL) {
387     fprintf(stderr,"Error: Unable to load font \"fixed\" for Control Bar\n");
388     exit(1);
389   }
390   fontheight = ctrlfont->ascent + ctrlfont->descent;
391   fontwidth = ctrlfont->max_bounds.width;
392 
393   if (fontheight < 4 || fontheight > 75 || fontwidth < 2 || fontwidth > 30) {
394     fprintf(stderr,"Warning: Font size seems suspect...guessing\n");
395     fontheight = 20;
396     fontwidth = 10; /* Maybe 13 and 6 are better */
397   }
398 
399   /* Set window sizes */
400   ftw_height = CtrlBarHeight-2*(ChildBorder+ChildMargin);
401                                              ftw_width = fontwidth * 21;
402   rww_height = ftw_height;                   rww_width = fontwidth * 8;
403   psw_height = rww_height;                   psw_width = fontwidth * 7;
404   stw_height = psw_height;                   stw_width = fontwidth * 6;
405   plw_height = stw_height;                   plw_width = fontwidth * 6;
406   lpw_height = plw_height;                   lpw_width = fontwidth * 10;
407   exw_height = lpw_height;                   exw_width = fontwidth * 6;
408   CtrlBarWidth = rww_width + psw_width + stw_width + plw_width + lpw_width
409     + exw_width + ftw_width + ChildMargin
410     + ChildCount*(ChildMargin + 2*ChildBorder);
411 
412   /* Figure out how to place control bar just above display window */
413   GetWindowOrigins(xinfo,&xpos,&ypos,&hint.x,&hint.y);
414 
415   /* Leave room for title bar decorations. Note this assumes */
416   /* control bar dec. same height as for display window */
417   hint.y = 2*hint.y - ypos;
418 
419   hint.y -= (CtrlBarHeight + 2*CtrlBarBorder + 1);  /* +1 for luck ;-) */
420   if (hint.y < 0) {
421     hint.y = 0;
422   }
423   hint.max_width  = hint.base_width  = hint.width = CtrlBarWidth;
424   hint.max_height = hint.base_height = hint.height = CtrlBarHeight;
425   hint.min_width  = hint.min_height  = 0;
426   hint.flags =  PMinSize | PMaxSize | PBaseSize |
427     PPosition | PSize | USPosition;
428 
429   screen = DefaultScreen (display);
430   fgcolor = BlackPixel(display, screen);
431   bgcolor = WhitePixel(display, screen);
432 
433   /* Create main control window */
434   ctrlwindow = XCreateSimpleWindow (display,
435 				    DefaultRootWindow(display),
436                                     hint.x, hint.y,
437                                     hint.base_width, hint.base_height,
438                                     CtrlBarBorder, fgcolor, bgcolor);
439 
440   /* Create child windows */
441   xpos = ChildMargin;
442   ypos = ChildMargin;
443   frametotalwin = XCreateSimpleWindow (display, ctrlwindow, xpos, ypos,
444              ftw_width, ftw_height, ChildBorder, fgcolor, bgcolor);
445   xpos += ftw_width + 2*ChildBorder + ChildMargin;
446   rewindwin = XCreateSimpleWindow (display, ctrlwindow, xpos, ypos,
447              rww_width, rww_height, ChildBorder, fgcolor, bgcolor);
448   xpos += rww_width + 2*ChildBorder + ChildMargin;
449   pausewin = XCreateSimpleWindow (display, ctrlwindow, xpos, ypos,
450              psw_width, psw_height, ChildBorder, fgcolor, bgcolor);
451   xpos += psw_width + 2*ChildBorder + ChildMargin;
452   stepwin = XCreateSimpleWindow (display, ctrlwindow, xpos, ypos,
453              stw_width, stw_height, ChildBorder, fgcolor, bgcolor);
454   xpos += stw_width + 2*ChildBorder + ChildMargin;
455   playwin = XCreateSimpleWindow (display, ctrlwindow, xpos, ypos,
456              plw_width, plw_height, ChildBorder, fgcolor, bgcolor);
457   xpos += plw_width + 2*ChildBorder + ChildMargin;
458   loopwin = XCreateSimpleWindow (display, ctrlwindow, xpos, ypos,
459              lpw_width, lpw_height, ChildBorder, fgcolor, bgcolor);
460   xpos += lpw_width + 2*ChildBorder + ChildMargin;
461   exitwin = XCreateSimpleWindow (display, ctrlwindow, xpos, ypos,
462              exw_width, exw_height, ChildBorder, fgcolor, bgcolor);
463 
464   /* Set up windows */
465   XSelectInput(display, ctrlwindow, StructureNotifyMask);
466   XSetStandardProperties(display, ctrlwindow, ctrlname, ctrlname, None,
467                          NULL, 0, &hint);
468   /*Safety*/
469   XResizeWindow(display,ctrlwindow, hint. base_width, hint. base_height);
470 
471   XSelectInput(display, rewindwin, ExposureMask | ButtonPressMask);
472   XSelectInput(display, pausewin,  ExposureMask | ButtonPressMask);
473   XSelectInput(display, stepwin,   ExposureMask | ButtonPressMask);
474   XSelectInput(display, playwin,   ExposureMask | ButtonPressMask);
475   XSelectInput(display, loopwin,   ExposureMask | ButtonPressMask);
476   XSelectInput(display, exitwin,   ExposureMask | ButtonPressMask);
477   XSelectInput(display, frametotalwin, ExposureMask );
478 
479   /* Add "Delete" option to system menus */
480   protocol_atom = XInternAtom(display,"WM_PROTOCOLS",False);
481   delete_atom   = XInternAtom(display,"WM_DELETE_WINDOW",False);
482   if ( protocol_atom != (Atom)None && delete_atom != (Atom)None) {
483     XSetWMProtocols(display, xinfo->window, &delete_atom, 1);/* Video window */
484     XSetWMProtocols(display, ctrlwindow, &delete_atom, 1);  /* Control bar */
485   }
486 
487   /* Map windows (or not ;-) */
488   XMapSubwindows(display, ctrlwindow);
489   ShowHideControls(xinfo);
490 
491   ctrl_init = 1;  /* Control Bar successfully initialized */
492 }
493 
494 
495 
496 /*
497  *--------------------------------------------------------------
498  *
499  * Child window draw functions --
500  *
501  *        (Re)draws child window
502  *
503  * Results:
504  *        None.
505  *
506  * Side effects:
507  *        None.
508  *
509  *--------------------------------------------------------------
510  */
511 
512 #if __STDC__
WriteCenteredText(Window win,GC gc,int winwidth,int winheight,char * str,Display * display)513 static void WriteCenteredText(Window win,
514 			      GC gc,
515 			      int winwidth,
516 			      int winheight,
517 			      char *str,
518 			      Display *display)
519 #else
520 static void WriteCenteredText(win,gc,winwidth,winheight,str,display)
521 Window win;
522 GC gc;
523 int winwidth, winheight;
524 char *str;
525 Display *display;
526 #endif
527 {
528   int xpos, ypos, len;
529   len = strlen(str);
530   ypos = (winheight + ctrlfont->ascent)/2 - 1; /* Ignore descenders */
531   xpos = (winwidth - len*fontwidth)/2;
532   XDrawImageString(display, win, gc, xpos, ypos, str, len);
533 }
534 
535 #if __STDC__
ExposeWindow(Window win,Display * display)536 static void ExposeWindow(Window win, Display *display)
537 #else
538 static void ExposeWindow(win,display)
539 Window win;
540 Display *display;
541 #endif
542 {
543   static XEvent event;
544   event.xexpose.type = Expose;
545   event.xexpose.serial = 0;
546   event.xexpose.send_event = TRUE;
547   event.xexpose.display = display;
548   event.xexpose.window = win;
549   event.xexpose.x = 0;
550   event.xexpose.y = 0;
551   event.xexpose.width = 0;
552   event.xexpose.height = 0;
553   event.xexpose.count = 0;
554   XSendEvent(display, win, FALSE, ExposureMask, &event);
555 }
556 
557 #if __STDC__
NormalColors(GC gc,Display * display)558 static void NormalColors(GC gc, Display *display)
559 #else
560 static void NormalColors(gc,display)
561 GC gc;
562 Display *display;
563 #endif
564 {
565   XSetForeground(display, gc, fgcolor);
566   XSetBackground(display, gc, bgcolor);
567 }
568 
569 #if __STDC__
InvertColors(GC gc,Display * display)570 static void InvertColors(GC gc, Display *display)
571 #else
572 static void InvertColors(gc,display)
573 GC gc;
574 Display *display;
575 #endif
576 {
577   XSetForeground(display, gc, bgcolor);
578   XSetBackground(display, gc, fgcolor);
579 }
580 
581 #if __STDC__
DrawRewind(GC gc,Display * display)582 static void DrawRewind(GC gc, Display *display)
583 #else
584 static void DrawRewind(gc,display)
585 GC gc;
586 Display *display;
587 #endif
588 {
589   if (ControlState == CTRL_REWIND) {
590     XFillRectangle(display, rewindwin, gc, 0, 0, rww_width, rww_height);
591     InvertColors(gc,display);
592     WriteCenteredText(rewindwin, gc, rww_width, rww_height, "Rewind",display);
593     NormalColors(gc,display);
594   }
595   else {
596     WriteCenteredText(rewindwin, gc, rww_width, rww_height, "Rewind",display);
597   }
598 }
599 
600 #if __STDC__
DrawPause(GC gc,Display * display)601 static void DrawPause(GC gc, Display *display)
602 #else
603 static void DrawPause(gc,display)
604 GC gc;
605 Display *display;
606 #endif
607 {
608   if (ControlState == CTRL_EOF || ControlState == CTRL_FFWD
609      || ControlState == CTRL_PAUSE) {
610     XFillRectangle(display,pausewin,gc,0,0,psw_width,psw_height);
611     InvertColors(gc,display);
612     switch(ControlState) {
613     case CTRL_EOF:
614       WriteCenteredText(pausewin,gc,psw_width,psw_height,"End",display);
615       break;
616     case CTRL_FFWD:
617       WriteCenteredText(pausewin,gc,psw_width,psw_height,"Wait",display);
618       break;
619     default:
620       WriteCenteredText(pausewin,gc,psw_width,psw_height,"Pause",display);
621       break;
622     }
623     NormalColors(gc,display);
624   }
625   else {
626     WriteCenteredText(pausewin,gc,psw_width,psw_height,"Pause",display);
627   }
628 }
629 
630 #if __STDC__
DrawStep(GC gc,Display * display)631 static void DrawStep(GC gc, Display *display)
632 #else
633 static void DrawStep(gc,display)
634 GC gc;
635 Display *display;
636 #endif
637 {
638   if (ControlState == CTRL_STEP) {
639     XFillRectangle(display, stepwin, gc, 0, 0, stw_width, stw_height);
640     InvertColors(gc,display);
641   }
642   WriteCenteredText(stepwin, gc, stw_width, stw_height, "Step",display);
643   if (ControlState == CTRL_STEP) {
644     NormalColors(gc,display);
645   }
646 }
647 
648 #if __STDC__
DrawPlay(GC gc,Display * display)649 static void DrawPlay(GC gc, Display *display)
650 #else
651 static void DrawPlay(gc,display)
652 GC gc;
653 Display *display;
654 #endif
655 {
656   if (ControlState == CTRL_PLAY ||
657      (ControlState == CTRL_EOF && ControlMotion == CTRLMOTION_ON)) {
658     XFillRectangle(display, playwin, gc, 0, 0, plw_width, plw_height);
659     InvertColors(gc,display);
660     WriteCenteredText(playwin, gc, plw_width, plw_height, "Play",display);
661     NormalColors(gc,display);
662   }
663   else {
664     WriteCenteredText(playwin, gc, plw_width, plw_height, "Play",display);
665   }
666 }
667 
668 #if __STDC__
DrawLoop(GC gc,Display * display)669 static void DrawLoop(GC gc, Display *display)
670 #else
671 static void DrawLoop(gc,display)
672 GC gc;
673 Display *display;
674 #endif
675 {
676   if (loopFlag) {
677     XFillRectangle(display, loopwin, gc, 0, 0, lpw_width, lpw_height);
678     InvertColors(gc,display);
679     WriteCenteredText(loopwin, gc, lpw_width, lpw_height, "Loop ON",display);
680     NormalColors(gc,display);
681   }
682   else WriteCenteredText(loopwin, gc, lpw_width, lpw_height, "Loop OFF",
683 			 display);
684 }
685 
686 #if __STDC__
DrawExit(GC gc,Display * display)687 static void DrawExit(GC gc, Display *display)
688 #else
689 static void DrawExit(gc,display)
690 GC gc;
691 Display *display;
692 #endif
693 {
694   if (ControlState == CTRL_EXIT) {
695     XFillRectangle(display,exitwin, gc, 0, 0, exw_width, exw_height);
696     InvertColors(gc,display);
697   }
698   WriteCenteredText(exitwin, gc, exw_width, exw_height, "Exit",display);
699   if (ControlState == CTRL_EXIT) {
700     NormalColors(gc,display);
701   }
702 }
703 
UpdateFrameTotal(display)704 void UpdateFrameTotal(display)
705 Display *display;
706 {
707   if (!ctrl_init) {
708     return;
709   }
710   ExposeWindow(frametotalwin,display);
711 }
712 
UpdateControlDisplay(display)713 void UpdateControlDisplay(display)
714 Display *display;
715 {
716   if (!ctrl_init) {
717     return;
718   }
719   ExposeWindow(rewindwin,display);
720   ExposeWindow(pausewin,display);
721   ExposeWindow(stepwin,display);
722   ExposeWindow(playwin,display);
723   ExposeWindow(loopwin,display);
724   ExposeWindow(exitwin,display);
725   ExposeWindow(frametotalwin,display);
726 }
727 
728 #if __STDC__
DrawFrameTotal(GC gc,VidStream ** vid_stream,Display * display,int numMovies)729 static void DrawFrameTotal(GC gc, VidStream **vid_stream, Display *display,
730 			   int numMovies)
731 #else
732 static void DrawFrameTotal(gc, vid_stream, display, numMovies)
733 GC gc;
734 VidStream **vid_stream;
735 Display *display;
736 int numMovies;
737 #endif
738 {
739   char str[32];
740   double dtemp;
741   int totNumFrames=0, i;
742 
743   dtemp = StopWatch(STOPWATCH_READ);
744 
745 
746   for (i=0;i<numMovies;i++) {
747      if ((vid_stream[i]!=NULL) &&
748 	 (vid_stream[i]->totNumFrames > totNumFrames)) {
749 	 totNumFrames= vid_stream[i]->totNumFrames;
750      }
751   }
752 
753   if (dtemp > 0.0) {
754     sprintf(str, "Frame/Rate%4d/%4.1f",
755 	totNumFrames, TotalFrameCount/dtemp);
756   }
757   else {
758     sprintf(str, "Frame/Rate%4d/----", totNumFrames);
759   }
760   WriteCenteredText(frametotalwin, gc, ftw_width, ftw_height, str, display);
761 }
762 
763 #if __STDC__
CreateCtrlGC(Display * display)764 static GC CreateCtrlGC(Display *display)
765 #else
766 static GC CreateCtrlGC(display)
767 Display *display;
768 #endif
769 {
770   XGCValues gcv;
771   GC gc;
772   gcv.foreground = BlackPixel(display, screen);
773   gcv.background = WhitePixel(display, screen);
774   gcv.font = ctrlfont->fid;
775   gcv.subwindow_mode = ClipByChildren;
776 /*  gcv.subwindow_mode = IncludeInferiors; */
777   gc=XCreateGC(display, ctrlwindow,
778                GCForeground|GCBackground|GCFont|GCSubwindowMode, &gcv);
779   return gc;
780 }
781 
782 
783 /*
784  *--------------------------------------------------------------
785  *
786  * GetStateButton --
787  *
788  *        Determines the window of the button associated with the
789  *        import ctrlstate.
790  *
791  * Results:
792  *        The associated window, if any; Otherwise 0.
793  *
794  * Side effects:
795  *        None.
796  *
797  *--------------------------------------------------------------
798  */
799 
800 #if __STDC__
GetStateButton(int ctrlstate)801 static Window GetStateButton(int ctrlstate)
802 #else
803 static Window GetStateButton(ctrlstate)
804 int ctrlstate;
805 #endif
806 {
807   switch(ctrlstate) {
808     case CTRL_REWIND:
809       return rewindwin;
810     case CTRL_PAUSE:
811     case CTRL_FFWD:
812     case CTRL_EOF:
813       return pausewin;
814     case CTRL_STEP:
815       return stepwin;
816     case CTRL_PLAY:
817       return playwin;
818     case CTRL_EXIT:
819       return exitwin;
820     default:
821       break;
822     }
823   return (Window)0;
824 }
825 
826 
827 /*
828  *--------------------------------------------------------------
829  *
830  * DrawButton --
831  *
832  *        Calls the draw button function associated with the import
833  *        window button.
834  *
835  * Results:
836  *        None.
837  *
838  * Side effects:
839  *        None.
840  *
841  *--------------------------------------------------------------
842  */
843 
844 #if __STDC__
DrawButton(Window button,GC gc,Display * display,VidStream ** vid_stream,int num)845 static void DrawButton(Window button, GC gc,
846 		       Display *display,
847 		       VidStream **vid_stream,
848 		       int num)
849 #else
850 static void DrawButton(button,gc,display,vid_stream, num)
851 Window button;
852 GC gc;
853 Display *display;
854 VidStream **vid_stream;
855 int num;
856 #endif
857 {
858   if (button == frametotalwin)  DrawFrameTotal(gc,vid_stream,display,num);
859   else if (button == rewindwin) DrawRewind(gc,display);
860   else if (button == pausewin)  DrawPause(gc,display);
861   else if (button == stepwin)   DrawStep(gc,display);
862   else if (button == playwin)   DrawPlay(gc,display);
863   else if (button == loopwin)   DrawLoop(gc,display);
864   else if (button == exitwin)   DrawExit(gc,display);
865   else fprintf(stderr, "DrawButton called with unknown button\n");
866 }
867 
868 
869 /*
870  *
871  * WindowSearch --
872  *
873  *        Search window id's to see if an expose event is on a display window
874  *
875  */
876 #if __STDC__
WindowSearch(XInfo * xinfo,Window win,int num)877 static int WindowSearch(XInfo *xinfo, Window win, int num)
878 #else
879 static int WindowSearch(xinfo, win, num)
880 XInfo *xinfo;
881 Window win;
882 int num;
883 #endif
884 {
885 	int i;
886 
887 	for (i=0;(i<num) && (xinfo[i].window!=win);i++) {
888 	}
889 	if (i==num) return -1;
890 	else return i;
891 }
892 
893 
894 /*
895  *--------------------------------------------------------------
896  *
897  * ControlBar --
898  *
899  *        Checks XEvent queue for control commands.
900  *
901  * Results:
902  *        Adjusts global variables ControlState, loopFlag as appropriate.
903  *
904  * Side effects:
905  *        May adjust StopWatch state.
906  *
907  *--------------------------------------------------------------
908  */
909 
ControlBar(vid_stream,xinfo,numMovies)910 void ControlBar(vid_stream,xinfo,numMovies)
911 VidStream **vid_stream;
912 XInfo *xinfo;
913 int numMovies;
914 {
915   GC gc;
916   int gcflag, winNum;
917   Window oldbutton, newbutton;
918   XEvent event;
919   static int LastState = CTRL_UNDEFINED;
920   Display *display=xinfo[0].display;
921 
922   gcflag = 0;
923 
924   /* Check to see if ControlState was modified outside this function, */
925   /* and update control displays if it was.                           */
926   if (LastState != ControlState) {
927     if (!gcflag) {
928       gc = CreateCtrlGC(display);
929       gcflag = 1;
930     }
931     if ((oldbutton = GetStateButton(LastState)) != (Window)NULL) {
932       XClearWindow(display, oldbutton);
933       DrawButton(oldbutton, gc, display, vid_stream, numMovies);
934       if (LastState == CTRL_EOF) {
935         XClearWindow(display, playwin);
936         DrawButton(playwin, gc, display, vid_stream, numMovies);
937       }
938     }
939     DrawButton(GetStateButton(LastState = ControlState), gc,
940 	       display, vid_stream, numMovies);
941   }
942 
943   /* Process events, if any */
944   if (XPending(display) < 1) { /* No events */
945     if (gcflag) {
946       XFreeGC(display, gc);
947     }
948     LastState = ControlState;
949     return;
950   }
951 
952   if (!gcflag) {
953     gc=CreateCtrlGC(display);
954     gcflag=1;
955   }
956   do {
957     XNextEvent(display, &event);
958 #ifdef HAVE_XFILTEREVENT /* Define if needed; Some older X's don't have this */
959     if (XFilterEvent(&event, ctrlwindow)) continue;
960 #endif
961     switch(event.type) {
962       case ButtonPress:
963         /* Toggle Buttons */
964         if (event.xbutton.window == loopwin) {
965           if (loopFlag) {
966             XClearWindow(display,loopwin);
967             loopFlag = 0;
968           }
969           else {
970             loopFlag = 1;
971             if (ControlState == CTRL_EOF && ControlMotion == CTRLMOTION_ON) {
972               ControlState = CTRL_REWIND;
973               DrawRewind(gc,display);
974               XClearWindow(display, playwin);
975               DrawPlay(gc,display);
976               XClearWindow(display, pausewin);
977               DrawPause(gc,display);
978             }
979           }
980           DrawLoop(gc,display);
981           break;
982         }
983         /* Click in display window */
984         else if (WindowSearch(xinfo,event.xbutton.window,numMovies) != -1) {
985           if (ControlShow) {
986             ControlShow = CTRLBAR_OFF;
987           } else {
988             ControlShow = CTRLBAR_ON;
989           }
990           ShowHideControls(&xinfo[0]);
991           break;
992         }
993         /* ControlState buttons --- */
994         /* Get currently selected button */
995         oldbutton = GetStateButton(ControlState);
996         /* Update state */
997         if (event.xbutton.window == pausewin)  {
998           if ((ControlState == CTRL_EOF || ControlState == CTRL_FFWD)
999              && ControlMotion == CTRLMOTION_ON) {
1000             ControlMotion = CTRLMOTION_OFF;
1001             XClearWindow(display, playwin);
1002             DrawPlay(gc,display);
1003           }
1004           else if (ControlState == CTRL_PLAY) {
1005             ControlMotion = CTRLMOTION_OFF;
1006             ControlState = CTRL_PAUSE;
1007           }
1008           else if (ControlState == CTRL_PAUSE) {
1009             ControlMotion = CTRLMOTION_ON;
1010             ControlState = CTRL_PLAY;
1011           }
1012         }
1013         else if (event.xbutton.window == stepwin) {
1014           if (ControlState == CTRL_PAUSE || ControlState == CTRL_PLAY)
1015             ControlState = CTRL_STEP;
1016           else if (ControlState == CTRL_EOF && loopFlag)
1017             ControlState = CTRL_REWIND;
1018           ControlMotion = CTRLMOTION_OFF;
1019         }
1020         else if (event.xbutton.window == playwin) {
1021           ControlMotion = CTRLMOTION_ON;
1022           if (ControlState == CTRL_EOF) {
1023             if (loopFlag) {
1024               ControlState = CTRL_REWIND;
1025             }
1026             DrawButton(playwin, gc, display, vid_stream, numMovies);
1027           }
1028           else if (ControlState == CTRL_PAUSE) {
1029             ControlState = CTRL_PLAY;
1030           }
1031         }
1032         else if (event.xbutton.window == rewindwin) {
1033           ControlState = CTRL_REWIND;
1034          }
1035         else if (event.xbutton.window == exitwin) {
1036           ControlState = CTRL_EXIT;
1037         }
1038         /* Get newly selected button */
1039         newbutton = GetStateButton(ControlState);
1040         if (LastState == ControlState) break;
1041         /* Adjust stopwatch */
1042         if (LastState == CTRL_PLAY)
1043           StopWatch(STOPWATCH_STOP);  /* Stop playing */
1044         else if (ControlState == CTRL_PLAY)
1045           StopWatch(STOPWATCH_START); /* Start playing */
1046         /* Update button display */
1047         if (oldbutton != (Window)NULL) {
1048           XClearWindow(display,oldbutton);
1049           DrawButton(oldbutton,gc,display,vid_stream,numMovies);
1050         }
1051         DrawButton(newbutton,gc,display,vid_stream,numMovies);
1052         break;
1053       case ClientMessage:
1054         if (event.xclient.message_type != protocol_atom ||
1055             event.xclient.data.l[0] != delete_atom      ||
1056             event.xclient.format != 32) break; /* Not WM_DELETE_WINDOW */
1057         /* Otherwise drop through to DestroyNotify */
1058       case DestroyNotify:
1059         ControlState=CTRL_EXIT;
1060         break;
1061       case Expose:
1062         if (event.xexpose.count > 0) {
1063           break; /* Wait for last expose event */
1064         }
1065         if ((winNum=
1066 	       WindowSearch(xinfo,event.xexpose.window, numMovies)) != -1) {
1067 	  if ( vid_stream[winNum]->current != NULL) {
1068 	    ExecuteDisplay(vid_stream[winNum],0,&xinfo[winNum]);
1069 	  }
1070         }
1071         else {
1072           DrawButton(event.xexpose.window,gc,display,vid_stream,numMovies);
1073         }
1074         break;
1075       default:
1076         break;
1077     }
1078   } while (XPending(display) > 0);
1079   if (gcflag) {
1080     XFreeGC(display, gc);
1081   }
1082   LastState = ControlState;
1083 }
1084 
1085 
1086 /*
1087  *--------------------------------------------------------------
1088  *
1089  * ControlLoop --
1090  *
1091  *        Main control loop.  Intermixes video processing (as
1092  *        determined by ControlState) with user input.
1093  *
1094  * Results:
1095  *        None.
1096  *
1097  * Side effects:
1098  *        Adjusts StopWatch state, totNumFrames, ControlState.
1099  *        May also reset video state.
1100  *
1101  *--------------------------------------------------------------
1102  */
1103 
ControlLoop(vid_stream,xinfo,numStreams)1104 void ControlLoop(vid_stream,xinfo,numStreams)
1105 VidStream **vid_stream;
1106 XInfo *xinfo;
1107 int numStreams;
1108 {
1109   int itemp, i, allMovies;
1110   XEvent event;
1111   Display *display=xinfo[0].display;
1112 
1113   for (i=0;(display==NULL) && (i<numStreams); i++)  {
1114     display=xinfo[i].display;
1115   }
1116 
1117   if (!ctrl_init) {
1118     fprintf(stderr,"ControlLoop() accessed without initialization\n");
1119     exit(1);
1120   }
1121   StopWatch(STOPWATCH_RESET);
1122   TotalFrameCount = 0;
1123   StopWatch(STOPWATCH_START);
1124 
1125   for (i=0;i<numStreams;i++) {
1126     itemp = vid_stream[i]->totNumFrames;
1127     while (vid_stream[i]->totNumFrames == itemp)
1128       mpegVidRsrc(0, vid_stream[i], 0, &xinfo[i]); /* Advance to 1st frame */
1129   }
1130   if (startFrame > vid_stream[0]->totNumFrames) {
1131     ControlState = CTRL_FFWD;
1132     ControlMotion = CTRLMOTION_OFF;
1133     StopWatch(STOPWATCH_STOP);
1134   }
1135   else if (ControlShow != CTRLBAR_ON || noDisplayFlag) {
1136     ControlState = CTRL_PLAY;
1137     ControlMotion = CTRLMOTION_ON;
1138   }
1139   else {
1140     ControlState = INITIAL_STATE;
1141     ControlMotion = CTRLMOTION_OFF;
1142     if (ControlState == CTRL_PAUSE) {
1143       StopWatch(STOPWATCH_STOP);
1144     } else {
1145       StopWatch(STOPWATCH_START);
1146     }
1147   }
1148 
1149   while (1) {
1150     ControlBar(vid_stream,&xinfo[0],numStreams);
1151     if (ControlState == CTRL_PAUSE || ControlState == CTRL_EOF) {
1152       XPeekEvent(display, &event);  /* Block until user input */
1153     }
1154     else {
1155       switch(ControlState) {
1156       case CTRL_PLAY:
1157 	allMovies=1;
1158 	for (i=0;i<numStreams;i++) {
1159           /* If Film end reached, don't play frames */
1160           if ((vid_stream[i]!=NULL) && (!vid_stream[i]->film_has_ended)) {
1161             itemp = vid_stream[i]->totNumFrames;  /* Advance 1 frame */
1162             while (vid_stream[i]->totNumFrames == itemp) {
1163               mpegVidRsrc(0, vid_stream[i], 0, &xinfo[i]);
1164             }
1165   	    allMovies=allMovies && (vid_stream[i]->film_has_ended);
1166           }
1167         }
1168         if (allMovies) { /* Film end reached for all movies*/
1169             StopWatch(STOPWATCH_STOP);
1170             XSync(display, FALSE); /* Kludge to update frametotalwin */
1171             if (loopFlag) {
1172               ControlState = CTRL_REWIND;
1173             }
1174             else {
1175               ControlState = CTRL_EOF;
1176             }
1177         }
1178         break;
1179       case CTRL_FFWD:
1180 	allMovies=1;
1181 	for (i=0;i<numStreams;i++) {
1182 	  if (vid_stream[i]!=NULL) {
1183             mpegVidRsrc(0, vid_stream[i], 0, &xinfo[i]);
1184             allMovies=allMovies && vid_stream[i]->film_has_ended;
1185           }
1186         }
1187 	for (i=0;(i<numStreams) && ((vid_stream[i]==NULL)
1188 		  || (startFrame <= vid_stream[i]->totNumFrames));i++) {
1189 		  ;
1190         }
1191 	if (i==numStreams) {
1192            if (ControlMotion == CTRLMOTION_ON) {
1193               ControlState = CTRL_PLAY;
1194               StopWatch(STOPWATCH_START);
1195            } else {
1196               ControlState = CTRL_PAUSE;
1197             }
1198         }
1199 
1200         /* Film end just reached---Degenerate case */
1201         if (allMovies) {
1202           StopWatch(STOPWATCH_STOP);
1203           if (loopFlag) {
1204             ControlState = CTRL_REWIND;
1205           }
1206           else {
1207             ControlState = CTRL_EOF;
1208           }
1209         }
1210         break;
1211       case CTRL_EOF:
1212         if (loopFlag) {
1213           ControlState = CTRL_REWIND;
1214         }
1215         break;
1216       case CTRL_STEP:
1217         StopWatch(STOPWATCH_START);
1218 	allMovies=1;
1219 	for (i=0;i<numStreams;i++) {
1220 	  if ((vid_stream[i]!=NULL) && !vid_stream[i]->film_has_ended) {
1221             itemp = vid_stream[i]->totNumFrames;          /* Advance 1 frame */
1222             while (vid_stream[i]->totNumFrames == itemp) {
1223               mpegVidRsrc(0, vid_stream[i], 0, &xinfo[i]);
1224             }
1225 	    allMovies=allMovies && vid_stream[i]->film_has_ended;
1226           }
1227         }
1228         StopWatch(STOPWATCH_STOP);
1229         ControlState = CTRLMOTION_OFF;
1230         /* Film end just reached for last ending movie */
1231         if (allMovies)
1232           ControlState = CTRL_EOF;
1233         else
1234           ControlState = CTRL_PAUSE;
1235         break;
1236       case CTRL_REWIND:
1237         StopWatch(STOPWATCH_STOP);
1238 	for (i=0;i<numStreams;i++) {
1239           rewind(vid_stream[i]->input);
1240         }
1241         ControlBar(vid_stream, &xinfo[0], numStreams);
1242 	for (i=0;i<numStreams;i++) {
1243 	  if (vid_stream[i]!=NULL) {
1244             ResetVidStream(vid_stream[i]);/* Reinitialize vid_stream pointers */
1245             if (vid_stream[i]->seekValue < 0) {
1246               vid_stream[i]->seekValue = 0 - vid_stream[i]->seekValue;
1247             }
1248           }
1249 	}
1250         for (i=0; i<numStreams; i++) {
1251 	  if (vid_stream[i] != NULL) {
1252             /* Process start codes */
1253             mpegVidRsrc(0, vid_stream[i], 1, &xinfo[i]);
1254           }
1255         }
1256         if (startFrame > 0) {
1257           ControlState = CTRL_FFWD;
1258         }
1259         else {
1260             /* Do 1st frame */
1261 	    for (i=0;i<numStreams;i++) {
1262               if (vid_stream[i] != NULL) {
1263                 vid_stream[i]->realTimeStart = ReadSysClock();
1264                 while (vid_stream[i]->totNumFrames == 0) {
1265                   mpegVidRsrc(0, vid_stream[i], 0, &xinfo[i]);
1266                 }
1267               }
1268             }
1269 	  /* Time like original pass */
1270           StopWatch(STOPWATCH_START);
1271 
1272             if (ControlMotion == CTRLMOTION_ON) {
1273               ControlState = CTRL_PLAY;
1274             } else {
1275               ControlState = CTRL_PAUSE;
1276               StopWatch(STOPWATCH_STOP);
1277             }
1278           }
1279         break;
1280       case CTRL_EXIT:
1281         if (ctrlfont != NULL) {
1282           XFreeFont(display, ctrlfont);
1283         }
1284         XDestroyWindow(display, ctrlwindow);
1285         return;
1286       default:
1287         fprintf(stderr,"Code error: Illegal control state: %d (main())",
1288                 ControlState);
1289         exit(1);
1290         break;
1291       }
1292     }
1293   }
1294 }
1295 #endif /* !NOCONTROLS */
1296