#include #include #include //#define USE_CAIRO #define USE_GTKGLEXT //#define USE_GLX //#define USE_WGL //#define USE_CGL /************************ * Cairo implementation * ************************/ #if defined(USE_CAIRO) #include gpointer expose_setup(GtkWidget *widget) { return NULL; } gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { GtkAllocation alloc; gtk_widget_get_allocation(widget, &alloc); cairo_t *cairo = gdk_cairo_create(gtk_widget_get_window(widget)); cairo_set_source_rgb(cairo, 1, 1, 1); cairo_arc(cairo, alloc.x + alloc.width/2, alloc.y + alloc.height/2, MIN(alloc.width/2,alloc.height/2), 0, 2*G_PI); cairo_fill(cairo); return FALSE; } /*************************** * GtkGlExt implementation * ***************************/ #elif defined(USE_GTKGLEXT) #include #include #include void realize(GtkWidget *widget, gpointer user_data) { gdk_window_ensure_native(gtk_widget_get_window(widget)); } gpointer expose_setup(GtkWidget *widget) { //GdkGLConfig *glconfig = gdk_gl_config_new_by_mode( // GDK_GL_MODE_RGBA | GDK_GL_MODE_DEPTH | // GDK_GL_MODE_ALPHA); GdkGLConfig *glconfig = gdk_gl_config_new_by_mode( GDK_GL_MODE_RGBA | GDK_GL_MODE_DEPTH | GDK_GL_MODE_ALPHA | GDK_GL_MODE_DOUBLE); gtk_widget_set_gl_capability(widget, glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); return NULL; } gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { GtkWidget *toplevel = gtk_widget_get_toplevel(widget); g_message("window: w=%x tl=%x", (guint)GDK_WINDOW_HWND(gtk_widget_get_window(widget)), (guint)GDK_WINDOW_HWND(gtk_widget_get_window(toplevel))); GtkAllocation alloc; gtk_widget_get_allocation(widget, &alloc); GdkGLContext *glcontext = gtk_widget_get_gl_context(widget); GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(widget); gdk_gl_drawable_gl_begin(gldrawable, glcontext); glViewport(0, 0, alloc.width, alloc.height); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glBegin(GL_TRIANGLE_FAN); glVertex2f(0.0, 0.0); for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100) glVertex2d(sin(i), cos(i)); glEnd(); gdk_gl_drawable_swap_buffers(gldrawable); gdk_gl_drawable_gl_end(gldrawable); return FALSE; } /********************** * X11 implementation * **********************/ #elif defined(USE_GLX) #include #include #include void realize(GtkWidget *widget, gpointer user_data) { gdk_window_ensure_native(gtk_widget_get_window(widget)); } gpointer expose_setup(GtkWidget *widget) { GdkScreen *screen = gdk_screen_get_default(); Display *xdisplay = GDK_SCREEN_XDISPLAY(screen); gint nscreen = GDK_SCREEN_XNUMBER(screen); /* Create context */ int attribs[] = {GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_ALPHA_SIZE, 1, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None}; XVisualInfo *xvinfo = glXChooseVisual(xdisplay, nscreen, attribs); GLXContext context = glXCreateContext(xdisplay, xvinfo, 0, False); /* Fix up colormap */ GdkVisual *visual = gdk_x11_screen_lookup_visual(screen, xvinfo->visualid); GdkColormap *cmap = gdk_colormap_new(visual, FALSE); gtk_widget_set_colormap(widget, cmap); /* Disable GTK double buffering */ gtk_widget_set_double_buffered(widget, FALSE); return context; } gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, GLXContext context) { /* Make current */ Display *xdisplay = GDK_SCREEN_XDISPLAY(gdk_screen_get_default()); Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(widget)); glXMakeCurrent(xdisplay, xwindow, context); GtkWidget *toplevel = gtk_widget_get_toplevel(widget); g_message("window: w=%x tl=%x", (guint)GDK_WINDOW_XID(gtk_widget_get_window(widget)), (guint)GDK_WINDOW_XID(gtk_widget_get_window(toplevel))); /* Drawing */ GtkAllocation alloc; gtk_widget_get_allocation(widget, &alloc); glViewport(0, 0, alloc.width, alloc.height); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glBegin(GL_TRIANGLE_FAN); glVertex2f(0.0, 0.0); for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100) glVertex2d(sin(i), cos(i)); glEnd(); /* Swap buffers */ glXSwapBuffers(xdisplay, xwindow); return FALSE; } /************************ * Win32 implementation * ************************/ #elif defined(USE_WGL) #include #include #include void realize(GtkWidget *widget, gpointer user_data) { gdk_window_ensure_native(gtk_widget_get_window(widget)); } gpointer expose_setup(GtkWidget *widget) { /* Create context */ //HWND hwnd = GDK_WINDOW_HWND(gtk_widget_get_window(widget)); //HGLRC hDC = GetDC(hwnd); // get the device context for window //HDC hRC = wglCreateContext(hDC); // create rendering context //wglMakeCurrent(hDC,hRC); // make rendering context current /* Delete context */ //wglMakeCurrent(hDC,NULL); // deselect rendering context //wglDeleteContext(hRC); // delete rendering context //PostQuitMessage(0); // send wm_quit /* Disable GTK double buffering */ gtk_widget_set_double_buffered(widget, FALSE); return FALSE; } gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { GtkWidget *toplevel = gtk_widget_get_toplevel(widget); GdkWindow *window = gtk_widget_get_window(widget); GdkWindow *topwin = gtk_widget_get_window(toplevel); gdk_window_ensure_native(window); PIXELFORMATDESCRIPTOR pfo = {}, pfd = { .nSize = sizeof(pfd), .nVersion = 1, .dwFlags = PFD_DRAW_TO_WINDOW // "Correct" way | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //.dwFlags = PFD_SUPPORT_OPENGL // Works in wine // | PFD_DRAW_TO_WINDOW, .iPixelType = PFD_TYPE_RGBA, .cColorBits = 24, .cAlphaBits = 8, .cDepthBits = 32, .iLayerType = PFD_MAIN_PLANE, }; HWND hwnd = GDK_WINDOW_HWND(window); HDC hDC = GetDC(hwnd); // get the device context for window int pf = ChoosePixelFormat(hDC, &pfd); int st0 = DescribePixelFormat(hDC, pf, sizeof(pfd), &pfo); int st1 = SetPixelFormat(hDC, pf, &pfd); HGLRC hRC = wglCreateContext(hDC); int st2 = wglMakeCurrent(hDC, hRC); g_message("dc: %p, %p, %p", hDC, GetDC(hwnd), wglGetCurrentDC()); g_message("window: pf=%d st=%d,%d,%d dc=%p rc=%p wins=%x=%x!=%x", pf, st0,st1,st2, hDC, hRC, (guint)hwnd, (guint)GDK_WINDOW_HWND(window), (guint)GDK_WINDOW_HWND(topwin)); g_message("pdfOut: dwFlags=%lx=%lx, ipt=%x=%x, layer=%x=%x, {c,a,d}bits=%d,%d,%d", pfo.dwFlags, pfd.dwFlags, pfo.iPixelType, pfd.iPixelType, pfo.iLayerType, pfd.iLayerType, pfo.cColorBits, pfo.cAlphaBits, pfo.cDepthBits); /* Drawing */ GtkAllocation alloc = widget->allocation; glViewport(0, 0, alloc.width, alloc.height); g_message("alloc: %dx%d", alloc.width, alloc.height); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glBegin(GL_TRIANGLE_FAN); glVertex2f(0.0, 0.0); for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100) glVertex2d(sin(i), cos(i)); glEnd(); /* Swap buffers */ SwapBuffers(hDC); /* Cleanup */ wglMakeCurrent(NULL, NULL); wglDeleteContext(hRC); return TRUE; } /************************** * Mac OSX implementation * **************************/ #elif defined(USE_CGL) #include gpointer expose_setup(GtkWidget *widget) { return FALSE; } gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { /* Drawing */ GtkAllocation alloc; gtk_widget_get_allocation(widget, &alloc); glViewport(0, 0, alloc.width, alloc.height); glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 1.0, 1.0); glBegin(GL_TRIANGLE_FAN); glVertex2f(0.0, 0.0); for (double i = 0; i < 2*G_PI; i+=(2*G_PI)/100) glVertex2d(sin(i), cos(i)); glEnd(); return FALSE; } /**************************** * Undefined implementation * ****************************/ #else gpointer expose_setup(GtkWidget *widget) { return NULL; } gboolean expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { g_message("unimplemented"); return FALSE; } #endif /*************** * Common code * ***************/ gboolean key_press_event(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { if (event->keyval == GDK_q) gtk_main_quit(); return FALSE; } int main(int argc, char **argv) { gtk_init_check(&argc, &argv); GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); GtkWidget *box = gtk_vbox_new(FALSE, 5); GtkWidget *draw = gtk_drawing_area_new(); GtkWidget *button = gtk_button_new_with_label("Hello, World"); gpointer data = expose_setup(draw); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); g_signal_connect(window, "key-press-event", G_CALLBACK(key_press_event), NULL); g_signal_connect(draw, "expose-event", G_CALLBACK(expose_event), data); gtk_widget_set_size_request(draw, 300, 300); gtk_widget_set_size_request(button, -1, 50); gtk_box_pack_start(GTK_BOX(box), draw, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(box), button, FALSE, TRUE, 0); gtk_container_add(GTK_CONTAINER(window), box); gtk_widget_show_all(window); gtk_main(); return 0; }