viewer.c: Fix a segfault when resizing the window.
[libopano.git] / src / viewer.c
index 8773a00..3494d19 100644 (file)
@@ -134,13 +134,13 @@ static int draw_window (const ui_image_t *img)
   if ((ximage != NULL) && ((img->width != ximage->width) || (img->height != ximage->height)))
   {
     free (ximage->data);
+    ximage->data = NULL;
     XDestroyImage (ximage);
     ximage = NULL;
   }
 
   if (ximage == NULL)
   {
-    char *data;
     ximage = XCreateImage(disp_g, visual_g, depth_g, ZPixmap, 0,
        NULL, img->width, img->height,
        8, 0);
@@ -149,8 +149,7 @@ static int draw_window (const ui_image_t *img)
 
     ximage->byte_order= MSBFirst;
 
-    data = (char *) malloc (img->width * img->height * depth_g / 8);
-    ximage->data = data;
+    ximage->data = (char *) malloc (img->width * img->height * depth_g / 8);
     if (ximage->data == NULL)
     {
       XDestroyImage (ximage);
@@ -184,7 +183,6 @@ static void zoom_out (double *fov)
 
 int main( int argc, char** argv )
 {
-  XSizeHints hint;
   unsigned long color_fg, color_bg;
   int done;
   static Atom                  proto_atom= None, delete_atom= None;
@@ -196,10 +194,11 @@ int main( int argc, char** argv )
   double pitch = 0.0;
 
   /* Detect mouse movement direction */
-  int pos_x_new = 0;
-  int pos_y_new = 0;
-  int pos_x_old;
-  int pos_y_old;
+  unsigned int btn_current_pressed = 0;
+  int btn_reference_pos_x = 0;
+  int btn_reference_pos_y = 0;
+  int btn_current_pos_x = 0;
+  int btn_current_pos_y = 0;
 
   ui_image_t *pano;
   ui_image_t *view;
@@ -243,10 +242,6 @@ int main( int argc, char** argv )
     exit (0);
   }
 
-  hint.width  = view->width;
-  hint.height = view->height;
-  hint.flags = PSize;
-
   window_g = XCreateSimpleWindow(disp_g,
       DefaultRootWindow(disp_g),
       0, 0, /* Position */
@@ -254,19 +249,29 @@ int main( int argc, char** argv )
       5,
       color_fg, color_bg);
 
-  XSetStandardProperties(disp_g,
-      window_g,
-      text,
-      text,
-      None,
-      argv,
-      argc,
-      &hint);
+  {
+    XSizeHints hint;
+
+    memset (&hint, '\0', sizeof (hint));
+    hint.width  = view->width;
+    hint.height = view->height;
+    hint.flags = PSize;
+
+    XSetStandardProperties(disp_g,
+       window_g,
+       text,
+       text,
+       None,
+       argv,
+       argc,
+       &hint);
+  }
+
   gc = XCreateGC(disp_g,window_g,0,0);
   XSetBackground(disp_g,gc,color_bg);
   XSetForeground(disp_g,gc,color_fg);
 
-  event_mask = ButtonPressMask | ButtonReleaseMask | Button1MotionMask
+  event_mask = ButtonPressMask | ButtonReleaseMask | ButtonMotionMask
     | KeyPressMask | KeyReleaseMask | StructureNotifyMask
     | EnterWindowMask | LeaveWindowMask| ExposureMask;
 
@@ -290,12 +295,47 @@ int main( int argc, char** argv )
     int isChanged = 0;
     XEvent event;
 
-    XMaskEvent (disp_g, event_mask, &event);
+    memset (&event, '\0', sizeof (event));
+
+    if (btn_current_pressed == 0)
+    {
+      /* No button is pressed -> block */
+      XMaskEvent (disp_g, event_mask, &event);
+    }
+    else
+    {
+      /* A button is pressed -> do not block */
+      XCheckMaskEvent (disp_g, event_mask, &event);
+    }
 
     switch (event.type)
     {
+      case 0: /* XCheckMaskEvent didn't return an event */
+       break;
+
       case Expose:
-       draw_window (view);
+       {
+         XExposeEvent *eev = (XExposeEvent *) &event;
+
+         while (eev->count != 0)
+         {
+           if (!XCheckTypedEvent (disp_g, Expose, &event))
+           {
+             eev = NULL;
+             break;
+           }
+           /* do nothing */
+         }
+
+         if (eev != NULL)
+           isChanged = 1;
+       }
+       break;
+
+      case EnterNotify:
+       break;
+
+      case LeaveNotify:
        break;
 
       case ConfigureNotify:
@@ -313,7 +353,15 @@ int main( int argc, char** argv )
       case KeyPress:
        {
          XKeyEvent *kev = (XKeyEvent *) &event;
-         KeySym ks = XLookupKeysym (kev, 0);
+         char buffer[64];
+         int buffer_len = sizeof (buffer);
+         KeySym ks;
+
+         buffer_len = XLookupString(kev, buffer, sizeof (buffer), &ks, NULL);
+
+         if (buffer_len >= sizeof (buffer))
+           buffer_len = sizeof (buffer) - 1;
+         buffer[buffer_len] = '\0';
 
          switch (ks)
          {
@@ -356,62 +404,48 @@ int main( int argc, char** argv )
                yaw += 360.0;
              isChanged = 1;
              break;
+
+           case XK_q:
+             done++;
+             break;
+
+           default:
+             printf ("Unhandeled KeySym 0x%02llx, buffer = %s\n", (uint64_t) ks, buffer);
          }
        }
        break;
 
+#if 0
       case KeyRelease:
        printf ("Ignoring KeyRelease event.\n");
        break;
+#endif
 
       case ButtonPress:
-      case ButtonRelease:
+      /* case ButtonRelease: */
        {
          XButtonEvent *bev = (XButtonEvent *) &event;
-         pos_x_old = pos_x_new = bev->x;
-         pos_y_old = pos_y_new = bev->y;
+
+         btn_current_pressed = bev->button;
+         btn_current_pos_x = btn_reference_pos_x = bev->x;
+         btn_current_pos_y = btn_reference_pos_y = bev->y;
        }
        break;
 
+      case ButtonRelease:
+       btn_current_pressed = 0;
+       break;
+
       case MotionNotify:
        {
          XMotionEvent *mev = (XMotionEvent *) &event;
 
-         pos_x_old = pos_x_new;
-         pos_y_old = pos_y_new;
-
          do
          {
-           pos_x_new = mev->x;
-           pos_y_new = mev->y;
+           btn_current_pos_x = mev->x;
+           btn_current_pos_y = mev->y;
          }
          while (XCheckTypedEvent (disp_g, MotionNotify, &event));
-
-         printf ("XMotionEvent received: [%u,%u] -> [%u,%u]\n",
-             pos_x_old, pos_y_old, pos_x_new, pos_y_new);
-
-         if (mev->state & Button1Mask)
-         {
-           double yaw_diff = (pos_x_new - pos_x_old) / 24.0;
-           if (yaw_diff > 90.0)
-             yaw_diff = 90.0;
-           else if (yaw_diff < -90.0)
-             yaw_diff = -90.0;
-
-           yaw += yaw_diff;
-           if (yaw > 180.0)
-             yaw -= 360.0;
-           else if (yaw <= -180.0)
-             yaw += 360.0;
-
-           pitch -= (pos_y_new - pos_y_old) / 24.0;
-           if (pitch > 90.0)
-             pitch = 90.0;
-           else if (pitch < -90.0)
-             pitch = -90.0;
-
-           isChanged = 1;
-         }
        }
        break;
 
@@ -420,6 +454,45 @@ int main( int argc, char** argv )
            event.type);
     } /* switch (event.type) */
 
+    /*
+     * Check for pressed buttons and change view accordingly
+     */
+    if (btn_current_pressed == Button1)
+    {
+      double yaw_diff = (btn_current_pos_x - btn_reference_pos_x) / 24.0;
+      if (yaw_diff > 90.0)
+       yaw_diff = 90.0;
+      else if (yaw_diff < -90.0)
+       yaw_diff = -90.0;
+
+      yaw += yaw_diff;
+      if (yaw > 180.0)
+       yaw -= 360.0;
+      else if (yaw <= -180.0)
+       yaw += 360.0;
+
+      pitch -= (btn_current_pos_y - btn_reference_pos_y) / 24.0;
+      if (pitch > 90.0)
+       pitch = 90.0;
+      else if (pitch < -90.0)
+       pitch = -90.0;
+
+      isChanged = 1;
+    }
+    else if (btn_current_pressed == Button3)
+    {
+      double zoom_diff = (btn_current_pos_y - btn_reference_pos_y) / 64.0;
+      double zoom_ratio = pow (ZOOM_SPEED, zoom_diff);
+
+      fov *= zoom_ratio;
+      if (fov < 10.5)
+       fov = 10.5;
+      else if (fov > 165.0)
+       fov = 165.0;
+
+      isChanged = 1;
+    }
+
     if (isChanged != 0)
     {
       pl_extract_view (view, pano, pitch, yaw, fov);