From f0d31ec6c4e24a7b40b2aeed2ee9bdacea646a63 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Tue, 7 Apr 2015 01:12:45 +0000 Subject: Further cleanup of scrolling, drawing, resize in Cocoa; thanks to Marc Culler for patches --- generic/tkCanvas.c | 13 +++++++ generic/tkInt.decls | 3 ++ generic/tkIntPlatDecls.h | 5 ++- generic/tkTextDisp.c | 30 +++++++-------- macosx/tkMacOSXButton.c | 21 ++++++----- macosx/tkMacOSXDraw.c | 86 ++++++++++++++++++++++++++++++++---------- macosx/tkMacOSXInt.h | 2 +- macosx/tkMacOSXScrlbr.c | 59 ++++++++++++++++------------- macosx/tkMacOSXSubwindows.c | 59 +++++++++++++++++++++++++++++ macosx/tkMacOSXWindowEvent.c | 90 ++++++++++++++++++++++++-------------------- 10 files changed, 253 insertions(+), 115 deletions(-) diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c index 8e14852..9c4d60a 100644 --- a/generic/tkCanvas.c +++ b/generic/tkCanvas.c @@ -2447,6 +2447,19 @@ DisplayCanvas( goto done; } +#ifdef MAC_OSX_TK + /* + * If drawing is disabled, all we need to do is + * clear the REDRAW_PENDING flag. + */ + TkWindow *winPtr = (TkWindow *)(canvasPtr->tkwin); + MacDrawable *macWin = winPtr->privatePtr; + if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ + canvasPtr->flags &= ~REDRAW_PENDING; + return; + } +#endif + /* * Choose a new current item if that is needed (this could cause event * handlers to be invoked). diff --git a/generic/tkInt.decls b/generic/tkInt.decls index ebbadba..8924d68 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -1017,6 +1017,9 @@ declare 50 aqua { declare 51 aqua { void TkGenWMDestroyEvent(Tk_Window tkwin) } +declare 52 aqua { + TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag); +} # removed duplicate from tkPlat table (tk.decls) #declare 52 aqua { diff --git a/generic/tkIntPlatDecls.h b/generic/tkIntPlatDecls.h index 3a2a8aa..3a4bdac 100644 --- a/generic/tkIntPlatDecls.h +++ b/generic/tkIntPlatDecls.h @@ -250,7 +250,8 @@ EXTERN int TkGenerateButtonEvent(int x, int y, Window window, unsigned int state); /* 51 */ EXTERN void TkGenWMDestroyEvent(Tk_Window tkwin); -/* Slot 52 is reserved */ +/* 52 */ +EXTERN void TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag); /* 53 */ EXTERN unsigned long TkpGetMS(void); /* 54 */ @@ -395,7 +396,7 @@ typedef struct TkIntPlatStubs { Window (*tkGetTransientMaster) (TkWindow *winPtr); /* 49 */ int (*tkGenerateButtonEvent) (int x, int y, Window window, unsigned int state); /* 50 */ void (*tkGenWMDestroyEvent) (Tk_Window tkwin); /* 51 */ - void (*reserved52)(void); + void (*tkMacOSXSetDrawingEnabled) (TkWindow *winPtr, int flag); /* 52 */ unsigned long (*tkpGetMS) (void); /* 53 */ void * (*tkMacOSXDrawable) (Drawable drawable); /* 54 */ int (*tkpScanWindowId) (Tcl_Interp *interp, const char *string, Window *idPtr); /* 55 */ diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 95ea935..c3bcd5e 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -3948,7 +3948,6 @@ DisplayText( * warnings. */ Tcl_Interp *interp; - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { /* * The widget has been deleted. Don't do anything. @@ -3957,6 +3956,19 @@ DisplayText( return; } +#ifdef MAC_OSX_TK + /* + * If drawing is disabled, all we need to do is + * clear the REDRAW_PENDING flag. + */ + TkWindow *winPtr = (TkWindow *)(textPtr->tkwin); + MacDrawable *macWin = winPtr->privatePtr; + if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ + dInfoPtr->flags &= ~REDRAW_PENDING; + return; + } +#endif + interp = textPtr->interp; Tcl_Preserve(interp); @@ -3964,14 +3976,6 @@ DisplayText( Tcl_SetVar2(interp, "tk_textRelayout", NULL, "", TCL_GLOBAL_ONLY); } - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - if (!Tk_IsMapped(textPtr->tkwin) || (dInfoPtr->maxX <= dInfoPtr->x) || (dInfoPtr->maxY <= dInfoPtr->y)) { UpdateDisplayInfo(textPtr); @@ -3983,14 +3987,6 @@ DisplayText( Tcl_SetVar2(interp, "tk_textRedraw", NULL, "", TCL_GLOBAL_ONLY); } - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { - /* - * The widget has been deleted. Don't do anything. - */ - - goto end; - } - /* * Choose a new current item if that is needed (this could cause event * handlers to be invoked, hence the preserve/release calls and the loop, diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 725c211..59d394e 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -30,10 +30,10 @@ * Default insets for controls */ -#define DEF_INSET_LEFT 2 -#define DEF_INSET_RIGHT 2 -#define DEF_INSET_TOP 2 -#define DEF_INSET_BOTTOM 4 +#define DEF_INSET_LEFT 12 +#define DEF_INSET_RIGHT 12 +#define DEF_INSET_TOP 1 +#define DEF_INSET_BOTTOM 1 /* * Some defines used to control what type of control is drawn. @@ -318,8 +318,8 @@ TkpComputeButtonGeometry( Tcl_GetString(butPtr->textPtr), -1, butPtr->wrapLength, butPtr->justify, 0, &butPtr->textWidth, &butPtr->textHeight); - txtWidth = butPtr->textWidth; - txtHeight = butPtr->textHeight; + txtWidth = butPtr->textWidth + DEF_INSET_LEFT + DEF_INSET_RIGHT; + txtHeight = butPtr->textHeight + DEF_INSET_BOTTOM + DEF_INSET_TOP; charWidth = Tk_TextWidth(butPtr->tkfont, "0", 1); Tk_GetFontMetrics(butPtr->tkfont, &fm); haveText = (txtWidth != 0 && txtHeight != 0); @@ -647,7 +647,7 @@ DrawButtonImageAndText( butPtr->textHeight, &x, &y); x += butPtr->indicatorSpace; Tk_DrawTextLayout(butPtr->display, pixmap, dpPtr->gc, butPtr->textLayout, - x, y, 0, -1); + x, y - DEF_INSET_BOTTOM, 0, -1); } /* @@ -807,9 +807,12 @@ TkMacOSXDrawButton( hiinfo.animation.time.start = hiinfo.animation.time.current; } - HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, &contHIRec); + HIThemeDrawButton(&cntrRect, &hiinfo, dc.context, kHIThemeOrientationNormal, + &contHIRec); + TkMacOSXRestoreDrawingContext(&dc); - ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, (MacButton *)mbPtr, 32, true); + ButtonContentDrawCB(&contHIRec, mbPtr->btnkind, &mbPtr->drawinfo, + (MacButton *)mbPtr, 32, true); } else { if (!TkMacOSXSetupDrawingContext(pixmap, dpPtr->gc, 1, &dc)) { diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c index 328f905..0f6d2f0 100644 --- a/macosx/tkMacOSXDraw.c +++ b/macosx/tkMacOSXDraw.c @@ -222,7 +222,8 @@ XCopyArea( } if (!TkMacOSXSetupDrawingContext(dst, gc, 1, &dc)) { - TkMacOSXDbgMsg("Failed to setup drawing context."); + return; + /*TkMacOSXDbgMsg("Failed to setup drawing context.");*/ } if ( dc.context ) { @@ -243,6 +244,8 @@ XCopyArea( CGRectMake(src_x, src_y, width, height), CGRectMake(dest_x, dest_y, width, height)); CFRelease(img); + + } else { TkMacOSXDbgMsg("Failed to construct CGImage."); } @@ -652,9 +655,9 @@ GetCGContextForDrawable( CGColorSpaceRef colorspace = NULL; CGBitmapInfo bitmapInfo = #ifdef __LITTLE_ENDIAN__ - kCGBitmapByteOrder32Host; + kCGBitmapByteOrder32Host; #else - kCGBitmapByteOrderDefault; + kCGBitmapByteOrderDefault; #endif char *data; CGRect bounds = CGRectMake(0, 0, macDraw->size.width, @@ -731,6 +734,7 @@ DrawCGImage( } } dstBounds = CGRectOffset(dstBounds, macDraw->xOff, macDraw->yOff); + if (CGImageIsMask(image)) { /*CGContextSaveGState(context);*/ if (macDraw->flags & TK_IS_BW_PIXMAP) { @@ -765,8 +769,8 @@ DrawCGImage( dstBounds.size.width, dstBounds.size.height); #else /* TK_MAC_DEBUG_IMAGE_DRAWING */ CGContextSaveGState(context); - CGContextTranslateCTM(context, - 0, dstBounds.origin.y + CGRectGetMaxY(dstBounds)); + CGContextTranslateCTM(context, 0, + dstBounds.origin.y + CGRectGetMaxY(dstBounds)); CGContextScaleCTM(context, 1, -1); CGContextDrawImage(context, dstBounds, image); CGContextRestoreGState(context); @@ -1478,10 +1482,9 @@ TkScrollWindow( MacDrawable *macDraw = (MacDrawable *) drawable; NSView *view = TkMacOSXDrawableView(macDraw); CGRect srcRect, dstRect; - HIShapeRef dmgRgn = NULL, extraRgn; + HIShapeRef dmgRgn = NULL, extraRgn = NULL; NSRect bounds, visRect, scrollSrc, scrollDst; - int result; - + int result = 0; if ( view ) { /* Get the scroll area in NSView coordinates (origin at bottom left). */ @@ -1491,36 +1494,79 @@ TkScrollWindow( bounds.size.height - height - (macDraw->yOff + y), width, height); scrollDst = NSOffsetRect(scrollSrc, dx, -dy); + /* Limit scrolling to the window content area. */ visRect = [view visibleRect]; scrollSrc = NSIntersectionRect(scrollSrc, visRect); scrollDst = NSIntersectionRect(scrollDst, visRect); - if ( !NSIsEmptyRect(scrollSrc) && !NSIsEmptyRect(scrollDst) ) { /* * Mark the difference between source and destination as damaged. - * This region is described in the Tk coordinate system. + * This region is described in NSView coordinates (y=0 at the bottom) + * and converted to Tk coordinates later. */ - srcRect = CGRectMake(x, y, width, height); - dstRect = CGRectOffset(srcRect, dx, dy); + srcRect = CGRectMake(x, y, width, height); + dstRect = CGRectOffset(srcRect, dx, dy); + + /* Expand the rectangles slightly to avoid degeneracies. */ + srcRect.origin.y -= 1; + srcRect.size.height += 2; + dstRect.origin.y += 1; + dstRect.size.height -= 2; + + /* Compute the damage. */ dmgRgn = HIShapeCreateMutableWithRect(&srcRect); extraRgn = HIShapeCreateWithRect(&dstRect); ChkErr(HIShapeDifference, dmgRgn, extraRgn, (HIMutableShapeRef) dmgRgn); - CFRelease(extraRgn); + result = HIShapeIsEmpty(dmgRgn) ? 0 : 1; + + /* Convert to Tk coordinates. */ + TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); + if (extraRgn) { + CFRelease(extraRgn); + } /* Scroll the rectangle. */ [view scrollRect:scrollSrc by:NSMakeSize(dx, -dy)]; + + /* Shift the Tk children which meet the source rectangle. */ + TkWindow *winPtr = (TkWindow *)tkwin; + TkWindow *childPtr; + CGRect childBounds; + for (childPtr = winPtr->childList; childPtr != NULL; childPtr = childPtr->nextPtr) { + if (Tk_IsMapped(childPtr) && !Tk_IsTopLevel(childPtr)) { + TkMacOSXWinCGBounds(childPtr, &childBounds); + if (CGRectIntersectsRect(srcRect, childBounds)) { + MacDrawable *macChild = childPtr->privatePtr; + if (macChild) { + macChild->yOff += dy; + macChild->xOff += dx; + childPtr->changes.y = macChild->yOff; + childPtr->changes.x = macChild->xOff; + } + } + } + } + + /* Queue up Expose events for the damage region. */ + int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); + [view generateExposeEvents:dmgRgn childrenOnly:1]; + Tcl_SetServiceMode(oldMode); + + /* Belt and suspenders: make the AppKit request a redraw + when it gets control again. */ + [view setNeedsDisplay:YES]; } + } else { + dmgRgn = HIShapeCreateEmpty(); + TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); } - if ( dmgRgn == NULL ) { - dmgRgn = HIShapeCreateEmpty(); + if (dmgRgn) { + CFRelease(dmgRgn); } - TkMacOSXSetWithNativeRegion(damageRgn, dmgRgn); - result = HIShapeIsEmpty(dmgRgn) ? 0 : 1; - CFRelease(dmgRgn); return result; } @@ -1855,6 +1901,7 @@ TkpClipDrawableToRect( CFRelease(macDraw->drawRgn); macDraw->drawRgn = NULL; } + if (width >= 0 && height >= 0) { CGRect clipRect = CGRectMake(x + macDraw->xOff, y + macDraw->yOff, width, height); @@ -2002,7 +2049,7 @@ TkpDrawHighlightBorder ( * TkpDrawFrame -- * * This procedure draws the rectangular frame area. If the user - * has request themeing, it draws with a the background theme. + * has requested themeing, it draws with the background theme. * * Results: * None. @@ -2032,6 +2079,7 @@ TkpDrawFrame( border = themedBorder; } } + Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin), border, highlightWidth, highlightWidth, Tk_Width(tkwin) - 2 * highlightWidth, diff --git a/macosx/tkMacOSXInt.h b/macosx/tkMacOSXInt.h index 249d5cf..6971e26 100644 --- a/macosx/tkMacOSXInt.h +++ b/macosx/tkMacOSXInt.h @@ -86,7 +86,7 @@ typedef struct TkWindowPrivate MacDrawable; #define TK_FOCUSED_VIEW 0x10 #define TK_IS_PIXMAP 0x20 #define TK_IS_BW_PIXMAP 0x40 - +#define TK_DO_NOT_DRAW 0x80 /* * I am reserving TK_EMBEDDED = 0x100 in the MacDrawable flags * This is defined in tk.h. We need to duplicate the TK_EMBEDDED flag in the diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index bdb76af..4d4949f 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -26,6 +26,7 @@ #define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum)) #endif /* __LP64__ */ +#define MOUNTAIN_LION_STYLE (NSAppKitVersionNumber < 1138) /* * Declaration of Mac specific scrollbar structure. @@ -80,7 +81,6 @@ static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr); static int ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr); static void UpdateControlValues(TkScrollbar *scrollPtr); - /* *---------------------------------------------------------------------- * @@ -137,7 +137,6 @@ TkpDisplayScrollbar( register TkScrollbar *scrollPtr = (TkScrollbar *) clientData; register Tk_Window tkwin = scrollPtr->tkwin; - if ((scrollPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { return; } @@ -150,7 +149,6 @@ TkpDisplayScrollbar( CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0, .ty = viewHeight}; - scrollPtr->flags &= ~REDRAW_PENDING; if (!scrollPtr->tkwin || !Tk_IsMapped(tkwin) || !view || !TkMacOSXSetupDrawingContext((Drawable) macWin, NULL, 1, &dc)) { @@ -173,7 +171,6 @@ TkpDisplayScrollbar( (Pixmap) macWin); } - Tk_Draw3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder, scrollPtr->highlightWidth, scrollPtr->highlightWidth, Tk_Width(tkwin) - 2*scrollPtr->highlightWidth, @@ -186,15 +183,11 @@ TkpDisplayScrollbar( /*Update values and draw in native rect.*/ UpdateControlValues(scrollPtr); -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 - if (scrollPtr->vertical) { - HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); - } else { + if (MOUNTAIN_LION_STYLE) { HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationInverted); + } else { + HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); } -#else - HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal); -#endif TkMacOSXRestoreDrawingContext(&dc); scrollPtr->flags &= ~REDRAW_PENDING; @@ -265,11 +258,12 @@ TkpComputeScrollbarGeometry( if (scrollPtr->sliderLast > fieldLength) { scrollPtr->sliderLast = fieldLength; } - scrollPtr->sliderFirst += scrollPtr->inset + + if (!(MOUNTAIN_LION_STYLE)) { + scrollPtr->sliderFirst += scrollPtr->inset + metrics[variant].topArrowHeight; - scrollPtr->sliderLast += scrollPtr->inset + + scrollPtr->sliderLast += scrollPtr->inset + metrics[variant].bottomArrowHeight; - + } /* * Register the desired geometry for the window (leave enough space * for the two arrows plus a minimum-size slider, plus border around @@ -370,21 +364,29 @@ TkpScrollbarPosition( int x, int y) /* Coordinates within scrollPtr's window. */ { - /*Using code from tkUnixScrlbr.c because Unix scroll bindings are driving the display at the script level. All the Mac scrollbar has to do is re-draw itself.*/ + /* + * Using code from tkUnixScrlbr.c because Unix scroll bindings are + * driving the display at the script level. All the Mac scrollbar + * has to do is re-draw itself. + */ - int length, width, tmp; + int length, fieldlength, width, tmp; register const int inset = scrollPtr->inset; + register const int arrowSize = scrollPtr->arrowLength + inset; if (scrollPtr->vertical) { length = Tk_Height(scrollPtr->tkwin); + fieldlength = length - 2 * arrowSize; width = Tk_Width(scrollPtr->tkwin); } else { tmp = x; x = y; y = tmp; length = Tk_Width(scrollPtr->tkwin); + fieldlength = length - 2 * arrowSize; width = Tk_Height(scrollPtr->tkwin); } + fieldlength = fieldlength < 0 ? 0 : fieldlength; if (x=width-inset || y=length-inset) { return OUTSIDE; @@ -395,19 +397,19 @@ TkpScrollbarPosition( * TkpDisplayScrollbar. Be sure to keep the two consistent. */ - if (y < inset + scrollPtr->arrowLength) { - return TOP_ARROW; - } if (y < scrollPtr->sliderFirst) { return TOP_GAP; } if (y < scrollPtr->sliderLast) { return SLIDER; } - if (y >= length - (scrollPtr->arrowLength + inset)) { - return BOTTOM_ARROW; + if (y < fieldlength){ + return BOTTOM_GAP; + } + if (y < fieldlength + arrowSize) { + return TOP_ARROW; } - return BOTTOM_GAP; + return BOTTOM_ARROW; } /* @@ -415,9 +417,11 @@ TkpScrollbarPosition( * * UpdateControlValues -- * - * This procedure updates the Macintosh scrollbar control to display the - * values defined by the Tk scrollbar. This is the key interface to the Mac-native * scrollbar; the Unix bindings drive scrolling in the Tk window and all the Mac - * scrollbar has to do is redraw itself. + * This procedure updates the Macintosh scrollbar control to + * display the values defined by the Tk scrollbar. This is the + * key interface to the Mac-native * scrollbar; the Unix bindings + * drive scrolling in the Tk window and all the Mac scrollbar has + * to do is redraw itself. * * Results: * None. @@ -432,7 +436,6 @@ static void UpdateControlValues( TkScrollbar *scrollPtr) /* Scrollbar data struct. */ { - Tk_Window tkwin = scrollPtr->tkwin; MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin); double dViewSize; @@ -484,7 +487,11 @@ UpdateControlValues( factor - dViewSize; info.trackInfo.scrollbar.viewsize = dViewSize; if (scrollPtr->vertical) { + if (MOUNTAIN_LION_STYLE) { + info.value = factor * scrollPtr->firstFraction; + } else { info.value = info.max - factor * scrollPtr->firstFraction; + } } else { info.value = MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction; } diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c index 869f717..2a88422 100644 --- a/macosx/tkMacOSXSubwindows.c +++ b/macosx/tkMacOSXSubwindows.c @@ -657,6 +657,65 @@ XConfigureWindow( /* *---------------------------------------------------------------------- * + * TkMacOSXSetDrawingEnabled -- + * + * This function sets the TK_DO_NOT_DRAW flag for a given window and + * all of its children. + * + * Results: + * None. + * + * Side effects: + * The clipping regions for the window and its children are cleared. + * + *---------------------------------------------------------------------- + */ + +void +TkMacOSXSetDrawingEnabled( + TkWindow *winPtr, + int flag) +{ + TkWindow *childPtr; + MacDrawable *macWin = winPtr->privatePtr; + + if (macWin) { + if (flag ) { + macWin->flags &= ~TK_DO_NOT_DRAW; + } else { + macWin->flags |= TK_DO_NOT_DRAW; + } + } + + /* + * Set the flag for all children & their descendants, excluding + * Toplevels. (??? Do we need to exclude Toplevels?) + */ + + childPtr = winPtr->childList; + while (childPtr) { + if (!Tk_IsTopLevel(childPtr)) { + TkMacOSXSetDrawingEnabled(childPtr, flag); + } + childPtr = childPtr->nextPtr; + } + + /* + * If the window is a container, set the flag for its embedded window. + */ + + if (Tk_IsContainer(winPtr)) { + childPtr = TkpGetOtherWindow(winPtr); + + if (childPtr) { + TkMacOSXSetDrawingEnabled(childPtr, flag); + } + } +} + +/* + *---------------------------------------------------------------------- + * * TkMacOSXUpdateClipRgn -- * * This function updates the clipping regions for a given window and all of diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 2e7c041..35f9f1c 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -29,7 +29,7 @@ * Declaration of functions used only in this file */ -static int GenerateUpdates(HIMutableShapeRef updateRgn, +static int GenerateUpdates(HIShapeRef updateRgn, CGRect *updateBounds, TkWindow *winPtr); static int GenerateActivateEvents(TkWindow *winPtr, int activeFlag); @@ -315,7 +315,7 @@ extern BOOL opaqueTag; static int GenerateUpdates( - HIMutableShapeRef updateRgn, + HIShapeRef updateRgn, CGRect *updateBounds, TkWindow *winPtr) { @@ -782,7 +782,8 @@ Tk_MacOSXIsAppInFront(void) @interface TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect; -- (void) generateExposeEvents: (HIMutableShapeRef) shape; +- (void) generateExposeEvents: (HIShapeRef) shape; +- (void) generateExposeEvents: (HIShapeRef) shape childrenOnly: (int) childrenOnly; - (void) viewDidEndLiveResize; - (void) tkToolbarButton: (id) sender; - (BOOL) isOpaque; @@ -792,6 +793,8 @@ Tk_MacOSXIsAppInFront(void) @end @implementation TKContentView +NSDate *_resizeStart; +NSTimeInterval _resizeDuration; @end /*Restrict event processing to Expose events.*/ @@ -829,7 +832,7 @@ ExposeRestrictProc( HIShapeUnionWithRect(drawShape, &r); } if (CFRunLoopGetMain() == CFRunLoopGetCurrent()) { - [self generateExposeEvents:drawShape]; + [self generateExposeEvents:(HIShapeRef)drawShape]; } else { [self performSelectorOnMainThread:@selector(generateExposeEvents:) withObject:(id)drawShape waitUntilDone:NO @@ -844,25 +847,33 @@ ExposeRestrictProc( -(void) setFrameSize: (NSSize)newsize { if ( [self inLiveResize] ) { - NSWindow *window = [self window]; - TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); + NSWindow *w = [self window]; + TkWindow *winPtr = TkMacOSXGetTkWindow(w); Tk_Window tkwin = (Tk_Window) winPtr; unsigned int width = (unsigned int)newsize.width; unsigned int height=(unsigned int)newsize.height; - /* Resize the Tk Window to the requested size.*/ - TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, - TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); - - /* Then resize the NSView to the actual window size*/ - newsize.width = (CGFloat)Tk_Width(tkwin); - newsize.height = (CGFloat)Tk_Height(tkwin); + /* Resize the NSView */ [super setFrameSize: newsize]; - /* Process all pending events to update the window. */ - while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} + /* Disable drawing until the window has been completely configured.*/ + TkMacOSXSetDrawingEnabled(winPtr, 0); + /* Generate and handle a ConfigureNotify event for the new size.*/ + TkGenWMConfigureEvent(tkwin, Tk_X(tkwin), Tk_Y(tkwin), width, height, + TK_SIZE_CHANGED | TK_MACOSX_HANDLE_EVENT_IMMEDIATELY); + while ( Tk_DoOneEvent(TK_X_EVENTS|TK_DONT_WAIT) ) {} + + /* Now that Tk has configured all subwindows we can create the clip regions. */ + TkMacOSXSetDrawingEnabled(winPtr, 1); + TkMacOSXInvalClipRgns(tkwin); + TkMacOSXUpdateClipRgn(winPtr); + + /* Finally, generate and process expose events to redraw the window. */ + HIRect bounds = NSRectToCGRect([self bounds]); + HIShapeRef shape = HIShapeCreateWithRect(&bounds); + [self generateExposeEvents: shape]; + while ( Tk_DoOneEvent(TK_ALL_EVENTS|TK_DONT_WAIT) ) {} } else { [super setFrameSize: newsize]; } @@ -881,46 +892,44 @@ ExposeRestrictProc( [self generateExposeEvents: shape]; } -/*Core function of this class, generates expose events for redrawing.*/ -- (void) generateExposeEvents: (HIMutableShapeRef) shape +/* Core method of this class: generates expose events for redrawing. + * Whereas drawRect is intended to be called only from the Appkit event + * loop, this can be called from Tk. If the Tcl_ServiceMode is set to + * TCL_SERVICE_ALL then the expose events will be immediately removed + * from the Tcl event loop and processed. Typically, they should be queued, + * however. + */ +- (void) generateExposeEvents: (HIShapeRef) shape +{ + [self generateExposeEvents:shape childrenOnly:0]; +} + +- (void) generateExposeEvents: (HIShapeRef) shape + childrenOnly: (int) childrenOnly { TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); unsigned long serial; CGRect updateBounds; + int updatesNeeded; if (!winPtr) { return; } + /* Generate Tk Expose events. */ HIShapeGetBounds(shape, &updateBounds); + /* All of these events will share the same serial number. */ serial = LastKnownRequestProcessed(Tk_Display(winPtr)); - if (GenerateUpdates(shape, &updateBounds, winPtr) && - ![[NSRunLoop currentRunLoop] currentMode] && - Tcl_GetServiceMode() != TCL_SERVICE_NONE) { - /* - * Ensure there are no pending idle-time redraws that could - * prevent the just posted Expose events from generating - * new redraws. - */ - - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} - - /* - * For smoother drawing, process Expose events and resulting - * redraws immediately instead of at idle time. - */ - - ClientData oldArg; + updatesNeeded = GenerateUpdates(shape, &updateBounds, winPtr); + + /* Process the Expose events if the service mode is TCL_SERVICE_ALL */ + if (updatesNeeded && Tcl_GetServiceMode() == TCL_SERVICE_ALL) { + ClientData oldArg; Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg); - while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {} - Tk_RestrictEvents(oldProc, oldArg, &oldArg); - - while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {} } - } /* @@ -936,7 +945,6 @@ ExposeRestrictProc( int x, y; TkWindow *winPtr = TkMacOSXGetTkWindow([self window]); Tk_Window tkwin = (Tk_Window) winPtr; - bzero(&event, sizeof(XVirtualEvent)); event.type = VirtualEvent; event.serial = LastKnownRequestProcessed(Tk_Display(tkwin)); -- cgit v0.12