"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.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 }