"Fossies" - the Fresh Open Source Software Archive

Member "gfsview-snapshot-121130/view/main.c" (30 Nov 2012, 21063 Bytes) of package /linux/privat/gfsview-snapshot-121130.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. For more information about "main.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) 1998 Janne L.bf <jlof@mail.student.oulu.fi>
    3  *
    4  * This library is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License as
    6  * published by the Free Software Foundation; either version 2 of the
    7  * License, or (at your option) any later version.
    8  *
    9  * This library is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   12  * Library General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU Library General Public
   15  * License along with this library; if not, write to the Free
   16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   17  */
   18 /*
   19  * Modified on 10th June 2002, for porting this program
   20  * to the 'gtkglext-0.1.0` extension of gtk-2.0.
   21  *
   22  * Alif Wahid, <awah005@users.sourceforge.net>
   23  */
   24 /*
   25  * Improved mouse operation.
   26  *
   27  * Naofumi Yasufuku  <naofumi@users.sourceforge.net>
   28  */
   29 /*
   30  * Adapted for gfsview. May 2004.
   31  *
   32  * Stephane Popinet <popinet@users.sf.net>
   33  */
   34 
   35 #include <stdlib.h>
   36 #include <string.h>
   37 #include <sys/time.h>
   38 #include <sys/types.h>
   39 #include <unistd.h>
   40 #include <getopt.h>
   41 #include <math.h>
   42 
   43 #include <gtk/gtk.h>
   44 #include <gdk/gdkkeysyms.h>
   45 #include <gdk/gdkx.h>
   46 
   47 #include <gtk/gtkgl.h>
   48 
   49 #define SN_API_NOT_YET_FROZEN
   50 #include <libsn/sn.h>
   51 
   52 #if defined(__APPLE__)
   53 #  include <OpenGL/gl.h>
   54 #  include <OpenGL/glu.h>
   55 #else
   56 #  include <GL/gl.h>
   57 #  include <GL/glu.h>
   58 #endif
   59 
   60 #include "gfkgl.h"
   61 
   62 #include "gl/trackball.h"
   63 #include "glade/interface.h"
   64 #include "glade/support.h"
   65 #include "glade/callbacks.h"
   66 
   67 static void pick (GtkWidget * widget, int winx, int winy, gboolean motion)
   68 {
   69   GLdouble model[16], proj[16];
   70   GLint viewport[4];
   71   GLdouble x, y, z;
   72   GfsGlRay r;
   73 
   74   glGetDoublev (GL_MODELVIEW_MATRIX, model);
   75   glGetDoublev (GL_PROJECTION_MATRIX, proj);
   76   glGetIntegerv (GL_VIEWPORT, viewport);
   77   winy = widget->allocation.height - winy;
   78   g_return_if_fail (gluUnProject (winx, winy, 0., model, proj, viewport, &x, &y, &z));
   79   r.a.x = x; r.a.y = y; r.a.z = z;
   80   g_return_if_fail (gluUnProject (winx, winy, 1., model, proj, viewport, &x, &y, &z));
   81   r.b.x = x; r.b.y = y; r.b.z = z;
   82   
   83   gfk_gl_view_pick (lookup_widget (widget, "view"), &r, motion);
   84 }
   85 
   86 static GList * get_symmetries (GtkTreeModel * list)
   87 {
   88   GtkTreeIter iter;  
   89   gboolean valid = gtk_tree_model_get_iter_first (list, &iter);
   90   GList * symmetry = NULL;
   91 
   92   while (valid) {
   93     gboolean visible;
   94     GfkGl * gl;
   95 
   96     gtk_tree_model_get (list, &iter, GL_COLUMN, &gl, VISIBLE_COLUMN, &visible, -1);
   97     if (visible && GFK_IS_GL_SYMMETRY (gl))
   98       symmetry = g_list_append (symmetry, gl->gl);
   99     valid = gtk_tree_model_iter_next (list, &iter);
  100   }
  101   return symmetry;
  102 }
  103 
  104 static gboolean
  105 expose(GtkWidget      * widget,
  106        GdkEventExpose * event)
  107 {
  108   GdkGLContext * glcontext = gtk_widget_get_gl_context (widget);
  109   GdkGLDrawable * gldrawable = gtk_widget_get_gl_drawable (widget);
  110   GfsGlViewParams * info = g_object_get_data (G_OBJECT (widget), "GfsGlViewParams");
  111 
  112   /* draw only last expose */
  113   if (event->count > 0)
  114     return TRUE;
  115 
  116   if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
  117     return TRUE;
  118 
  119   /* basic initialization */
  120   if (info->do_init == TRUE) {
  121     gfs_gl_init_gl ();
  122     info->do_init = FALSE;
  123   }
  124 
  125   glMatrixMode (GL_PROJECTION);
  126   glLoadIdentity ();
  127   GfsDomain * domain = g_object_get_data (G_OBJECT (widget), "sim");
  128   GtkWidget * view = lookup_widget (widget, "view");
  129   GtkTreeModel * list = gtk_tree_view_get_model (GTK_TREE_VIEW (lookup_widget (view, "gl_list")));
  130   GList * symmetries = get_symmetries (list);
  131   gdouble max = gfs_gl_domain_extent (domain, symmetries);
  132   g_list_free (symmetries);
  133   gluPerspective (info->fov, widget->allocation.width/(float) widget->allocation.height,
  134           1., 1. + 2.*max);
  135   glMatrixMode (GL_MODELVIEW);
  136 
  137   /* draw object */
  138   glLoadIdentity ();
  139   glTranslatef (info->tx, info->ty, - (1. + max));
  140   gfs_gl_add_quats (info->dquat, info->quat, info->quat);
  141   GLfloat m[4][4];
  142   gfs_gl_build_rotmatrix (m, info->quat);
  143   glMultMatrixf (&m[0][0]);
  144   glScalef (info->sx, info->sy, info->sz);
  145 
  146   /* draw object */
  147   glClearColor (info->bg.r, info->bg.g, info->bg.b, 1);
  148   glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  149 
  150   gfk_gl_view_draw (view, GFSGL_SCREEN);
  151 
  152   /* swap backbuffer to front */
  153   if (gdk_gl_drawable_is_double_buffered (gldrawable))
  154     gdk_gl_drawable_swap_buffers (gldrawable);
  155   else
  156     glFlush ();
  157 
  158   gdk_gl_drawable_gl_end (gldrawable);
  159 
  160   return FALSE;
  161 }
  162 
  163 static gboolean
  164 configure(GtkWidget         *widget,
  165           GdkEventConfigure *event)
  166 {
  167   GdkGLContext *glcontext;
  168   GdkGLDrawable *gldrawable;
  169 
  170   g_return_val_if_fail(widget && event, FALSE);
  171 
  172   glcontext = gtk_widget_get_gl_context(widget);
  173   gldrawable = gtk_widget_get_gl_drawable(widget);
  174 
  175   /*** OpenGL BEGIN ***/
  176   if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
  177     return TRUE;
  178 
  179   glViewport (0, 0, widget->allocation.width, widget->allocation.height);
  180 
  181   gdk_gl_drawable_gl_end(gldrawable);
  182   /*** OpenGL END ***/
  183   return TRUE;
  184 }
  185 
  186 static void
  187 destroy(GtkWidget *widget)
  188 {
  189   /* delete mesh info */
  190   GfsGlViewParams *info = (GfsGlViewParams*)g_object_get_data(G_OBJECT(widget), "GfsGlViewParams");
  191 
  192   g_free(info);
  193 }
  194 
  195 static gboolean
  196 button_press(GtkWidget      *widget,
  197              GdkEventButton *event)
  198 {
  199   if (event->button == 1 && event->state & GDK_CONTROL_MASK) {
  200     pick (widget, event->x, event->y, FALSE);
  201     return FALSE;
  202   }
  203   else {
  204     GfsGlViewParams * info = g_object_get_data (G_OBJECT (widget), "GfsGlViewParams");
  205     
  206     info->dquat[0] = 0.0;
  207     info->dquat[1] = 0.0;
  208     info->dquat[2] = 0.0;
  209     info->dquat[3] = 1.0;
  210     
  211     /* beginning of drag, reset mouse position */
  212     info->beginx = event->x;
  213     info->beginy = event->y;
  214     info->motion = TRUE;
  215     
  216     return FALSE;
  217   }
  218 }
  219 
  220 static gboolean
  221 button_release(GtkWidget      *widget,
  222                GdkEventButton *event)
  223 {
  224   GfsGlViewParams *info = (GfsGlViewParams*)g_object_get_data(G_OBJECT(widget), "GfsGlViewParams");
  225 
  226   info->dquat[0] = 0.0;
  227   info->dquat[1] = 0.0;
  228   info->dquat[2] = 0.0;
  229   info->dquat[3] = 1.0;
  230 
  231   info->dx = 0.0;
  232   info->dy = 0.0;
  233   info->motion = FALSE;
  234   if (info->res != info->base_res)
  235     gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
  236 
  237   return FALSE;
  238 }
  239 
  240 static gboolean
  241 motion_notify(GtkWidget      *widget,
  242               GdkEventMotion *event)
  243 {
  244   int x = 0;
  245   int y = 0;
  246   GdkModifierType state = 0;
  247   float width, height;
  248   gboolean redraw = FALSE;
  249   GfsGlViewParams *info = (GfsGlViewParams*)g_object_get_data(G_OBJECT(widget), "GfsGlViewParams");
  250 
  251   if (event->is_hint)
  252     gdk_window_get_pointer(event->window, &x, &y, &state);
  253   else {
  254     x = event->x;
  255     y = event->y;
  256     state = event->state;
  257   }
  258 
  259   width = widget->allocation.width;
  260   height = widget->allocation.height;
  261 
  262   if (state & GDK_CONTROL_MASK && state & GDK_BUTTON1_MASK) {
  263     if (x >= 0 && y >= 0 && x < width && y < height)
  264       pick (widget, x, y, TRUE);
  265     return TRUE;
  266   }
  267 
  268   if (state & GDK_BUTTON1_MASK) {
  269     /* drag in progress, simulate trackball */
  270     gfs_gl_trackball( info->dquat,
  271               (2.0*info->beginx -            width) / width,
  272               (          height - 2.0*info->beginy) / height,
  273               (           2.0*x -            width) / width,
  274               (          height -            2.0*y) / height );
  275 #if FTT_2D
  276     if (!(event->state & GDK_SHIFT_MASK)) {
  277       /* constrain the rotations in the plane */
  278       info->dquat[0] = info->dquat[1] = 0.;
  279       gdouble n = sqrt (info->dquat[2]*info->dquat[2] + info->dquat[3]*info->dquat[3]);
  280       info->dquat[2] /= n; info->dquat[3] /= n;
  281     }
  282 #endif
  283     info->dx = x - info->beginx;
  284     info->dy = y - info->beginy;
  285     
  286     /* orientation has changed, redraw mesh */
  287     redraw = TRUE;
  288   }
  289 
  290   if (state & GDK_BUTTON2_MASK) {
  291     /* zooming drag */
  292     info->fov += (0.1 + 3.*info->fov)*(y - info->beginy)/height;
  293     if (info->fov > 100.)
  294       info->fov = 100.;
  295     else if (info->fov < 0.01)
  296       info->fov = 0.01;
  297     /* zoom has changed, redraw mesh */
  298     redraw = TRUE;
  299   }
  300 
  301   if (state & GDK_BUTTON3_MASK) {
  302     /* translate drag */
  303     info->tx += (x - info->beginx)/width*0.02*(0.01 + 3.*info->fov);
  304     info->ty -= (y - info->beginy)/height*0.02*(0.01 + 3.*info->fov);
  305     
  306     /* translate has changed, redraw mesh */
  307     redraw = TRUE;
  308   }
  309 
  310   info->beginx = x;
  311   info->beginy = y;
  312 
  313   if (redraw)
  314     gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
  315 
  316   return TRUE;
  317 }
  318 
  319 static gboolean
  320 scroll_notify(GtkWidget      *widget,
  321           GdkEventScroll *event)
  322 {
  323   GfsGlViewParams *info = (GfsGlViewParams*)g_object_get_data(G_OBJECT(widget), "GfsGlViewParams");
  324 
  325   switch (event->direction) {
  326   case GDK_SCROLL_UP:
  327     info->fov -= 0.02*(0.1 + 3.*info->fov);
  328     if (info->fov > 100.)
  329       info->fov = 100.;
  330     else if (info->fov < 0.01)
  331       info->fov = 0.01;
  332     /* zoom has changed, redraw mesh */
  333     gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
  334     break;
  335   case GDK_SCROLL_DOWN:
  336     info->fov += 0.02*(0.1 + 3.*info->fov);
  337     if (info->fov > 100.)
  338       info->fov = 100.;
  339     else if (info->fov < 0.01)
  340       info->fov = 0.01;
  341     /* zoom has changed, redraw mesh */
  342     gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
  343     break;
  344   default:
  345     ;
  346   }
  347   return FALSE;
  348 }
  349 
  350 static gboolean
  351 key_press_event(GtkWidget   *widget,
  352                 GdkEventKey *event)
  353 {
  354   GfsGlViewParams *info = (GfsGlViewParams*)g_object_get_data(G_OBJECT(widget), "GfsGlViewParams");
  355 
  356   switch (event->keyval) {
  357   case GDK_plus:
  358     info->fov -= 0.02*(0.1 + 3.*info->fov);
  359     if (info->fov > 100.)
  360       info->fov = 100.;
  361     else if (info->fov < 0.01)
  362       info->fov = 0.01;
  363     /* zoom has changed, redraw mesh */
  364     gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
  365     break;
  366     
  367   case GDK_minus:
  368     info->fov += 0.02*(0.1 + 3.*info->fov);
  369     if (info->fov > 100.)
  370       info->fov = 100.;
  371     else if (info->fov < 0.01)
  372       info->fov = 0.01;
  373     /* zoom has changed, redraw mesh */
  374     gdk_window_invalidate_rect (widget->window, &widget->allocation, FALSE);
  375     break;
  376     
  377   default:
  378     return FALSE;
  379   }
  380   
  381   return TRUE;
  382 }
  383 
  384 static GtkWidget * gl_area_new (GdkGLConfig * glconfig)
  385 {
  386   GtkWidget * glarea;
  387   
  388   /* create new OpenGL widget */
  389   glarea = gtk_drawing_area_new ();
  390   if (glarea == NULL) {
  391     fprintf (stderr, "gfsview: cannot create GtkDrawingArea widget\n");
  392     return NULL;
  393   }
  394 
  395   /* Set OpenGL-capability to the widget. */
  396   gtk_widget_set_gl_capability (GTK_WIDGET (glarea),
  397                 glconfig,
  398                 NULL,
  399                 TRUE,
  400                 GDK_GL_RGBA_TYPE);
  401 
  402   /* set up events and signals for OpenGL widget */
  403   gtk_widget_set_events (glarea,
  404              GDK_EXPOSURE_MASK|
  405              GDK_BUTTON_PRESS_MASK|
  406              GDK_BUTTON_RELEASE_MASK|
  407              GDK_POINTER_MOTION_MASK|
  408              GDK_POINTER_MOTION_HINT_MASK);
  409 
  410   g_signal_connect (G_OBJECT (glarea), "expose_event",
  411             G_CALLBACK (expose), NULL);
  412   g_signal_connect (G_OBJECT (glarea), "motion_notify_event",
  413             G_CALLBACK (motion_notify), NULL);
  414   g_signal_connect (G_OBJECT (glarea), "button_press_event",
  415             G_CALLBACK (button_press), NULL);
  416   g_signal_connect (G_OBJECT (glarea), "button_release_event",
  417             G_CALLBACK (button_release), NULL);
  418   g_signal_connect (G_OBJECT (glarea), "scroll_event",
  419             G_CALLBACK (scroll_notify), NULL);
  420   g_signal_connect (G_OBJECT (glarea), "configure_event",
  421             G_CALLBACK (configure), NULL);
  422   g_signal_connect (G_OBJECT (glarea), "destroy",
  423             G_CALLBACK (destroy), NULL);
  424   g_signal_connect (G_OBJECT (glarea), "key_press_event",
  425             G_CALLBACK (key_press_event), glarea);
  426 
  427   return glarea;
  428 }
  429 
  430 typedef struct {
  431   GtkWidget * view;
  432   gboolean survive_broken_pipe;
  433 } ScriptingArgs;
  434 
  435 G_LOCK_DEFINE (main_loop_started);
  436 
  437 static void send_scripting_message (GfkScriptingEvent event, GtkWidget * view, gpointer data)
  438 {
  439   G_LOCK (scripting_pending);
  440   GfkScriptingMessage * msg = g_malloc (sizeof (GfkScriptingMessage));
  441   msg->event = event;
  442   msg->view = view;
  443   msg->data = data;
  444   if (!g_idle_add (gfk_receive_scripting_message, msg)) {
  445     g_warning ("could not send scripting message");
  446     g_free (msg->data);
  447     g_free (msg);
  448     G_UNLOCK (scripting_pending);
  449   }
  450 }
  451 
  452 static gpointer scripting (ScriptingArgs * s)
  453 {
  454   gboolean scripting_off;
  455   fd_set rfds;
  456 
  457   G_LOCK (main_loop_started); /* make sure main loop has been started */
  458   G_UNLOCK (main_loop_started);
  459 
  460   FD_ZERO (&rfds);
  461   FD_SET (0, &rfds);
  462   while (select (1, &rfds, NULL, NULL, NULL) > 0) {
  463     GtsFile * fp = gts_file_new (stdin);
  464 
  465     while (fp->type != GTS_ERROR) {
  466       if (feof (stdin)) {
  467     if (!s->survive_broken_pipe) {
  468       G_LOCK (scripting_pending); /* wait for pending scripting events */
  469       gdk_threads_enter ();
  470       gtk_main_quit ();
  471       gdk_threads_leave ();
  472     }
  473     return NULL;
  474       }
  475       else if (fp->type == '\n')
  476     gts_file_next_token (fp);
  477       else if (fp->type == GTS_INT || !strcmp (fp->token->str, "GModule")) {
  478     GfsSimulation * sim = gfs_simulation_read (fp);
  479 
  480     if (sim == NULL)
  481       break;
  482 
  483     G_LOCK (gfk_gl_scripting);
  484     scripting_off = !gfk_gl_scripting;
  485     G_UNLOCK (gfk_gl_scripting);
  486     if (scripting_off)
  487       gts_object_destroy (GTS_OBJECT (sim));
  488     else {
  489       gfs_simulation_init (sim);
  490 
  491       gdk_threads_enter ();
  492       gfk_gl_view_set_simulation (s->view, sim, "<stdin>");
  493       gdk_threads_leave ();
  494     }
  495       }
  496       else if (fp->type == GTS_STRING) {
  497     if (!strcmp (fp->token->str, "Save") || !strcmp (fp->token->str, "Append")) {
  498       gboolean append = !strcmp (fp->token->str, "Append");
  499       GfsOutputFile * out = NULL;
  500       GfsGl2PSParams * p;
  501       gchar * fname;
  502 
  503       gts_file_next_token (fp);
  504       if (fp->type != GTS_STRING) {
  505         gts_file_error (fp, "expecting a string (filename)");
  506         break;
  507       }
  508       fname = g_strdup (fp->token->str);
  509       gts_file_next_token (fp);
  510       p = g_malloc (sizeof (GfsGl2PSParams));
  511       gfs_gl2ps_params_read (p, fp);
  512       if (fp->type == GTS_ERROR) {
  513         g_free (fname);
  514         g_free (p);
  515         break;
  516       }
  517 
  518       G_LOCK (gfk_gl_scripting);
  519       scripting_off = !gfk_gl_scripting;
  520       G_UNLOCK (gfk_gl_scripting);
  521 
  522       if (!scripting_off) {
  523         if (append) {
  524           if ((out = gfs_output_file_open (fp->token->str, "w")))
  525         p->fp = out->fp;
  526         }
  527         else /* Save */
  528           p->fp = (!strcmp (fname, "stdout") ? stdout :
  529                !strcmp (fname, "stderr") ? stderr :
  530                fopen (fname, "w"));
  531         if (p->fp == NULL)
  532           fprintf (stderr, "gfsview: <stdin>: cannot open file `%s'\n", fname);
  533         else {
  534           send_scripting_message (append ? GFS_APPEND_EVENT : GFS_SAVE_EVENT, s->view, p);
  535           /* p is freed by the receiver of the message */
  536           p = NULL;
  537           if (out) {
  538         /* Append mode, just free memory, do not close file */
  539         out->refcount++;
  540         gfs_output_file_close (out);
  541           }
  542         }
  543       }
  544       g_free (fname);
  545       g_free (p);
  546     }
  547     else if (!strcmp (fp->token->str, "View")) {
  548       G_LOCK (gfk_gl_scripting);
  549       scripting_off = !gfk_gl_scripting;
  550       G_UNLOCK (gfk_gl_scripting);
  551 
  552       gdk_threads_enter ();
  553       if (!gfk_gl_view_read_parameters (s->view, fp, scripting_off)) {
  554         gdk_threads_leave ();
  555         break;
  556       }
  557       gdk_threads_leave ();
  558     }
  559     else if (!strcmp (fp->token->str, "Clear")) {
  560       gdk_threads_enter ();
  561       gfk_gl_view_clear (s->view);
  562       gdk_threads_leave ();
  563       gts_file_next_token (fp);
  564     }
  565     else if (!strcmp (fp->token->str, "Echo")) {
  566       gts_file_next_token (fp);
  567       if (fp->type != '{') {
  568         gts_file_error (fp, "expecting an opening brace");
  569         break;
  570       }
  571       GString * echo = g_string_new ("");
  572       guint scope = fp->scope_max;
  573       gint c = gts_file_getc (fp);
  574       while (c != EOF && fp->scope > scope) {
  575         g_string_append_c (echo, c);
  576         c = gts_file_getc (fp);
  577       }
  578       if (fp->scope != scope) {
  579         g_string_free (echo, TRUE);
  580         gts_file_error (fp, "parse error");
  581         break;
  582       }
  583       gts_file_next_token (fp);
  584 
  585       send_scripting_message (GFS_ECHO_EVENT, s->view, echo->str);
  586       /* echo->str is freed by the receiver of the message */
  587       g_string_free (echo, FALSE);
  588     }
  589     else {
  590       gts_file_error (fp, "unknown keyword `%s'", fp->token->str);
  591       break;
  592     }
  593       }
  594       else {
  595     gts_file_error (fp, "expecting an integer got %d", fp->type);
  596     break;
  597       }
  598     }
  599     gdk_threads_enter ();
  600     gfk_gl_view_set_scripting (s->view, FALSE);
  601     GtkWidget * msg = gtk_message_dialog_new (GTK_WINDOW (s->view), 0,
  602                           GTK_MESSAGE_WARNING,
  603                           GTK_BUTTONS_CLOSE,
  604                           "GfsView: error in scripting thread\n"
  605                           "%d:%d: %s\n\n"
  606                           "Scripting is disabled",
  607                           fp->line, fp->pos, fp->error);
  608     gtk_dialog_run (GTK_DIALOG (msg));
  609     gtk_widget_destroy (msg);
  610     gdk_threads_leave ();
  611     gts_file_destroy (fp);
  612     while (fgetc (stdin) != EOF)
  613       ;
  614   }
  615   return NULL;
  616 }
  617 
  618 static void error_trap_push (SnDisplay * display,
  619                  Display   * xdisplay)
  620 {
  621 }
  622 
  623 static void error_trap_pop (SnDisplay * display,
  624                 Display   * xdisplay)
  625 {
  626   XSync (xdisplay, False); /* get all errors out of the queue */
  627 }
  628 
  629 static gboolean unlock_main_loop (gpointer data)
  630 {
  631   G_UNLOCK (main_loop_started);  
  632   return FALSE;
  633 }
  634 
  635 int main (int argc, char * argv[])
  636 {
  637   GdkGLConfig * glconfig;
  638   ScriptingArgs s;
  639   GtkWidget * glarea;
  640   int c = 0;
  641 
  642   /* initialize multithreading */
  643   g_thread_init (NULL);
  644   gdk_threads_init ();
  645 
  646   /* initialize gtk */
  647   gtk_set_locale ();
  648   gtk_init (&argc, &argv);
  649 
  650   add_pixmap_directory (PACKAGE_DATA_DIR "/pixmaps");
  651 
  652   /* initialize gtkglext */
  653   gtk_gl_init(&argc, &argv);
  654 
  655   /* initialize gfs */
  656   gfs_init (&argc, &argv);
  657 
  658   /* OpenGL drivers seem to often generate floating-point
  659      exceptions... turn them off so that people don't blame
  660      gfsview! */
  661   gfs_disable_floating_point_exceptions ();
  662 
  663   /* options */
  664   s.survive_broken_pipe = FALSE;
  665   while (c != EOF) {
  666     static struct option long_options[] = {
  667       {"survive-broken-pipe", no_argument, NULL, 's'},
  668       {"help", no_argument, NULL, 'h'},
  669       {"version", no_argument, NULL, 'V'},
  670       { NULL }
  671     };
  672     int option_index = 0;
  673     switch ((c = getopt_long (argc, argv, "hVs", long_options, &option_index))) {
  674     case 's': /* survive-broken-pipe */
  675       s.survive_broken_pipe = TRUE;
  676       break;
  677     case 'h': /* help */
  678       fprintf (stderr,
  679              "Usage: gfsview [OPTION] FILE1 FILE2 ...\n"
  680          "The Gerris flow solver visualisation tool.\n"
  681          "\n"
  682              "  -s    --survive-broken-pipe GfsView will not terminate\n"
  683          "                              if the standard input pipe is broken\n"
  684          "  -h    --help                display this help and exit\n"
  685          "  -V    --version             output version information and exit\n"
  686          "\n"
  687          "Reports bugs to %s\n",
  688          FTT_MAINTAINER);
  689       return 0; /* success */
  690       break;
  691     case 'V': /* version */
  692       fprintf (stderr,
  693            "gfsview: %dD version %s\n",
  694            FTT_DIMENSION, VERSION);
  695       return 0; /* succes */
  696       break;
  697     case '?': /* wrong options */
  698       fprintf (stderr, "Try `gfsview --help' for more information.\n");
  699       return 1; /* failure */
  700     }
  701   }
  702 
  703   /* Configure OpenGL-capable visual. */
  704 
  705   /* Try double-buffered visual */
  706   glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
  707                     GDK_GL_MODE_DEPTH |
  708                     GDK_GL_MODE_DOUBLE);
  709   if (glconfig == NULL) {
  710     g_print ("*** Cannot find the double-buffered visual.\n");
  711     g_print ("*** Trying single-buffered visual.\n");
  712     
  713     /* Try single-buffered visual */
  714     glconfig = gdk_gl_config_new_by_mode (GDK_GL_MODE_RGB |
  715                       GDK_GL_MODE_DEPTH);
  716     if (glconfig == NULL) {
  717       g_print ("*** No appropriate OpenGL-capable visual found.\n");
  718       exit(1);
  719     }
  720   }
  721 
  722   /* startup notification */
  723   Display * xdisplay = GDK_DISPLAY ();
  724   SnDisplay * display = sn_display_new (xdisplay, error_trap_push, error_trap_pop);
  725   SnLauncheeContext * 
  726     launched = sn_launchee_context_new_from_environment (display, DefaultScreen (xdisplay));
  727 
  728   /* Create view */
  729   glarea = gl_area_new (glconfig);
  730   gtk_widget_show (glarea);
  731   s.view = gfk_gl_view (glarea);
  732   
  733   /* Register scripting thread */
  734   G_LOCK (main_loop_started);
  735   if (!isatty (STDIN_FILENO) && g_thread_supported ()) {
  736     GError * error;
  737     if (g_thread_create ((GThreadFunc) scripting, &s, FALSE, &error))
  738       gfk_gl_view_set_scripting (s.view, TRUE);
  739     else {
  740       GtkWidget * msg = gtk_message_dialog_new (NULL, 0,
  741                         GTK_MESSAGE_WARNING,
  742                         GTK_BUTTONS_CLOSE,
  743                         "GfsView could not start scripting thread:\n\n"
  744                         "%s\n\n"
  745                         "Scripting is disabled\n",
  746                         error->message);
  747       gtk_dialog_run (GTK_DIALOG (msg));
  748       gtk_widget_destroy (msg);
  749       g_clear_error (&error);
  750     }
  751   }
  752 
  753   /* Read files on command line */
  754   gtk_widget_show (s.view);
  755   for (c = optind; c < argc; c++)
  756     gfk_gl_simulation_read (argv[c], s.view, TRUE);
  757 
  758   /* startup finished */
  759   if (launched)
  760     sn_launchee_context_complete (launched);
  761 
  762   g_timeout_add (0, unlock_main_loop, NULL);
  763   gtk_main ();
  764 
  765   return 0;
  766 }