~gabriel1984sibiu/gerris/gfsview

« back to all changes in this revision

Viewing changes to view/main.c

  • Committer: Grevutiu Gabriel
  • Date: 2015-06-01 13:43:24 UTC
  • Revision ID: gabriel1984sibiu@gmail.com-20150601134324-g00cmlsr4udwhs5z
initial state of source code

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 1998 Janne L.b��f <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
}