/* * displaywindow.c * * The display window * * (c) 2007 Thomas White * dtr - Diffraction Tomography Reconstruction * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "trackball.h" #include "reflections.h" #include "main.h" #include "structure.h" enum { DW_ORTHO, DW_PERSPECTIVE }; GtkUIManager *displaywindow_ui; GtkActionGroup *displaywindow_action_group; GtkWidget *displaywindow_window; GtkWidget *displaywindow_bigvbox; GtkWidget *displaywindow_status_bar; int displaywindow_view = DW_ORTHO; GtkWidget *displaywindow_drawing_area; GLfloat displaywindow_distance = 150; GLfloat displaywindow_x_pos = 0; GLfloat displaywindow_y_pos = 0; OctTree *o; OctTreeLinkedList *ol; void disp_oct_stack(OctTree *o) { int i; for (i=0;i<8;i++) { if (o->child[i] != NULL) { glVertex3f(o->ox/1e9,o->oy/1e9,o->oz/1e9); glVertex3f(o->child[i]->ox/1e9,o->child[i]->oy/1e9,o->child[i]->oz/1e9); disp_oct_stack(o->child[i]); } } } void disp_oct_list(OctTreeLinkedList *ol) { OctTree *o; do { o=ol->o; glVertex3f(o->ox/1e9, o->oy/1e9, o->oz/1e9); } while((ol=ol->next)!=NULL); } void error_report(const char *message) { GtkWidget *window; window = gtk_message_dialog_new(GTK_WINDOW(displaywindow_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_CLOSE, message); g_signal_connect_swapped(window, "response", G_CALLBACK(gtk_widget_destroy), window); gtk_widget_show(window); } static void displaywindow_about() { GtkWidget *window; const gchar *authors[] = { "Thomas White ", "Gordon Ball ", "Paul Midgley ", NULL }; window = gtk_about_dialog_new(); gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(window), PACKAGE_NAME); gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(window), PACKAGE_VERSION); gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(window), "(c) 2006-2007 Thomas White "); gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(window), "Diffraction Tomography Reconstruction"); gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(window), "(c) 2006-2007 Thomas White \n" "Virtual trackball (c) Copyright 1993, 1994, Silicon Graphics, Inc.\n" "\n" "Research funded by:\n" "The Engineering and Physical Sciences Research Council\n" "FEI Electron Optics B.V."); gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(window), "http://www-hrem.msm.cam.ac.uk/"); gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(window), authors); g_signal_connect(window, "response", G_CALLBACK(gtk_widget_destroy), NULL); gtk_widget_show_all(window); } static void displaywindow_close() { gtk_exit(0); } static void displaywindow_gl_set_ortho(GLfloat w, GLfloat h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); if ( w > h ) { GLfloat aspect = w/h; glOrtho(-aspect*(displaywindow_distance/2), aspect*(displaywindow_distance/2), -(displaywindow_distance/2), (displaywindow_distance/2), 2.0, 1000.0); } else { GLfloat aspect = h/w; glOrtho(-(displaywindow_distance/2), (displaywindow_distance/2), -aspect*(displaywindow_distance/2), aspect*(displaywindow_distance/2), 2.0, 1000.0); } glMatrixMode(GL_MODELVIEW); } static void displaywindow_gl_set_perspective(GLfloat w, GLfloat h) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); if ( w > h ) { GLfloat aspect = w/h; glFrustum(-aspect, aspect, -1.0, 1.0, 2.0, 1000.0); } else { GLfloat aspect = h/w; glFrustum(-1.0, 1.0, -aspect, aspect, 2.0, 1000.0); } glMatrixMode(GL_MODELVIEW); } static gint displaywindow_changeview(GtkWidget *widget, GtkRadioAction *action) { GLfloat w = displaywindow_drawing_area->allocation.width; GLfloat h = displaywindow_drawing_area->allocation.height; displaywindow_view = gtk_radio_action_get_current_value(action); if ( displaywindow_view == DW_ORTHO ) { displaywindow_gl_set_ortho(w, h); } else { displaywindow_gl_set_perspective(w, h); } return 0; } static void displaywindow_addui_callback(GtkUIManager *ui, GtkWidget *widget, GtkContainer *container) { gtk_box_pack_start(GTK_BOX(container), widget, FALSE, FALSE, 0); /* Enable overflow menu if this is a toolbar */ if ( GTK_IS_TOOLBAR(widget) ) { gtk_toolbar_set_show_arrow(GTK_TOOLBAR(widget), TRUE); } } static void displaywindow_addmenubar() { GtkActionEntry entries[] = { { "FileAction", NULL, "_File", NULL, NULL, NULL }, { "SaveAction", GTK_STOCK_SAVE, "_Save Image...", NULL, NULL, G_CALLBACK(NULL) }, { "CloseAction", GTK_STOCK_CLOSE, "_Close", NULL, NULL, G_CALLBACK(displaywindow_close) }, { "ViewAction", NULL, "_View", NULL, NULL, NULL }, { "ToolsAction", NULL, "_Tools", NULL, NULL, NULL }, { "HelpAction", NULL, "_Help", NULL, NULL, NULL }, { "AboutAction", GTK_STOCK_ABOUT, "_About DTR...", NULL, NULL, G_CALLBACK(displaywindow_about) }, }; guint n_entries = G_N_ELEMENTS(entries); GtkRadioActionEntry toggles[] = { { "OrthoAction", NULL, "_Orthographic", NULL, NULL, DW_ORTHO }, { "PerspectiveAction", NULL, "_Perspective", NULL, NULL, DW_PERSPECTIVE }, }; guint n_toggles = G_N_ELEMENTS(toggles); GError *error = NULL; displaywindow_action_group = gtk_action_group_new("dtrdisplaywindow"); gtk_action_group_add_actions(displaywindow_action_group, entries, n_entries, displaywindow_window); gtk_action_group_add_radio_actions(displaywindow_action_group, toggles, n_toggles, -1, G_CALLBACK(displaywindow_changeview), NULL); displaywindow_ui = gtk_ui_manager_new(); gtk_ui_manager_insert_action_group(displaywindow_ui, displaywindow_action_group, 0); g_signal_connect(displaywindow_ui, "add_widget", G_CALLBACK(displaywindow_addui_callback), displaywindow_bigvbox); if ( gtk_ui_manager_add_ui_from_file(displaywindow_ui, DATADIR"/dtr/displaywindow.ui", &error) == 0 ) { fprintf(stderr, "Error loading message window menu bar: %s\n", error->message); return; } gtk_window_add_accel_group(GTK_WINDOW(displaywindow_window), gtk_ui_manager_get_accel_group(displaywindow_ui)); gtk_ui_manager_ensure_update(displaywindow_ui); } static float displaywindow_x_start = 0.0; static float displaywindow_y_start = 0.0; static float view_quat[4] = { 0.0, 0.0, 0.0, 1.0 }; static gboolean displaywindow_gl_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) { displaywindow_x_start = event->x; displaywindow_y_start = event->y; return FALSE; } static gint displaywindow_gl_motion_notify(GtkWidget *widget, GdkEventMotion *event, gpointer data) { float w = widget->allocation.width; float h = widget->allocation.height; float x = event->x; float y = event->y; float d_quat[4]; if ( event->state & GDK_CONTROL_MASK ) { /* Control-click changes 'zoom' */ displaywindow_distance += event->y - displaywindow_y_start; if ( displaywindow_view == DW_ORTHO ) { displaywindow_gl_set_ortho(w, h); } } else if ( event->state & GDK_SHIFT_MASK ) { /* Shift-click translates */ displaywindow_x_pos += (event->x - displaywindow_x_start)/5; displaywindow_y_pos += (event->y - displaywindow_y_start)/5; } else { /* Click rotates */ trackball(d_quat, (2.0*displaywindow_x_start - w)/w, (h-2.0*displaywindow_y_start)/h, (2.0*x-w)/w, (h-2.0*y)/h); add_quats(d_quat, view_quat, view_quat); } displaywindow_x_start = x; displaywindow_y_start = y; gdk_window_invalidate_rect(widget->window, &widget->allocation, FALSE); return TRUE; } static gint displaywindow_gl_expose(GtkWidget *widget, GdkEventExpose *event, ControlContext *ctx) { GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); GLfloat light0_position[] = { 0.0, 0.0, 100.0, 0.0 }; GLfloat light0_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; GLfloat light0_specular[] = { 0.5, 0.5, 0.5, 1.0 }; GLfloat light1_position[] = { 0.0, 0.0, -100.0, 0.0 }; GLfloat light1_diffuse[] = { 0.8, 0.8, 0.8, 1.0 }; GLfloat light1_specular[] = { 0.5, 0.5, 0.5, 1.0 }; GLfloat green[] = { 0.0, 1.0, 0.0, 1.0 }; GLfloat blue[] = { 0.0, 0.0, 1.0, 1.0 }; GLfloat red[] = { 1.0, 0.0, 0.0, 1.0 }; GLfloat gold[] = { 0.7, 0.7, 0.0, 1.0 }; GLfloat yellow[] = { 1.0, 1.0, 0.0, 1.0 }; GLfloat yellow_glass[] = { 1.0, 1.0, 0.0, 000.1 }; float m[4][4]; // GLfloat fog_density = 0.03; Reflection *reflection; GLUquadricObj *quadric; if ( !gdk_gl_drawable_gl_begin(gldrawable, glcontext) ) { return 0; } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); // glEnable(GL_FOG); // glFogfv(GL_FOG_DENSITY, &fog_density); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glLoadIdentity(); glTranslatef(displaywindow_x_pos, -displaywindow_y_pos, -displaywindow_distance); build_rotmatrix(m, view_quat); glMultMatrixf(&m[0][0]); /* Set up lighting */ glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, light0_position); glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse); glLightfv(GL_LIGHT0, GL_SPECULAR, light0_specular); glEnable(GL_LIGHT1); glLightfv(GL_LIGHT1, GL_POSITION, light1_position); glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular); /* Bounding cube: 100 nm^-1 side length */ glBegin(GL_LINE_LOOP); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red); glVertex3f(50, 50, 50); glVertex3f(-50, 50, 50); glVertex3f(-50, -50, 50); glVertex3f(50, -50, 50); glEnd(); glBegin(GL_LINE_LOOP); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red); glVertex3f(50, 50, -50); glVertex3f(-50, 50, -50); glVertex3f(-50, -50, -50); glVertex3f(50, -50, -50); glEnd(); glBegin(GL_LINES); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red); glVertex3f(50, 50, 50); glVertex3f(50, 50, -50); glVertex3f(-50, 50, 50); glVertex3f(-50, 50, -50); glVertex3f(-50, -50, 50); glVertex3f(-50, -50, -50); glVertex3f(50, -50, 50); glVertex3f(50, -50, -50); glEnd(); /* Tilt axis */ glBegin(GL_LINES); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow); glVertex3f(50, 0.0, 0.0); glVertex3f(-50, 0.0, 0.0); glEnd(); glBegin(GL_TRIANGLE_FAN); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow); glVertex3f(50, 0.0, 0.0); glVertex3f(50-5, 1.0, 1.0); glVertex3f(50-5, -1.0, 1.0); glVertex3f(50-5, -1.0, -1.0); glVertex3f(50-5, 1.0, -1.0); glVertex3f(50-5, 1.0, 1.0); glEnd(); /* Plot all the normal (measured) reflections */ reflection = ctx->reflectionctx->reflections; glBegin(GL_POINTS); do { if ( reflection->type == REFLECTION_NORMAL ) { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green); glVertex3f(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9); } reflection = reflection->next; } while ( reflection != NULL ); glEnd(); /* Plot the other reflections */ reflection = ctx->reflectionctx->reflections; quadric = gluNewQuadric(); do { if ( reflection->type == REFLECTION_CENTRAL ) { glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue); glPushMatrix(); glTranslatef(reflection->x/1e9, reflection->y/1e9, reflection->z/1e9); gluSphere(quadric, 0.2, 32, 32); glPopMatrix(); } if ( reflection->type == REFLECTION_GENERATED ) { /* Generated reflections are displayed by index, not coordinates. xyz field in Reflection will be used later for "measured" location. */ double x, y, z; signed int h, k, l; glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, gold); glPushMatrix(); /* Change hkl to xyz */ h = reflection->h; k = reflection->k; l = reflection->l; x = h*ctx->reflectionctx->basis->a.x + k*ctx->reflectionctx->basis->b.x + l*ctx->reflectionctx->basis->c.x; y = h*ctx->reflectionctx->basis->a.y + k*ctx->reflectionctx->basis->b.y + l*ctx->reflectionctx->basis->c.y; z = h*ctx->reflectionctx->basis->a.z + k*ctx->reflectionctx->basis->b.z + l*ctx->reflectionctx->basis->c.z; glTranslatef(x/1e9, y/1e9, z/1e9); gluSphere(quadric, 0.2, 32, 32); glPopMatrix(); } reflection = reflection->next; } while ( reflection != NULL ); /* If this is an iterative prediction-refinement reconstruction, draw the unit cell */ if ( ctx->rmode == RECONSTRUCTION_PREDICTION ) { glBegin(GL_LINE_STRIP); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue); glVertex3f(0.0, 0.0, 0.0); glVertex3f(ctx->reflectionctx->basis->a.x/1e9, ctx->reflectionctx->basis->a.y/1e9, ctx->reflectionctx->basis->a.z/1e9); glVertex3f(ctx->reflectionctx->basis->a.x/1e9 + ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->a.y/1e9 + ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->a.z/1e9 + ctx->reflectionctx->basis->b.z/1e9); glVertex3f(ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->b.z/1e9); glVertex3f(0.0, 0.0, 0.0); glVertex3f(ctx->reflectionctx->basis->c.x/1e9, ctx->reflectionctx->basis->c.y/1e9, ctx->reflectionctx->basis->c.z/1e9); glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->a.x/1e9, ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->a.y/1e9, ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->a.z/1e9); glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->a.x/1e9 + ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->a.y/1e9 + ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->a.z/1e9 + ctx->reflectionctx->basis->b.z/1e9); glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->b.z/1e9); glVertex3f(ctx->reflectionctx->basis->c.x/1e9, ctx->reflectionctx->basis->c.y/1e9, ctx->reflectionctx->basis->c.z/1e9); glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->b.z/1e9); glVertex3f(ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->b.z/1e9); glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->b.z/1e9); glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->a.x/1e9 + ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->a.y/1e9 + ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->a.z/1e9 + ctx->reflectionctx->basis->b.z/1e9); glVertex3f(ctx->reflectionctx->basis->a.x/1e9 + ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->a.y/1e9 + ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->a.z/1e9 + ctx->reflectionctx->basis->b.z/1e9); glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->a.x/1e9 + ctx->reflectionctx->basis->b.x/1e9, ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->a.y/1e9 + ctx->reflectionctx->basis->b.y/1e9, ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->a.z/1e9 + ctx->reflectionctx->basis->b.z/1e9); glVertex3f(ctx->reflectionctx->basis->c.x/1e9 + ctx->reflectionctx->basis->a.x/1e9, ctx->reflectionctx->basis->c.y/1e9 + ctx->reflectionctx->basis->a.y/1e9, ctx->reflectionctx->basis->c.z/1e9 + ctx->reflectionctx->basis->a.z/1e9); glVertex3f(ctx->reflectionctx->basis->a.x/1e9, ctx->reflectionctx->basis->a.y/1e9, ctx->reflectionctx->basis->a.z/1e9); glEnd(); } /* Zero plane */ glBegin(GL_QUADS); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow_glass); glVertex3f(50, 50, 0.0); glVertex3f(50, -50, 0.0); glVertex3f(-50, -50, 0.0); glVertex3f(-50, 50, 0.0); glEnd(); //octtree bit - temporary /*glBegin(GL_LINES); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue); disp_oct_stack(o); glEnd(); glBegin(GL_POINTS); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red); disp_oct_list(ol); glEnd();*/ if ( gdk_gl_drawable_is_double_buffered(gldrawable) ) { gdk_gl_drawable_swap_buffers(gldrawable); } else { glFlush(); } gdk_gl_drawable_gl_end(gldrawable); return 0; } static gint displaywindow_gl_realise(GtkWidget *widget, gpointer data) { GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); GLfloat w = widget->allocation.width; GLfloat h = widget->allocation.height; if ( !gdk_gl_drawable_gl_begin(gldrawable, glcontext) ) { return 0; } glClearColor(0.002, 0.0, 0.1, 1.0); glClearDepth(1.0); displaywindow_gl_set_ortho(w, h); gdk_gl_drawable_gl_end(gldrawable); return 0; } static gboolean displaywindow_gl_configure(GtkWidget *widget, GdkEventConfigure *event, gpointer data) { GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); GLfloat w = widget->allocation.width; GLfloat h = widget->allocation.height; /* Set viewport */ if ( !gdk_gl_drawable_gl_begin(gldrawable, glcontext) ) { return FALSE; } glViewport(0, 0, w, h); gdk_gl_drawable_gl_end(gldrawable); /* Nudge the projection matrix routines to preserve the aspect ratio */ if ( displaywindow_view == DW_ORTHO ) { displaywindow_gl_set_ortho(w, h); } else { displaywindow_gl_set_perspective(w, h); } return FALSE; } static gint displaywindow_closedown(GtkWidget *widget, gpointer data) { return 0; } void displaywindow_open(ControlContext *ctx) { const char *filename; char *title; GdkGLConfig *glconfig; /*o = gen_octtree(ctx->reflectionctx,15); print_octtree(o); int count=0; ol = find_sparse_trees(o,3,1,&count); */ filename = basename(ctx->filename); title = malloc(10+strlen(filename)); strcpy(title, "dtr: "); strcat(title, filename); displaywindow_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(displaywindow_window), title); free(title); displaywindow_bigvbox = gtk_vbox_new(FALSE, FALSE); gtk_container_add(GTK_CONTAINER(displaywindow_window), displaywindow_bigvbox); displaywindow_addmenubar(); displaywindow_status_bar = gtk_statusbar_new(); gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(displaywindow_status_bar), FALSE); gtk_box_pack_end(GTK_BOX(displaywindow_bigvbox), displaywindow_status_bar, FALSE, FALSE, 0); g_signal_connect(GTK_OBJECT(displaywindow_window), "destroy", G_CALLBACK(displaywindow_closedown), NULL); g_signal_connect_after(GTK_OBJECT(displaywindow_window), "destroy", G_CALLBACK(gtk_main_quit), NULL); /* GL stuff */ glconfig = gdk_gl_config_new_by_mode(GDK_GL_MODE_RGB | GDK_GL_MODE_DEPTH | GDK_GL_MODE_DOUBLE); if ( glconfig == NULL ) { fprintf(stderr, "Can't find double-buffered visual.\n"); exit(1); } gtk_container_set_reallocate_redraws(GTK_CONTAINER(displaywindow_window), TRUE); displaywindow_drawing_area = gtk_drawing_area_new(); gtk_widget_set_size_request(displaywindow_drawing_area, 640, 640); gtk_widget_set_gl_capability(displaywindow_drawing_area, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); gtk_box_pack_start(GTK_BOX(displaywindow_bigvbox), displaywindow_drawing_area, TRUE, TRUE, 0); gtk_widget_add_events(displaywindow_drawing_area, GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_VISIBILITY_NOTIFY_MASK); g_signal_connect(GTK_OBJECT(displaywindow_drawing_area), "configure_event", G_CALLBACK(displaywindow_gl_configure), NULL); g_signal_connect(GTK_OBJECT(displaywindow_drawing_area), "realize", G_CALLBACK(displaywindow_gl_realise), NULL); g_signal_connect(GTK_OBJECT(displaywindow_drawing_area), "expose_event", G_CALLBACK(displaywindow_gl_expose), ctx); g_signal_connect(GTK_OBJECT(displaywindow_drawing_area), "button_press_event", G_CALLBACK(displaywindow_gl_button_press), NULL); g_signal_connect(GTK_OBJECT(displaywindow_drawing_area), "motion_notify_event", G_CALLBACK(displaywindow_gl_motion_notify), NULL); gtk_widget_show_all(displaywindow_window); }