glasgow@POPEYE.NOSC.MIL (Michael Glasgow) (11/02/89)
The following is the bug report I submitted to xbugs. X Window System Bug Report xbugs@expo.lcs.mit.edu VERSION: R3 CLIENT MACHINE and OPERATING SYSTEM: Sun 4/110 ( Navy DTC ) Sun OS 4.0.3 and XNews Server DISPLAY: Sun CG6 WINDOW MANAGER: Sun PostScript Window Manager AREA: X Toolkit - XtGetGC SYNOPSIS: XtGetGC causes BadDrawable errors to occur when accessing multiple displays. DESCRIPTION: The problem is cuased by the way XtGetGC creates and stores drawables to be used in the call to XCreateGC. A valid drawable must be passed to this routine. It is checked for validity by the X server, and then ( apparently ) discarded. XtGetGC uses the RootWindow of the display if it matches the depth of the requested GC. However, if it does not match, it creates a drawable of the given depth, and stores this in an array called GCParents. This drawable is then used to create the GC. If another GC is requested of the same depth, the Drawable that was stored in the GCParents array is used instead of creating a new one. This works well if only a single display is used. But if a second display is opened, and a GC is requested that has a depth different from the RootWindow, a drawable is taken from the array. This drawable was created by the first server, and the result is a BadDrawble error. REPEAT BY: Open a display, then create and realize a widget ( such as the HP MenuButton Widget ) that uses a GC ( Window ) of different depth than the root window. Open a second display, create and realize this same widget on the second display. SAMPLE FIX: *** oldXt/GCManager.c Wed Nov 1 20:52:01 1989 --- Xt/GCManager.c Wed Nov 1 20:52:14 1989 *************** *** 42,50 **** struct _GCrec *next; /* Next GC for this widgetkind. */ } GCrec, *GCptr; - static Drawable GCparents[256]; /* static initialized to zero, K&R ss 4.9 */ static GCrec *GClist = NULL; static Bool Matches(ptr, valueMask, v) GCptr ptr; register XtValueMask valueMask; --- 42,88 ---- struct _GCrec *next; /* Next GC for this widgetkind. */ } GCrec, *GCptr; static GCrec *GClist = NULL; + typedef struct _GCParentRec { + Display *dpy; + Drawable drawables[ 256 ]; + } GCParentRec; + + GCParentRec parents[10]; + int nparents = 0; + + static void AddGCParent( dpy, depth, drawable ) + Display *dpy; + int depth; + Drawable drawable; + { + int i; + + for ( i = 0; i < nparents; i++ ) + if ( parents[ i ].dpy == dpy ) { + parents[ i ].drawables[ depth ] = drawable; + return; + } + parents[ nparents ].dpy = dpy; + parents[ nparents ].drawables[ depth ] = drawable; + nparents++; + } + + + static Drawable GetGCParent( dpy, depth ) + Display *dpy; + int depth; + { + int i; + + for ( i = 0; i < nparents; i++ ) { + if ( parents[ i ].dpy == dpy ) + return( parents[ i ].drawables[ depth ] ); + } + return( 0 ); + } + static Bool Matches(ptr, valueMask, v) GCptr ptr; register XtValueMask valueMask; *************** *** 100,106 **** * Return a read-only GC with the given values. */ ! GC XtGetGC(widget, valueMask, values) Widget widget; register XtGCMask valueMask; XGCValues *values; --- 138,144 ---- * Return a read-only GC with the given values. */ ! GC XtGetGC( widget, valueMask, values ) Widget widget; register XtGCMask valueMask; XGCValues *values; *************** *** 114,122 **** /* Search for existing GC that matches exactly */ for (cur = GClist, prev = NULL; cur != NULL; prev = cur, cur = cur->next) { ! if (cur->valueMask == valueMask && cur->depth == depth ! && cur->screen == screen && cur->dpy == dpy ! && Matches(cur, valueMask, values)) { cur->ref_count++; /* Move this GC to front of list if not already there */ if (prev != NULL) { --- 152,163 ---- /* Search for existing GC that matches exactly */ for (cur = GClist, prev = NULL; cur != NULL; prev = cur, cur = cur->next) { ! if ( ( cur->valueMask == valueMask ) && ! ( cur->depth == depth ) && ! ( cur->screen == screen ) && ! ( cur->dpy == dpy ) && ! ( Matches(cur, valueMask, values ) ) ) { ! cur->ref_count++; /* Move this GC to front of list if not already there */ if (prev != NULL) { *************** *** 124,160 **** cur->next = GClist; GClist = cur; } ! return cur->gc; } } /* No matches, have to create a new one */ ! cur = XtNew(GCrec); cur->next = GClist; GClist = cur; ! cur->dpy = XtDisplay(widget); cur->screen = screen; cur->depth = depth; cur->ref_count = 1; cur->valueMask = valueMask; ! cur->values = *values; ! if (XtWindow(widget) == NULL) { /* Have to create a bogus pixmap for the GC. Stupid X protocol. */ ! if (GCparents[depth] != 0) { ! drawable = GCparents[depth]; ! } else { if (depth == DefaultDepthOfScreen(screen)) drawable = RootWindowOfScreen(screen); else ! drawable = XCreatePixmap(cur->dpy, screen->root, 1, 1, depth); ! GCparents[depth] = drawable; } } else { ! drawable = XtWindow(widget); } cur->gc = XCreateGC(cur->dpy, drawable, valueMask, values); ! return cur->gc; } /* XtGetGC */ void XtReleaseGC(widget, gc) --- 165,201 ---- cur->next = GClist; GClist = cur; } ! return( cur->gc ); } } /* No matches, have to create a new one */ ! cur = XtNew( GCrec ); cur->next = GClist; GClist = cur; ! cur->dpy = XtDisplay( widget ); cur->screen = screen; cur->depth = depth; cur->ref_count = 1; cur->valueMask = valueMask; ! /* cur->values = *values; */ ! memcpy( ( char * )&( cur->values ), ( char * )values, sizeof( XGCValues ) ); ! if ( XtWindow( widget ) == NULL ) { /* Have to create a bogus pixmap for the GC. Stupid X protocol. */ ! drawable = GetGCParent( cur->dpy, depth ); ! if ( drawable == 0 ) { if (depth == DefaultDepthOfScreen(screen)) drawable = RootWindowOfScreen(screen); else ! drawable = XCreatePixmap( cur->dpy, screen->root, 1, 1, depth ); ! AddGCParent( cur->dpy, depth, drawable ); } } else { ! drawable = XtWindow( widget ); } cur->gc = XCreateGC(cur->dpy, drawable, valueMask, values); ! return( cur->gc ); } /* XtGetGC */ void XtReleaseGC(widget, gc) Michael Glasgow glasogw@popeye.nosc.mil