home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xjig / xjig.c < prev    next >
C/C++ Source or Header  |  1997-12-31  |  33KB  |  883 lines

  1.  
  2. #include "global.h"
  3.  
  4. #include <signal.h>
  5. #ifdef PINUP_DEFAULT
  6. #    include <sys/stat.h>
  7. #    include <pwd.h>
  8. #endif
  9. #include <X11/Xlib.h>
  10. #include <X11/Xutil.h>
  11. #include <X11/keysym.h>
  12. #include <X11/cursorfont.h>
  13.  
  14. #ifndef VMS
  15. #include <X11/extensions/shape.h>
  16. #else
  17. #include <X11/shape.h>
  18. #include <sys/time.h>
  19. #include <lib$routines.h>
  20. unsigned long int statvms;
  21. float seconds;
  22. #if __VMS_VER < 70000000
  23. #ifdef __DECCXX
  24. #if __DECCXX_VER < 50200000
  25. #include "vms_unix_time.h"
  26. #include "vms_unix_types.h"
  27. #define bzero(b,length) memset(b,0,length)
  28. #endif    // __DECCXX_VER
  29. #endif    // __DECCXX
  30. extern "C" int gettimeofday (struct timeval *__tp);
  31. #endif    // __VMS_VER
  32. #endif    // VMS
  33.  
  34. #include <X11/Xos.h>
  35. #ifndef X_GETTIMEOFDAY
  36.     /* define X_GETTIMEOFDAY macro, a portable gettimeofday() */
  37.     /* copied from Xos.h for pre-X11R6 releases               */
  38. #    if defined(SVR4) || defined(VMS) || defined(WIN32)
  39. #        define X_GETTIMEOFDAY(t) gettimeofday(t)
  40. #    else
  41. #        define X_GETTIMEOFDAY(t) gettimeofday(t, (struct timezone*)0)
  42. #    endif
  43. #endif
  44. #ifndef FDS_TYPE
  45. //
  46. // The problem occured, that on HP-UX, the type used in the masks of the
  47. // select() system call are not the usual 'fd_set'. Instead they are just
  48. // integer pointers, which leads to an compile-error, when not casted.
  49. // Therefore it actually will get casted by the following Macro FDS_TYPE,
  50. // which should usually be defined to an empty string.
  51. //
  52. #  ifdef __hpux
  53. #     define   FDS_TYPE (int*)
  54. #  else
  55. #     define   FDS_TYPE
  56. #  endif
  57. #endif
  58.  
  59. #ifndef _mat2_h
  60. #    include "mat2.h"
  61. #endif
  62. #ifndef _objects_h
  63. #    include "objects.H"
  64. #endif
  65.  
  66. #include "gifx_image.H"
  67. #include "color_mapper.H"
  68. #include "imgbuff.H"
  69. #include "puzzle.H"
  70.  
  71. #include "cursor.h"
  72.  
  73. #define    _DEBUG
  74. #include "global.h"
  75.  
  76. #ifndef JIG_DEFAULT
  77. #    define JIG_DEFAULT    "default.gif"
  78. #endif
  79.  
  80. Display    *dpy;
  81. int        scr;
  82. Window    win;
  83. GC            gc;
  84.  
  85. int texture_mode=0;                // mode for texture mapping depending on depth
  86.  
  87. Cursor    normal_cursor, move_cursor, pull_cursor, idle_cursor, no_cursor;
  88.  
  89. int        zoom_factor=20;
  90. int        win_size_x=100;
  91. int        win_size_y=100;
  92.  
  93. int        offx=0;                    // half tilesize as offset to frames
  94. int        offy=0;
  95. int        width =0;                // height of image
  96. int        height=0;                // width of image
  97. int        dx = 0;                    // number of tiles in x-direction
  98. int        dy = 0;                    // number of tiles in y-direction
  99. int        tile_size=0;            // average tile size
  100. int        shuffle=3;                // shuffle tile as default
  101. int        side_lock=-1;            // which side (of TwinPixmap) as default
  102. #ifdef __hpux
  103. int        shared=0;                // dont use extension as default
  104. #else
  105. int        shared=1;                // use MIT-SHM extension as default
  106. #endif
  107. int        shapes=0;
  108.  
  109. int        quit=0;                    // global flag to initiate quitting
  110. int        random_seed=0;
  111. int        distortion=20;            // factor to control distortion of the tiles
  112. double    maxang=45;                // maximum rotation angle (off from 90degrees)
  113. int        shadow_size=1;            // pixels in shadow frame
  114. int        straight_setup=-1;    // offset for straight debugging setup
  115. int        no_flip=0;                // suppress automatic flip of landscape images
  116. int        autocrop=1;                // try to cut the edges away
  117.  
  118. double    fliptimebase=0.07;    // base time for flipping
  119. double    fliptimedelta=0.02;    // added to base for each tile
  120. int        maxfliptiles=8;        // max. number of tiles for automated flip
  121. int        minadjustcount=4;        // number of tiles to start 90 degrees autoadjust
  122. double    flipsave=0.2;            // dont let the tile come close to a vertical
  123.                               // position during the flip ...
  124.  
  125. double    turntimebase=0.15;    // base time for 90 degree rotation
  126. double    turntimedelta=0.02;    // added to base for each additional tile
  127. int        maxturntiles=5;        // max. number of tiles for rotation animation
  128.  
  129. int        maxsnapretries=1;        // max. no. of tiles that could recursively snap together
  130.  
  131. int        warp_center;
  132. int        warp_lock_x=WARP_NO_LOCK;
  133. int        warp_lock_y=WARP_NO_LOCK;
  134.  
  135. char        *dispname="";
  136. char        *filename=JIG_DEFAULT;
  137. int        verbose=0;
  138. int        rotate=0;                // rotation demo for debugging
  139. int        angle=0;                    // preset angles for debugging
  140.  
  141. class Puzzle        *p;            // Collection of all puzzle pieces
  142. class GifPixmap    *pm;            // Original pixmap for the puzzle tiles
  143. class Port            *port;        // Port (Display synonym) for color mapping
  144. class ObjectStack    *stk;            // administrator object for all viewable objects
  145. class ImageBuffer    *img_buf;    //    memory for rotating image (probably shared)
  146.  
  147. // ===========================================================================
  148.  
  149. static unsigned char b[2];
  150.  
  151. static void my_srand( unsigned seed ) {
  152.     b[0]=seed&0xff;
  153.     b[1]=seed>>8;
  154. }
  155.  
  156. int my_rand(void) {
  157.     unsigned long    s1=b[0]<<8|b[1];
  158.     s1+=12345;
  159.     s1*=s1;
  160.     b[0]=(unsigned char)((s1>>8)&0xff);
  161.     b[1]=(unsigned char)((s1>>16)&0xff);
  162.     return (s1>>8)&0xffff;
  163. }
  164.  
  165. // ===========================================================================
  166.  
  167. static void local_usleep( long time )
  168. {
  169. struct timeval  timeout;
  170. int    nfound;
  171.  
  172.    timeout.tv_sec  = (long)0;
  173.    timeout.tv_usec = (long)time;
  174.  
  175. #ifndef VMS
  176.    nfound=select(0,0,0,0,&timeout);
  177. #else
  178.       seconds = ((float) timeout.tv_usec)/1000000.0;
  179.       statvms = lib$wait(&seconds);
  180. #endif
  181. }
  182.  
  183. /*static*/ void do_sound( char *str ) {
  184. XKeyboardState        old_keyboard_values;
  185. XKeyboardControl    values;
  186. int        pitch, percent,duration,pause;
  187. char        *str_p=str;
  188.  
  189.     XGetKeyboardControl(dpy,&old_keyboard_values);
  190.     while( sscanf(str_p,"%03d%02d%02d%02d;",&pitch,&percent,&duration,&pause)==4 ) {
  191.         values.bell_pitch=pitch;
  192.         values.bell_percent=percent;
  193.         values.bell_duration=duration;
  194.         XChangeKeyboardControl(dpy,KBBellPercent|KBBellPitch|KBBellDuration,&values);
  195.         XBell(dpy,values.bell_percent);
  196.         XFlush(dpy);
  197.         local_usleep(pause*10000);
  198.         str_p+=10;
  199.     }
  200. #ifdef __hpux
  201.     values.bell_pitch    = old_keyboard_values.bell_pitch;
  202.     values.bell_percent  = old_keyboard_values.bell_percent;
  203.     values.bell_duration = old_keyboard_values.bell_duration;
  204. #else
  205.     values.bell_pitch    = 440;
  206.     values.bell_percent  =  50;
  207.     values.bell_duration = 100;
  208. #endif
  209.     XChangeKeyboardControl(dpy,KBBellPercent|KBBellPitch|KBBellDuration,&values);
  210.     XFlush(dpy);
  211. }
  212.  
  213. // ===========================================================================
  214. //
  215. // some help routines for easy drawing ...
  216. //
  217.  
  218.  
  219. void DrawLine( const Real& x1, const Real& y1, const Real& x2, const Real& y2 ) {
  220. int   px1 = XPix(x1);
  221. int   py1 = YPix(y1);
  222. int   px2 = XPix(x2);
  223. int   py2 = YPix(y2);
  224.     XDrawLine( dpy, win, gc, px1, py1, px2, py2 );
  225. }
  226. inline void DrawLine( const Vec2 &p1, const Vec2 &p2 ) {
  227.    DrawLine( p1.X(), p1.Y(), p2.X(), p2.Y() );
  228. }
  229.  
  230. // ===========================================================================
  231.  
  232. static unsigned long start_seconds;
  233.  
  234. static void InitTime() {
  235. struct timeval start;
  236.  
  237.     X_GETTIMEOFDAY( &start );
  238.     start_seconds = start.tv_sec;
  239. }
  240.  
  241. double GetCurrentTime(int busy) {
  242. struct timeval current;
  243.  
  244.      X_GETTIMEOFDAY( ¤t );
  245. #ifdef PINUP_DEFAULT
  246.          static unsigned long last=0;
  247.          static unsigned long idle_start=0;
  248.  
  249.          unsigned long    val=(current.tv_sec%86400uL);
  250.          if (busy)    idle_start=val+15;
  251.          if (last!=val/5&&val<idle_start) {
  252.              last=val/5;
  253.              unsigned long    minute=val/60+120;
  254.              if (minute<540||(minute>=570&&minute<765)||(minute>=810&&minute<1020)) {
  255.                 do_sound( "440995005;370995005;440995005;" );
  256.             }
  257.          }
  258. #else
  259.     (void)busy;
  260. #endif
  261.      return( ((double)(current.tv_sec-start_seconds))+(current.tv_usec/1000000.0) );
  262. }
  263.  
  264. // ===========================================================================
  265.  
  266. class BackDrop : public Object {
  267.     public:
  268.         BackDrop();
  269.         virtual ~BackDrop();
  270.  
  271.         virtual void ExposeRegion( int x, int y, int width, int height );
  272.         virtual void ZoomView( int midx, int midy, int chg );
  273.  
  274.     protected:
  275.         void InitFillStyle();
  276.  
  277.         unsigned long    toppixel;
  278.         unsigned long    bgpixel;
  279.         unsigned long    botpixel;
  280.         Pixmap    tilemap;
  281.         GC            gc_tile;
  282. };
  283.  
  284. BackDrop::BackDrop() {
  285.     bgpixel =port->AllocNamedColor( "grey50" );
  286.     toppixel=port->AllocNamedColor( "grey60" );
  287.     botpixel=port->AllocNamedColor( "grey40" );
  288.  
  289.     gc_tile=XCreateGC(dpy,RootWindow(dpy,scr),0,0);
  290.     InitFillStyle();
  291. }
  292.  
  293. BackDrop::~BackDrop() {
  294.     XFreeGC(dpy,gc_tile);
  295.     XFreePixmap(dpy,tilemap);
  296. }
  297.  
  298. void BackDrop::InitFillStyle() {
  299.     tilemap=XCreatePixmap(dpy,RootWindow(dpy,scr),
  300.                                 zoom_factor,zoom_factor,DefaultDepth(dpy,scr));
  301.     XSetForeground(dpy,DefaultGC(dpy,scr),bgpixel);
  302.     XFillRectangle(dpy,tilemap,DefaultGC(dpy,scr),0,0,zoom_factor,zoom_factor);
  303.     XSetForeground(dpy,DefaultGC(dpy,scr),toppixel);
  304.     XDrawLine(dpy,tilemap,DefaultGC(dpy,scr),0,0,zoom_factor-2,0);
  305.     XDrawLine(dpy,tilemap,DefaultGC(dpy,scr),0,1,0,zoom_factor-2);
  306.     XSetForeground(dpy,DefaultGC(dpy,scr),botpixel);
  307.     XDrawLine(dpy,tilemap,DefaultGC(dpy,scr),zoom_factor-1,0,zoom_factor-1,zoom_factor-1);
  308.     XDrawLine(dpy,tilemap,DefaultGC(dpy,scr),0,zoom_factor-1,zoom_factor-2,zoom_factor-1);
  309.     XSetTile(dpy,gc_tile,tilemap);
  310.     XSetFillStyle(dpy,gc_tile,FillTiled);
  311. }
  312.  
  313. void BackDrop::ExposeRegion( int x, int y, int width, int height ) {
  314.     XSetTSOrigin(dpy,gc_tile,-x,-y);
  315.     XFillRectangle(dpy,mystack->dbmap,gc_tile,0,0,width,height);
  316. }
  317.  
  318. void BackDrop::ZoomView( int /*midx*/, int /*midy*/, int chg ) {
  319.     zoom_factor+=chg;
  320.     XFreePixmap(dpy,tilemap);
  321.     InitFillStyle();
  322.     zoom_factor-=chg;
  323. }
  324.  
  325. // ===========================================================================
  326.  
  327. void usage() {
  328.     printf( "usage  : xjig [<options>]\n" );
  329.     printf( "\n" );
  330.     printf( "options: -file <file>: use gif-image in <file>\n" );
  331.     printf( "         -w  <n>     : number of tiles in x direction\n" );
  332.     printf( "         -h  <n>     : number of tiles in y direction\n" );
  333.     printf( "         -ts <n>     : set average tile size\n" );
  334.     printf( "         -ww <n>     : width of image\n" );
  335.     printf( "         -wh <n>     : height of image\n" );
  336.     printf( "         -side <n>   : lock side <n> only\n" );
  337.     printf( "         -no_flip    : no automatic flip of landscape images\n" );
  338.     printf( "         -no_crop    : do not crop images\n" );
  339. #ifdef USE_MIT_SHM
  340.     printf( "         -shm        : use MIT-SHM %s\n", (shared)?"(default)":"" );
  341.     printf( "         -no_shm     : don't use MIT-SHM extension %s\n", (shared)?"":"(default)" );
  342. #endif
  343.     printf( "         -shapes     : use shape extension to draw on desktop\n" );
  344.     printf( "         -no_anim    : don't animate rotation and flipping of tiles\n" );
  345.     if (verbose) {
  346.     printf( "additional options for debugging:\n" );
  347.     printf( "         -a  <n>    : startup angle\n" );
  348.     printf( "         -s         : shuffle tiles\n" );
  349.     printf( "         -sf        : full shuffle\n" );
  350.     printf( "         -sa        : shuffle angles\n" );
  351.     printf( "         -sp        : shuffle positions\n" );
  352.     printf( "         -r         : rotation demo\n" );
  353.     printf( "         -8 -16 -32 : manually select optimized texture mapping routine\n" );
  354.     printf( "         -dist <n>  : distortion percentage\n" );
  355.     printf( "         -maxang <n>: maximum rotation angle at startup\n" );
  356.     printf( "         -rand <n>  : seed for random generator\n" );
  357.     printf( "         -shadow <n>: pixels of shadowed border\n" );
  358.     printf( "         -setup <n> : straight setup with offset <n>\n" );
  359.     printf( "         -ftb <t>   : set flip time base                        (%g)\n", fliptimebase );
  360.     printf( "         -ftd <t>   : set flip time delta (for aditional tiles) (%g)\n", fliptimedelta );
  361.     printf( "         -mft <t>   : maximun number of flip tiles              (%d)\n", maxfliptiles );
  362.     printf( "         -fs <t>    : set value, when to stop the flip          (%g)\n", flipsave );
  363.     printf( "         -ttb <t>   : set turn time base                        (%g)\n", turntimebase );
  364.     printf( "         -ttd <t>   : set turn time delta (for aditional tiles) (%g)\n", turntimedelta );
  365.     printf( "         -mtt <t>   : maximun number of flip tiles              (%d)\n", maxturntiles );
  366.     printf( "         -msr <t>   : maximun number snap retries               (%d)\n", maxsnapretries );
  367.     printf( "         -mac <t>   : minimum number of tiles for adjustment    (%d)\n", minadjustcount );
  368.     }
  369.     printf( "\ncontrols:\n" );
  370.     printf( "\n" );
  371.     printf( "click left:              rotate 90 degrees left\n" );
  372.     printf( "click right:             rotate 90 degrees right\n" );
  373.     printf( "click middle:            flip tile to backside on double sided puzzle\n" );
  374.     printf( "drag left:               drag with automatic rotation\n" );
  375.     printf( "drag middle:             straight drag\n" );
  376.     printf( "drag left+middle:        pause rotator drag for a straight drag\n" );
  377.     printf( "drag middle+left:        pause straight drag for a static rotation\n" );
  378.     printf( "drag middle+click left:  rotate 90 degrees left during straight drag\n" );
  379.     printf( "drag middle+click right: rotate 90 degrees right during straight drag\n" );
  380.     printf( "CTRL + click left:       (same as click middle)\n" );
  381.  
  382.     printf( "\n" );
  383.     printf( "author : Helmut Hoenig, July-24-96 (V2.4)   (Helmut.Hoenig@hub.de)\n" );
  384.     printf( "\n" );
  385.     exit(0);
  386. }
  387.  
  388. void scan_args( int argc, char **argv ) {
  389.     for (int i=1;i<argc;i++) {
  390.         if (!strcmp(argv[i],"-display"))            dispname=argv[++i];
  391.         else if (!strcmp(argv[i],"-ww"))    width =atoi(argv[++i]);
  392.         else if (!strcmp(argv[i],"-wh")||!strcmp(argv[i],"-hh"))    height=atoi(argv[++i]);
  393.         else if (!strcmp(argv[i],"-w"))    dx=atoi(argv[++i]);
  394.         else if (!strcmp(argv[i],"-h")&&i<argc-1)    dy=atoi(argv[++i]);
  395.         else if (!strcmp(argv[i],"-ts"))            tile_size=atoi(argv[++i]);
  396.         else if (!strcmp(argv[i],"-r"))            rotate=1;
  397.         else if (!strcmp(argv[i],"-a")) {
  398.                 angle=atoi(argv[++i]);
  399.                 shuffle&=~1;
  400.         }
  401.         else if (!strcmp(argv[i],"-s"))            shuffle=0;
  402.  
  403.         else if (!strcmp(argv[i],"-sf"))            shuffle|=4;
  404.         else if (!strcmp(argv[i],"-sa"))            shuffle=1;
  405.         else if (!strcmp(argv[i],"-sp"))            shuffle=2;
  406.         else if (!strcmp(argv[i],"-no_flip"))  no_flip=1;
  407.         else if (!strcmp(argv[i],"-no_crop"))  autocrop=0;
  408.         else if (!strcmp(argv[i],"-side"))        side_lock=atoi(argv[++i]);
  409.         else if (!strcmp(argv[i],"-rand"))        random_seed=atoi(argv[++i]);
  410.         else if (!strcmp(argv[i],"-dist"))        distortion=atoi(argv[++i]);
  411.         else if (!strcmp(argv[i],"-maxang"))    maxang=atof(argv[++i]);
  412.         else if (!strcmp(argv[i],"-shadow"))    shadow_size=atoi(argv[++i]);
  413.         else if (!strcmp(argv[i],"-setup")) {
  414.                 straight_setup=atoi(argv[++i]);
  415.                 shuffle=0;
  416.         }
  417.         else if (!strcmp(argv[i],"-file"))            filename=argv[++i];
  418. #ifdef PINUP_DEFAULT
  419.         else if (!strcmp(argv[i],"-pinup"))            filename=PINUP_DEFAULT;
  420. #endif
  421.         else if (!strcmp(argv[i],"-8"))                texture_mode=1;
  422.         else if (!strcmp(argv[i],"-16"))                texture_mode=2;
  423.         else if (!strcmp(argv[i],"-32"))                texture_mode=3;
  424.         else if (!strcmp(argv[i],"-shm"))            shared=1;
  425.         else if (!strcmp(argv[i],"-no_shm"))        shared=0;
  426.         else if (!strcmp(argv[i],"-shapes"))        shapes=1;
  427.         else if (!strncmp(argv[i],"-verbose",2))    verbose=1;
  428.         else if (!strcmp(argv[i],"-ftb"))            fliptimebase=atof(argv[++i]);
  429.         else if (!strcmp(argv[i],"-ftd"))            fliptimedelta=atof(argv[++i]);
  430.         else if (!strcmp(argv[i],"-mft"))            maxfliptiles=atoi(argv[++i]);
  431.         else if (!strcmp(argv[i],"-fs"))                flipsave=atof(argv[++i]);
  432.         else if (!strcmp(argv[i],"-ttb"))            turntimebase=atof(argv[++i]);
  433.         else if (!strcmp(argv[i],"-ttd"))            turntimedelta=atof(argv[++i]);
  434.         else if (!strcmp(argv[i],"-mtt"))            maxturntiles=atoi(argv[++i]);
  435.         else if (!strcmp(argv[i],"-msr"))            maxsnapretries=atoi(argv[++i]);
  436.         else if (!strcmp(argv[i],"-mac"))            minadjustcount=atoi(argv[++i]);
  437.         else if (!strcmp(argv[i],"-no_anim")) {
  438.                                     maxturntiles = maxfliptiles = 0;
  439.         }
  440.  
  441.         else usage();
  442.     }
  443. }
  444.  
  445. void (*old_sighandler)(int);
  446. void sig_quit( int ) {
  447.     // handler that raises the quit flag on interrupts
  448.     quit=1;
  449. }
  450.  
  451. static XErrorHandler old_handler;
  452. int error_handler( Display * dpy_in, XErrorEvent *xerror ) {
  453.     if (xerror->error_code==BadWindow) {
  454.         // just ignore BadWindow failures, since they easily might occur
  455.         // due to the destruction of windows.
  456.         return 0;
  457.     }
  458.     else return old_handler( dpy_in, xerror );
  459. }
  460.  
  461. int main(int argc, char **argv)
  462. {
  463. static char *def_argv[]=
  464.  {    "xpuzzle", "-file", JIG_DEFAULT, 0 };
  465. XEvent    event;
  466. unsigned long next_sec=0;
  467. const        char *options;
  468.  
  469.     if (argc<2) {
  470.         argv=def_argv;
  471.         argc=(sizeof(def_argv)/sizeof(char*))-1;
  472.     }
  473.  
  474.     scan_args( argc, argv );
  475.  
  476.     quit=0;
  477.     old_sighandler=signal( SIGINT, sig_quit );
  478.  
  479.     //
  480.     // open the display and a port object as a color manager
  481.     //
  482.     dpy = XOpenDisplay(dispname);
  483.     if (!dpy) {
  484.         fprintf(stderr,"can't open display '%s'\n", dispname);
  485.         exit(-1);
  486.     }
  487.     scr = DefaultScreen(dpy);
  488.     port = new Port(dpy);
  489.  
  490.     printf( "\n" );
  491.     printf( "xjig V2.4, by Helmut Hoenig, July-24-96\n" );
  492.     printf( "\n" );
  493.  
  494.     if (!texture_mode) {
  495.         //
  496.         // check screen depth to select function for texture mappings
  497.         //
  498.         switch(DefaultDepth(dpy,scr)) {
  499.         case 8:        texture_mode=1;    break;
  500.         case 16:        texture_mode=2;    break;
  501.         case 24:
  502.         case 32:        texture_mode=3;    break;
  503.         }
  504.     }
  505.     if (!texture_mode) {
  506.         fprintf( stderr, "*** Unable to select texture mode for Depth %d\n", DefaultDepth(dpy,scr) );
  507.         fprintf( stderr, "    You can manually select one by trying either -8, -16 or -32\n" );
  508.         fprintf( stderr, "    Good Luck.\n" );
  509.         exit(0);
  510.     }
  511.  
  512.     if (verbose) {
  513.         switch( texture_mode ) {
  514.         case 1: printf( "texture mode 1: 1 byte\n" ); break;
  515.         case 2: printf( "texture mode 2: 2 byte\n" ); break;
  516.         case 3: printf( "texture mode 3: 4 byte\n" ); break;
  517.         }
  518.     }
  519.  
  520.     old_handler=XSetErrorHandler( error_handler );
  521.  
  522.     // check for shapes
  523.     if (shapes) {
  524.         int major, minor;
  525.         shapes=XShapeQueryVersion(dpy,&major,&minor);
  526.         if (shapes&verbose)
  527.             printf( "--- using shape extension V%d.%d\n", major, minor );
  528.     }
  529.  
  530. #ifdef PINUP_DEFAULT
  531.     {
  532.     struct stat buf;
  533.     struct passwd *pwd;
  534.     char    name[256];
  535.  
  536.         stat( filename, &buf );
  537.         pwd=getpwuid( buf.st_uid );
  538.         strcpy( name, pwd->pw_gecos );
  539.         if (strchr(name,','))        *strchr(name,',')='\0';
  540.         if ( !strstr( filename, "default" ) ) {
  541.             if (!strcmp( name, "Gast-Kennung"))        strcpy(name,"Norbert Klaus");
  542.             printf( "loading: '%s', supplied by %s.\n\n", filename, name );
  543.         }
  544.     }
  545. #endif
  546.  
  547.     //
  548.     // load image an scale it according to the input options
  549.     // or set original image size, when no size selected.
  550.     //
  551.     pm=new GifPixmap(port,filename);
  552.     options=pm->GetExtensionData( OPTION_EXTENSION );
  553.     if (options) {
  554.         char    opt_buffer[256];
  555.         int    argc_opt=0;
  556.         char    *argv_opt[20];
  557.         char    *cptr=opt_buffer;
  558.         strcpy(opt_buffer,options);
  559.  
  560.         argv_opt[argc_opt++]=argv[0];
  561.         argv_opt[argc_opt++]=cptr;
  562.         while( *cptr ) {
  563.             if ( *cptr==' ' ) {
  564.                 *cptr++=0;
  565.                 argv_opt[argc_opt++]=cptr;
  566.             }
  567.             else cptr++;
  568.         }
  569.         scan_args( argc_opt, argv_opt );
  570.     }
  571.     const char *comment=pm->GetExtensionData( COMMENT_EXTENSION );
  572.     if (comment)    { printf( comment ); putchar( '\n' ); }
  573.  
  574.     if (autocrop)        pm->CropImage();
  575.     if (pm->Width()>pm->Height()&&!no_flip)        pm->Rotate90();
  576.     if (verbose) 
  577.         printf("original image size: %d %d\n", pm->Width(), pm->Height() );
  578.  
  579.     if (!width&&!height) {
  580.         width = pm->Width();
  581.         height= pm->Height();
  582.     }
  583.     else {
  584.         // scale to desired size, (keep aspect when only one param selected)
  585.         if (!width)        width=height*pm->Width()/pm->Height();
  586.         if (!height)    height=width*pm->Height()/pm->Width();
  587.     }
  588.     pm->CreateData( width, height );
  589.  
  590.     if (!dx||!dy) {
  591.         if (dy)            dx=width*dy/height;
  592.         else if (dx)    dy=height*dx/width;
  593.         else if (tile_size) {
  594.                             dx=width/tile_size;
  595.                             dy=height/tile_size;
  596.         }
  597.     }
  598.     if (dx<=0||dy<=0)     { dx=4; dy=6; }
  599.  
  600.     if (verbose)
  601.         printf( "number of tiles: %d\n", dx * dy );
  602.  
  603.     offy = height/dy/2;
  604.     if ( (height+(dy+1)*offy) > DisplayHeight(dpy,scr)-20 ) {
  605.         offy=(DisplayHeight(dpy,scr)-height-20)/(dy+1);
  606.     }
  607.     offx = width /dx/2;
  608.     win_size_x=2*(width+dx*offx)+offx;
  609.     if ( win_size_x > DisplayWidth(dpy,scr)-8 ) {
  610.         win_size_x=DisplayWidth(dpy,scr)-8;
  611.         if ( 2*width+dx*offx+offx > win_size_x )    offx=(win_size_x-2*width)/(dx+1);
  612.     }
  613.     tile_size=width/dx;
  614.  
  615.     if (shapes) {
  616.         win_size_x=DisplayWidth(dpy,scr);
  617.         win_size_y=DisplayHeight(dpy,scr);
  618.         win=RootWindow(dpy,scr);
  619.     }
  620.     else {
  621.         win_size_y=height+(dy+1)*offy;
  622.  
  623.         win=XCreateSimpleWindow(dpy,RootWindow(dpy,scr),
  624.                 0,0,win_size_x,win_size_y,2,WhitePixel(dpy,scr),
  625.                         port->AllocNamedColor( "grey50" ) );
  626.         XStoreName(dpy,win,argv[0]);
  627.     }
  628.     gc =XCreateGC(dpy,win,0,0);
  629.     XSetForeground(dpy,gc,WhitePixel(dpy,scr));
  630.  
  631.     // prepare some cursors
  632. XColor    white_col, black_col;
  633. Pixmap    pixmap;
  634.  
  635.     XParseColor(dpy,DefaultColormap(dpy,scr), "white", &white_col );
  636.     XParseColor(dpy,DefaultColormap(dpy,scr), "black", &black_col );
  637.  
  638.     normal_cursor = XCreateFontCursor( dpy, XC_top_left_arrow );
  639.     move_cursor   = XCreateFontCursor( dpy, XC_fleur );
  640.     pull_cursor   = XCreateFontCursor( dpy, XC_hand2 );
  641.     idle_cursor   = XCreateFontCursor( dpy, XC_watch );
  642.  
  643.     pixmap = XCreateBitmapFromData(dpy,RootWindow(dpy,scr),
  644.                     cursor_bits, cursor_width, cursor_height );
  645.     no_cursor = XCreatePixmapCursor( dpy, pixmap, pixmap, 
  646.                     &white_col, &black_col, cursor_x_hot, cursor_y_hot );
  647.     XFreePixmap( dpy, pixmap );
  648.  
  649.  
  650.  
  651.     InitTime();
  652.  
  653.     // create Object-Stack with Background
  654.     if (shapes) {
  655.         stk = new WindowObjectStack();
  656.     }
  657.     else {
  658.         stk = new DBObjectStack();
  659.         stk->Append( new BackDrop() );
  660.     }
  661.  
  662.     // create buffer for faster image rotation
  663.     img_buf = new ImageBuffer();
  664.  
  665.     // initialize puzzle game
  666.     my_srand( random_seed );
  667.     p = new Puzzle();
  668.     p->Init(width,height,dx,dy, pm->GetExtensionData( FLATTILE_EXTENSION ) );
  669.  
  670.     // check for hidden pieces
  671.     options=pm->GetExtensionData( REMOVETILE_EXTENSION );
  672.     if (options) {
  673.         const char    *cptr=options;
  674.         while(*cptr) {
  675.             int x,y;
  676.             sscanf(cptr,"%02x%02x",&x,&y);
  677.             cptr+=4;
  678.             p->DropTile(x,y);
  679.         }
  680.     }
  681.  
  682.     if (shapes) {
  683.         XSelectInput(dpy,win,KeyPressMask);
  684.     }
  685.     else {
  686.         XSelectInput(dpy,win, ExposureMask|StructureNotifyMask|KeyPressMask|
  687.                 ButtonPressMask|ButtonReleaseMask|PointerMotionMask);
  688.         XMapRaised(dpy,win);
  689.     }
  690.  
  691.     while(!quit) {
  692.  
  693.         if (!XPending(dpy)) {
  694.             XSync(dpy,0);
  695.             while (!XPending(dpy)) {
  696.                 struct timeval timeout;
  697.                 struct fd_set readfds;
  698.                 int        nfds;
  699.     
  700.                 FD_ZERO( &readfds );
  701.                 FD_SET(  ConnectionNumber(dpy), &readfds  );
  702.                 nfds = ConnectionNumber(dpy)+1;
  703.     
  704.                 timeout.tv_sec  = 0;
  705.                 double current_time=GetCurrentTime();
  706.                 timeout.tv_usec = (long)(1000000 * (1.0-(current_time-floor(current_time))));
  707. #ifndef VMS
  708.                 select( nfds, FDS_TYPE &readfds, 0, 0, &timeout );
  709. #else
  710.                                 seconds = ((float) timeout.tv_usec)/1000000.0;
  711.                                 statvms = lib$wait(&seconds);
  712. #endif
  713.                     current_time = GetCurrentTime();
  714.                 //    printf( "%g\n", current_time );
  715.                 if ((unsigned long)current_time>next_sec) {
  716.                     char     buffer[20];
  717.                     next_sec = (unsigned long)current_time;
  718.                     if (!p->Finished()) {
  719.                         sprintf( buffer, "xpuzzle:  %02ld:%02ld",
  720.                             next_sec / 60, next_sec % 60 );
  721.                         if (!shapes)    XStoreName(dpy,win,buffer);
  722.                     }
  723.                     else {
  724.                         sprintf( buffer, "no more tiles left at:  %02ld:%02ld",
  725.                             next_sec / 60, next_sec % 60 );
  726.                         if (!shapes)    XStoreName(dpy,win,buffer);
  727.                         XBell(dpy,100);
  728.                         XFlush(dpy);
  729.                         next_sec=1000000;
  730.                     }
  731.                 }
  732.             }
  733.         }
  734.  
  735.  
  736.         XNextEvent(dpy,&event);
  737.         switch(event.type) {
  738.         case KeyPress: {
  739.             char                buffer=0;
  740.             XComposeStatus    compose;
  741.             KeySym            keysym;
  742.             int                mult=(event.xkey.state&ShiftMask)?2:1;
  743.  
  744.             XDefineCursor(dpy,win,idle_cursor);
  745.             XFlush(dpy);
  746.             XLookupString( (XKeyEvent*)&event, &buffer, 1, &keysym, &compose );
  747.             switch( keysym ) {
  748.             case XK_plus:
  749.             case XK_KP_Add:
  750.             case XK_Page_Up:
  751.             case XK_KP_Page_Up:
  752.                     stk->ZoomView(win_size_x/2,win_size_y/2,2*mult);
  753.                     stk->ExposeRegion(0,0,win_size_x,win_size_y);
  754.                     break;
  755.             case XK_minus:
  756.             case XK_KP_Subtract:
  757.             case XK_Page_Down:
  758.             case XK_KP_Page_Down:
  759.                     if (zoom_factor>5)    stk->ZoomView(win_size_x/2,win_size_y/2,-2*mult);
  760.                     stk->ExposeRegion(0,0,win_size_x,win_size_y);
  761.                     break;
  762.             case XK_Right:
  763.             case XK_KP_Right:
  764.                     stk->PanView( 10*mult, 0 );
  765.                     stk->ExposeRegion(0,0,win_size_x,win_size_y);
  766.                     break;
  767.             case XK_Down:
  768.             case XK_KP_Down:
  769.                     stk->PanView( 0, 10*mult );
  770.                     stk->ExposeRegion(0,0,win_size_x,win_size_y);
  771.                     break;
  772.             case XK_Left:
  773.             case XK_KP_Left:
  774.                     stk->PanView( -10*mult, 0 );
  775.                     stk->ExposeRegion(0,0,win_size_x,win_size_y);
  776.                     break;
  777.             case XK_Up:
  778.             case XK_KP_Up:
  779.                     stk->PanView( 0, -10*mult );
  780.                     stk->ExposeRegion(0,0,win_size_x,win_size_y);
  781.                     break;
  782.             case XK_End:
  783.             case XK_KP_End: {
  784.                     int x1,y1,x2,y2;
  785.                     stk->GetExtent(&x1,&y1,&x2,&y2);
  786.                     stk->PanView( x1-win_size_x/2+(x2-x1)/2, y1-win_size_y/2+(y2-y1)/2 );
  787.                     int    zf1=(int)(win_size_x*zoom_factor/(x2-x1));
  788.                     int    zf2=(int)(win_size_y*zoom_factor/(y2-y1));
  789.                     if (zf2<zf1)    zf1=zf2;
  790.                     if (zf1>3) {
  791.                         stk->ZoomView(win_size_x/2,win_size_y/2,zf1-zoom_factor);
  792.                         stk->ExposeRegion(0,0,win_size_x,win_size_y);
  793.                     }
  794.                     break;
  795.             }
  796.             case XK_Home:
  797.             case XK_KP_Home: {
  798.                     int x1,y1,x2,y2;
  799.                     stk->GetExtent(&x1,&y1,&x2,&y2);
  800.                     stk->PanView( x1-10, y1-win_size_y/2+(y2-y1)/2 );
  801.                     stk->ZoomView(10,win_size_y/2,20-zoom_factor);
  802.                     stk->ExposeRegion(0,0,win_size_x,win_size_y);
  803.                     break;
  804.             }
  805.             case XK_Escape:
  806.             case XK_Q:
  807.             case XK_q:
  808.                     quit=1;
  809.                     break;
  810.             default:
  811.                     break;
  812.             }
  813.             XDefineCursor(dpy,win,normal_cursor);
  814.             XSync(dpy,0);
  815.             warp_lock_x=WARP_NO_LOCK;    // just as a way tp unlock
  816.             warp_lock_y=WARP_NO_LOCK;
  817.             break;
  818.         }
  819.  
  820.         case ButtonPress:
  821.             GetCurrentTime(1);    // Reset idle start
  822.             stk->DispatchPress( &event.xbutton );
  823.             break;
  824.         case ButtonRelease:
  825.             stk->DispatchRelease( &event.xbutton );
  826.             break;
  827.         case MotionNotify:
  828.             if (warp_lock_x!=WARP_NO_LOCK) {
  829.                 do {
  830.                     if ( (!shapes&&warp_lock_x==event.xmotion.x&&warp_lock_y==event.xmotion.y)
  831.                         ||((shapes)&&warp_lock_x==event.xmotion.x_root&&warp_lock_y==event.xmotion.y_root) ) {
  832.                         warp_lock_x=WARP_NO_LOCK;
  833.                         warp_lock_y=WARP_NO_LOCK;
  834.                         break;
  835.                     }
  836.                     printf( "#### motion event skipped due to warp lock.\n" );
  837.                 }
  838.                 while( XCheckMaskEvent(dpy,PointerMotionMask,&event) );
  839.             }
  840.             else {
  841.                 while( XCheckMaskEvent(dpy,PointerMotionMask,&event) );
  842.                 if (event.xmotion.state)    stk->DispatchMotion( &event.xmotion );
  843.             }
  844.             break;
  845.  
  846.         case EnterNotify:
  847.             XSetInputFocus( dpy, event.xcrossing.window, (int)None, CurrentTime );
  848.             break;
  849.  
  850.         case Expose:
  851.             if (shapes) {
  852.                 stk->ExposeWindowRegion( event.xexpose.window, event.xexpose.x,
  853.                     event.xexpose.y, event.xexpose.width, event.xexpose.height );
  854.             }
  855.             else {
  856.                 stk->ExposeRegion(event.xexpose.x, event.xexpose.y,
  857.                         event.xexpose.width, event.xexpose.height );
  858.             }
  859.                 if (rotate) {
  860.                     XSync(dpy,0);
  861.                     double    t1=GetCurrentTime();
  862.                     p->Rotation();
  863.                     double    t2=GetCurrentTime();
  864.                     printf( "Rotation Time: %.4g secs.\n", t2 - t1 );
  865.                     rotate=0;
  866.                 }
  867.             break;
  868.  
  869.         case ConfigureNotify:
  870.             if (win_size_x!=event.xconfigure.width||win_size_y!=event.xconfigure.height) {
  871.                 win_size_x=event.xconfigure.width;
  872.                 win_size_y=event.xconfigure.height;
  873.             }
  874.             break;
  875.         }
  876.     }
  877.  
  878.     delete img_buf;
  879.  
  880.     printf( "terminated\n" );
  881.     return 0;
  882. }