mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
devdraw: MacBook retina support
Enable with export devdrawretina=1 (everything will be smaller). R=rsc CC=plan9port.codebot http://codereview.appspot.com/6592072
This commit is contained in:
parent
60a47420a8
commit
ef99c9f1ae
2 changed files with 128 additions and 8 deletions
|
@ -10,6 +10,13 @@ invoked via
|
||||||
.I Devdraw
|
.I Devdraw
|
||||||
serves a custom graphics protocol and is the only program
|
serves a custom graphics protocol and is the only program
|
||||||
that talks directly to X window servers.
|
that talks directly to X window servers.
|
||||||
|
On Macintosh, setting
|
||||||
|
.BI devdrawretina
|
||||||
|
to
|
||||||
|
.BI 1
|
||||||
|
will cause
|
||||||
|
.I devdraw
|
||||||
|
to use all available physical pixels on a retina display.
|
||||||
.SH SOURCE
|
.SH SOURCE
|
||||||
.B \*9/src/cmd/devdraw
|
.B \*9/src/cmd/devdraw
|
||||||
.SH "SEE ALSO
|
.SH "SEE ALSO
|
||||||
|
|
|
@ -38,6 +38,12 @@ int useliveresizing = 0;
|
||||||
int useoldfullscreen = 0;
|
int useoldfullscreen = 0;
|
||||||
int usebigarrow = 0;
|
int usebigarrow = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* By default, devdraw ignores retina displays. A non-zero evironment variable
|
||||||
|
* |devdrawretina| will override this.
|
||||||
|
*/
|
||||||
|
int devdrawretina = 0;
|
||||||
|
|
||||||
void
|
void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +56,8 @@ usage(void)
|
||||||
void
|
void
|
||||||
threadmain(int argc, char **argv)
|
threadmain(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
char *envvar;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Move the protocol off stdin/stdout so that
|
* Move the protocol off stdin/stdout so that
|
||||||
* any inadvertent prints don't screw things up.
|
* any inadvertent prints don't screw things up.
|
||||||
|
@ -77,6 +85,9 @@ threadmain(int argc, char **argv)
|
||||||
usage();
|
usage();
|
||||||
}ARGEND
|
}ARGEND
|
||||||
|
|
||||||
|
if (envvar = getenv("devdrawretina"))
|
||||||
|
devdrawretina = atoi(envvar) > 0;
|
||||||
|
|
||||||
if(OSX_VERSION < 100700)
|
if(OSX_VERSION < 100700)
|
||||||
[NSAutoreleasePool new];
|
[NSAutoreleasePool new];
|
||||||
|
|
||||||
|
@ -99,6 +110,8 @@ struct
|
||||||
int needimg;
|
int needimg;
|
||||||
int deferflush;
|
int deferflush;
|
||||||
NSCursor *cursor;
|
NSCursor *cursor;
|
||||||
|
CGFloat topointscale;
|
||||||
|
CGFloat topixelscale;
|
||||||
} win;
|
} win;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
|
@ -127,6 +140,12 @@ static void acceptresizing(int);
|
||||||
|
|
||||||
static NSCursor* makecursor(Cursor*);
|
static NSCursor* makecursor(Cursor*);
|
||||||
|
|
||||||
|
static NSSize winsizepixels();
|
||||||
|
static NSSize winsizepoints();
|
||||||
|
static NSRect scalerect(NSRect, CGFloat);
|
||||||
|
static NSPoint scalepoint(NSPoint, CGFloat);
|
||||||
|
static NSRect dilate(NSRect);
|
||||||
|
|
||||||
@implementation appdelegate
|
@implementation appdelegate
|
||||||
- (void)applicationDidFinishLaunching:(id)arg
|
- (void)applicationDidFinishLaunching:(id)arg
|
||||||
{
|
{
|
||||||
|
@ -349,10 +368,10 @@ static Memimage*
|
||||||
initimg(void)
|
initimg(void)
|
||||||
{
|
{
|
||||||
Memimage *i;
|
Memimage *i;
|
||||||
NSSize size;
|
NSSize size, ptsize;
|
||||||
Rectangle r;
|
Rectangle r;
|
||||||
|
|
||||||
size = [win.content bounds].size;
|
size = winsizepixels();
|
||||||
LOG(@"initimg %.0f %.0f", size.width, size.height);
|
LOG(@"initimg %.0f %.0f", size.width, size.height);
|
||||||
|
|
||||||
r = Rect(0, 0, size.width, size.height);
|
r = Rect(0, 0, size.width, size.height);
|
||||||
|
@ -373,6 +392,10 @@ initimg(void)
|
||||||
colorSpaceName:NSDeviceRGBColorSpace
|
colorSpaceName:NSDeviceRGBColorSpace
|
||||||
bytesPerRow:bytesperline(r, 32)
|
bytesPerRow:bytesperline(r, 32)
|
||||||
bitsPerPixel:32];
|
bitsPerPixel:32];
|
||||||
|
ptsize = winsizepoints();
|
||||||
|
[win.img setSize: ptsize];
|
||||||
|
win.topixelscale = size.width / ptsize.width;
|
||||||
|
win.topointscale = 1.0f / win.topixelscale;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,6 +475,9 @@ enum
|
||||||
Handlesize = 3*Barsize + 1*Pixel,
|
Handlesize = 3*Barsize + 1*Pixel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* |rect| is in pixel coordinates.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
flushimg(NSRect rect)
|
flushimg(NSRect rect)
|
||||||
{
|
{
|
||||||
|
@ -461,7 +487,7 @@ flushimg(NSRect rect)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(win.needimg){
|
if(win.needimg){
|
||||||
if(!NSEqualSizes(rect.size, [win.img size])){
|
if(!NSEqualSizes(scalerect(rect, win.topointscale).size, [win.img size])){
|
||||||
LOG(@"flushimg reject %.0f %.0f",
|
LOG(@"flushimg reject %.0f %.0f",
|
||||||
rect.size.width, rect.size.height);
|
rect.size.width, rect.size.height);
|
||||||
[win.content unlockFocus];
|
[win.content unlockFocus];
|
||||||
|
@ -482,8 +508,12 @@ flushimg(NSRect rect)
|
||||||
* Acme.
|
* Acme.
|
||||||
*/
|
*/
|
||||||
r = [win.content bounds];
|
r = [win.content bounds];
|
||||||
|
rect = dilate(scalerect(rect, win.topointscale));
|
||||||
r.size.height -= Cornersize;
|
r.size.height -= Cornersize;
|
||||||
dr = NSIntersectionRect(r, rect);
|
dr = NSIntersectionRect(r, rect);
|
||||||
|
LOG(@"r %.0f %.0f", r.origin.x, r.origin.y, rect.size.width, rect.size.height);
|
||||||
|
LOG(@"rect in points %f %f %.0f %.0f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
||||||
|
LOG(@"dr in points %f %f %.0f %.0f", dr.origin.x, dr.origin.y, dr.size.width, dr.size.height);
|
||||||
drawimg(dr, NSCompositeCopy);
|
drawimg(dr, NSCompositeCopy);
|
||||||
|
|
||||||
r.origin.y = r.size.height;
|
r.origin.y = r.size.height;
|
||||||
|
@ -545,6 +575,9 @@ flushwin(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* |dr| is sized in points. What if I make it pixels?
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
drawimg(NSRect dr, uint op)
|
drawimg(NSRect dr, uint op)
|
||||||
{
|
{
|
||||||
|
@ -556,7 +589,14 @@ drawimg(NSRect dr, uint op)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sr = [win.content convertRect:dr fromView:nil];
|
sr = [win.content convertRect:dr fromView:nil];
|
||||||
|
LOG(@"before dr: %f %f %f %f\n", dr.origin.x, dr.origin.y, dr.size.width, dr.size.height);
|
||||||
|
LOG(@"before sr: %f %f %f %f\n", sr.origin.x, sr.origin.y, sr.size.width, sr.size.height);
|
||||||
|
|
||||||
|
dr = scalerect(dr, win.topixelscale);
|
||||||
|
sr = scalerect(sr, win.topixelscale);
|
||||||
|
|
||||||
|
LOG(@"dr: %f %f %f %f\n", dr.origin.x, dr.origin.y, dr.size.width, dr.size.height);
|
||||||
|
LOG(@"sr: %f %f %f %f\n", sr.origin.x, sr.origin.y, sr.size.width, sr.size.height);
|
||||||
if(OSX_VERSION >= 100800){
|
if(OSX_VERSION >= 100800){
|
||||||
i = CGImageCreateWithImageInRect([win.img CGImage], NSRectToCGRect(dr));
|
i = CGImageCreateWithImageInRect([win.img CGImage], NSRectToCGRect(dr));
|
||||||
c = [[WIN graphicsContext] graphicsPort];
|
c = [[WIN graphicsContext] graphicsPort];
|
||||||
|
@ -564,8 +604,9 @@ drawimg(NSRect dr, uint op)
|
||||||
CGContextSaveGState(c);
|
CGContextSaveGState(c);
|
||||||
if(op == NSCompositeSourceIn)
|
if(op == NSCompositeSourceIn)
|
||||||
CGContextSetBlendMode(c, kCGBlendModeSourceIn);
|
CGContextSetBlendMode(c, kCGBlendModeSourceIn);
|
||||||
|
LOG(@"wim.img size %f %f\n", [win.img size].width, [win.img size].height);
|
||||||
CGContextTranslateCTM(c, 0, [win.img size].height);
|
CGContextTranslateCTM(c, 0, [win.img size].height);
|
||||||
CGContextScaleCTM(c, 1, -1);
|
CGContextScaleCTM(c, win.topointscale, -win.topointscale);
|
||||||
CGContextDrawImage(c, NSRectToCGRect(sr), i);
|
CGContextDrawImage(c, NSRectToCGRect(sr), i);
|
||||||
CGContextRestoreGState(c);
|
CGContextRestoreGState(c);
|
||||||
|
|
||||||
|
@ -871,6 +912,10 @@ getmousepos(void)
|
||||||
|
|
||||||
p = [WIN mouseLocationOutsideOfEventStream];
|
p = [WIN mouseLocationOutsideOfEventStream];
|
||||||
q = [win.content convertPoint:p fromView:nil];
|
q = [win.content convertPoint:p fromView:nil];
|
||||||
|
|
||||||
|
/* q is in point coordinates. in.mpos is in pixels. */
|
||||||
|
q = scalepoint(q, win.topixelscale);
|
||||||
|
|
||||||
in.mpos.x = round(q.x);
|
in.mpos.x = round(q.x);
|
||||||
in.mpos.y = round(q.y);
|
in.mpos.y = round(q.y);
|
||||||
|
|
||||||
|
@ -1023,7 +1068,7 @@ sendmouse(void)
|
||||||
NSSize size;
|
NSSize size;
|
||||||
int b;
|
int b;
|
||||||
|
|
||||||
size = [win.content bounds].size;
|
size = winsizepixels();
|
||||||
mouserect = Rect(0, 0, size.width, size.height);
|
mouserect = Rect(0, 0, size.width, size.height);
|
||||||
|
|
||||||
b = in.kbuttons | in.mbuttons | in.mscroll;
|
b = in.kbuttons | in.mbuttons | in.mscroll;
|
||||||
|
@ -1031,6 +1076,9 @@ sendmouse(void)
|
||||||
in.mscroll = 0;
|
in.mscroll = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* |p| is in pixels.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
setmouse(Point p)
|
setmouse(Point p)
|
||||||
{
|
{
|
||||||
|
@ -1049,7 +1097,7 @@ setmouse(Point p)
|
||||||
if([WIN inLiveResize])
|
if([WIN inLiveResize])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
in.mpos = NSMakePoint(p.x, p.y); // race condition
|
in.mpos = scalepoint(NSMakePoint(p.x, p.y), win.topointscale); // race condition
|
||||||
|
|
||||||
q = [win.content convertPoint:in.mpos toView:nil];
|
q = [win.content convertPoint:in.mpos toView:nil];
|
||||||
q = [WIN convertBaseToScreen:q];
|
q = [WIN convertBaseToScreen:q];
|
||||||
|
@ -1060,19 +1108,31 @@ setmouse(Point p)
|
||||||
CGWarpMouseCursorPosition(NSPointToCGPoint(q));
|
CGWarpMouseCursorPosition(NSPointToCGPoint(q));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* |r| is in points.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
followzoombutton(NSRect r)
|
followzoombutton(NSRect r)
|
||||||
{
|
{
|
||||||
NSRect wr;
|
NSRect wr;
|
||||||
Point p;
|
Point p;
|
||||||
|
NSPoint pt;
|
||||||
|
|
||||||
wr = [WIN frame];
|
wr = [WIN frame];
|
||||||
wr.origin.y += wr.size.height;
|
wr.origin.y += wr.size.height;
|
||||||
r.origin.y += r.size.height;
|
r.origin.y += r.size.height;
|
||||||
|
|
||||||
getmousepos();
|
getmousepos();
|
||||||
p.x = (r.origin.x - wr.origin.x) + in.mpos.x;
|
pt.x = in.mpos.x;
|
||||||
p.y = -(r.origin.y - wr.origin.y) + in.mpos.y;
|
pt.y = in.mpos.y;
|
||||||
|
pt = scalepoint(pt, win.topointscale);
|
||||||
|
pt.x = (r.origin.x - wr.origin.x) + pt.x;
|
||||||
|
pt.y = -(r.origin.y - wr.origin.y) + pt.y;
|
||||||
|
pt = scalepoint(pt, win.topixelscale);
|
||||||
|
|
||||||
|
p.x = pt.x;
|
||||||
|
p.y = pt.y;
|
||||||
|
|
||||||
setmouse(p);
|
setmouse(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1181,6 +1241,7 @@ makemenu(void)
|
||||||
[m release];
|
[m release];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Introduce a high-resolution Glenda image.
|
||||||
static void
|
static void
|
||||||
makeicon(void)
|
makeicon(void)
|
||||||
{
|
{
|
||||||
|
@ -1285,6 +1346,9 @@ setcursor0(Cursor *c)
|
||||||
[d release];
|
[d release];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cursors will be scaled on retina display.
|
||||||
|
*/
|
||||||
static NSCursor*
|
static NSCursor*
|
||||||
makecursor(Cursor *c)
|
makecursor(Cursor *c)
|
||||||
{
|
{
|
||||||
|
@ -1334,3 +1398,52 @@ topwin(void)
|
||||||
in.willactivate = 1;
|
in.willactivate = 1;
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NSSize
|
||||||
|
winsizepoints()
|
||||||
|
{
|
||||||
|
return [win.content bounds].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSSize
|
||||||
|
winsizepixels()
|
||||||
|
{
|
||||||
|
if (OSX_VERSION >= 100700 && devdrawretina)
|
||||||
|
return [win.content convertSizeToBacking: winsizepoints()];
|
||||||
|
else
|
||||||
|
return winsizepoints();
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSRect
|
||||||
|
scalerect(NSRect r, CGFloat scale)
|
||||||
|
{
|
||||||
|
r.origin.x *= scale;
|
||||||
|
r.origin.y *= scale;
|
||||||
|
r.size.width *= scale;
|
||||||
|
r.size.height *= scale;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expands rectangle |r|'s bounds to more inclusive integer bounds to
|
||||||
|
* eliminate 1 pixel gaps.
|
||||||
|
*/
|
||||||
|
static NSRect
|
||||||
|
dilate(NSRect r)
|
||||||
|
{
|
||||||
|
if(win.topixelscale > 1.0f){
|
||||||
|
r.origin.x = floorf(r.origin.x);
|
||||||
|
r.origin.y = floorf(r.origin.y);
|
||||||
|
r.size.width = ceilf(r.size.width + 0.5);
|
||||||
|
r.size.height = ceilf(r.size.height + 0.5);
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSPoint
|
||||||
|
scalepoint(NSPoint pt, CGFloat scale)
|
||||||
|
{
|
||||||
|
pt.x *= scale;
|
||||||
|
pt.y *= scale;
|
||||||
|
return pt;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue