devdraw: draft of new Cocoa-based devdraw

Can test with
	cd $PLAN9/src/cmd/devdraw
	mk devdraw-cocoa
	DEVDRAW=devdraw-cocoa colors
This commit is contained in:
Jeff Sickel 2009-09-29 09:35:23 -07:00
parent daea2c7d50
commit 113867b836
5 changed files with 1439 additions and 1 deletions

View file

@ -7,7 +7,7 @@ WSYSOFILES=\
latin1.$O\
mouseswap.$O\
winsize.$O\
<|sh ./mkwsysrules.sh
OFILES=$WSYSOFILES
@ -32,3 +32,12 @@ latin1.h: $PLAN9/lib/keyboard $O.mklatinkbd
./$O.mklatinkbd -r $PLAN9/lib/keyboard | sed 's/, }/ }/' >$target
CLEANFILES=latin1.h $O.mklatinkbd
# Still in progress: Cocoa/Objective C version of devdraw
%-objc.$O: %.m
$CC $CFLAGS -o $target $stem.m
devdraw-cocoa: devdraw.o latin1.o mouseswap.o winsize.o osx-screen-objc.o osx-draw.o osx-srv-objc.o osx-delegate-objc.o
$LD -o $target $prereq

View file

@ -0,0 +1,15 @@
#import <Foundation/NSObject.h>
#import <AppKit/NSMenu.h>
@class NSFileHandle;
@interface DevdrawDelegate : NSObject
{
NSFileHandle *readHandle;
}
+(void)populateMainMenu;
+(void)populateApplicationMenu:(NSMenu *)aMenu;
+(void)populateViewMenu:(NSMenu *)aMenu;
+(void)populateWindowMenu:(NSMenu *)aMenu;
+(void)populateHelpMenu:(NSMenu *)aMenu;
@end

View file

@ -0,0 +1,282 @@
#define Point OSXPoint
#define Rect OSXRect
#define Cursor OSXCursor
#import "osx-delegate.h"
#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#undef Cursor
#undef Rect
#undef Point
#include <u.h>
#include <errno.h>
#include <sys/select.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
#include <keyboard.h>
#include <mouse.h>
#include <cursor.h>
#include <drawfcall.h>
AUTOFRAMEWORK(Foundation)
AUTOFRAMEWORK(AppKit)
extern int trace;
extern void fullscreen(int);
extern void kbdevent(NSEvent *event);
extern void mouseevent(NSEvent *event);
extern void eresized(int);
extern void runmsg(Wsysmsg *m);
extern void seticon();
@implementation DevdrawDelegate
+(void)populateMainMenu
{
NSMenu *mainMenu = [[NSMenu alloc] initWithTitle:@"MainMenu"];
NSMenuItem *menuItem;
NSMenu *submenu;
menuItem = [mainMenu addItemWithTitle:@"Apple" action:NULL keyEquivalent:@""];
submenu = [[NSMenu alloc] initWithTitle:@"Apple"];
[NSApp performSelector:@selector(setAppleMenu:) withObject:submenu];
[self populateApplicationMenu:submenu];
[mainMenu setSubmenu:submenu forItem:menuItem];
menuItem = [mainMenu addItemWithTitle:@"View" action:NULL keyEquivalent:@""];
submenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"View", "@The View menu")];
[self populateViewMenu:submenu];
[mainMenu setSubmenu:submenu forItem:menuItem];
menuItem = [mainMenu addItemWithTitle:@"Window" action:NULL keyEquivalent:@""];
submenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Window", @"The Window menu")];
[self populateWindowMenu:submenu];
[mainMenu setSubmenu:submenu forItem:menuItem];
[NSApp setWindowsMenu:submenu];
menuItem = [mainMenu addItemWithTitle:@"Help" action:NULL keyEquivalent:@""];
submenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Help", @"The Help menu")];
[self populateHelpMenu:submenu];
[mainMenu setSubmenu:submenu forItem:menuItem];
[NSApp setMainMenu:mainMenu];
}
+(void)populateApplicationMenu:(NSMenu *)aMenu
{
NSString *applicationName = [[NSProcessInfo processInfo] processName];
NSMenuItem *menuItem;
menuItem = [aMenu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"About", nil), applicationName]
action:@selector(orderFrontStandardAboutPanel:)
keyEquivalent:@""];
[menuItem setTarget:NSApp];
[aMenu addItem:[NSMenuItem separatorItem]];
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Preferences...", nil)
action:NULL
keyEquivalent:@","];
[aMenu addItem:[NSMenuItem separatorItem]];
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Services", nil)
action:NULL
keyEquivalent:@""];
NSMenu * servicesMenu = [[NSMenu alloc] initWithTitle:@"Services"];
[aMenu setSubmenu:servicesMenu forItem:menuItem];
[NSApp setServicesMenu:servicesMenu];
[aMenu addItem:[NSMenuItem separatorItem]];
menuItem = [aMenu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Hide", nil), applicationName]
action:@selector(hide:)
keyEquivalent:@"h"];
[menuItem setTarget:NSApp];
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Hide Others", nil)
action:@selector(hideOtherApplications:)
keyEquivalent:@"h"];
[menuItem setKeyEquivalentModifierMask:NSCommandKeyMask | NSAlternateKeyMask];
[menuItem setTarget:NSApp];
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Show All", nil)
action:@selector(unhideAllApplications:)
keyEquivalent:@""];
[menuItem setTarget:NSApp];
[aMenu addItem:[NSMenuItem separatorItem]];
menuItem = [aMenu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Quit", nil), applicationName]
action:@selector(terminate:)
keyEquivalent:@"q"];
[menuItem setTarget:NSApp];
}
+(void)populateViewMenu:(NSMenu *)aMenu
{
NSMenuItem *menuItem;
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Full Screen", nil)
action:@selector(fullscreen:) keyEquivalent:@"F"];
[menuItem setTarget:NSApp];
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Cmd-F exits full screen", nil)
action:NULL keyEquivalent:@""];
}
+(void)populateWindowMenu:(NSMenu *)aMenu
{
}
+(void)populateHelpMenu:(NSMenu *)aMenu
{
}
- (void)applicationWillFinishLaunching:(NSNotification *)notification
{
seticon();
}
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
[DevdrawDelegate populateMainMenu];
// [NSThread detachNewThreadSelector:@selector(devdrawMain)
// toTarget:self withObject:nil];
// [NSApplication detachDrawingThread:@selector(devdrawMain)
// toTarget:self withObject:nil];
[readHandle waitForDataInBackgroundAndNotify];
}
- (id)init
{
if(self = [super init]){
readHandle = [[NSFileHandle alloc] initWithFileDescriptor:3 closeOnDealloc:YES];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(devdrawMain:)
name:NSFileHandleDataAvailableNotification
object:readHandle];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
selector:@selector(receiveWake:)
name:NSWorkspaceDidWakeNotification
object:NULL];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[readHandle release];
return [super dealloc];
}
- (void)devdrawMain:(NSNotification *)notification
{
uchar buf[4], *mbuf;
int nmbuf, n, nn;
Wsysmsg m;
NSData *data;
mbuf = nil;
nmbuf = 0;
data = [readHandle readDataOfLength:4];
if([data length] == 4){
[data getBytes:buf length:4];
GET(buf, n);
if(n > nmbuf){
free(mbuf);
mbuf = malloc(4+n);
if(mbuf == nil)
sysfatal("malloc: %r");
nmbuf = n;
}
memmove(mbuf, buf, 4);
data = [readHandle readDataOfLength:(n-4)];
[data getBytes:(mbuf+4)];
nn = [data length];
if(nn != n-4)
sysfatal("eof during message");
/* pick off messages one by one */
if(convM2W(mbuf, nn+4, &m) <= 0)
sysfatal("cannot convert message");
if(trace) fprint(2, "<- %W\n", &m);
runmsg(&m);
} else {
[NSApp terminate:self];
}
[readHandle waitForDataInBackgroundAndNotify];
return;
while((n = read(3, buf, 4)) == 4){
GET(buf, n);
if(n > nmbuf){
free(mbuf);
mbuf = malloc(4+n);
if(mbuf == nil)
sysfatal("malloc: %r");
nmbuf = n;
}
memmove(mbuf, buf, 4);
nn = readn(3, mbuf+4, n-4);
if(nn != n-4)
sysfatal("eof during message");
/* pick off messages one by one */
if(convM2W(mbuf, nn+4, &m) <= 0)
sysfatal("cannot convert message");
if(trace) fprint(2, "<- %W\n", &m);
runmsg(&m);
}
}
#pragma mark Notifications
- (void)fullscreen:(NSNotification *)notification
{
fullscreen(1);
}
- (void)windowWillClose:(NSNotification *)notification
{
// if(osx.window == [notification object]){
[[NSNotificationCenter defaultCenter] removeObserver:self];
[NSApp terminate:self];
// }
}
- (void)windowDidResize:(NSNotification *)notification
{
// if(osx.window == [notification object]) {
eresized(1);
// }
}
- (void)receiveWake:(NSNotification *)notification
{
if(trace) NSLog(@"%s:%d %@", __FILE__, __LINE__, notification);
// redraw
}
- (void)mouseDown:(NSEvent *)anEvent
{
mouseevent(anEvent);
}
- (void)mouseDragged:(NSEvent *)anEvent
{
mouseevent(anEvent);
}
- (void)keydown:(NSEvent *)anEvent
{
kbdevent(anEvent);
}
@end

View file

@ -0,0 +1,680 @@
#define Point OSXPoint
#define Rect OSXRect
#define Cursor OSXCursor
#import <Cocoa/Cocoa.h>
#import <AppKit/AppKit.h>
#undef Rect
#undef Point
#undef Cursor
#undef offsetof
#undef nil
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <keyboard.h>
#include <mouse.h>
#include <cursor.h>
#include "osx-screen.h"
#include "osx-keycodes.h"
#include "devdraw.h"
#include "glendapng.h"
AUTOFRAMEWORK(Cocoa)
#define panic sysfatal
extern Rectangle mouserect;
struct {
char *label;
char *winsize;
QLock labellock;
Rectangle fullscreenr;
Rectangle screenr;
Memimage *screenimage;
int isfullscreen;
ulong fullscreentime;
Point xy;
int buttons;
int kbuttons;
CGDataProviderRef provider;
NSWindow *window;
CGImageRef image;
CGContextRef windowctx;
int needflush;
QLock flushlock;
int active;
int infullscreen;
int kalting; // last keystroke was Kalt
} osx;
enum
{
WindowAttrs = NSClosableWindowMask |
NSTitledWindowMask |
NSMiniaturizableWindowMask |
NSResizableWindowMask
};
static void screenproc(void*);
void eresized(int);
void fullscreen(int);
void seticon(void);
static void activated(int);
enum
{
CmdFullScreen = 1,
};
@interface P9View : NSView
{}
@end
@implementation P9View
- (BOOL)acceptsFirstResponder
{
return YES;
}
@end
void screeninit(void);
void _flushmemscreen(Rectangle r);
Memimage*
attachscreen(char *label, char *winsize)
{
if(label == nil)
label = "gnot a label";
osx.label = strdup(label);
osx.winsize = winsize;
if(osx.screenimage == nil){
screeninit();
if(osx.screenimage == nil)
panic("cannot create OS X screen");
}
return osx.screenimage;
}
void
_screeninit(void)
{
CGRect cgr;
NSRect or;
Rectangle r;
int havemin;
memimageinit();
cgr = CGDisplayBounds(CGMainDisplayID());
osx.fullscreenr = Rect(0, 0, cgr.size.width, cgr.size.height);
// Create the window.
r = Rect(0, 0, Dx(osx.fullscreenr)*2/3, Dy(osx.fullscreenr)*2/3);
havemin = 0;
if(osx.winsize && osx.winsize[0]){
if(parsewinsize(osx.winsize, &r, &havemin) < 0)
sysfatal("%r");
}
if(!havemin)
r = rectaddpt(r, Pt((Dx(osx.fullscreenr)-Dx(r))/2, (Dy(osx.fullscreenr)-Dy(r))/2));
or = NSMakeRect(r.min.x, r.min.y, r.max.x, r.max.y);
osx.window = [[NSWindow alloc] initWithContentRect:or styleMask:WindowAttrs
backing:NSBackingStoreBuffered defer:NO screen:[NSScreen mainScreen]];
[osx.window setDelegate:[NSApp delegate]];
[osx.window setAcceptsMouseMovedEvents:YES];
P9View *view = [[P9View alloc] initWithFrame:or];
[osx.window setContentView:view];
[view release];
setlabel(osx.label);
seticon();
// Finally, put the window on the screen.
eresized(0);
[osx.window makeKeyAndOrderFront:nil];
[NSCursor unhide];
}
static Rendez scr;
static QLock slock;
void
screeninit(void)
{
scr.l = &slock;
qlock(scr.l);
// proccreate(screenproc, nil, 256*1024);
screenproc(NULL);
while(osx.window == nil)
rsleep(&scr);
qunlock(scr.l);
}
static void
screenproc(void *v)
{
qlock(scr.l);
_screeninit();
rwakeup(&scr);
qunlock(scr.l);
}
static ulong
msec(void)
{
return nsec()/1000000;
}
//static void
void
mouseevent(NSEvent *event)
{
int wheel;
NSPoint op;
op = [event locationInWindow];
osx.xy = subpt(Pt(op.x, op.y), osx.screenr.min);
wheel = 0;
switch([event type]){
case NSScrollWheel:;
CGFloat delta = [event deltaY];
if(delta > 0)
wheel = 8;
else
wheel = 16;
break;
case NSLeftMouseDown:
case NSRightMouseDown:
case NSOtherMouseDown:
case NSLeftMouseUp:
case NSRightMouseUp:
case NSOtherMouseUp:;
NSInteger but;
NSUInteger mod;
but = [event buttonNumber];
mod = [event modifierFlags];
// OS X swaps button 2 and 3
but = (but & ~6) | ((but & 4)>>1) | ((but&2)<<1);
but = mouseswap(but);
// Apply keyboard modifiers and pretend it was a real mouse button.
// (Modifiers typed while holding the button go into kbuttons,
// but this one does not.)
if(but == 1){
if(mod & NSAlternateKeyMask) {
// Take the ALT away from the keyboard handler.
if(osx.kalting) {
osx.kalting = 0;
keystroke(Kalt);
}
but = 2;
}
else if(mod & NSCommandKeyMask)
but = 4;
}
osx.buttons = but;
break;
case NSMouseMoved:
case NSLeftMouseDragged:
case NSRightMouseDragged:
case NSOtherMouseDragged:
break;
default:
return;
}
mousetrack(osx.xy.x, osx.xy.y, osx.buttons|osx.kbuttons|wheel, msec());
}
static int keycvt[] =
{
[QZ_IBOOK_ENTER] '\n',
[QZ_RETURN] '\n',
[QZ_ESCAPE] 27,
[QZ_BACKSPACE] '\b',
[QZ_LALT] Kalt,
[QZ_LCTRL] Kctl,
[QZ_LSHIFT] Kshift,
[QZ_F1] KF+1,
[QZ_F2] KF+2,
[QZ_F3] KF+3,
[QZ_F4] KF+4,
[QZ_F5] KF+5,
[QZ_F6] KF+6,
[QZ_F7] KF+7,
[QZ_F8] KF+8,
[QZ_F9] KF+9,
[QZ_F10] KF+10,
[QZ_F11] KF+11,
[QZ_F12] KF+12,
[QZ_INSERT] Kins,
[QZ_DELETE] 0x7F,
[QZ_HOME] Khome,
[QZ_END] Kend,
[QZ_KP_PLUS] '+',
[QZ_KP_MINUS] '-',
[QZ_TAB] '\t',
[QZ_PAGEUP] Kpgup,
[QZ_PAGEDOWN] Kpgdown,
[QZ_UP] Kup,
[QZ_DOWN] Kdown,
[QZ_LEFT] Kleft,
[QZ_RIGHT] Kright,
[QZ_KP_MULTIPLY] '*',
[QZ_KP_DIVIDE] '/',
[QZ_KP_ENTER] '\n',
[QZ_KP_PERIOD] '.',
[QZ_KP0] '0',
[QZ_KP1] '1',
[QZ_KP2] '2',
[QZ_KP3] '3',
[QZ_KP4] '4',
[QZ_KP5] '5',
[QZ_KP6] '6',
[QZ_KP7] '7',
[QZ_KP8] '8',
[QZ_KP9] '9',
};
//static void
void
kbdevent(NSEvent *event)
{
char ch;
UInt32 code;
UInt32 mod;
int k;
ch = [[event characters] characterAtIndex:0];
code = [event keyCode];
mod = [event modifierFlags];
switch([event type]){
case NSKeyDown:
osx.kalting = 0;
if(mod == NSCommandKeyMask){
if(ch == 'F' || ch == 'f'){
if(osx.isfullscreen && msec() - osx.fullscreentime > 500)
fullscreen(0);
return;
}
// Pass most Cmd keys through as Kcmd + ch.
// OS X interprets a few no matter what we do,
// so it is useless to pass them through as keystrokes too.
switch(ch) {
case 'm': // minimize window
case 'h': // hide window
case 'H': // hide others
case 'q': // quit
return;
}
if(' ' <= ch && ch <= '~') {
keystroke(Kcmd + ch);
return;
}
return;
}
k = ch;
if(code < nelem(keycvt) && keycvt[code])
k = keycvt[code];
if(k >= 0)
keystroke(k);
else{
keystroke(ch);
}
break;
case NSFlagsChanged:
if(!osx.buttons && !osx.kbuttons){
if(mod == NSAlternateKeyMask) {
osx.kalting = 1;
keystroke(Kalt);
}
break;
}
// If the mouse button is being held down, treat
// changes in the keyboard modifiers as changes
// in the mouse buttons.
osx.kbuttons = 0;
if(mod & NSAlternateKeyMask)
osx.kbuttons |= 2;
if(mod & NSCommandKeyMask)
osx.kbuttons |= 4;
mousetrack(osx.xy.x, osx.xy.y, osx.buttons|osx.kbuttons, msec());
break;
}
return;
}
//static void
void
eresized(int new)
{
Memimage *m;
NSRect or;
ulong chan;
Rectangle r;
int bpl;
CGDataProviderRef provider;
CGImageRef image;
CGColorSpaceRef cspace;
or = [[osx.window contentView] bounds];
r = Rect(or.origin.x, or.origin.y, or.size.width, or.size.height);
if(Dx(r) == Dx(osx.screenr) && Dy(r) == Dy(osx.screenr)){
// No need to make new image.
osx.screenr = r;
return;
}
chan = XBGR32;
m = allocmemimage(Rect(0, 0, Dx(r), Dy(r)), chan);
if(m == nil)
panic("allocmemimage: %r");
if(m->data == nil)
panic("m->data == nil");
bpl = bytesperline(r, 32);
provider = CGDataProviderCreateWithData(0,
m->data->bdata, Dy(r)*bpl, 0);
//cspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
cspace = CGColorSpaceCreateDeviceRGB();
image = CGImageCreate(Dx(r), Dy(r), 8, 32, bpl,
cspace,
kCGImageAlphaNoneSkipLast,
provider, 0, 0, kCGRenderingIntentDefault);
CGColorSpaceRelease(cspace);
CGDataProviderRelease(provider); // CGImageCreate did incref
mouserect = m->r;
if(new){
mouseresized = 1;
mousetrack(osx.xy.x, osx.xy.y, osx.buttons|osx.kbuttons, msec());
}
// termreplacescreenimage(m);
_drawreplacescreenimage(m); // frees old osx.screenimage if any
if(osx.image)
CGImageRelease(osx.image);
osx.image = image;
osx.screenimage = m;
osx.screenr = r;
}
void
flushproc(void *v)
{
for(;;){
if(osx.needflush && osx.windowctx && canqlock(&osx.flushlock)){
if(osx.windowctx){
CGContextFlush(osx.windowctx);
osx.needflush = 0;
}
qunlock(&osx.flushlock);
}
usleep(33333);
}
}
void
_flushmemscreen(Rectangle r)
{
CGRect cgr;
CGImageRef subimg;
qlock(&osx.flushlock);
if(osx.windowctx == nil){
osx.windowctx = [[osx.window graphicsContext] graphicsPort];
// [osx.window flushWindow];
// proccreate(flushproc, nil, 256*1024);
}
cgr.origin.x = r.min.x;
cgr.origin.y = r.min.y;
cgr.size.width = Dx(r);
cgr.size.height = Dy(r);
subimg = CGImageCreateWithImageInRect(osx.image, cgr);
cgr.origin.y = Dy(osx.screenr) - r.max.y; // XXX how does this make any sense?
CGContextDrawImage(osx.windowctx, cgr, subimg);
osx.needflush = 1;
qunlock(&osx.flushlock);
CGImageRelease(subimg);
}
void
activated(int active)
{
osx.active = active;
}
void
fullscreen(int wascmd)
{
NSView *view = [osx.window contentView];
if(osx.isfullscreen){
[view exitFullScreenModeWithOptions:nil];
osx.isfullscreen = 0;
}else{
[view enterFullScreenMode:[osx.window screen] withOptions:nil];
osx.isfullscreen = 1;
osx.fullscreentime = msec();
}
eresized(1);
}
void
setmouse(Point p)
{
CGPoint cgp;
cgp.x = p.x + osx.screenr.min.x;
cgp.y = p.y + osx.screenr.min.y;
CGWarpMouseCursorPosition(cgp);
}
void
setcursor(Cursor *c)
{
NSImage *image;
NSBitmapImageRep *bitmap;
NSCursor *nsc;
unsigned char *planes[5];
int i;
if(c == nil){
[NSCursor pop];
return;
}
image = [[NSImage alloc] initWithSize:NSMakeSize(16.0, 16.0)];
bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:16
pixelsHigh:16
bitsPerSample:1
samplesPerPixel:2
hasAlpha:YES
isPlanar:YES
colorSpaceName:NSCalibratedWhiteColorSpace
bytesPerRow:2
bitsPerPixel:1];
[bitmap getBitmapDataPlanes:planes];
for(i=0; i<16; i++){
planes[0][i] = ((ushort*)c->set)[i];
planes[1][i] = planes[0][i] | ((ushort*)c->clr)[i];
}
[image addRepresentation:bitmap];
nsc = [[NSCursor alloc] initWithImage:image
hotSpot:NSMakePoint(c->offset.x, c->offset.y)];
[nsc push];
[image release];
[bitmap release];
[nsc release];
}
void
getcolor(ulong i, ulong *r, ulong *g, ulong *b)
{
ulong v;
v = 0;
*r = (v>>16)&0xFF;
*g = (v>>8)&0xFF;
*b = v&0xFF;
}
int
setcolor(ulong i, ulong r, ulong g, ulong b)
{
/* no-op */
return 0;
}
int
hwdraw(Memdrawparam *p)
{
return 0;
}
struct {
QLock lk;
char buf[SnarfSize];
Rune rbuf[SnarfSize];
NSPasteboard *apple;
} clip;
char*
getsnarf(void)
{
char *s, *t;
NSArray *types;
NSString *string;
NSData * data;
NSUInteger ndata;
/* fprint(2, "applegetsnarf\n"); */
qlock(&clip.lk);
clip.apple = [NSPasteboard generalPasteboard];
types = [clip.apple types];
string = [clip.apple stringForType:NSStringPboardType];
if(string == nil){
fprint(2, "apple pasteboard get item type failed\n");
qunlock(&clip.lk);
return nil;
}
data = [string dataUsingEncoding:NSUnicodeStringEncoding];
if(data != nil){
ndata = [data length];
qunlock(&clip.lk);
s = smprint("%.*S", ndata/2, (Rune*)[data bytes]);
for(t=s; *t; t++)
if(*t == '\r')
*t = '\n';
return s;
}
qunlock(&clip.lk);
return nil;
}
void
putsnarf(char *s)
{
NSArray *pboardTypes;
NSString *string;
/* fprint(2, "appleputsnarf\n"); */
if(strlen(s) >= SnarfSize)
return;
qlock(&clip.lk);
strcpy(clip.buf, s);
runesnprint(clip.rbuf, nelem(clip.rbuf), "%s", s);
pboardTypes = [NSArray arrayWithObject:NSStringPboardType];
clip.apple = [NSPasteboard generalPasteboard];
[clip.apple declareTypes:pboardTypes owner:nil];
assert(sizeof(clip.rbuf[0]) == 2);
string = [NSString stringWithCharacters:clip.rbuf length:runestrlen(clip.rbuf)*2];
if(string == nil){
fprint(2, "apple pasteboard data create failed\n");
qunlock(&clip.lk);
return;
}
if(![clip.apple setString:string forType:NSStringPboardType]){
fprint(2, "apple pasteboard putitem failed\n");
qunlock(&clip.lk);
return;
}
qunlock(&clip.lk);
}
void
setlabel(char *label)
{
CFStringRef cs;
cs = CFStringCreateWithBytes(nil, (uchar*)label, strlen(osx.label), kCFStringEncodingUTF8, false);
[osx.window setTitle:(NSString*)cs];
CFRelease(cs);
}
void
kicklabel(char *label)
{
char *p;
p = strdup(label);
if(p == nil)
return;
qlock(&osx.labellock);
free(osx.label);
osx.label = p;
qunlock(&osx.labellock);
setlabel(label);
}
// static void
void
seticon(void)
{
NSImage *im;
NSData *d;
d = [[NSData alloc] initWithBytes:glenda_png length:(sizeof glenda_png)];
im = [[NSImage alloc] initWithData:d];
if(im){
NSLog(@"here");
[NSApp setApplicationIconImage:im];
[[NSApp dockTile] setShowsApplicationBadge:YES];
[[NSApp dockTile] display];
}
[d release];
[im release];
}

452
src/cmd/devdraw/osx-srv.m Normal file
View file

@ -0,0 +1,452 @@
#define Point OSXPoint
#define Rect OSXRect
#define Cursor OSXCursor
#import <AppKit/AppKit.h>
#undef Rect
#undef Point
#undef Cursor
/*
* Window system protocol server.
*/
#include <u.h>
#include <errno.h>
#include <sys/select.h>
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
#include <keyboard.h>
#include <mouse.h>
#include <cursor.h>
#include <drawfcall.h>
#include "osx-screen.h"
#include "devdraw.h"
AUTOFRAMEWORK(AppKit)
#import "osx-delegate.h"
#undef time
#define MouseMask (\
ButtonPressMask|\
ButtonReleaseMask|\
PointerMotionMask|\
Button1MotionMask|\
Button2MotionMask|\
Button3MotionMask)
#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask
typedef struct Kbdbuf Kbdbuf;
typedef struct Mousebuf Mousebuf;
typedef struct Fdbuf Fdbuf;
typedef struct Tagbuf Tagbuf;
struct Kbdbuf
{
Rune r[32];
int ri;
int wi;
int stall;
};
struct Mousebuf
{
Mouse m[32];
Mouse last;
int ri;
int wi;
int stall;
};
struct Tagbuf
{
int t[32];
int ri;
int wi;
};
Kbdbuf kbd;
Mousebuf mouse;
Tagbuf kbdtags;
Tagbuf mousetags;
void fdslide(Fdbuf*);
void runmsg(Wsysmsg*);
void replymsg(Wsysmsg*);
void matchkbd(void);
void matchmouse(void);
int fdnoblock(int);
Rectangle mouserect;
int mouseresized;
QLock lk;
void
zlock(void)
{
qlock(&lk);
}
void
zunlock(void)
{
qunlock(&lk);
}
int chatty;
int drawsleep;
int trace;
void
usage(void)
{
fprint(2, "usage: devdraw (don't run directly)\n");
exits("usage");
}
void
bell(void *v, char *msg)
{
if(strcmp(msg, "alarm") == 0)
drawsleep = drawsleep ? 0 : 1000;
noted(NCONT);
}
int
main(int argc, char **argv)
{
NSAutoreleasePool *pool = nil;
NSApplication *application = nil;
/*
* Move the protocol off stdin/stdout so that
* any inadvertent prints don't screw things up.
*/
dup(0, 3);
dup(1, 4);
close(0);
close(1);
open("/dev/null", OREAD);
open("/dev/null", OWRITE);
trace = 1;
fmtinstall('W', drawfcallfmt);
ARGBEGIN{
case 'D':
chatty++;
break;
default:
usage();
}ARGEND
/*
* Ignore arguments. They're only for good ps -a listings.
*/
notify(bell);
pool = [[NSAutoreleasePool alloc] init];
application = [NSApplication sharedApplication];
[application setDelegate:[[DevdrawDelegate alloc] init]];
[application run];
[application setDelegate:nil];
[pool release];
return 0;
}
void
replyerror(Wsysmsg *m)
{
char err[256];
rerrstr(err, sizeof err);
m->type = Rerror;
m->error = err;
replymsg(m);
}
/*
* Handle a single wsysmsg.
* Might queue for later (kbd, mouse read)
*/
void
runmsg(Wsysmsg *m)
{
static uchar buf[65536];
int n;
Memimage *i;
switch(m->type){
case Tinit:
memimageinit();
i = attachscreen(m->label, m->winsize);
_initdisplaymemimage(i);
replymsg(m);
break;
case Trdmouse:
// zlock();
mousetags.t[mousetags.wi++] = m->tag;
if(mousetags.wi == nelem(mousetags.t))
mousetags.wi = 0;
if(mousetags.wi == mousetags.ri)
sysfatal("too many queued mouse reads");
mouse.stall = 0;
matchmouse();
// zunlock();
break;
case Trdkbd:
zlock();
kbdtags.t[kbdtags.wi++] = m->tag;
if(kbdtags.wi == nelem(kbdtags.t))
kbdtags.wi = 0;
if(kbdtags.wi == kbdtags.ri)
sysfatal("too many queued keyboard reads");
kbd.stall = 0;
matchkbd();
zunlock();
break;
case Tmoveto:
setmouse(m->mouse.xy);
replymsg(m);
break;
case Tcursor:
if(m->arrowcursor)
setcursor(nil);
else
setcursor(&m->cursor);
replymsg(m);
break;
case Tbouncemouse:
// _xbouncemouse(&m->mouse);
replymsg(m);
break;
case Tlabel:
kicklabel(m->label);
replymsg(m);
break;
case Trdsnarf:
m->snarf = getsnarf();
replymsg(m);
free(m->snarf);
break;
case Twrsnarf:
putsnarf(m->snarf);
replymsg(m);
break;
case Trddraw:
n = m->count;
if(n > sizeof buf)
n = sizeof buf;
n = _drawmsgread(buf, n);
if(n < 0)
replyerror(m);
else{
m->count = n;
m->data = buf;
replymsg(m);
}
break;
case Twrdraw:
if(_drawmsgwrite(m->data, m->count) < 0)
replyerror(m);
else
replymsg(m);
break;
case Ttop:
// _xtopwindow();
replymsg(m);
break;
case Tresize:
// _xresizewindow(m->rect);
replymsg(m);
break;
}
}
/*
* Reply to m.
*/
QLock replylock;
void
replymsg(Wsysmsg *m)
{
int n;
static uchar *mbuf;
static int nmbuf;
/* T -> R msg */
if(m->type%2 == 0)
m->type++;
if(trace) fprint(2, "-> %W\n", m);
/* copy to output buffer */
n = sizeW2M(m);
qlock(&replylock);
if(n > nmbuf){
free(mbuf);
mbuf = malloc(n);
if(mbuf == nil)
sysfatal("out of memory");
nmbuf = n;
}
convW2M(m, mbuf, n);
if(write(4, mbuf, n) != n)
sysfatal("write: %r");
qunlock(&replylock);
}
/*
* Match queued kbd reads with queued kbd characters.
*/
void
matchkbd(void)
{
Wsysmsg m;
if(kbd.stall)
return;
while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){
m.type = Rrdkbd;
m.tag = kbdtags.t[kbdtags.ri++];
if(kbdtags.ri == nelem(kbdtags.t))
kbdtags.ri = 0;
m.rune = kbd.r[kbd.ri++];
if(kbd.ri == nelem(kbd.r))
kbd.ri = 0;
replymsg(&m);
}
}
/*
* Match queued mouse reads with queued mouse events.
*/
void
matchmouse(void)
{
Wsysmsg m;
while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){
m.type = Rrdmouse;
m.tag = mousetags.t[mousetags.ri++];
if(mousetags.ri == nelem(mousetags.t))
mousetags.ri = 0;
m.mouse = mouse.m[mouse.ri];
m.resized = mouseresized;
/*
if(m.resized)
fprint(2, "sending resize\n");
*/
mouseresized = 0;
mouse.ri++;
if(mouse.ri == nelem(mouse.m))
mouse.ri = 0;
replymsg(&m);
}
}
void
mousetrack(int x, int y, int b, int ms)
{
Mouse *m;
if(x < mouserect.min.x)
x = mouserect.min.x;
if(x > mouserect.max.x)
x = mouserect.max.x;
if(y < mouserect.min.y)
y = mouserect.min.y;
if(y > mouserect.max.y)
y = mouserect.max.y;
// zlock();
// If reader has stopped reading, don't bother.
// If reader is completely caught up, definitely queue.
// Otherwise, queue only button change events.
if(!mouse.stall)
if(mouse.wi == mouse.ri || mouse.last.buttons != b){
m = &mouse.last;
m->xy.x = x;
m->xy.y = y;
m->buttons = b;
m->msec = ms;
mouse.m[mouse.wi] = *m;
if(++mouse.wi == nelem(mouse.m))
mouse.wi = 0;
if(mouse.wi == mouse.ri){
mouse.stall = 1;
mouse.ri = 0;
mouse.wi = 1;
mouse.m[0] = *m;
}
matchmouse();
}
// zunlock();
}
void
kputc(int c)
{
zlock();
kbd.r[kbd.wi++] = c;
if(kbd.wi == nelem(kbd.r))
kbd.wi = 0;
if(kbd.ri == kbd.wi)
kbd.stall = 1;
matchkbd();
zunlock();
}
void
keystroke(int c)
{
static Rune k[10];
static int alting, nk;
int i;
if(c == Kalt){
alting = !alting;
return;
}
if(!alting){
kputc(c);
return;
}
if(nk >= nelem(k)) // should not happen
nk = 0;
k[nk++] = c;
c = _latin1(k, nk);
if(c > 0){
alting = 0;
kputc(c);
nk = 0;
return;
}
if(c == -1){
alting = 0;
for(i=0; i<nk; i++)
kputc(k[i]);
nk = 0;
return;
}
// need more input
return;
}