diff options
Diffstat (limited to 'generic/tkZinc.c')
-rw-r--r-- | generic/tkZinc.c | 295 |
1 files changed, 209 insertions, 86 deletions
diff --git a/generic/tkZinc.c b/generic/tkZinc.c index 736cebd..f014aee 100644 --- a/generic/tkZinc.c +++ b/generic/tkZinc.c @@ -49,7 +49,6 @@ static const char * const zinc_version = "zinc-version-" VERSION; #include "perfos.h" #endif -#include <GL/glu.h> #include <ctype.h> #include <stdlib.h> #include <stdio.h> @@ -59,6 +58,10 @@ static const char * const zinc_version = "zinc-version-" VERSION; #if defined(_WIN32) && defined(PTK) && !defined(PTK_800) #include <tkPlatDecls.m> #endif +#if defined(MAC_OSX_TK) && defined(GL) +#include <tkMacOSX.h> +#include <tkMacOSXInt.h> +#endif typedef struct _TagSearchExpr { @@ -123,7 +126,18 @@ static Tk_Uid star_uid; #ifdef GL static ZnGLContextEntry *gl_contexts = NULL; -#ifndef _WIN32 +#if defined(MAC_OSX_TK) +static GLint ZnGLAttribs[] = { + AGL_RGBA, + AGL_DOUBLEBUFFER, + AGL_RED_SIZE, 8, + AGL_GREEN_SIZE, 8, + AGL_BLUE_SIZE, 8, + AGL_STENCIL_SIZE, 8, + AGL_DEPTH_SIZE, 0, + AGL_NONE +}; +#elif !defined(_WIN32) static int ZnMajorGlx, ZnMinorGlx; static int ZnGLAttribs[] = { GLX_RGBA, @@ -900,19 +914,37 @@ ZnNeedRedisplay(ZnWInfo *wi) * * ZnGetGlContext -- * + * On AGL there is one context per window/widget. The Oldest context + * is used to share the resources until it is destroyed, this task is + * then transferred to the next older and so on. + * On the other platforms a single context is created and shared + * amongst all the windows for a sinlge display. + * *---------------------------------------------------------------------- */ #ifdef GL ZnGLContextEntry * ZnGetGLContext(Display *dpy) { - ZnGLContextEntry *context_entry; + ZnGLContextEntry *cur, *last; - for (context_entry = gl_contexts; - context_entry && context_entry->dpy != dpy; - context_entry = context_entry->next); + // + // Find the first context matching. + for (cur = gl_contexts; cur && cur->dpy != dpy; cur = cur->next); + + if (!cur) { + return cur; + } - return context_entry; + // + // Now proceed to the oldest. + for (last = cur; cur->next; cur = cur->next) { + if (cur->dpy == dpy) { + last = cur; + } + } + + return last; } ZnGLContextEntry * @@ -954,6 +986,10 @@ ZnGLMakeCurrent(Display *dpy, if (!wglMakeCurrent(ce->hdc, ce->context)) { fprintf(stderr, "Can't make the GL context current: %d\n", GetLastError()); } +#elif defined(MAC_OSX_TK) + if (aglSetCurrentContext(ce->context) == GL_FALSE) { + fprintf(stderr, "Can't make the GL context current\n"); + } #else glXMakeCurrent(dpy, Tk_WindowId(wi->win), ce->context); #endif @@ -980,6 +1016,8 @@ ZnGLSwapBuffers(ZnGLContextEntry *ce, if (ce) { #ifdef _WIN32 SwapBuffers(ce->hdc); +#elif defined(MAC_OSX_TK) + aglSwapBuffers(ce->context); #else glXSwapBuffers(ce->dpy, Tk_WindowId(wi->win)); #endif @@ -994,8 +1032,8 @@ InitRendering1(ZnWInfo *wi) { if (wi->render) { -# ifndef _WIN32 - ZnGLContextEntry *ce; +# if !defined(_WIN32) && !defined(MAC_OSX_TK) + ZnGLContextEntry *ce; ZnGLContext gl_context; XVisualInfo *gl_visual = NULL; Colormap colormap = 0; @@ -1075,24 +1113,45 @@ InitRendering1(ZnWInfo *wi) if (gl_visual && colormap) { Tk_SetWindowVisual(wi->win, gl_visual->visual, 24, colormap); } -# endif /* _WIN32 */ +# endif } } +#if defined(MAC_OSX_TK) static void -InitRendering2(ZnWInfo *wi) +UpdateBufferRect(ZnGLContextEntry *ce, + Tk_Window win) { - ZnGLContextEntry *ce; - ZnGLContext gl_context; - GLfloat r[2]; /* Min, Max */ - GLint i[1]; + GLint rect[4]; + Rect bounds; + + TkMacOSXWinBounds((TkWindow *) win, &bounds); + rect[0] = bounds.left; + rect[1] = Tk_Height(ce->top_win) - bounds.bottom; + rect[2] = bounds.right - bounds.left; + rect[3] = bounds.bottom - bounds.top;; + //printf("BUFFER_RECT: %d %d %d %d\n", rect[0], rect[1], rect[2], rect[3]); + aglSetInteger(ce->context, AGL_BUFFER_RECT, rect); + aglEnable(ce->context, AGL_BUFFER_RECT); +} +#endif + +static void +InitRendering2(ZnWInfo *wi, + Tk_Window top_level) +{ + ZnGLContextEntry *ce; + ZnGLContext gl_context; + GLfloat r[2]; /* Min, Max */ + GLint i[1]; if (wi->render) { -# ifdef _WIN32 /* * Look for a matching context already available. */ ce = ZnGetGLContext(wi->dpy); + +# ifdef _WIN32 if (ce) { gl_context = ce->context; ce->hwnd = Tk_GetHWND(Tk_WindowId(wi->win)); @@ -1151,6 +1210,48 @@ InitRendering2(ZnWInfo *wi) } } ReleaseDC(ce->hwnd, ce->hdc); + +#elif defined(MAC_OSX_TK) + + { + AGLPixelFormat pix_fmt; + GLenum err; + + pix_fmt = aglChoosePixelFormat(NULL, 0, ZnGLAttribs); + err = aglGetError(); + if (pix_fmt && (err == AGL_NO_ERROR)) { + gl_context = aglCreateContext(pix_fmt, ce ? ce->context : NULL); + err = aglGetError(); + } + else { + fprintf(stderr, "error when selecting a pixel format 0x%x %d\n", pix_fmt, err); + return; + } + if ((err != AGL_NO_ERROR) || (gl_context == NULL)) { + fprintf(stderr, "No GL context\n"); + return; + } + else { + ce = ZnMalloc(sizeof(ZnGLContextEntry)); + ce->widgets = ZnListNew(1, sizeof(ZnWInfo *)); + ZnListAdd(ce->widgets, &wi, ZnListTail); + + ce->context = gl_context; + ce->dpy = wi->dpy; + ce->max_tex_size = 64; /* Minimum value is always valid */ + ce->max_line_width = 1; + ce->max_point_width = 1; + ce->next = gl_contexts; + gl_contexts = ce; + ce->pix_fmt = pix_fmt; + ce->gworld = TkMacOSXGetDrawablePort(Tk_WindowId(wi->win)); + ce->top_win = top_level; + if (aglSetDrawable(ce->context, ce->gworld) == GL_FALSE) { + fprintf(stderr, "Can't attach the window to the GL context\n"); + } + } + } + #endif ce = ZnGLMakeCurrent(wi->dpy, wi); @@ -1178,6 +1279,9 @@ InitRendering2(ZnWInfo *wi) ce->max_tex_size); } +#if defined(MAC_OSX_TK) + UpdateBufferRect(ce, wi->win); +#endif ZnGLReleaseContext(ce); } } @@ -1209,7 +1313,7 @@ ZincObjCmd(ClientData client_data, /* Main window associated with #endif unsigned int num; ZnBool has_gl = False; -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(MAC_OSX_TK) # if defined(GL) || defined(SHAPE) int major_op, first_err, first_evt; # endif @@ -1222,7 +1326,7 @@ ZincObjCmd(ClientData client_data, /* Main window associated with InitZinc(interp); #ifdef GL -# ifdef _WIN32 +# if defined(_WIN32) || defined(MAC_OSX_TK) has_gl = True; # else if (XQueryExtension(dpy, "GLX", &major_op, &first_evt, &first_err)) { @@ -1287,7 +1391,7 @@ ZincObjCmd(ClientData client_data, /* Main window associated with wi->real_top = None; ASSIGN(wi->flags, ZN_HAS_GL, has_gl); -#if defined(SHAPE) && !defined(_WIN32) +#if defined(SHAPE) ASSIGN(wi->flags, ZN_HAS_X_SHAPE, XQueryExtension(wi->dpy, "SHAPE", &major_op, &first_evt, &first_err)); wi->reshape = wi->full_reshape = True; @@ -2643,7 +2747,7 @@ LayoutItems(ZnWInfo *wi, /* *---------------------------------------------------------------------- * - * SetOrigin -- + * ZnSetOrigin -- * * This procedure is invoked to translate the viewed area so * that the given point is displayed in the top left corner. @@ -2661,9 +2765,9 @@ LayoutItems(ZnWInfo *wi, *---------------------------------------------------------------------- */ static void -SetOrigin(ZnWInfo *wi, - ZnReal x_origin, - ZnReal y_origin) +ZnSetOrigin(ZnWInfo *wi, + ZnReal x_origin, + ZnReal y_origin) { int left, right, top, bottom, delta; @@ -6490,7 +6594,7 @@ WidgetObjCmd(ClientData client_data, /* Information about the widget. } break; } - SetOrigin(wi, new_x, wi->origin.y); + ZnSetOrigin(wi, new_x, wi->origin.y); } break; } @@ -6534,7 +6638,7 @@ WidgetObjCmd(ClientData client_data, /* Information about the widget. } break; } - SetOrigin(wi, wi->origin.x, new_y); + ZnSetOrigin(wi, wi->origin.x, new_y); } break; } @@ -6783,7 +6887,7 @@ Configure(Tcl_Interp *interp,/* Used for error reporting. */ if (CONFIG_PROBE(SCROLL_REGION_SPEC) || CONFIG_PROBE(CONFINE_SPEC)) { - SetOrigin(wi, wi->origin.x, wi->origin.y); + ZnSetOrigin(wi, wi->origin.x, wi->origin.y); SET(wi->flags, ZN_UPDATE_SCROLLBARS); } @@ -6900,7 +7004,7 @@ Configure(Tcl_Interp *interp,/* Used for error reporting. */ } if ((mask & CONFIG_SET_ORIGIN) || init) { - SetOrigin(wi, wi->origin.x, wi->origin.y); + ZnSetOrigin(wi, wi->origin.x, wi->origin.y); SET(wi->flags, ZN_UPDATE_SCROLLBARS); } @@ -7184,75 +7288,82 @@ TopEvent(ClientData client_data, /* Information about widget. */ } static void -Event(ClientData client_data, /* Information about widget. */ - XEvent *event) /* Information about event. */ +FinishSetup(ZnWInfo *wi) { - ZnWInfo *wi = (ZnWInfo *) client_data; - XGCValues values; - ZnBBox bbox; + XGCValues values; + Tk_Window top_level; - /*printf("=============== DEBUT %s %d EVENT ==================\n", - event->type == MapNotify ? "MAP": - event->type == Expose? "EXPOSE" : - event->type == ConfigureNotify ? "CONFIGURE" : - event->type == VisibilityNotify ? "VISIBILITY" : - event->type == DestroyNotify ? "DESTROY" : - "??", event->type);*/ - if (event->type == MapNotify) { - SET(wi->flags, ZN_CONFIGURE_EVENT); - if (!wi->gc) { - SET(wi->flags, ZN_REALIZED); + if (!wi->gc) { + SET(wi->flags, ZN_REALIZED); + top_level = wi->win; + while (!Tk_IsTopLevel(top_level)) { + top_level = Tk_Parent(top_level); + } #ifdef GL - InitRendering2(wi); + InitRendering2(wi, top_level); #endif - /* - * Get the work GC and suppress GraphicExpose - * and NoExpose events reception. - */ - wi->gc = XCreateGC(wi->dpy, Tk_WindowId(wi->win), 0, NULL); - values.graphics_exposures = False; - XChangeGC(wi->dpy, wi->gc, GCGraphicsExposures, &values); + /* + * Get the work GC and suppress GraphicExpose + * and NoExpose events reception. + */ + wi->gc = XCreateGC(wi->dpy, Tk_WindowId(wi->win), 0, NULL); + values.graphics_exposures = False; + XChangeGC(wi->dpy, wi->gc, GCGraphicsExposures, &values); + /* + * Set the real top window above us. + */ + { + Window parent, root, *children=NULL; + int num_children, success; + + success = XQueryTree(wi->dpy, Tk_WindowId(top_level), &root, &parent, + &children, &num_children); + if (!success || (root == parent)) { + wi->real_top = Tk_WindowId(top_level); + } + else { + wi->real_top = parent; + } /* - * Set the real top window above us. + * Needed under glx to suspend update with scissors after + * a move to synchronise the two buffers. Fix a refresh + * bug when the window is partially clipped by the display + * border. Can be usefull under Windows too. */ - { - Window parent, root, *children=NULL; - Tk_Window top_level; - int num_children, success; - - top_level = wi->win; - while (!Tk_IsTopLevel(top_level)) { - top_level = Tk_Parent(top_level); - } - success = XQueryTree(wi->dpy, Tk_WindowId(top_level), &root, &parent, - &children, &num_children); - if (!success || (root == parent)) { - wi->real_top = Tk_WindowId(top_level); - } - else { - wi->real_top = parent; - } - /* - * Needed under glx to suspend update with scissors after - * a move to synchronise the two buffers. Fix a refresh - * bug when the window is partially clipped by the display - * border. Can be usefull under Windows too. - */ - Tk_CreateEventHandler(top_level, StructureNotifyMask, TopEvent, (ClientData) wi); - if (children && success) { - XFree(children); - } + Tk_CreateEventHandler(top_level, StructureNotifyMask, TopEvent, (ClientData) wi); + if (children && success) { + XFree(children); } } + } +} + +static void +Event(ClientData client_data, /* Information about widget. */ + XEvent *event) /* Information about event. */ +{ + ZnWInfo *wi = (ZnWInfo *) client_data; + ZnBBox bbox; + + //printf("=============== DEBUT %s %d EVENT ==================\n", + // event->type == MapNotify ? "MAP": + // event->type == Expose? "EXPOSE" : + // event->type == ConfigureNotify ? "CONFIGURE" : + // event->type == VisibilityNotify ? "VISIBILITY" : + // event->type == DestroyNotify ? "DESTROY" : + // "??", event->type); + if (event->type == MapNotify) { + SET(wi->flags, ZN_CONFIGURE_EVENT); + FinishSetup(wi); ZnNeedRedisplay(wi); } else if (event->type == Expose) { ZnDim width, height; SET(wi->flags, ZN_CONFIGURE_EVENT); - + FinishSetup(wi); bbox.orig.x = (((XExposeEvent*) event)->x); bbox.orig.y = (((XExposeEvent*) event)->y); width = ((XExposeEvent*) event)->width; @@ -7268,9 +7379,9 @@ Event(ClientData client_data, /* Information about widget. */ bbox.corner.x = MIN(wi->width, bbox.orig.x + width); bbox.corner.y = MIN(wi->height, bbox.orig.y + height); - /*printf("expose %d %d %d %d\n", - ((XExposeEvent*) event)->x, ((XExposeEvent*) event)->y, - ((XExposeEvent*) event)->width, ((XExposeEvent*) event)->height);*/ + //printf("expose %d %d %d %d\n", + // ((XExposeEvent*) event)->x, ((XExposeEvent*) event)->y, + // ((XExposeEvent*) event)->width, ((XExposeEvent*) event)->height); /* * Add the exposed area to the expose region and * schedule an asynchronous redisplay of the window @@ -7292,6 +7403,7 @@ Event(ClientData client_data, /* Information about widget. */ int int_width, int_height; SET(wi->flags, ZN_CONFIGURE_EVENT); + FinishSetup(wi); int_width = Tk_Width(wi->win); int_height = Tk_Height(wi->win); @@ -7311,7 +7423,7 @@ Event(ClientData client_data, /* Information about widget. */ * it's confined and the scroll region is smaller than the * window. */ - SetOrigin(wi, wi->origin.x, wi->origin.y); + ZnSetOrigin(wi, wi->origin.x, wi->origin.y); ZnDamage(wi, &bbox); ZnITEM.Invalidate(wi->top_group, ZN_TRANSFO_FLAG); @@ -7328,6 +7440,14 @@ Event(ClientData client_data, /* Information about widget. */ int_width, int_height, DefaultDepthOfScreen(wi->screen)); } +#if defined(MAC_OSX_TK) + else { + ZnGLContextEntry *ce = ZnGLMakeCurrent(wi->dpy, wi); + UpdateBufferRect(ce, wi->win); + aglUpdateContext(ce->context); + } +#endif + } else { /* @@ -8237,9 +8357,12 @@ Destroy(ZnWInfo *wi) } } } -#ifdef _WIN32 +#if defined(_WIN32) ZnGLReleaseContext(ce); wglDeleteContext(ce->context); +#elif defined(MAC_OSX_TK) + aglDestroyPixelFormat(ce->pix_fmt); + aglDestroyContext(ce->context); #else glXDestroyContext(ce->dpy, ce->context); /* @@ -8447,7 +8570,7 @@ Repair(ZnWInfo *wi) } #endif - /*printf("Repair, scissors: %d\n", ISCLEAR(wi->flags, ZN_CONFIGURE_EVENT));*/ + //printf("Repair, scissors: %d\n", ISCLEAR(wi->flags, ZN_CONFIGURE_EVENT)); ce = ZnGLMakeCurrent(wi->dpy, wi); glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); |