From 6137cff44fac896616e033bcba2aa90cd3d4adf5 Mon Sep 17 00:00:00 2001 From: Kevin Walzer Date: Wed, 24 Dec 2014 04:43:40 +0000 Subject: All on Tk/Cocoa: Improve view performance during resizing; implement custom drawing of scroller to remove flickering and ghosted appearance during window operations; reduce flickering of menubutton during resizing, but do not completely eliminate ghosted rendering when widget is unmapped --- macosx/tkMacOSXButton.c | 2 +- macosx/tkMacOSXMenubutton.c | 2 +- macosx/tkMacOSXScrlbr.c | 117 ++++++++++++++++++++++++++++++------------- macosx/tkMacOSXWindowEvent.c | 46 +++++++++-------- macosx/ttkMacOSXTheme.c | 10 ++++ 5 files changed, 119 insertions(+), 58 deletions(-) diff --git a/macosx/tkMacOSXButton.c b/macosx/tkMacOSXButton.c index 720e40d..627565a 100644 --- a/macosx/tkMacOSXButton.c +++ b/macosx/tkMacOSXButton.c @@ -38,7 +38,7 @@ static NSRect TkMacOSXGetButtonFrame(TkButton *butPtr); */ @interface TkNSButton: NSButton - +- (void)drawRect:(NSRect)dirtyRect; @end @implementation TkNSButton diff --git a/macosx/tkMacOSXMenubutton.c b/macosx/tkMacOSXMenubutton.c index df42763..02a7a38 100644 --- a/macosx/tkMacOSXMenubutton.c +++ b/macosx/tkMacOSXMenubutton.c @@ -15,7 +15,7 @@ #include "tkMacOSXPrivate.h" #include "tkMenubutton.h" #include "tkMacOSXFont.h" -#include "tkMacOSXDebug.h" +#include "tkMacOSXDebug.h" /* #ifdef TK_MAC_DEBUG diff --git a/macosx/tkMacOSXScrlbr.c b/macosx/tkMacOSXScrlbr.c index 405558b..bd05df8 100644 --- a/macosx/tkMacOSXScrlbr.c +++ b/macosx/tkMacOSXScrlbr.c @@ -7,7 +7,8 @@ * Copyright (c) 1996 by Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen - * + * Copyright (c) 2014 Marc Culler. + * Copyright (c) 2014 Kevin Walzer/WordTech Commununications LLC. * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. */ @@ -21,6 +22,7 @@ #endif */ + NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); /* @@ -31,56 +33,103 @@ NSRect TkMacOSXGetScrollFrame(TkScrollbar *scrlPtr); * aware of the state of its Tk parent. This subclass overrides the drawRect * method so that it will not draw itself if the widget is completely outside * of its container. + * + * Custom drawing of the knob seems to work around the flickering visible after * private API's were removed. Based on technique outlined at + * http://stackoverflow.com/questions/1604682/nsscroller- + * graphical-glitches-lag. Only supported on 10.7 and above. */ @interface TkNSScroller: NSScroller -(void) drawRect:(NSRect)dirtyRect; - +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 +-(BOOL) isHorizontal; +-(void) drawKnob; +- (void)drawArrow:(NSScrollerArrow)arrow highlightPart:(int)flag; +- (void)drawKnobSlotInRect:(NSRect)rect highlight:(BOOL)highlight; +#endif @end @implementation TkNSScroller - - (void)drawRect:(NSRect)dirtyRect - { - NSInteger tag = [self tag]; - if ( tag != -1) { - TkScrollbar *scrollPtr = (TkScrollbar *)tag; - MacDrawable* macWin = (MacDrawable *)scrollPtr; - Tk_Window tkwin = scrollPtr->tkwin; - NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); - /* Do not draw if the widget is misplaced or unmapped. */ - if ( NSIsEmptyRect(Tkframe) || - ! macWin->winPtr->flags & TK_MAPPED || - ! NSEqualRects(Tkframe, [self frame]) - ) { + +- (void)drawRect:(NSRect)dirtyRect +{ + NSInteger tag = [self tag]; + if ( tag != -1) { + TkScrollbar *scrollPtr = (TkScrollbar *)tag; + MacDrawable* macWin = (MacDrawable *)scrollPtr; + Tk_Window tkwin = scrollPtr->tkwin; + NSRect Tkframe = TkMacOSXGetScrollFrame(scrollPtr); + /* Do not draw if the widget is misplaced or unmapped. */ + if ( NSIsEmptyRect(Tkframe) || + ! macWin->winPtr->flags & TK_MAPPED || + ! NSEqualRects(Tkframe, [self frame]) + ) { + return; + } + + /* + * Do not draw if the widget is completely outside of its parent. + */ + if (tkwin) { + int parent_height = Tk_Height(Tk_Parent(tkwin)); + int widget_height = Tk_Height(tkwin); + int y = Tk_Y(tkwin); + if ( y > parent_height || y + widget_height < 0 ) { return; } - /* - * Do not draw if the widget is completely outside of its parent. - */ - if (tkwin) { - int parent_height = Tk_Height(Tk_Parent(tkwin)); - int widget_height = Tk_Height(tkwin); - int y = Tk_Y(tkwin); - if ( y > parent_height || y + widget_height < 0 ) { - return; - } - - int parent_width = Tk_Width(Tk_Parent(tkwin)); - int widget_width = Tk_Width(tkwin); - int x = Tk_X(tkwin); - if (x > parent_width || x + widget_width < 0) { - return; - } + int parent_width = Tk_Width(Tk_Parent(tkwin)); + int widget_width = Tk_Width(tkwin); + int x = Tk_X(tkwin); + if (x > parent_width || x + widget_width < 0) { + return; } } - [super drawRect:dirtyRect]; } + [super drawRect:dirtyRect]; +} -@end +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 +- (BOOL)isHorizontal { + NSRect bounds = [self bounds]; + return NSWidth(bounds) < NSHeight (bounds); +} +- (void)drawKnob +{ + NSRect knobRect = [self rectForPart:NSScrollerKnob]; + + if ([self isHorizontal]) { + NSRect newRect = NSMakeRect(knobRect.origin.x, knobRect.origin.y, knobRect.size.width - 5, knobRect.size.height); + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:newRect xRadius:7 yRadius:7]; + + [[NSColor lightGrayColor] set]; + [path fill]; + } else { + NSRect newRect = NSMakeRect(knobRect.origin.x, knobRect.origin.y, knobRect.size.width, knobRect.size.height - 5); + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:newRect xRadius:7 yRadius:7]; + + [[NSColor lightGrayColor] set]; + [path fill]; + } + +} + +- (void)drawArrow:(NSScrollerArrow)arrow highlightPart:(int)flag +{ + // We don't want arrows +} + +- (void)drawKnobSlotInRect:(NSRect)rect highlight:(BOOL)highlight +{ + +} +#endif + +@end + /* * Declaration of Mac specific scrollbar structure. diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c index 6546070..7207859 100644 --- a/macosx/tkMacOSXWindowEvent.c +++ b/macosx/tkMacOSXWindowEvent.c @@ -769,6 +769,8 @@ Tk_MacOSXIsAppInFront(void) @interface TKContentView(TKWindowEvent) - (void) drawRect: (NSRect) rect; - (void) generateExposeEvents: (HIMutableShapeRef) shape; +- (BOOL) preservesContentDuringLiveResize; +- (void) viewWillStartLiveResize; - (void) viewDidEndLiveResize; - (void) viewWillDraw; - (BOOL) isOpaque; @@ -780,15 +782,6 @@ Tk_MacOSXIsAppInFront(void) @implementation TKContentView @end -double drawTime; - -/* - * Set a minimum time for drawing to render. With removal of private NSView API's, default drawing - * is slower and less responsive. This number, which seems feasible after some experimentatation, skips - * some drawing to avoid lag. - */ - -#define MAX_DYNAMIC_TIME .000000001 /*Restrict event processing to Expose events.*/ static Tk_RestrictAction @@ -805,10 +798,12 @@ ExposeRestrictProc( - (void) drawRect: (NSRect) rect { + const NSRect *rectsBeingDrawn; NSInteger rectsBeingDrawnCount; [self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount]; + #ifdef TK_MAC_DEBUG_DRAWING TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, NSStringFromRect(rect)); [[NSColor colorWithDeviceRed:0.0 green:1.0 blue:0.0 alpha:.1] setFill]; @@ -816,11 +811,7 @@ ExposeRestrictProc( NSCompositeSourceOver); #endif - NSDate *beginTime=[NSDate date]; - - /*Skip drawing during live resize if redraw is too slow.*/ - if([self inLiveResize] && drawTime>MAX_DYNAMIC_TIME) return; - + CGFloat height = [self bounds].size.height; HIMutableShapeRef drawShape = HIShapeCreateMutable(); @@ -841,24 +832,35 @@ ExposeRestrictProc( } CFRelease(drawShape); - drawTime=-[beginTime timeIntervalSinceNow]; - [super setNeedsDisplayInRect:rect]; } -/*At conclusion of resize event, send notification and set view for redraw if earlier drawing was skipped because of lagginess.*/ + +/*Provide more fine-grained control over resizing of content to reduce flicker after removal of private API's.*/ + +- (BOOL) preservesContentDuringLiveResize +{ + return YES; +} + +- (void)viewWillStartLiveResize +{ + [super viewWillStartLiveResize]; + [self setNeedsDisplay:NO]; +} + + - (void)viewDidEndLiveResize { - if(drawTime>MAX_DYNAMIC_TIME) { + [self setNeedsDisplay:YES]; + [super setNeedsDisplay:YES]; [super viewDidEndLiveResize]; - } + } --(void) viewWillDraw { - [self setNeedsDisplay:YES]; - } +/*Core function of this class, generates expose events for redrawing.*/ - (void) generateExposeEvents: (HIMutableShapeRef) shape { diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c index a4abc7b..c5be354 100644 --- a/macosx/ttkMacOSXTheme.c +++ b/macosx/ttkMacOSXTheme.c @@ -528,6 +528,10 @@ static Ttk_ElementSpec ComboboxElementSpec = { ComboboxElementDraw }; + + + + /*---------------------------------------------------------------------- * +++ Spinbuttons. * @@ -600,6 +604,11 @@ static TrackElementData ScaleData = { kThemeSlider, kThemeMetricHSliderHeight }; +static TrackElementData ScrollData = { + kThemeScrollBarMedium +}; + + typedef struct { Tcl_Obj *fromObj; /* minimum value */ Tcl_Obj *toObj; /* maximum value */ @@ -661,6 +670,7 @@ static void TrackElementDraw( info.trackInfo.slider.thumbDir = kThemeThumbPlain; } + BEGIN_DRAWING(d) ChkErr(HIThemeDrawTrack, &info, NULL, dc.context, HIOrientation); END_DRAWING -- cgit v0.12