tdevdraw: draft of new Cocoa-based devdraw - plan9port - [fork] Plan 9 from use… | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 113867b836eaa85215e4b2ece5ccf612f34c3e03 | |
parent daea2c7d501c3e825bede80992ade6b241efdce1 | |
Author: Jeff Sickel <[email protected]> | |
Date: Tue, 29 Sep 2009 09:35:23 -0700 | |
devdraw: draft of new Cocoa-based devdraw | |
Can test with | |
cd $PLAN9/src/cmd/devdraw | |
mk devdraw-cocoa | |
DEVDRAW=devdraw-cocoa colors | |
Diffstat: | |
M src/cmd/devdraw/mkfile | 11 ++++++++++- | |
A src/cmd/devdraw/osx-delegate.h | 15 +++++++++++++++ | |
A src/cmd/devdraw/osx-delegate.m | 282 +++++++++++++++++++++++++++++… | |
A src/cmd/devdraw/osx-screen.m | 680 +++++++++++++++++++++++++++++… | |
A src/cmd/devdraw/osx-srv.m | 452 +++++++++++++++++++++++++++++… | |
5 files changed, 1439 insertions(+), 1 deletion(-) | |
--- | |
diff --git a/src/cmd/devdraw/mkfile b/src/cmd/devdraw/mkfile | |
t@@ -7,7 +7,7 @@ WSYSOFILES=\ | |
latin1.$O\ | |
mouseswap.$O\ | |
winsize.$O\ | |
- | |
+ | |
<|sh ./mkwsysrules.sh | |
OFILES=$WSYSOFILES | |
t@@ -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-… | |
+ $LD -o $target $prereq | |
+ | |
diff --git a/src/cmd/devdraw/osx-delegate.h b/src/cmd/devdraw/osx-delegate.h | |
t@@ -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 | |
diff --git a/src/cmd/devdraw/osx-delegate.m b/src/cmd/devdraw/osx-delegate.m | |
t@@ -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 keyEquivale… | |
+ 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 keyEquivalen… | |
+ submenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"View", "@T… | |
+ [self populateViewMenu:submenu]; | |
+ [mainMenu setSubmenu:submenu forItem:menuItem]; | |
+ | |
+ menuItem = [mainMenu addItemWithTitle:@"Window" action:NULL keyEquival… | |
+ submenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Window", @… | |
+ [self populateWindowMenu:submenu]; | |
+ [mainMenu setSubmenu:submenu forItem:menuItem]; | |
+ [NSApp setWindowsMenu:submenu]; | |
+ | |
+ menuItem = [mainMenu addItemWithTitle:@"Help" action:NULL keyEquivalen… | |
+ submenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Help", @"T… | |
+ [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:@"%@ %@"… | |
+ action:@select… | |
+ keyEquivalent:@""]; | |
+ [menuItem setTarget:NSApp]; | |
+ | |
+ [aMenu addItem:[NSMenuItem separatorItem]]; | |
+ | |
+ menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Preferences..."… | |
+ 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:@"%@ %@"… | |
+ action:@select… | |
+ keyEquivalent:@"h"]; | |
+ [menuItem setTarget:NSApp]; | |
+ | |
+ menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Hide Others", n… | |
+ action:@select… | |
+ keyEquivalent:@"h"]; | |
+ [menuItem setKeyEquivalentModifierMask:NSCommandKeyMask | NSAlternateK… | |
+ [menuItem setTarget:NSApp]; | |
+ | |
+ menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Show All", nil) | |
+ action:@select… | |
+ keyEquivalent:@""]; | |
+ [menuItem setTarget:NSApp]; | |
+ | |
+ [aMenu addItem:[NSMenuItem separatorItem]]; | |
+ | |
+ menuItem = [aMenu addItemWithTitle:[NSString stringWithFormat:@"%@ %@"… | |
+ action:@select… | |
+ keyEquivalent:@"q"]; | |
+ [menuItem setTarget:NSApp]; | |
+} | |
+ | |
++(void)populateViewMenu:(NSMenu *)aMenu | |
+{ | |
+ NSMenuItem *menuItem; | |
+ menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Full Screen", n… | |
+ action:@selector(fullscreen:) keyEquivalent:@"… | |
+ [menuItem setTarget:NSApp]; | |
+ | |
+ menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Cmd-F exits ful… | |
+ 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 cl… | |
+ [[NSNotificationCenter defaultCenter] addObserver:self | |
+ selector:@selector(devdrawMain:) | |
+ name:NSFileHandleDataAvailableNotification | |
+ object:readHandle]; | |
+ [[[NSWorkspace sharedWorkspace] notificationCenter] addObserve… | |
+ 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 | |
diff --git a/src/cmd/devdraw/osx-screen.m b/src/cmd/devdraw/osx-screen.m | |
t@@ -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.ful… | |
+ or = NSMakeRect(r.min.x, r.min.y, r.max.x, r.max.y); | |
+ osx.window = [[NSWindow alloc] initWithContentRect:or styleMask:Window… | |
+ backing:NSBackingStoreBuffered defer:NO screen:[NSScreen main… | |
+ [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 bu… | |
+ // (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.fullscreen… | |
+ 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… | |
+ 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 an… | |
+ 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(cl… | |
+ 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), kC… | |
+ [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]; | |
+} | |
diff --git a/src/cmd/devdraw/osx-srv.m b/src/cmd/devdraw/osx-srv.m | |
t@@ -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|EnterWind… | |
+ | |
+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; | |
+} |