commit e769e79cbe9454c7a317f53db28954df0c6d6f9b
parent c7c041c8ea44d3c1cc93a9b882963caabf26b4a1
Author: Russ Cox <rsc@swtch.com>
Date: Sat, 28 Jun 2008 15:08:36 -0400
9vx/OSX: attempt at native GUI code
Diffstat:
6 files changed, 897 insertions(+), 2 deletions(-)
diff --git a/src/9vx/Makefrag b/src/9vx/Makefrag
@@ -10,7 +10,8 @@ endif
ifeq ($(OS),darwin)
PLAN9VX=1
- # TODO: carbon
+# TODO: osx works except that Carbon gets confused
+# that we can survive an EXC_BAD_ACCESS
PLAN9GUI=x11
PLAN9AUDIO=none
endif
@@ -124,9 +125,16 @@ PLAN9_x11_OBJS = \
x11-kernel.o \
x11-keysym2rune.o \
)
-
PLAN9_x11_LIBS = -L/usr/X11R6/lib -L/usr/local/lib -lX11
+PLAN9_osx_OBJS =\
+ $(addprefix 9vx/osx/, \
+ screen.o \
+ draw.o \
+ )
+PLAN9_osx_LIBS = -ggdb -framework Carbon -framework QuickTime
+
+
PLAN9_GUI_OBJS = $(PLAN9_$(PLAN9GUI)_OBJS)
PLAN9_GUI_LIBS = $(PLAN9_$(PLAN9GUI)_LIBS)
@@ -149,6 +157,9 @@ PLAN9_DEPS = \
9vx/x11/%.o: 9vx/x11/%.c
$(HOST_CC) $(HOST_CFLAGS) -I. -I9vx -I9vx/a -I/usr/X11R6/include -I/usr/local/include -Wall -Wno-missing-braces -c -o $@ $<
+9vx/osx/%.o: 9vx/osx/%.c
+ $(HOST_CC) $(HOST_CFLAGS) -I. -I9vx -I9vx/a -Wall -Wno-missing-braces -c -o $@ $<
+
9vx/%.o: 9vx/%.c
$(HOST_CC) $(HOST_CFLAGS) -I. -I9vx -I9vx/a -Wall -Wno-missing-braces -c -o $@ $<
diff --git a/src/9vx/main.c b/src/9vx/main.c
@@ -4,6 +4,10 @@
#define WANT_M
+#ifdef __APPLE__
+#define __DARWIN_UNIX03 0
+#endif
+
#include "u.h"
#include "libvx32/vx32.h"
#include <sys/mman.h>
diff --git a/src/9vx/osx/draw.c b/src/9vx/osx/draw.c
@@ -0,0 +1,54 @@
+#include "u.h"
+#include "lib.h"
+#include "draw.h"
+#include "memdraw.h"
+
+Memimage*
+allocmemimage(Rectangle r, ulong chan)
+{
+ return _allocmemimage(r, chan);
+}
+
+void
+freememimage(Memimage *i)
+{
+ _freememimage(i);
+}
+
+void
+memfillcolor(Memimage *i, ulong val)
+{
+ _memfillcolor(i, val);
+}
+
+
+int
+cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+ return _cloadmemimage(i, r, data, ndata);
+}
+
+void
+memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point sp, Memimage *mask, Point mp, int op)
+{
+ _memimagedraw(_memimagedrawsetup(dst, r, src, sp, mask, mp, op));
+}
+
+ulong
+pixelbits(Memimage *m, Point p)
+{
+ return _pixelbits(m, p);
+}
+
+int
+loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+ return _loadmemimage(i, r, data, ndata);
+}
+
+int
+unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
+{
+ return _unloadmemimage(i, r, data, ndata);
+}
+
diff --git a/src/9vx/osx/keycodes.h b/src/9vx/osx/keycodes.h
@@ -0,0 +1,189 @@
+/* These are the Macintosh key scancode constants -- from Inside Macintosh */
+#define QZ_ESCAPE 0x35
+#define QZ_F1 0x7A
+#define QZ_F2 0x78
+#define QZ_F3 0x63
+#define QZ_F4 0x76
+#define QZ_F5 0x60
+#define QZ_F6 0x61
+#define QZ_F7 0x62
+#define QZ_F8 0x64
+#define QZ_F9 0x65
+#define QZ_F10 0x6D
+#define QZ_F11 0x67
+#define QZ_F12 0x6F
+#define QZ_PRINT 0x69
+#define QZ_SCROLLOCK 0x6B
+#define QZ_PAUSE 0x71
+#define QZ_POWER 0x7F
+#define QZ_BACKQUOTE 0x32
+#define QZ_1 0x12
+#define QZ_2 0x13
+#define QZ_3 0x14
+#define QZ_4 0x15
+#define QZ_5 0x17
+#define QZ_6 0x16
+#define QZ_7 0x1A
+#define QZ_8 0x1C
+#define QZ_9 0x19
+#define QZ_0 0x1D
+#define QZ_MINUS 0x1B
+#define QZ_EQUALS 0x18
+#define QZ_BACKSPACE 0x33
+#define QZ_INSERT 0x72
+#define QZ_HOME 0x73
+#define QZ_PAGEUP 0x74
+#define QZ_NUMLOCK 0x47
+#define QZ_KP_EQUALS 0x51
+#define QZ_KP_DIVIDE 0x4B
+#define QZ_KP_MULTIPLY 0x43
+#define QZ_TAB 0x30
+#define QZ_q 0x0C
+#define QZ_w 0x0D
+#define QZ_e 0x0E
+#define QZ_r 0x0F
+#define QZ_t 0x11
+#define QZ_y 0x10
+#define QZ_u 0x20
+#define QZ_i 0x22
+#define QZ_o 0x1F
+#define QZ_p 0x23
+#define QZ_LEFTBRACKET 0x21
+#define QZ_RIGHTBRACKET 0x1E
+#define QZ_BACKSLASH 0x2A
+#define QZ_DELETE 0x75
+#define QZ_END 0x77
+#define QZ_PAGEDOWN 0x79
+#define QZ_KP7 0x59
+#define QZ_KP8 0x5B
+#define QZ_KP9 0x5C
+#define QZ_KP_MINUS 0x4E
+#define QZ_CAPSLOCK 0x39
+#define QZ_a 0x00
+#define QZ_s 0x01
+#define QZ_d 0x02
+#define QZ_f 0x03
+#define QZ_g 0x05
+#define QZ_h 0x04
+#define QZ_j 0x26
+#define QZ_k 0x28
+#define QZ_l 0x25
+#define QZ_SEMICOLON 0x29
+#define QZ_QUOTE 0x27
+#define QZ_RETURN 0x24
+#define QZ_KP4 0x56
+#define QZ_KP5 0x57
+#define QZ_KP6 0x58
+#define QZ_KP_PLUS 0x45
+#define QZ_LSHIFT 0x38
+#define QZ_z 0x06
+#define QZ_x 0x07
+#define QZ_c 0x08
+#define QZ_v 0x09
+#define QZ_b 0x0B
+#define QZ_n 0x2D
+#define QZ_m 0x2E
+#define QZ_COMMA 0x2B
+#define QZ_PERIOD 0x2F
+#define QZ_SLASH 0x2C
+/* These are the same as the left versions - use left by default */
+#if 0
+#define QZ_RSHIFT 0x38
+#endif
+#define QZ_UP 0x7E
+#define QZ_KP1 0x53
+#define QZ_KP2 0x54
+#define QZ_KP3 0x55
+#define QZ_KP_ENTER 0x4C
+#define QZ_LCTRL 0x3B
+#define QZ_LALT 0x3A
+#define QZ_LMETA 0x37
+#define QZ_SPACE 0x31
+/* These are the same as the left versions - use left by default */
+#if 0
+#define QZ_RMETA 0x37
+#define QZ_RALT 0x3A
+#define QZ_RCTRL 0x3B
+#endif
+#define QZ_LEFT 0x7B
+#define QZ_DOWN 0x7D
+#define QZ_RIGHT 0x7C
+#define QZ_KP0 0x52
+#define QZ_KP_PERIOD 0x41
+
+/* Wierd, these keys are on my iBook under MacOS X */
+#define QZ_IBOOK_ENTER 0x34
+#define QZ_IBOOK_LEFT 0x3B
+#define QZ_IBOOK_RIGHT 0x3C
+#define QZ_IBOOK_DOWN 0x3D
+#define QZ_IBOOK_UP 0x3E
+#define KEY_ENTER 13
+#define KEY_TAB 9
+
+#define KEY_BASE 0x100
+
+/* Function keys */
+#define KEY_F (KEY_BASE+64)
+
+/* Control keys */
+#define KEY_CTRL (KEY_BASE)
+#define KEY_BACKSPACE (KEY_CTRL+0)
+#define KEY_DELETE (KEY_CTRL+1)
+#define KEY_INSERT (KEY_CTRL+2)
+#define KEY_HOME (KEY_CTRL+3)
+#define KEY_END (KEY_CTRL+4)
+#define KEY_PAGE_UP (KEY_CTRL+5)
+#define KEY_PAGE_DOWN (KEY_CTRL+6)
+#define KEY_ESC (KEY_CTRL+7)
+
+/* Control keys short name */
+#define KEY_BS KEY_BACKSPACE
+#define KEY_DEL KEY_DELETE
+#define KEY_INS KEY_INSERT
+#define KEY_PGUP KEY_PAGE_UP
+#define KEY_PGDOWN KEY_PAGE_DOWN
+#define KEY_PGDWN KEY_PAGE_DOWN
+
+/* Cursor movement */
+#define KEY_CRSR (KEY_BASE+16)
+#define KEY_RIGHT (KEY_CRSR+0)
+#define KEY_LEFT (KEY_CRSR+1)
+#define KEY_DOWN (KEY_CRSR+2)
+#define KEY_UP (KEY_CRSR+3)
+
+/* Multimedia keyboard/remote keys */
+#define KEY_MM_BASE (0x100+384)
+#define KEY_POWER (KEY_MM_BASE+0)
+#define KEY_MENU (KEY_MM_BASE+1)
+#define KEY_PLAY (KEY_MM_BASE+2)
+#define KEY_PAUSE (KEY_MM_BASE+3)
+#define KEY_PLAYPAUSE (KEY_MM_BASE+4)
+#define KEY_STOP (KEY_MM_BASE+5)
+#define KEY_FORWARD (KEY_MM_BASE+6)
+#define KEY_REWIND (KEY_MM_BASE+7)
+#define KEY_NEXT (KEY_MM_BASE+8)
+#define KEY_PREV (KEY_MM_BASE+9)
+#define KEY_VOLUME_UP (KEY_MM_BASE+10)
+#define KEY_VOLUME_DOWN (KEY_MM_BASE+11)
+#define KEY_MUTE (KEY_MM_BASE+12)
+
+/* Keypad keys */
+#define KEY_KEYPAD (KEY_BASE+32)
+#define KEY_KP0 (KEY_KEYPAD+0)
+#define KEY_KP1 (KEY_KEYPAD+1)
+#define KEY_KP2 (KEY_KEYPAD+2)
+#define KEY_KP3 (KEY_KEYPAD+3)
+#define KEY_KP4 (KEY_KEYPAD+4)
+#define KEY_KP5 (KEY_KEYPAD+5)
+#define KEY_KP6 (KEY_KEYPAD+6)
+#define KEY_KP7 (KEY_KEYPAD+7)
+#define KEY_KP8 (KEY_KEYPAD+8)
+#define KEY_KP9 (KEY_KEYPAD+9)
+#define KEY_KPDEC (KEY_KEYPAD+10)
+#define KEY_KPINS (KEY_KEYPAD+11)
+#define KEY_KPDEL (KEY_KEYPAD+12)
+#define KEY_KPENTER (KEY_KEYPAD+13)
+
+/* Special keys */
+#define KEY_INTERN (0x1000)
+#define KEY_CLOSE_WIN (KEY_INTERN+0)
diff --git a/src/9vx/osx/screen.c b/src/9vx/osx/screen.c
@@ -0,0 +1,632 @@
+#define Point OSXPoint
+#define Rect OSXRect
+#define Cursor OSXCursor
+#include <Carbon/Carbon.h>
+#include <QuickTime/QuickTime.h> // for full screen
+#undef Rect
+#undef Point
+#undef Cursor
+#undef offsetof
+#undef nil
+
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+#define Image IMAGE /* kernel has its own Image */
+#include <draw.h>
+#include <memdraw.h>
+#include <keyboard.h>
+#include <cursor.h>
+#include "screen.h"
+#include "mouse.h"
+#include "keycodes.h"
+
+struct {
+ Rectangle fullscreenr;
+ Rectangle screenr;
+ Memimage *screenimage;
+ int isfullscreen;
+ Rectangle nonfullscreenr;
+
+ Point xy;
+ int buttons;
+ int kbuttons;
+
+ CGDataProviderRef provider;
+ MenuRef wmenu;
+ MenuRef vmenu;
+ WindowRef window;
+ CGImageRef image;
+ WindowGroupRef wingroup;
+ PasteboardRef snarf;
+} osx;
+
+enum
+{
+ WindowAttrs =
+ kWindowCloseBoxAttribute |
+ kWindowCollapseBoxAttribute |
+ kWindowResizableAttribute |
+ kWindowStandardHandlerAttribute |
+ kWindowFullZoomAttribute
+};
+
+static OSStatus eventhandler(EventHandlerCallRef, EventRef, void*);
+static void screenproc(void*);
+static void eresized(int);
+static void fullscreen(int);
+
+enum
+{
+ CmdFullScreen = 1,
+};
+
+uchar*
+attachscreen(Rectangle *r, ulong *chan, int *depth,
+ int *width, int *softscreen, void **X)
+{
+ Memimage *m;
+
+ if(osx.screenimage == nil){
+ screeninit();
+ if(osx.screenimage == nil)
+ panic("cannot create OS X screen");
+ }
+ m = osx.screenimage;
+ *r = m->r;
+ *chan = m->chan;
+ *depth = m->depth;
+ *width = m->width;
+ *X = nil;
+ *softscreen = 1;
+ return m->data->bdata;
+}
+
+void
+screeninit(void)
+{
+ CGRect cgr;
+ OSXRect or;
+
+ _memimageinit();
+
+ ProcessSerialNumber psn = { 0, kCurrentProcess };
+ TransformProcessType(&psn, kProcessTransformToForegroundApplication);
+ SetFrontProcess(&psn);
+
+ cgr = CGDisplayBounds(CGMainDisplayID());
+ osx.fullscreenr = Rect(0, 0, cgr.size.width, cgr.size.height);
+
+ InitCursor();
+
+ // Create minimal menu with full-screen option.
+ ClearMenuBar();
+ CreateStandardWindowMenu(0, &osx.wmenu);
+ InsertMenu(osx.wmenu, 0);
+ MenuItemIndex ix;
+ CreateNewMenu(1004, 0, &osx.vmenu); // XXX 1004?
+ SetMenuTitleWithCFString(osx.vmenu, CFSTR("View"));
+ AppendMenuItemTextWithCFString(osx.vmenu,
+ CFSTR("Full Screen"), 0, CmdFullScreen, &ix);
+ SetMenuItemCommandKey(osx.vmenu, ix, 0, 'F');
+ AppendMenuItemTextWithCFString(osx.vmenu,
+ CFSTR("Ctl-Opt exits full screen"),
+ kMenuItemAttrDisabled, CmdFullScreen, &ix);
+ InsertMenu(osx.vmenu, GetMenuID(osx.wmenu));
+ DrawMenuBar();
+
+ // Create the window.
+ or.left = 0;
+ or.top = 30;
+ or.bottom = Dy(osx.fullscreenr) - 100;
+ or.right = Dx(osx.fullscreenr);
+ CreateNewWindow(kDocumentWindowClass, WindowAttrs, &or, &osx.window);
+ CreateWindowGroup(0, &osx.wingroup);
+ SetWindowGroup(osx.window, osx.wingroup);
+ SetWindowTitleWithCFString(osx.window, CFSTR("Plan 9 VX"));
+
+ // Set up the clip board.
+ if(PasteboardCreate(kPasteboardClipboard, &osx.snarf) != noErr)
+ panic("pasteboard create");
+
+ // Explain in great detail which events we want to handle.
+ // Why can't we just have one handler?
+ const EventTypeSpec quits[] = {
+ { kEventClassApplication, kEventAppQuit }
+ };
+ const EventTypeSpec commands[] = {
+ { kEventClassWindow, kEventWindowClosed },
+ { kEventClassWindow, kEventWindowBoundsChanged },
+ { kEventClassCommand, kEventCommandProcess }
+ };
+ const EventTypeSpec events[] = {
+ { kEventClassKeyboard, kEventRawKeyDown },
+ { kEventClassKeyboard, kEventRawKeyModifiersChanged },
+ { kEventClassKeyboard, kEventRawKeyRepeat },
+ { kEventClassMouse, kEventMouseDown },
+ { kEventClassMouse, kEventMouseUp },
+ { kEventClassMouse, kEventMouseMoved },
+ { kEventClassMouse, kEventMouseDragged },
+ { kEventClassMouse, kEventMouseWheelMoved },
+ };
+ InstallApplicationEventHandler(
+ NewEventHandlerUPP(eventhandler),
+ nelem(quits), quits, nil, nil);
+ InstallApplicationEventHandler(
+ NewEventHandlerUPP(eventhandler),
+ nelem(events), events, osx.window, nil);
+ InstallWindowEventHandler(osx.window,
+ NewEventHandlerUPP(eventhandler),
+ nelem(commands), commands, osx.window, nil);
+
+ // Finally, put the window on the screen.
+ ShowWindow(osx.window);
+ ShowMenuBar();
+ eresized(0);
+ SelectWindow(osx.window);
+
+ InitCursor();
+
+ kproc("*screen*", screenproc, nil);
+}
+
+static void
+screenproc(void *v)
+{
+ RunApplicationEventLoop();
+}
+
+static OSStatus kbdevent(EventRef);
+static OSStatus mouseevent(EventRef);
+
+static OSStatus
+eventhandler(EventHandlerCallRef next, EventRef event, void *arg)
+{
+ OSStatus result;
+
+ result = CallNextEventHandler(next, event);
+
+ switch(GetEventClass(event)){
+ case kEventClassKeyboard:
+ return kbdevent(event);
+ break;
+
+ case kEventClassMouse:
+ return mouseevent(event);
+ break;
+
+ case kEventClassCommand:;
+ HICommand cmd;
+ GetEventParameter(event, kEventParamDirectObject,
+ typeHICommand, nil, sizeof cmd, nil, &cmd);
+ switch(cmd.commandID){
+ case kHICommandQuit:
+ exit(0);
+
+ case CmdFullScreen:
+ fullscreen(1);
+ break;
+
+ default:
+ return eventNotHandledErr;
+ }
+ break;
+
+ case kEventClassWindow:;
+ switch(GetEventKind(event)){
+ case kEventWindowClosed:
+ exit(0);
+
+ case kEventWindowBoundsChanged:
+ eresized(1);
+ break;
+
+ default:
+ return eventNotHandledErr;
+ }
+ break;
+ }
+
+ return result;
+}
+
+static OSStatus
+mouseevent(EventRef event)
+{
+ int wheel;
+ OSXPoint op;
+
+ GetEventParameter(event, kEventParamMouseLocation,
+ typeQDPoint, 0, sizeof op, 0, &op);
+ osx.xy = subpt(Pt(op.h, op.v), osx.screenr.min);
+ wheel = 0;
+
+ switch(GetEventKind(event)){
+ case kEventMouseWheelMoved:;
+ SInt32 delta;
+ GetEventParameter(event, kEventParamMouseWheelDelta,
+ typeSInt32, 0, sizeof delta, 0, &delta);
+ if(delta > 0)
+ wheel = 8;
+ else
+ wheel = 16;
+ break;
+
+ case kEventMouseDown:
+ case kEventMouseUp:;
+ UInt32 but, mod;
+ GetEventParameter(event, kEventParamMouseChord,
+ typeUInt32, 0, sizeof but, 0, &but);
+ GetEventParameter(event, kEventParamKeyModifiers,
+ typeUInt32, 0, sizeof mod, 0, &mod);
+
+ // OS X swaps button 2 and 3
+ but = (but & ~6) | ((but & 4)>>1) | ((but&2)<<1);
+
+ // 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 & optionKey)
+ but = 2;
+ else if(mod & cmdKey)
+ but = 4;
+ }
+ osx.buttons = but;
+ break;
+
+ case kEventMouseMoved:
+ break;
+
+ default:
+ return eventNotHandledErr;
+ }
+
+ mousetrack(osx.xy.x, osx.xy.y, osx.buttons|osx.kbuttons, msec());
+ return noErr;
+}
+
+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
+kputc(int c)
+{
+ kbdputc(kbdq, c);
+}
+
+static OSStatus
+kbdevent(EventRef event)
+{
+ char ch;
+ UInt32 code;
+ UInt32 mod;
+ int k;
+
+ GetEventParameter(event, kEventParamKeyMacCharCodes,
+ typeChar, nil, sizeof ch, nil, &ch);
+ GetEventParameter(event, kEventParamKeyCode,
+ typeUInt32, nil, sizeof code, nil, &code);
+ GetEventParameter(event, kEventParamKeyModifiers,
+ typeUInt32, nil, sizeof mod, nil, &mod);
+
+ switch(GetEventKind(event)){
+ case kEventRawKeyDown:
+ case kEventRawKeyRepeat:
+ if(mod == cmdKey){
+ if(ch == 'F' && osx.isfullscreen){
+ fullscreen(0);
+ break;
+ }
+ return eventNotHandledErr;
+ }
+ k = ch;
+ if(code < nelem(keycvt) && keycvt[code])
+ k = keycvt[code];
+ if(k >= 0)
+ latin1putc(k, kputc);
+ break;
+
+ case kEventRawKeyModifiersChanged:
+ if(!osx.buttons && !osx.kbuttons){
+ if(mod == optionKey)
+ kbdputc(kbdq, 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 & optionKey)
+ osx.kbuttons |= 2;
+ if(mod & cmdKey)
+ osx.kbuttons |= 4;
+ mousetrack(osx.xy.x, osx.xy.y, osx.buttons|osx.kbuttons, msec());
+ break;
+ }
+ return noErr;
+}
+
+static void
+eresized(int new)
+{
+ Memimage *m;
+ OSXRect or;
+ ulong chan;
+ Rectangle r;
+ int bpl;
+ CGDataProviderRef provider;
+ CGImageRef image;
+
+ GetWindowBounds(osx.window, kWindowContentRgn, &or);
+ r = Rect(or.left, or.top, or.right, or.bottom);
+ 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);
+ image = CGImageCreate(Dx(r), Dy(r), 8, 32, bpl,
+ CGColorSpaceCreateDeviceRGB(),
+ kCGImageAlphaNoneSkipLast,
+ provider, 0, 0, kCGRenderingIntentDefault);
+ CGDataProviderRelease(provider); // CGImageCreate did incref
+
+ 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
+flushmemscreen(Rectangle r)
+{
+ CGRect cgr;
+ CGContextRef context;
+ CGImageRef subimg;
+
+ QDBeginCGContext(GetWindowPort(osx.window), &context);
+
+ 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);
+ CGContextDrawImage(context, cgr, subimg);
+ CGContextFlush(context);
+ CGImageRelease(subimg);
+
+ QDEndCGContext(GetWindowPort(osx.window), &context);
+}
+
+void
+fullscreen(int x)
+{
+}
+
+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(struct Cursor *c)
+{
+ OSXCursor oc;
+ int i;
+
+ // SetCursor is deprecated, but what replaces it?
+ for(i=0; i<16; i++){
+ oc.data[i] = ((ushort*)c->set)[i];
+ oc.mask[i] = oc.data[i] | ((ushort*)c->clr)[i];
+ }
+ oc.hotSpot.h = - c->offset.x;
+ oc.hotSpot.v = - c->offset.y;
+ SetCursor(&oc);
+}
+
+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];
+ PasteboardRef apple;
+} clip;
+
+char*
+getsnarf(void)
+{
+ char *s, *t;
+ CFArrayRef flavors;
+ CFDataRef data;
+ CFIndex nflavor, ndata, j;
+ CFStringRef type;
+ ItemCount nitem;
+ PasteboardItemID id;
+ PasteboardSyncFlags flags;
+ UInt32 i;
+
+/* fprint(2, "applegetsnarf\n"); */
+ qlock(&clip.lk);
+ clip.apple = osx.snarf;
+ if(clip.apple == nil){
+ if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){
+ fprint(2, "apple pasteboard create failed\n");
+ qunlock(&clip.lk);
+ return nil;
+ }
+ }
+ flags = PasteboardSynchronize(clip.apple);
+ if(flags&kPasteboardClientIsOwner){
+ s = strdup(clip.buf);
+ qunlock(&clip.lk);
+ return s;
+ }
+ if(PasteboardGetItemCount(clip.apple, &nitem) != noErr){
+ fprint(2, "apple pasteboard get item count failed\n");
+ qunlock(&clip.lk);
+ return nil;
+ }
+ for(i=1; i<=nitem; i++){
+ if(PasteboardGetItemIdentifier(clip.apple, i, &id) != noErr)
+ continue;
+ if(PasteboardCopyItemFlavors(clip.apple, id, &flavors) != noErr)
+ continue;
+ nflavor = CFArrayGetCount(flavors);
+ for(j=0; j<nflavor; j++){
+ type = (CFStringRef)CFArrayGetValueAtIndex(flavors, j);
+ if(!UTTypeConformsTo(type, CFSTR("public.utf16-plain-text")))
+ continue;
+ if(PasteboardCopyItemFlavorData(clip.apple, id, type, &data) != noErr)
+ continue;
+ ndata = CFDataGetLength(data);
+ qunlock(&clip.lk);
+ s = smprint("%.*S", ndata/2, (Rune*)CFDataGetBytePtr(data));
+ CFRelease(flavors);
+ CFRelease(data);
+ for(t=s; *t; t++)
+ if(*t == '\r')
+ *t = '\n';
+ return s;
+ }
+ CFRelease(flavors);
+ }
+ qunlock(&clip.lk);
+ return nil;
+}
+
+void
+putsnarf(char *s)
+{
+ CFDataRef cfdata;
+ PasteboardSyncFlags flags;
+
+/* fprint(2, "appleputsnarf\n"); */
+
+ if(strlen(s) >= SnarfSize)
+ return;
+ qlock(&clip.lk);
+ strcpy(clip.buf, s);
+ runesnprint(clip.rbuf, nelem(clip.rbuf), "%s", s);
+ clip.apple = osx.snarf;
+ if(PasteboardClear(clip.apple) != noErr){
+ fprint(2, "apple pasteboard clear failed\n");
+ qunlock(&clip.lk);
+ return;
+ }
+ flags = PasteboardSynchronize(clip.apple);
+ if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){
+ fprint(2, "apple pasteboard cannot assert ownership\n");
+ qunlock(&clip.lk);
+ return;
+ }
+ cfdata = CFDataCreate(kCFAllocatorDefault,
+ (uchar*)clip.rbuf, runestrlen(clip.rbuf)*2);
+ if(cfdata == nil){
+ fprint(2, "apple pasteboard cfdatacreate failed\n");
+ qunlock(&clip.lk);
+ return;
+ }
+ if(PasteboardPutItemFlavor(clip.apple, (PasteboardItemID)1,
+ CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){
+ fprint(2, "apple pasteboard putitem failed\n");
+ CFRelease(cfdata);
+ qunlock(&clip.lk);
+ return;
+ }
+ /* CFRelease(cfdata); ??? */
+ qunlock(&clip.lk);
+}
+
diff --git a/src/9vx/stub.c b/src/9vx/stub.c
@@ -1,5 +1,10 @@
+
#define WANT_M
+#ifdef __APPLE__
+#define __DARWIN_UNIX03 0
+#endif
+
#include "u.h"
#include <sched.h>
#include <signal.h>