summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarc_culler <marc.culler@gmail.com>2020-06-03 03:23:12 (GMT)
committermarc_culler <marc.culler@gmail.com>2020-06-03 03:23:12 (GMT)
commit876fc6d65e63ae72fe52d8435ef703efa50fe814 (patch)
treec4fbfa804523b101ed086d4a5ea89f787ae08735
parentaeb89ef62c14b00be0853a7539e807bb3937a6f8 (diff)
downloadtk-876fc6d65e63ae72fe52d8435ef703efa50fe814.zip
tk-876fc6d65e63ae72fe52d8435ef703efa50fe814.tar.gz
tk-876fc6d65e63ae72fe52d8435ef703efa50fe814.tar.bz2
Do not draw in the setup proc. Fix the heartbeat so it can wake up Tcl_WaitForEvent. Handle the first drawing of a window.
-rw-r--r--macosx/tkMacOSXDraw.c22
-rw-r--r--macosx/tkMacOSXNotify.c84
-rw-r--r--macosx/tkMacOSXWindowEvent.c21
3 files changed, 71 insertions, 56 deletions
diff --git a/macosx/tkMacOSXDraw.c b/macosx/tkMacOSXDraw.c
index 1ec2cfe..6a63449 100644
--- a/macosx/tkMacOSXDraw.c
+++ b/macosx/tkMacOSXDraw.c
@@ -1658,19 +1658,19 @@ TkMacOSXSetupDrawingContext(
} else if (dc.clipRgn) {
/*
- * Drawing can also fail when we are being called from drawRect but
- * the clipping region set by drawRect does not contain the clipping
- * region of our drawing context. See bug [2a61eca3a8].
+ * Drawing will also fail if we are being called from drawRect but
+ * the clipping rectangle set by drawRect does not contain the
+ * clipping region of our drawing context. See bug [2a61eca3a8].
+ * If we can't draw all of the clipping region of the drawing
+ * context then we draw whatever we can, but we also add a dirty
+ * rectangle so the entire widget will get redrawn in the next
+ * cycle.
*/
CGRect currentClip = CGContextGetClipBoundingBox(
[NSGraphicsContext currentContext].CGContext);
if (!NSContainsRect(currentClip, clipBounds)) {
[view addTkDirtyRect:clipBounds];
- // XXXX we should be able to skip drawing but sometimes the clipBounds
- // are wrong.
- //canDraw = false;
- //goto end;
}
}
@@ -1715,10 +1715,10 @@ TkMacOSXSetupDrawingContext(
CGRect r;
if (!HIShapeIsRectangular(dc.clipRgn) || !CGRectContainsRect(
- *HIShapeGetBounds(dc.clipRgn, &r),
- CGRectApplyAffineTransform(clipBounds, t))) {
- ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context);
- CGContextEOClip(dc.context);
+ *HIShapeGetBounds(dc.clipRgn, &r),
+ CGRectApplyAffineTransform(clipBounds, t))) {
+ ChkErr(HIShapeReplacePathInCGContext, dc.clipRgn, dc.context);
+ CGContextEOClip(dc.context);
}
}
if (gc) {
diff --git a/macosx/tkMacOSXNotify.c b/macosx/tkMacOSXNotify.c
index 7de6bec..8bf5e66 100644
--- a/macosx/tkMacOSXNotify.c
+++ b/macosx/tkMacOSXNotify.c
@@ -398,12 +398,24 @@ TkMacOSXDrawAllViews(
*----------------------------------------------------------------------
*/
+#define TICK 100
+static Tcl_TimerToken ticker = NULL;
+
+static void
+Heartbeat(
+ ClientData clientData)
+{
+
+ if (ticker) {
+ ticker = Tcl_CreateTimerHandler(TICK, Heartbeat, NULL);
+ }
+}
+
static void
TkMacOSXEventsSetupProc(
ClientData clientData,
int flags)
{
- static Bool havePeriodicEvents = NO;
NSString *runloopMode = [[NSRunLoop currentRunLoop] currentMode];
/*
@@ -412,6 +424,7 @@ TkMacOSXEventsSetupProc(
if (flags & TCL_WINDOW_EVENTS && !runloopMode) {
static const Tcl_Time zeroBlockTime = { 0, 0 };
+
[NSApp _resetAutoreleasePool];
/*
@@ -427,26 +440,21 @@ TkMacOSXEventsSetupProc(
untilDate:[NSDate distantPast]
inMode:GetRunLoopMode(TkMacOSXGetModalSession())
dequeue:NO];
- if (currentEvent) {
- if (currentEvent.type > 0) {
+ if (currentEvent && currentEvent.type > 0) {
Tcl_SetMaxBlockTime(&zeroBlockTime);
- [NSEvent stopPeriodicEvents];
- havePeriodicEvents = NO;
- }
- } else if (!havePeriodicEvents){
-
- /*
- * When the user is not generating events we schedule a "heartbeat"
- * event to fire every 0.1 seconds. This helps to make the vwait
- * command more responsive when there is no user input, e.g. when
- * running the test suite.
- */
-
- havePeriodicEvents = YES;
- [NSEvent startPeriodicEventsAfterDelay:0.0 withPeriod:0.1];
- }
- while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {};
- TkMacOSXDrawAllViews(NULL);
+ Tcl_DeleteTimerHandler(ticker);
+ ticker = NULL;
+ } else if (ticker == NULL) {
+
+ /*
+ * When the user is not generating events we schedule a "heartbeat"
+ * TimerHandler to fire every 200 milliseconds. The handler does
+ * nothing, but when its timer fires TclWaitForEvent will return,
+ * causing TkMacOSXCheckProc to be called.
+ */
+
+ ticker = Tcl_CreateTimerHandler(TICK, Heartbeat, NULL);
+ }
}
}
@@ -543,28 +551,24 @@ TkMacOSXEventsCheckProc(
*/
[NSApp _unlockAutoreleasePool];
- if (eventsFound == 0) {
- /*
- * We found no events for Tcl in this iteration of the Tcl event
- * loop, so it should proceed to servicing idle tasks. We add an
- * idle task to the end of the idle queue which will redisplay all
- * of our dirty windows. We want this to happen after all other
- * idle tasks have run so that all widgets will be configured
- * before they are displayed. The drawRect method "borrows" the
- * idle queue while drawing views. That is, it sends expose events
- * which cause display procs to be posted as idle tasks and then
- * runs an inner event loop to processes those idle tasks. We are
- * trying to arrange for the idle queue to be empty when it starts
- * that process and empty when it finishes.
- */
+ /*
+ * Add an idle task to the end of the idle queue which will redisplay
+ * all of our dirty windows. We want this to happen after all other
+ * idle tasks have run so that all widgets will be configured before
+ * they are displayed. The drawRect method "borrows" the idle queue
+ * while drawing views. That is, it sends expose events which cause
+ * display procs to be posted as idle tasks and then runs an inner
+ * event loop to processes those idle tasks. We are trying to arrange
+ * for the idle queue to be empty when it starts that process and empty
+ * when it finishes.
+ */
- int dirtyCount = 0;
- TkMacOSXDrawAllViews(&dirtyCount);
- if (dirtyCount > 0) {
- Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL);
- Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL);
- }
+ int dirtyCount = 0;
+ TkMacOSXDrawAllViews(&dirtyCount);
+ if (dirtyCount > 0) {
+ Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL);
+ Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL);
}
}
}
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index 0f58c70..d052005 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -38,6 +38,8 @@ static void DoWindowActivate(ClientData clientData);
#pragma mark TKApplication(TKWindowEvent)
+extern NSString *NSWindowDidOrderOnScreenNotification;
+
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
extern NSString *NSWindowWillOrderOnScreenNotification;
extern NSString *NSWindowDidOrderOnScreenNotification;
@@ -208,6 +210,18 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
return (winPtr ? NO : YES);
}
+- (void) windowBecameVisible: (NSNotification *) notification
+{
+ NSWindow *window = [notification object];
+ TkWindow *winPtr = TkMacOSXGetTkWindow(window);
+ if (winPtr) {
+ TKContentView *view = [window contentView];
+ while(Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {};
+ [view setTkDirtyRect:[view bounds]];
+ TkMacOSXDrawAllViews(NULL);
+ }
+}
+
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
- (void) windowDragStart: (NSNotification *) notification
@@ -227,16 +241,12 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
NSWindow *w = [notification object];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
+ printf("windowMapped\n");
if (winPtr) {
//Tk_MapWindow((Tk_Window) winPtr);
}
}
-- (void) windowBecameVisible: (NSNotification *) notification
-{
- TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
-}
-
- (void) windowUnmapped: (NSNotification *) notification
{
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
@@ -263,6 +273,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
observe(NSWindowDidResizeNotification, windowBoundsChanged:);
observe(NSWindowDidDeminiaturizeNotification, windowExpanded:);
observe(NSWindowDidMiniaturizeNotification, windowCollapsed:);
+ observe(NSWindowDidOrderOnScreenNotification, windowBecameVisible:);
#if !(MAC_OS_X_VERSION_MAX_ALLOWED < 1070)
observe(NSWindowDidEnterFullScreenNotification, windowEnteredFullScreen:);