mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
devdraw: draft cocoa support
R=rsc CC=plan9port.codebot http://codereview.appspot.com/4974060
This commit is contained in:
parent
f0a4e8bd6c
commit
a287dbab23
8 changed files with 1340 additions and 0 deletions
|
@ -10,6 +10,7 @@ Anthony Sorace <a@9srv.net>
|
||||||
Arvindh Rajesh Tamilmani <art@a-30.net>
|
Arvindh Rajesh Tamilmani <art@a-30.net>
|
||||||
Benjamin Huntsman <BHuntsman@mail2.cu-portland.edu>
|
Benjamin Huntsman <BHuntsman@mail2.cu-portland.edu>
|
||||||
David du Colombier <0intro@gmail.com>
|
David du Colombier <0intro@gmail.com>
|
||||||
|
David Jeannot <djeannot24@gmail.com>
|
||||||
David Swasey <david.swasey@gmail.com>
|
David Swasey <david.swasey@gmail.com>
|
||||||
Enrique Soriano <enrique.soriano@gmail.com>
|
Enrique Soriano <enrique.soriano@gmail.com>
|
||||||
Eoghan Sherry <ejsherry@gmail.com>
|
Eoghan Sherry <ejsherry@gmail.com>
|
||||||
|
|
|
@ -751,6 +751,10 @@ texttype(Text *t, Rune r)
|
||||||
typecommit(t);
|
typecommit(t);
|
||||||
cut(t, t, nil, TRUE, FALSE, nil, 0);
|
cut(t, t, nil, TRUE, FALSE, nil, 0);
|
||||||
return;
|
return;
|
||||||
|
case Kcmd+'z': /* %Z: undo */
|
||||||
|
typecommit(t);
|
||||||
|
undo(t, nil, nil, TRUE, 0, nil, 0);
|
||||||
|
return;
|
||||||
|
|
||||||
Tagdown:
|
Tagdown:
|
||||||
/* expand tag to show all text */
|
/* expand tag to show all text */
|
||||||
|
|
19
src/cmd/devdraw/cocoa-screen.h
Normal file
19
src/cmd/devdraw/cocoa-screen.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#define setcursor dsetcursor
|
||||||
|
|
||||||
|
Memimage *attachscreen(char*, char*);
|
||||||
|
void setmouse(Point);
|
||||||
|
void setcursor(Cursor*);
|
||||||
|
void setlabel(char*);
|
||||||
|
char* getsnarf(void);
|
||||||
|
void putsnarf(char*);
|
||||||
|
|
||||||
|
void mousetrack(int, int, int, int);
|
||||||
|
void keystroke(int);
|
||||||
|
void kicklabel(char*);
|
||||||
|
|
||||||
|
void servep9p(void);
|
||||||
|
void zlock(void);
|
||||||
|
void zunlock(void);
|
||||||
|
|
||||||
|
Rectangle mouserect;
|
||||||
|
int mouseresized;
|
835
src/cmd/devdraw/cocoa-screen.m
Normal file
835
src/cmd/devdraw/cocoa-screen.m
Normal file
|
@ -0,0 +1,835 @@
|
||||||
|
/*
|
||||||
|
* Cocoa's event loop must be in the main thread.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define Point OSXPoint
|
||||||
|
#define Rect OSXRect
|
||||||
|
#define Cursor OSXCursor
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
#undef Rect
|
||||||
|
#undef Point
|
||||||
|
#undef Cursor
|
||||||
|
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include "cocoa-thread.h"
|
||||||
|
#include <draw.h>
|
||||||
|
#include <memdraw.h>
|
||||||
|
#include <keyboard.h>
|
||||||
|
#include <cursor.h>
|
||||||
|
#include "cocoa-screen.h"
|
||||||
|
#include "osx-keycodes.h"
|
||||||
|
#include "devdraw.h"
|
||||||
|
#include "glendapng.h"
|
||||||
|
|
||||||
|
#define DEBUG if(0)NSLog
|
||||||
|
|
||||||
|
AUTOFRAMEWORK(Cocoa)
|
||||||
|
|
||||||
|
#define panic sysfatal
|
||||||
|
|
||||||
|
struct {
|
||||||
|
NSWindow *obj;
|
||||||
|
NSString *label;
|
||||||
|
char *winsize;
|
||||||
|
int ispositioned;
|
||||||
|
|
||||||
|
NSImage *img;
|
||||||
|
Memimage *imgbuf;
|
||||||
|
NSSize imgsize;
|
||||||
|
|
||||||
|
QLock lock;
|
||||||
|
Rendez meeting;
|
||||||
|
NSRect flushr;
|
||||||
|
int osxdrawing;
|
||||||
|
int p9pflushing;
|
||||||
|
int isresizing;
|
||||||
|
} win;
|
||||||
|
|
||||||
|
@interface appdelegate : NSObject
|
||||||
|
+(void)callmakewin:(id)arg; @end
|
||||||
|
@interface appthreads : NSObject
|
||||||
|
+(void)callservep9p:(id)arg; @end
|
||||||
|
@interface appview : NSView @end
|
||||||
|
|
||||||
|
int chatty;
|
||||||
|
int multitouch = 1;
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: devdraw (don't run directly)\n");
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'D':
|
||||||
|
chatty++;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
multitouch = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore arguments. They're only for good ps -a listings.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
[NSApplication sharedApplication];
|
||||||
|
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||||
|
[NSApp setDelegate:[appdelegate new]];
|
||||||
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
[NSApp run];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void eresized(int);
|
||||||
|
static void getmousepos(void);
|
||||||
|
static void makemenu(NSString*);
|
||||||
|
static void makewin();
|
||||||
|
static void seticon(NSString*);
|
||||||
|
|
||||||
|
@implementation appdelegate
|
||||||
|
- (void)applicationDidFinishLaunching:(id)arg
|
||||||
|
{
|
||||||
|
[NSApplication detachDrawingThread:@selector(callservep9p:)
|
||||||
|
toTarget:[appthreads class] withObject:nil];
|
||||||
|
}
|
||||||
|
+ (void)callmakewin:(id)arg
|
||||||
|
{
|
||||||
|
makewin();
|
||||||
|
}
|
||||||
|
- (void)windowDidResize:(id)arg
|
||||||
|
{
|
||||||
|
eresized(1);
|
||||||
|
}
|
||||||
|
- (void)windowDidBecomeKey:(id)arg
|
||||||
|
{
|
||||||
|
getmousepos();
|
||||||
|
}
|
||||||
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(id)arg
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation appthreads
|
||||||
|
+(void)callservep9p:(id)arg
|
||||||
|
{
|
||||||
|
servep9p();
|
||||||
|
[NSApp terminate:self];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
Memimage*
|
||||||
|
attachscreen(char *label, char *winsize)
|
||||||
|
{
|
||||||
|
static int first = 1;
|
||||||
|
|
||||||
|
if(! first--)
|
||||||
|
panic("attachscreen called twice");
|
||||||
|
|
||||||
|
if(label == nil)
|
||||||
|
label = "gnot a label";
|
||||||
|
|
||||||
|
win.label = [[NSString alloc] initWithUTF8String:label];
|
||||||
|
win.meeting.l = &win.lock;
|
||||||
|
win.winsize = strdup(winsize);
|
||||||
|
|
||||||
|
makemenu(win.label);
|
||||||
|
|
||||||
|
// make NSWindow in the main thread,
|
||||||
|
// else no resize cursor when resizing.
|
||||||
|
[appdelegate
|
||||||
|
performSelectorOnMainThread:@selector(callmakewin:)
|
||||||
|
withObject:nil
|
||||||
|
waitUntilDone:YES];
|
||||||
|
// makewin();
|
||||||
|
|
||||||
|
seticon(win.label);
|
||||||
|
|
||||||
|
eresized(0);
|
||||||
|
|
||||||
|
return win.imgbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
makewin(id winsize)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
int style;
|
||||||
|
NSWindow *w;
|
||||||
|
NSRect r, sr;
|
||||||
|
Rectangle wr;
|
||||||
|
|
||||||
|
s = win.winsize;
|
||||||
|
|
||||||
|
if(s && *s){
|
||||||
|
if(parsewinsize(s, &wr, &win.ispositioned) < 0)
|
||||||
|
sysfatal("%r");
|
||||||
|
}else{
|
||||||
|
sr = [[NSScreen mainScreen] frame];
|
||||||
|
wr = Rect(0, 0, sr.size.width*2/3, sr.size.height*2/3);
|
||||||
|
}
|
||||||
|
// The origin is the left-bottom corner with Cocoa.
|
||||||
|
// Does the following work with any rectangles?
|
||||||
|
r = NSMakeRect(wr.min.x, r.size.height-wr.min.y, Dx(wr), Dy(wr));
|
||||||
|
|
||||||
|
style = NSTitledWindowMask
|
||||||
|
| NSClosableWindowMask
|
||||||
|
| NSResizableWindowMask
|
||||||
|
| NSMiniaturizableWindowMask;
|
||||||
|
|
||||||
|
w = [[NSWindow alloc]
|
||||||
|
initWithContentRect:r
|
||||||
|
styleMask:style
|
||||||
|
backing:NSBackingStoreBuffered
|
||||||
|
defer:NO];
|
||||||
|
|
||||||
|
[w setAcceptsMouseMovedEvents:YES];
|
||||||
|
#if OSX_VERSION >= 100700
|
||||||
|
[w setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
|
||||||
|
#endif
|
||||||
|
[w setContentView:[appview new]];
|
||||||
|
[w setDelegate:[NSApp delegate]];
|
||||||
|
[w setMinSize:NSMakeSize(128,128)];
|
||||||
|
[[w contentView] setAcceptsTouchEvents:YES];
|
||||||
|
|
||||||
|
if(win.ispositioned == 0)
|
||||||
|
[w center];
|
||||||
|
|
||||||
|
[w setTitle:win.label];
|
||||||
|
[w makeKeyAndOrderFront:nil];
|
||||||
|
|
||||||
|
win.obj = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendmouse(int);
|
||||||
|
|
||||||
|
static void
|
||||||
|
eresized(int new)
|
||||||
|
{
|
||||||
|
static int first = 1;
|
||||||
|
uint ch;
|
||||||
|
NSSize size;
|
||||||
|
Rectangle r;
|
||||||
|
Memimage *m;
|
||||||
|
int bpl;
|
||||||
|
|
||||||
|
if(first--)
|
||||||
|
memimageinit();
|
||||||
|
|
||||||
|
size = [[win.obj contentView] bounds].size;
|
||||||
|
DEBUG(@"eresized called new=%d, [%.0f %.0f] -> [%.0f %.0f]", new,
|
||||||
|
win.imgsize.width, win.imgsize.height, size.width, size.height);
|
||||||
|
|
||||||
|
r = Rect(0, 0, size.width, size.height);
|
||||||
|
ch = XBGR32;
|
||||||
|
m = allocmemimage(r, ch);
|
||||||
|
if(m == nil)
|
||||||
|
panic("allocmemimage: %r");
|
||||||
|
if(m->data == nil)
|
||||||
|
panic("m->data == nil");
|
||||||
|
|
||||||
|
bpl = bytesperline(r, 32);
|
||||||
|
|
||||||
|
CGDataProviderRef dp;
|
||||||
|
CGImageRef i;
|
||||||
|
CGColorSpaceRef cs;
|
||||||
|
|
||||||
|
dp = CGDataProviderCreateWithData(0, m->data->bdata, Dy(r)*bpl, 0);
|
||||||
|
cs = CGColorSpaceCreateDeviceRGB();
|
||||||
|
i = CGImageCreate(Dx(r), Dy(r), 8, 32, bpl,
|
||||||
|
cs, kCGImageAlphaNone, dp, 0, 0, kCGRenderingIntentDefault);
|
||||||
|
|
||||||
|
_drawreplacescreenimage(m);
|
||||||
|
if(win.img)
|
||||||
|
[win.img release];
|
||||||
|
|
||||||
|
win.img = [[NSImage alloc] initWithCGImage:i size:size];
|
||||||
|
win.imgbuf = m;
|
||||||
|
win.imgsize = size;
|
||||||
|
|
||||||
|
CGColorSpaceRelease(cs);
|
||||||
|
CGDataProviderRelease(dp);
|
||||||
|
CGImageRelease(i);
|
||||||
|
|
||||||
|
if(new){
|
||||||
|
win.isresizing = 1; // to call before mousetrack
|
||||||
|
sendmouse(1);
|
||||||
|
}
|
||||||
|
DEBUG(@"eresized exit");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void getgesture(NSEvent*);
|
||||||
|
static void getkeyboard(NSEvent*);
|
||||||
|
static void getmouse(NSEvent*);
|
||||||
|
|
||||||
|
@implementation appview
|
||||||
|
|
||||||
|
- (void)mouseMoved:(NSEvent*)e{ getmouse(e);}
|
||||||
|
- (void)mouseDown:(NSEvent*)e{ getmouse(e);}
|
||||||
|
- (void)mouseDragged:(NSEvent*)e{ getmouse(e);}
|
||||||
|
- (void)mouseUp:(NSEvent*)e{ getmouse(e);}
|
||||||
|
- (void)otherMouseDown:(NSEvent*)e{ getmouse(e);}
|
||||||
|
- (void)otherMouseDragged:(NSEvent*)e{ getmouse(e);}
|
||||||
|
- (void)otherMouseUp:(NSEvent*)e{ getmouse(e);}
|
||||||
|
- (void)rightMouseDown:(NSEvent*)e{ getmouse(e);}
|
||||||
|
- (void)rightMouseDragged:(NSEvent*)e{ getmouse(e);}
|
||||||
|
- (void)rightMouseUp:(NSEvent*)e{ getmouse(e);}
|
||||||
|
- (void)scrollWheel:(NSEvent*)e{ getmouse(e);}
|
||||||
|
|
||||||
|
- (void)keyDown:(NSEvent*)e{ getkeyboard(e);}
|
||||||
|
- (void)flagsChanged:(NSEvent*)e{ getkeyboard(e);}
|
||||||
|
|
||||||
|
- (void)magnifyWithEvent:(NSEvent*)e{ DEBUG(@"magnifyWithEvent"); getgesture(e);}
|
||||||
|
- (void)swipeWithEvent:(NSEvent*)e{ DEBUG(@"swipeWithEvent"); getgesture(e);}
|
||||||
|
- (void)touchesEndedWithEvent:(NSEvent*)e{ DEBUG(@"touchesEndedWithEvent"); getgesture(e);}
|
||||||
|
|
||||||
|
- (BOOL)acceptsFirstResponder{ return YES; } // to receive mouseMoved events
|
||||||
|
- (BOOL)isFlipped{ return YES; }
|
||||||
|
- (BOOL)isOpaque{ return YES; } // to disable background painting before drawRect calls
|
||||||
|
|
||||||
|
- (void)drawRect:(NSRect)r
|
||||||
|
{
|
||||||
|
NSRect sr;
|
||||||
|
NSView *v;
|
||||||
|
|
||||||
|
v = [win.obj contentView];
|
||||||
|
|
||||||
|
DEBUG(@"drawRect called [%.0f %.0f] [%.0f %.0f]",
|
||||||
|
r.origin.x, r.origin.y, r.size.width, r.size.height);
|
||||||
|
|
||||||
|
if(! NSEqualSizes([v bounds].size, win.imgsize)){
|
||||||
|
DEBUG(@"drawRect: contentview & img don't correspond: [%.0f %.0f] [%.0f %.0f]",
|
||||||
|
[v bounds].size.width, [v bounds].size.height,
|
||||||
|
win.imgsize.width, win.imgsize.height);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qlock(win.meeting.l);
|
||||||
|
if(win.isresizing){
|
||||||
|
if(! NSEqualRects(r, [v bounds])){
|
||||||
|
DEBUG(@"drawRect reject osx");
|
||||||
|
goto Return;
|
||||||
|
}
|
||||||
|
win.isresizing = 0;
|
||||||
|
DEBUG(@"drawRect serve osx");
|
||||||
|
}else{
|
||||||
|
if(! NSEqualRects(r, win.flushr)){
|
||||||
|
DEBUG(@"drawRect reject p9p");
|
||||||
|
goto Return;
|
||||||
|
}
|
||||||
|
DEBUG(@"drawRect serve p9p");
|
||||||
|
}
|
||||||
|
win.flushr = r;
|
||||||
|
win.osxdrawing = 1;
|
||||||
|
rwakeup(&win.meeting);
|
||||||
|
DEBUG(@"drawRect rsleep for p9pflushing=1");
|
||||||
|
while(win.p9pflushing == 0)
|
||||||
|
rsleep(&win.meeting);
|
||||||
|
|
||||||
|
DEBUG(@"drawRect drawInRect [%.0f %.0f] [%.0f %.0f]",
|
||||||
|
r.origin.x, r.origin.y, r.size.width, r.size.height);
|
||||||
|
|
||||||
|
sr = [v convertRect:r fromView:nil];
|
||||||
|
[win.img drawInRect:r fromRect:sr
|
||||||
|
operation:NSCompositeCopy fraction:1
|
||||||
|
respectFlipped:YES hints:nil];
|
||||||
|
|
||||||
|
[win.obj flushWindow];
|
||||||
|
|
||||||
|
win.osxdrawing = 0;
|
||||||
|
rwakeup(&win.meeting);
|
||||||
|
Return:
|
||||||
|
DEBUG(@"drawRect exit");
|
||||||
|
qunlock(win.meeting.l);
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
void
|
||||||
|
_flushmemscreen(Rectangle r)
|
||||||
|
{
|
||||||
|
NSRect rect;
|
||||||
|
NSView *v;
|
||||||
|
|
||||||
|
v = [win.obj contentView];
|
||||||
|
rect = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r));
|
||||||
|
|
||||||
|
DEBUG(@"_flushmemscreen called [%.0f %.0f] [%.0f %.0f]",
|
||||||
|
rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
|
||||||
|
qlock(win.meeting.l);
|
||||||
|
if(win.osxdrawing == 0){
|
||||||
|
DEBUG(@"_flushmemscreen setNeedsDisplayInRect");
|
||||||
|
[v setNeedsDisplayInRect:rect];
|
||||||
|
win.flushr = rect;
|
||||||
|
DEBUG(@"_flushmemscreen rsleep for osxdrawing=1");
|
||||||
|
while(win.osxdrawing == 0)
|
||||||
|
rsleep(&win.meeting);
|
||||||
|
}
|
||||||
|
if(! NSEqualRects(rect, win.flushr)){
|
||||||
|
qunlock(win.meeting.l);
|
||||||
|
DEBUG(@"_flushmemscreen bad rectangle");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
win.flushr = NSMakeRect(0,0,0,0);
|
||||||
|
win.p9pflushing = 1;
|
||||||
|
rwakeup(&win.meeting);
|
||||||
|
DEBUG(@"_flushmemscreen rsleep for osxdrawing=0");
|
||||||
|
while(win.osxdrawing)
|
||||||
|
rsleep(&win.meeting);
|
||||||
|
|
||||||
|
win.p9pflushing = 0;
|
||||||
|
DEBUG(@"_flushmemscreen exit");
|
||||||
|
qunlock(win.meeting.l);
|
||||||
|
}
|
||||||
|
|
||||||
|
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',
|
||||||
|
};
|
||||||
|
|
||||||
|
int kalting;
|
||||||
|
int kbuttons;
|
||||||
|
int mbuttons;
|
||||||
|
Point mpos;
|
||||||
|
int scroll;
|
||||||
|
|
||||||
|
static void
|
||||||
|
getkeyboard(NSEvent *e)
|
||||||
|
{
|
||||||
|
uint code;
|
||||||
|
int k, m;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
m = [e modifierFlags];
|
||||||
|
|
||||||
|
switch([e type]){
|
||||||
|
case NSKeyDown:
|
||||||
|
kalting = 0;
|
||||||
|
c = [[e characters] characterAtIndex:0];
|
||||||
|
if(m & NSCommandKeyMask){
|
||||||
|
|
||||||
|
// If I add cmd+h in the menu, does the combination
|
||||||
|
// appear here? If it doesn't, remove the following
|
||||||
|
//
|
||||||
|
// // OS X interprets a few no matter what we do,
|
||||||
|
// switch(c) {
|
||||||
|
// case 'm': // minimize window
|
||||||
|
// case 'h': // hide window
|
||||||
|
// case 'H': // hide others
|
||||||
|
// case 'q': // quit
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
if(' '<=c && c<='~') {
|
||||||
|
keystroke(Kcmd+c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// to undersand
|
||||||
|
k = c;
|
||||||
|
code = [e keyCode];
|
||||||
|
if(code < nelem(keycvt) && keycvt[code])
|
||||||
|
k = keycvt[code];
|
||||||
|
if(k == 0)
|
||||||
|
return;
|
||||||
|
if(k > 0)
|
||||||
|
keystroke(k);
|
||||||
|
else
|
||||||
|
keystroke(c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSFlagsChanged:
|
||||||
|
if(mbuttons || kbuttons){
|
||||||
|
kbuttons = 0;
|
||||||
|
if(m & NSAlternateKeyMask)
|
||||||
|
kbuttons |= 2;
|
||||||
|
if(m & NSCommandKeyMask)
|
||||||
|
kbuttons |= 4;
|
||||||
|
sendmouse(0);
|
||||||
|
}else
|
||||||
|
if(m & NSAlternateKeyMask) {
|
||||||
|
kalting = 1;
|
||||||
|
keystroke(Kalt);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("getkey: unexpected event type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getmousepos(void)
|
||||||
|
{
|
||||||
|
NSPoint p;
|
||||||
|
|
||||||
|
p = [win.obj mouseLocationOutsideOfEventStream];
|
||||||
|
p = [[win.obj contentView] convertPoint:p fromView:nil];
|
||||||
|
// DEBUG(@"getmousepos: %0.f %0.f", p.x, p.y);
|
||||||
|
mpos = Pt(p.x, p.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
getmouse(NSEvent *e)
|
||||||
|
{
|
||||||
|
int b, m;
|
||||||
|
float d;
|
||||||
|
|
||||||
|
getmousepos();
|
||||||
|
|
||||||
|
switch([e type]){
|
||||||
|
case NSLeftMouseDown:
|
||||||
|
case NSLeftMouseUp:
|
||||||
|
case NSOtherMouseDown:
|
||||||
|
case NSOtherMouseUp:
|
||||||
|
case NSRightMouseDown:
|
||||||
|
case NSRightMouseUp:
|
||||||
|
|
||||||
|
b = [NSEvent pressedMouseButtons];
|
||||||
|
b = b&~6 | (b&4)>>1 | (b&2)<<1;
|
||||||
|
b = mouseswap(b);
|
||||||
|
|
||||||
|
if(b == 1){
|
||||||
|
m = [e modifierFlags];
|
||||||
|
if(m & NSAlternateKeyMask) {
|
||||||
|
b = 2;
|
||||||
|
// Take the ALT away from the keyboard handler.
|
||||||
|
if(kalting) {
|
||||||
|
kalting = 0;
|
||||||
|
keystroke(Kalt);
|
||||||
|
}
|
||||||
|
}else
|
||||||
|
if(m & NSCommandKeyMask)
|
||||||
|
b = 4;
|
||||||
|
}
|
||||||
|
mbuttons = b;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSScrollWheel:
|
||||||
|
#if OSX_VERSION >= 100700
|
||||||
|
d = [e scrollingDeltaY];
|
||||||
|
#else
|
||||||
|
d = [e deltaY];
|
||||||
|
#endif
|
||||||
|
if(d>0)
|
||||||
|
scroll = 8;
|
||||||
|
else if(d<0)
|
||||||
|
scroll = 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSMouseMoved:
|
||||||
|
case NSLeftMouseDragged:
|
||||||
|
case NSRightMouseDragged:
|
||||||
|
case NSOtherMouseDragged:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
panic("getmouse: unexpected event type");
|
||||||
|
}
|
||||||
|
sendmouse(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendexec(int);
|
||||||
|
static void sendcmd(int, int*);
|
||||||
|
|
||||||
|
static void
|
||||||
|
getgesture(NSEvent *e)
|
||||||
|
{
|
||||||
|
static int undo;
|
||||||
|
int dx, dy;
|
||||||
|
|
||||||
|
switch([e type]){
|
||||||
|
|
||||||
|
case NSEventTypeMagnify:
|
||||||
|
#if OSX_VERSION >= 100700
|
||||||
|
[win.obj toggleFullScreen:nil];
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSEventTypeSwipe:
|
||||||
|
|
||||||
|
dx = - [e deltaX];
|
||||||
|
dy = - [e deltaY];
|
||||||
|
|
||||||
|
if(dx == -1)
|
||||||
|
sendcmd('x', &undo);
|
||||||
|
else
|
||||||
|
if(dx == +1)
|
||||||
|
sendcmd('v', &undo);
|
||||||
|
else
|
||||||
|
if(dy == -1)
|
||||||
|
sendexec(0);
|
||||||
|
else
|
||||||
|
if(dy == +1)
|
||||||
|
sendexec(1);
|
||||||
|
else // fingers lifted
|
||||||
|
undo = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// When I lift the fingers from the trackpad, I
|
||||||
|
// receive 1, 2, or 3 events "touchesEndedWithEvent".
|
||||||
|
// Their type is either generic (NSEventTypeGesture)
|
||||||
|
// or specific (NSEventTypeSwipe for example). I
|
||||||
|
// always receive at least 1 event of specific type.
|
||||||
|
|
||||||
|
// I sometimes receive NSEventTypeEndGesture
|
||||||
|
// apparently, even without implementing
|
||||||
|
// "endGestureWithEvent"
|
||||||
|
// I even received a NSEventTypeBeginGesture once.
|
||||||
|
|
||||||
|
case NSEventTypeBeginGesture:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NSEventTypeGesture:
|
||||||
|
case NSEventTypeEndGesture:
|
||||||
|
// do a undo here? because 2 times I had the impression undo was still 1
|
||||||
|
// after having lifted my fingers
|
||||||
|
undo = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DEBUG(@"getgesture: unexpected event type: %d", [e type]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sendcmd(int c, int *undo)
|
||||||
|
{
|
||||||
|
if(*undo)
|
||||||
|
c = 'z';
|
||||||
|
*undo = ! *undo;
|
||||||
|
keystroke(Kcmd+c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sendexec(int giveargs)
|
||||||
|
{
|
||||||
|
mbuttons = 2;
|
||||||
|
sendmouse(0);
|
||||||
|
|
||||||
|
if(giveargs){
|
||||||
|
mbuttons |= 1;
|
||||||
|
sendmouse(0);
|
||||||
|
}
|
||||||
|
mbuttons = 0;
|
||||||
|
sendmouse(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint
|
||||||
|
msec(void)
|
||||||
|
{
|
||||||
|
return nsec()/1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sendmouse(int resized)
|
||||||
|
{
|
||||||
|
if(resized)
|
||||||
|
mouseresized = 1;
|
||||||
|
mouserect = win.imgbuf->r;
|
||||||
|
mousetrack(mpos.x, mpos.y, kbuttons|mbuttons|scroll, msec());
|
||||||
|
scroll = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setmouse(Point p)
|
||||||
|
{
|
||||||
|
NSPoint q;
|
||||||
|
NSRect r;
|
||||||
|
|
||||||
|
r = [[NSScreen mainScreen] frame];
|
||||||
|
|
||||||
|
q = NSMakePoint(p.x,p.y);
|
||||||
|
q = [[win.obj contentView] convertPoint:q toView:nil];
|
||||||
|
q = [win.obj convertBaseToScreen:q];
|
||||||
|
q.y = r.size.height - q.y;
|
||||||
|
|
||||||
|
CGWarpMouseCursorPosition(q);
|
||||||
|
|
||||||
|
// race condition
|
||||||
|
mpos = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setBadgeLabel don't have to be in this function.
|
||||||
|
// Remove seticon's argument too.
|
||||||
|
static void
|
||||||
|
seticon(NSString *s)
|
||||||
|
{
|
||||||
|
NSData *d;
|
||||||
|
NSImage *i;
|
||||||
|
|
||||||
|
d = [[NSData alloc]
|
||||||
|
initWithBytes:glenda_png
|
||||||
|
length:(sizeof glenda_png)];
|
||||||
|
|
||||||
|
i = [[NSImage alloc] initWithData:d];
|
||||||
|
if(i){
|
||||||
|
[NSApp setApplicationIconImage:i];
|
||||||
|
[[NSApp dockTile] display];
|
||||||
|
[[NSApp dockTile] setBadgeLabel:s];
|
||||||
|
}
|
||||||
|
[d release];
|
||||||
|
[i release];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Menu should be called during app creation, not window creation.
|
||||||
|
// See ./osx-delegate.m implementation.
|
||||||
|
|
||||||
|
// If an application supports fullscreen, it should
|
||||||
|
// add an "Enter Full Screen" menu item to the View
|
||||||
|
// menu. The menu item is now available through
|
||||||
|
// Xcode 4. You can also add the item
|
||||||
|
// programmatically, with toggleFullScreen: as the
|
||||||
|
// action, nil as the target, and cmd-ctrl-f as the
|
||||||
|
// key equivalent. AppKit will automatically update
|
||||||
|
// the menu item title as part of its menu item
|
||||||
|
// validation.
|
||||||
|
static void
|
||||||
|
makemenu(NSString *s)
|
||||||
|
{
|
||||||
|
NSString *title;
|
||||||
|
NSMenu *menu;
|
||||||
|
NSMenuItem *appmenu, *item;
|
||||||
|
|
||||||
|
menu = [NSMenu new];
|
||||||
|
appmenu = [NSMenuItem new];
|
||||||
|
[menu addItem:appmenu];
|
||||||
|
[NSApp setMenu:menu];
|
||||||
|
[menu release];
|
||||||
|
|
||||||
|
title = [@"Quit " stringByAppendingString:win.label];
|
||||||
|
item = [[NSMenuItem alloc]
|
||||||
|
initWithTitle:title
|
||||||
|
action:@selector(terminate:) keyEquivalent:@"q"];
|
||||||
|
|
||||||
|
menu = [NSMenu new];
|
||||||
|
[menu addItem:item];
|
||||||
|
[item release];
|
||||||
|
[appmenu setSubmenu:menu];
|
||||||
|
[appmenu release];
|
||||||
|
[menu release];
|
||||||
|
}
|
||||||
|
|
||||||
|
QLock snarfl;
|
||||||
|
|
||||||
|
char*
|
||||||
|
getsnarf(void)
|
||||||
|
{
|
||||||
|
NSString *s;
|
||||||
|
NSPasteboard *pb;
|
||||||
|
|
||||||
|
pb = [NSPasteboard generalPasteboard];
|
||||||
|
|
||||||
|
// use NSPasteboardTypeString instead of NSStringPboardType
|
||||||
|
qlock(&snarfl);
|
||||||
|
s = [pb stringForType:NSStringPboardType];
|
||||||
|
qunlock(&snarfl);
|
||||||
|
|
||||||
|
// change the pastebuffer here to see if s is
|
||||||
|
// altered. Move the lock accordingly.
|
||||||
|
|
||||||
|
if(s)
|
||||||
|
return strdup((char*)[s UTF8String]);
|
||||||
|
else
|
||||||
|
return nil;
|
||||||
|
// should I call autorelease here for example?
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
putsnarf(char *s)
|
||||||
|
{
|
||||||
|
NSArray *t;
|
||||||
|
NSString *str;
|
||||||
|
NSPasteboard *pb;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if(strlen(s) >= SnarfSize)
|
||||||
|
return;
|
||||||
|
|
||||||
|
t = [NSArray arrayWithObject:NSPasteboardTypeString];
|
||||||
|
pb = [NSPasteboard generalPasteboard];
|
||||||
|
str = [[NSString alloc] initWithUTF8String:s];
|
||||||
|
|
||||||
|
qlock(&snarfl);
|
||||||
|
[pb declareTypes:t owner:nil];
|
||||||
|
r = [pb setString:str forType:NSPasteboardTypeString];
|
||||||
|
qunlock(&snarfl);
|
||||||
|
|
||||||
|
if(!r)
|
||||||
|
DEBUG(@"putsnarf: setString failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
kicklabel(char *c)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setcursor(Cursor *c)
|
||||||
|
{
|
||||||
|
}
|
397
src/cmd/devdraw/cocoa-srv.c
Normal file
397
src/cmd/devdraw/cocoa-srv.c
Normal file
|
@ -0,0 +1,397 @@
|
||||||
|
/*
|
||||||
|
* Window system protocol server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include "cocoa-thread.h"
|
||||||
|
#include <draw.h>
|
||||||
|
#include <memdraw.h>
|
||||||
|
#include <keyboard.h>
|
||||||
|
#include <mouse.h>
|
||||||
|
#include <cursor.h>
|
||||||
|
#include <drawfcall.h>
|
||||||
|
#include "cocoa-screen.h"
|
||||||
|
#include "devdraw.h"
|
||||||
|
|
||||||
|
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 runmsg(Wsysmsg*);
|
||||||
|
void replymsg(Wsysmsg*);
|
||||||
|
void matchkbd(void);
|
||||||
|
void matchmouse(void);
|
||||||
|
|
||||||
|
|
||||||
|
QLock lk;
|
||||||
|
void
|
||||||
|
zlock(void)
|
||||||
|
{
|
||||||
|
qlock(&lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
zunlock(void)
|
||||||
|
{
|
||||||
|
qunlock(&lk);
|
||||||
|
}
|
||||||
|
|
||||||
|
int trace = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
servep9p(void)
|
||||||
|
{
|
||||||
|
uchar buf[4], *mbuf;
|
||||||
|
int nmbuf, n, nn;
|
||||||
|
Wsysmsg m;
|
||||||
|
|
||||||
|
fmtinstall('W', drawfcallfmt);
|
||||||
|
|
||||||
|
// notify(bell);
|
||||||
|
|
||||||
|
mbuf = nil;
|
||||||
|
nmbuf = 0;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
54
src/cmd/devdraw/cocoa-thread.c
Normal file
54
src/cmd/devdraw/cocoa-thread.c
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include "cocoa-thread.h"
|
||||||
|
|
||||||
|
static pthread_mutex_t initlock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
void
|
||||||
|
qlock(QLock *q)
|
||||||
|
{
|
||||||
|
if(q->init == 0){
|
||||||
|
pthread_mutex_lock(&initlock);
|
||||||
|
if(q->init == 0){
|
||||||
|
pthread_mutex_init(&q->m, nil);
|
||||||
|
q->init = 1;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&initlock);
|
||||||
|
}
|
||||||
|
pthread_mutex_lock(&q->m);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
qunlock(QLock *q)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&q->m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
rinit(Rendez *r)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&initlock);
|
||||||
|
if(r->init == 0){
|
||||||
|
pthread_cond_init(&r->c, nil);
|
||||||
|
r->init = 1;
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&initlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rsleep(Rendez *r)
|
||||||
|
{
|
||||||
|
if(r->init == 0)
|
||||||
|
rinit(r);
|
||||||
|
pthread_cond_wait(&r->c, &r->l->m);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rwakeup(Rendez *r)
|
||||||
|
{
|
||||||
|
if(r->init == 0)
|
||||||
|
rinit(r);
|
||||||
|
pthread_cond_signal(&r->c);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
27
src/cmd/devdraw/cocoa-thread.h
Normal file
27
src/cmd/devdraw/cocoa-thread.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#define QLock DQLock
|
||||||
|
#define qlock dqlock
|
||||||
|
#define qunlock dqunlock
|
||||||
|
#define Rendez DRendez
|
||||||
|
#define rsleep drsleep
|
||||||
|
#define rwakeup drwakeup
|
||||||
|
|
||||||
|
typedef struct QLock QLock;
|
||||||
|
typedef struct Rendez Rendez;
|
||||||
|
|
||||||
|
struct QLock
|
||||||
|
{
|
||||||
|
pthread_mutex_t m;
|
||||||
|
int init;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Rendez
|
||||||
|
{
|
||||||
|
QLock *l;
|
||||||
|
pthread_cond_t c;
|
||||||
|
int init;
|
||||||
|
};
|
||||||
|
|
||||||
|
void qlock(QLock*);
|
||||||
|
void qunlock(QLock*);
|
||||||
|
void rsleep(Rendez*);
|
||||||
|
int rwakeup(Rendez*); /* BUG: always returns 0 */
|
|
@ -38,6 +38,9 @@ CLEANFILES=latin1.h $O.mklatinkbd
|
||||||
%-objc.$O: %.m
|
%-objc.$O: %.m
|
||||||
$CC $CFLAGS -o $target $stem.m
|
$CC $CFLAGS -o $target $stem.m
|
||||||
|
|
||||||
|
cocoa: devdraw.o latin1.o mouseswap.o winsize.o osx-draw.o cocoa-screen-objc.o cocoa-srv.o cocoa-thread.o
|
||||||
|
$LD -o $target $prereq
|
||||||
|
|
||||||
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
|
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
|
$LD -o $target $prereq
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue