aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/devdraw/cocoa-screen.m300
1 files changed, 226 insertions, 74 deletions
diff --git a/src/cmd/devdraw/cocoa-screen.m b/src/cmd/devdraw/cocoa-screen.m
index 3f2bcb8b..9cc0e134 100644
--- a/src/cmd/devdraw/cocoa-screen.m
+++ b/src/cmd/devdraw/cocoa-screen.m
@@ -1,5 +1,8 @@
/*
* Cocoa's event loop must be in main thread.
+ *
+ * Unless otherwise stated, all coordinate systems
+ * are bottom-left-based.
*/
#define Cursor OSXCursor
@@ -27,9 +30,11 @@
AUTOFRAMEWORK(Cocoa)
-#define panic sysfatal
+#define LOG if(0)NSLog
+#define panic sysfatal
int usegestures = 0;
+int useliveresizing = 0;
int useoldfullscreen = 0;
int usebigarrow = 0;
@@ -91,7 +96,8 @@ struct
int isnfs;
NSView *content;
NSBitmapImageRep *img;
- int needflush;
+ int needimg;
+ int deferflush;
NSCursor *cursor;
} win;
@@ -106,7 +112,8 @@ struct
} in;
static void hidebars(int);
-static void drawimg(NSRect);
+static void flushimg(NSRect);
+static void autoflushwin(int);
static void flushwin(void);
static void followzoombutton(NSRect);
static void getmousepos(void);
@@ -140,9 +147,15 @@ static NSCursor* makecursor(Cursor*);
getmousepos();
sendmouse();
}
+- (void)windowWillStartLiveResize:(id)arg
+{
+ if(useliveresizing == 0)
+ [win.content setHidden:YES];
+}
- (void)windowDidEndLiveResize:(id)arg
{
- [win.content display];
+ if(useliveresizing == 0)
+ [win.content setHidden:NO];
}
- (void)windowDidChangeScreen:(id)arg
{
@@ -174,6 +187,10 @@ static NSCursor* makecursor(Cursor*);
hidebars(0);
}
}
+- (void)windowWillClose:(id)arg
+{
+ autoflushwin(0); /* can crash otherwise */
+}
+ (void)callservep9p:(id)arg
{
@@ -189,7 +206,7 @@ static NSCursor* makecursor(Cursor*);
+ (void)callflushwin:(id)arg{ flushwin();}
- (void)calltogglefs:(id)arg{ togglefs();}
-+ (void)calldrawimg:(NSValue*)v{ drawimg([v rectValue]);}
++ (void)callflushimg:(NSValue*)v{ flushimg([v rectValue]);}
+ (void)callmakewin:(NSValue*)v{ makewin([v pointerValue]);}
+ (void)callsetcursor0:(NSValue*)v{ setcursor0([v pointerValue]);}
@end
@@ -208,6 +225,8 @@ attachscreen(char *label, char *winsize)
if(label == nil)
label = "gnot a label";
+ if(strcmp(label, "page") == 0)
+ useliveresizing = 1;
/*
* Create window in main thread, else no cursor
@@ -235,6 +254,28 @@ attachscreen(char *label, char *winsize)
{
return YES; /* else no keyboard for old fullscreen */
}
+- (void)makeKeyAndOrderFront:(id)arg
+{
+ LOG(@"makeKeyAndOrderFront");
+
+ autoflushwin(1);
+ [win.content setHidden:NO];
+ [super makeKeyAndOrderFront:arg];
+}
+- (void)miniaturize:(id)arg
+{
+ [super miniaturize:arg];
+ [NSApp hide:nil];
+
+ [win.content setHidden:YES];
+ autoflushwin(0);
+}
+- (void)deminiaturize:(id)arg
+{
+ autoflushwin(1);
+ [win.content setHidden:NO];
+ [super deminiaturize:arg];
+}
@end
double
@@ -302,7 +343,6 @@ makewin(char *s)
win.isofs = 0;
win.content = [contentview new];
[WIN setContentView:win.content];
- [WIN makeKeyAndOrderFront:nil];
}
static Memimage*
@@ -313,6 +353,7 @@ initimg(void)
Rectangle r;
size = [win.content bounds].size;
+ LOG(@"initimg %.0f %.0f", size.width, size.height);
r = Rect(0, 0, size.width, size.height);
i = allocmemimage(r, XBGR32);
@@ -332,102 +373,204 @@ initimg(void)
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:bytesperline(r, 32)
bitsPerPixel:32];
-
return i;
}
+static void
+resizeimg()
+{
+ [win.img release];
+ _drawreplacescreenimage(initimg());
+
+ mouseresized = 1;
+ sendmouse();
+}
+
+static void
+waitimg(int msec)
+{
+ NSDate *limit;
+ int n;
+
+ win.needimg = 1;
+ win.deferflush = 0;
+
+ n = 0;
+ limit = [NSDate dateWithTimeIntervalSinceNow:msec/1000.0];
+ do{
+ [[NSRunLoop currentRunLoop]
+ runMode:@"waiting image"
+ beforeDate:limit];
+ n++;
+ }while(win.needimg && [(NSDate*)[NSDate date] compare:limit]<0);
+
+ win.deferflush = win.needimg;
+
+ LOG(@"waitimg %s (%d loop)", win.needimg?"defer":"ok", n);
+}
+
void
_flushmemscreen(Rectangle r)
{
+ static int n;
NSRect rect;
- rect = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r));
+ LOG(@"_flushmemscreen");
+
+ if(n==0){
+ n++;
+ return; /* to skip useless white init rect */
+ }else
+ if(n==1){
+ [WIN performSelectorOnMainThread:
+ @selector(makeKeyAndOrderFront:)
+ withObject:nil
+ waitUntilDone:NO];
+ n++;
+ }else
+ if([win.content canDraw] == 0)
+ return;
- /*
- * Call "lockFocusIfCanDraw" from main thread, else
- * we deadlock while synchronizing both threads with
- * qlock(): main thread must apparently be idle while
- * we call it. (This is also why Devdraw shows
- * occasionally an empty window: I found no
- * satisfactory way to wait for P9P's image.)
- */
+ rect = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r));
[appdelegate
- performSelectorOnMainThread:@selector(calldrawimg:)
+ performSelectorOnMainThread:@selector(callflushimg:)
withObject:[NSValue valueWithRect:rect]
- waitUntilDone:YES];
+ waitUntilDone:YES
+ modes:[NSArray arrayWithObjects:
+ NSRunLoopCommonModes,
+ @"waiting image", nil]];
}
-static void drawresizehandle(NSRect);
+static void drawimg(NSRect, uint);
+static void drawresizehandle(void);
+
+enum
+{
+ Pixel = 1,
+ Barsize = 4*Pixel,
+ Cornersize = 3*Pixel,
+ Handlesize = 3*Barsize + 1*Pixel,
+};
static void
-drawimg(NSRect dr)
+flushimg(NSRect rect)
{
- static int first = 1;
- NSRect sr;
+ NSRect dr, r;
- if(first){
- [NSTimer scheduledTimerWithTimeInterval:0.033
- target:[appdelegate class]
- selector:@selector(callflushwin:) userInfo:nil
- repeats:YES];
- first = 0;
+ if([win.content lockFocusIfCanDraw] == 0)
+ return;
+
+ if(win.needimg){
+ if(!NSEqualSizes(rect.size, [win.img size])){
+ LOG(@"flushimg reject %.0f %.0f",
+ rect.size.width, rect.size.height);
+ [win.content unlockFocus];
+ return;
+ }
+ win.needimg = 0;
+ }else
+ win.deferflush = 1;
+
+ LOG(@"flushimg ok %.0f %.0f", rect.size.width, rect.size.height);
+
+ /*
+ * Unless we are inside "drawRect", we have to round
+ * the corners ourselves, if this is the custom.
+ * "NSCompositeSourceIn" can do that, but we don't
+ * apply it to the whole rectangle, because this
+ * slows down trackpad scrolling considerably in
+ * Acme.
+ */
+ r = [win.content bounds];
+ r.size.height -= Cornersize;
+ dr = NSIntersectionRect(r, rect);
+ drawimg(dr, NSCompositeCopy);
+
+ r.origin.y = r.size.height;
+ r.size = NSMakeSize(Cornersize, Cornersize);
+ dr = NSIntersectionRect(r, rect);
+ drawimg(dr, NSCompositeSourceIn);
+
+ r.origin.x = [win.img size].width - Cornersize;
+ dr = NSIntersectionRect(r, rect);
+ drawimg(dr, NSCompositeSourceIn);
+
+ r.size.width = r.origin.x - Cornersize;
+ r.origin.x -= r.size.width;
+ dr = NSIntersectionRect(r, rect);
+ drawimg(dr, NSCompositeCopy);
+
+ if(OSX_VERSION<100700 && win.isofs==0){
+ r.origin.x = [win.img size].width - Handlesize;
+ r.origin.y = [win.img size].height - Handlesize;
+ r.size = NSMakeSize(Handlesize, Handlesize);
+ if(NSIntersectsRect(r, rect))
+ drawresizehandle();
}
- sr = [win.content convertRect:dr fromView:nil];
+ [win.content unlockFocus];
+}
- if([win.content lockFocusIfCanDraw]){
+static void
+autoflushwin(int set)
+{
+ static NSTimer *t;
+ if(set){
+ if(t)
+ return;
/*
- * To round the window's bottom corners, we can use
- * "NSCompositeSourceIn", but this slows down
- * trackpad scrolling considerably in Acme. Else we
- * can use "bezierPathWithRoundedRect" with "addClip",
- * but it's still too slow for wide Acme windows.
+ * We need "NSRunLoopCommonModes", otherwise the
+ * timer will not fire during live resizing.
*/
- [win.img drawInRect:dr fromRect:sr
-// operation:NSCompositeSourceIn fraction:1
- operation:NSCompositeCopy fraction:1
- respectFlipped:YES hints:nil];
-
- if(OSX_VERSION<100700 && win.isofs==0)
- drawresizehandle(dr);
-
- [win.content unlockFocus];
- win.needflush = 1;
+ t = [NSTimer
+ timerWithTimeInterval:0.033
+ target:[appdelegate class]
+ selector:@selector(callflushwin:) userInfo:nil
+ repeats:YES];
+ [[NSRunLoop currentRunLoop] addTimer:t
+ forMode:NSRunLoopCommonModes];
+ }else{
+ [t invalidate];
+ t = nil;
+ win.deferflush = 0;
}
}
static void
flushwin(void)
{
- if(win.needflush){
+ if(win.deferflush && win.needimg==0){
[WIN flushWindow];
- win.needflush = 0;
+ win.deferflush = 0;
}
}
-enum
+static void
+drawimg(NSRect dr, uint op)
{
- Pixel = 1,
- Barsize = 4*Pixel,
- Handlesize = 3*Barsize + 1*Pixel,
-};
+ NSRect sr;
+
+ if(NSIsEmptyRect(dr))
+ return;
+
+ sr = [win.content convertRect:dr fromView:nil];
+
+ [win.img drawInRect:dr fromRect:sr
+ operation:op fraction:1
+ respectFlipped:YES hints:nil];
+
+// NSFrameRect(dr);
+}
static void
-drawresizehandle(NSRect dr)
+drawresizehandle(void)
{
NSColor *color[Barsize];
NSPoint a,b;
- NSRect r;
- NSSize size;
Point c;
int i,j;
- size = [win.img size];
- c = Pt(size.width, size.height);
- r = NSMakeRect(0, 0, Handlesize, Handlesize);
- r.origin = NSMakePoint(c.x-Handlesize, c.y-Handlesize);
- if(NSIntersectsRect(r,dr) == 0)
- return;
+ c = Pt([win.img size].width, [win.img size].height);
[[WIN graphicsContext] setShouldAntialias:NO];
@@ -446,15 +589,6 @@ drawresizehandle(NSRect dr)
}
}
-static void
-resizeimg()
-{
- [win.img release];
- _drawreplacescreenimage(initimg());
- mouseresized = 1;
- sendmouse();
-}
-
static void getgesture(NSEvent*);
static void getkeyboard(NSEvent*);
static void getmouse(NSEvent*);
@@ -462,20 +596,28 @@ static void gettouch(NSEvent*, int);
static void updatecursor(void);
@implementation contentview
-
+/*
+ * "drawRect" is called each time Cocoa needs an
+ * image, and each time we call "display". It is
+ * preceded by background painting, and followed by
+ * "flushWindow".
+ */
- (void)drawRect:(NSRect)r
{
static int first = 1;
- if([WIN inLiveResize])
- return;
+ LOG(@"drawrect %.0f %.0f %.0f %.0f",
+ r.origin.x, r.origin.y, r.size.width, r.size.height);
if(first)
first = 0;
else
resizeimg();
- /* We should wait for P9P's image here. */
+ if([WIN inLiveResize])
+ waitimg(100);
+ else
+ waitimg(500);
}
- (BOOL)isFlipped
{
@@ -489,8 +631,15 @@ static void updatecursor(void);
{
[super initWithFrame:r];
[self setAcceptsTouchEvents:YES];
+ [self setHidden:YES]; /* to avoid early "drawRect" call */
return self;
}
+- (void)setHidden:(BOOL)set
+{
+ if(!set)
+ [WIN makeFirstResponder:self]; /* for keyboard focus */
+ [super setHidden:set];
+}
- (void)cursorUpdate:(NSEvent*)e{ updatecursor();}
- (void)mouseMoved:(NSEvent*)e{ getmouse(e);}
@@ -881,6 +1030,9 @@ setmouse(Point p)
CGSetLocalEventsSuppressionInterval(0);
first = 0;
}
+ if([WIN inLiveResize])
+ return;
+
in.mpos = NSMakePoint(p.x, p.y); // race condition
r = [[WIN screen] frame];