mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
devdraw: draft of new Cocoa-based devdraw
Can test with cd $PLAN9/src/cmd/devdraw mk devdraw-cocoa DEVDRAW=devdraw-cocoa colors
This commit is contained in:
parent
daea2c7d50
commit
113867b836
5 changed files with 1439 additions and 1 deletions
|
@ -7,7 +7,7 @@ WSYSOFILES=\
|
|||
latin1.$O\
|
||||
mouseswap.$O\
|
||||
winsize.$O\
|
||||
|
||||
|
||||
<|sh ./mkwsysrules.sh
|
||||
|
||||
OFILES=$WSYSOFILES
|
||||
|
@ -32,3 +32,12 @@ latin1.h: $PLAN9/lib/keyboard $O.mklatinkbd
|
|||
./$O.mklatinkbd -r $PLAN9/lib/keyboard | sed 's/, }/ }/' >$target
|
||||
|
||||
CLEANFILES=latin1.h $O.mklatinkbd
|
||||
|
||||
# Still in progress: Cocoa/Objective C version of devdraw
|
||||
|
||||
%-objc.$O: %.m
|
||||
$CC $CFLAGS -o $target $stem.m
|
||||
|
||||
devdraw-cocoa: devdraw.o latin1.o mouseswap.o winsize.o osx-screen-objc.o osx-draw.o osx-srv-objc.o osx-delegate-objc.o
|
||||
$LD -o $target $prereq
|
||||
|
||||
|
|
15
src/cmd/devdraw/osx-delegate.h
Normal file
15
src/cmd/devdraw/osx-delegate.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#import <Foundation/NSObject.h>
|
||||
#import <AppKit/NSMenu.h>
|
||||
|
||||
@class NSFileHandle;
|
||||
|
||||
@interface DevdrawDelegate : NSObject
|
||||
{
|
||||
NSFileHandle *readHandle;
|
||||
}
|
||||
+(void)populateMainMenu;
|
||||
+(void)populateApplicationMenu:(NSMenu *)aMenu;
|
||||
+(void)populateViewMenu:(NSMenu *)aMenu;
|
||||
+(void)populateWindowMenu:(NSMenu *)aMenu;
|
||||
+(void)populateHelpMenu:(NSMenu *)aMenu;
|
||||
@end
|
282
src/cmd/devdraw/osx-delegate.m
Normal file
282
src/cmd/devdraw/osx-delegate.m
Normal file
|
@ -0,0 +1,282 @@
|
|||
#define Point OSXPoint
|
||||
#define Rect OSXRect
|
||||
#define Cursor OSXCursor
|
||||
#import "osx-delegate.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#undef Cursor
|
||||
#undef Rect
|
||||
#undef Point
|
||||
|
||||
#include <u.h>
|
||||
#include <errno.h>
|
||||
#include <sys/select.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <memlayer.h>
|
||||
#include <keyboard.h>
|
||||
#include <mouse.h>
|
||||
#include <cursor.h>
|
||||
#include <drawfcall.h>
|
||||
|
||||
AUTOFRAMEWORK(Foundation)
|
||||
AUTOFRAMEWORK(AppKit)
|
||||
|
||||
extern int trace;
|
||||
|
||||
extern void fullscreen(int);
|
||||
extern void kbdevent(NSEvent *event);
|
||||
extern void mouseevent(NSEvent *event);
|
||||
extern void eresized(int);
|
||||
|
||||
extern void runmsg(Wsysmsg *m);
|
||||
extern void seticon();
|
||||
|
||||
@implementation DevdrawDelegate
|
||||
+(void)populateMainMenu
|
||||
{
|
||||
NSMenu *mainMenu = [[NSMenu alloc] initWithTitle:@"MainMenu"];
|
||||
NSMenuItem *menuItem;
|
||||
NSMenu *submenu;
|
||||
|
||||
menuItem = [mainMenu addItemWithTitle:@"Apple" action:NULL keyEquivalent:@""];
|
||||
submenu = [[NSMenu alloc] initWithTitle:@"Apple"];
|
||||
[NSApp performSelector:@selector(setAppleMenu:) withObject:submenu];
|
||||
[self populateApplicationMenu:submenu];
|
||||
[mainMenu setSubmenu:submenu forItem:menuItem];
|
||||
|
||||
menuItem = [mainMenu addItemWithTitle:@"View" action:NULL keyEquivalent:@""];
|
||||
submenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"View", "@The View menu")];
|
||||
[self populateViewMenu:submenu];
|
||||
[mainMenu setSubmenu:submenu forItem:menuItem];
|
||||
|
||||
menuItem = [mainMenu addItemWithTitle:@"Window" action:NULL keyEquivalent:@""];
|
||||
submenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Window", @"The Window menu")];
|
||||
[self populateWindowMenu:submenu];
|
||||
[mainMenu setSubmenu:submenu forItem:menuItem];
|
||||
[NSApp setWindowsMenu:submenu];
|
||||
|
||||
menuItem = [mainMenu addItemWithTitle:@"Help" action:NULL keyEquivalent:@""];
|
||||
submenu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Help", @"The Help menu")];
|
||||
[self populateHelpMenu:submenu];
|
||||
[mainMenu setSubmenu:submenu forItem:menuItem];
|
||||
|
||||
[NSApp setMainMenu:mainMenu];
|
||||
}
|
||||
|
||||
+(void)populateApplicationMenu:(NSMenu *)aMenu
|
||||
{
|
||||
NSString *applicationName = [[NSProcessInfo processInfo] processName];
|
||||
NSMenuItem *menuItem;
|
||||
|
||||
menuItem = [aMenu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"About", nil), applicationName]
|
||||
action:@selector(orderFrontStandardAboutPanel:)
|
||||
keyEquivalent:@""];
|
||||
[menuItem setTarget:NSApp];
|
||||
|
||||
[aMenu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Preferences...", nil)
|
||||
action:NULL
|
||||
keyEquivalent:@","];
|
||||
|
||||
[aMenu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Services", nil)
|
||||
action:NULL
|
||||
keyEquivalent:@""];
|
||||
NSMenu * servicesMenu = [[NSMenu alloc] initWithTitle:@"Services"];
|
||||
[aMenu setSubmenu:servicesMenu forItem:menuItem];
|
||||
[NSApp setServicesMenu:servicesMenu];
|
||||
|
||||
[aMenu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
menuItem = [aMenu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Hide", nil), applicationName]
|
||||
action:@selector(hide:)
|
||||
keyEquivalent:@"h"];
|
||||
[menuItem setTarget:NSApp];
|
||||
|
||||
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Hide Others", nil)
|
||||
action:@selector(hideOtherApplications:)
|
||||
keyEquivalent:@"h"];
|
||||
[menuItem setKeyEquivalentModifierMask:NSCommandKeyMask | NSAlternateKeyMask];
|
||||
[menuItem setTarget:NSApp];
|
||||
|
||||
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Show All", nil)
|
||||
action:@selector(unhideAllApplications:)
|
||||
keyEquivalent:@""];
|
||||
[menuItem setTarget:NSApp];
|
||||
|
||||
[aMenu addItem:[NSMenuItem separatorItem]];
|
||||
|
||||
menuItem = [aMenu addItemWithTitle:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Quit", nil), applicationName]
|
||||
action:@selector(terminate:)
|
||||
keyEquivalent:@"q"];
|
||||
[menuItem setTarget:NSApp];
|
||||
}
|
||||
|
||||
+(void)populateViewMenu:(NSMenu *)aMenu
|
||||
{
|
||||
NSMenuItem *menuItem;
|
||||
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Full Screen", nil)
|
||||
action:@selector(fullscreen:) keyEquivalent:@"F"];
|
||||
[menuItem setTarget:NSApp];
|
||||
|
||||
menuItem = [aMenu addItemWithTitle:NSLocalizedString(@"Cmd-F exits full screen", nil)
|
||||
action:NULL keyEquivalent:@""];
|
||||
}
|
||||
|
||||
+(void)populateWindowMenu:(NSMenu *)aMenu
|
||||
{
|
||||
}
|
||||
|
||||
+(void)populateHelpMenu:(NSMenu *)aMenu
|
||||
{
|
||||
}
|
||||
|
||||
- (void)applicationWillFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
seticon();
|
||||
}
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)notification
|
||||
{
|
||||
[DevdrawDelegate populateMainMenu];
|
||||
|
||||
// [NSThread detachNewThreadSelector:@selector(devdrawMain)
|
||||
// toTarget:self withObject:nil];
|
||||
// [NSApplication detachDrawingThread:@selector(devdrawMain)
|
||||
// toTarget:self withObject:nil];
|
||||
[readHandle waitForDataInBackgroundAndNotify];
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if(self = [super init]){
|
||||
readHandle = [[NSFileHandle alloc] initWithFileDescriptor:3 closeOnDealloc:YES];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(devdrawMain:)
|
||||
name:NSFileHandleDataAvailableNotification
|
||||
object:readHandle];
|
||||
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self
|
||||
selector:@selector(receiveWake:)
|
||||
name:NSWorkspaceDidWakeNotification
|
||||
object:NULL];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[readHandle release];
|
||||
return [super dealloc];
|
||||
}
|
||||
|
||||
- (void)devdrawMain:(NSNotification *)notification
|
||||
{
|
||||
uchar buf[4], *mbuf;
|
||||
int nmbuf, n, nn;
|
||||
Wsysmsg m;
|
||||
NSData *data;
|
||||
|
||||
mbuf = nil;
|
||||
nmbuf = 0;
|
||||
|
||||
data = [readHandle readDataOfLength:4];
|
||||
if([data length] == 4){
|
||||
[data getBytes:buf length:4];
|
||||
GET(buf, n);
|
||||
if(n > nmbuf){
|
||||
free(mbuf);
|
||||
mbuf = malloc(4+n);
|
||||
if(mbuf == nil)
|
||||
sysfatal("malloc: %r");
|
||||
nmbuf = n;
|
||||
}
|
||||
memmove(mbuf, buf, 4);
|
||||
data = [readHandle readDataOfLength:(n-4)];
|
||||
[data getBytes:(mbuf+4)];
|
||||
nn = [data length];
|
||||
if(nn != n-4)
|
||||
sysfatal("eof during message");
|
||||
|
||||
/* pick off messages one by one */
|
||||
if(convM2W(mbuf, nn+4, &m) <= 0)
|
||||
sysfatal("cannot convert message");
|
||||
if(trace) fprint(2, "<- %W\n", &m);
|
||||
runmsg(&m);
|
||||
} else {
|
||||
[NSApp terminate:self];
|
||||
}
|
||||
[readHandle waitForDataInBackgroundAndNotify];
|
||||
|
||||
return;
|
||||
|
||||
while((n = read(3, buf, 4)) == 4){
|
||||
GET(buf, n);
|
||||
if(n > nmbuf){
|
||||
free(mbuf);
|
||||
mbuf = malloc(4+n);
|
||||
if(mbuf == nil)
|
||||
sysfatal("malloc: %r");
|
||||
nmbuf = n;
|
||||
}
|
||||
memmove(mbuf, buf, 4);
|
||||
nn = readn(3, mbuf+4, n-4);
|
||||
if(nn != n-4)
|
||||
sysfatal("eof during message");
|
||||
|
||||
/* pick off messages one by one */
|
||||
if(convM2W(mbuf, nn+4, &m) <= 0)
|
||||
sysfatal("cannot convert message");
|
||||
if(trace) fprint(2, "<- %W\n", &m);
|
||||
runmsg(&m);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Notifications
|
||||
|
||||
- (void)fullscreen:(NSNotification *)notification
|
||||
{
|
||||
fullscreen(1);
|
||||
}
|
||||
|
||||
- (void)windowWillClose:(NSNotification *)notification
|
||||
{
|
||||
// if(osx.window == [notification object]){
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[NSApp terminate:self];
|
||||
// }
|
||||
}
|
||||
|
||||
- (void)windowDidResize:(NSNotification *)notification
|
||||
{
|
||||
// if(osx.window == [notification object]) {
|
||||
eresized(1);
|
||||
// }
|
||||
}
|
||||
|
||||
- (void)receiveWake:(NSNotification *)notification
|
||||
{
|
||||
if(trace) NSLog(@"%s:%d %@", __FILE__, __LINE__, notification);
|
||||
// redraw
|
||||
}
|
||||
|
||||
- (void)mouseDown:(NSEvent *)anEvent
|
||||
{
|
||||
mouseevent(anEvent);
|
||||
}
|
||||
|
||||
- (void)mouseDragged:(NSEvent *)anEvent
|
||||
{
|
||||
mouseevent(anEvent);
|
||||
}
|
||||
|
||||
- (void)keydown:(NSEvent *)anEvent
|
||||
{
|
||||
kbdevent(anEvent);
|
||||
}
|
||||
|
||||
@end
|
680
src/cmd/devdraw/osx-screen.m
Normal file
680
src/cmd/devdraw/osx-screen.m
Normal file
|
@ -0,0 +1,680 @@
|
|||
#define Point OSXPoint
|
||||
#define Rect OSXRect
|
||||
#define Cursor OSXCursor
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
#undef Rect
|
||||
#undef Point
|
||||
#undef Cursor
|
||||
#undef offsetof
|
||||
#undef nil
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <keyboard.h>
|
||||
#include <mouse.h>
|
||||
#include <cursor.h>
|
||||
#include "osx-screen.h"
|
||||
#include "osx-keycodes.h"
|
||||
#include "devdraw.h"
|
||||
#include "glendapng.h"
|
||||
|
||||
AUTOFRAMEWORK(Cocoa)
|
||||
|
||||
#define panic sysfatal
|
||||
|
||||
extern Rectangle mouserect;
|
||||
|
||||
struct {
|
||||
char *label;
|
||||
char *winsize;
|
||||
QLock labellock;
|
||||
|
||||
Rectangle fullscreenr;
|
||||
Rectangle screenr;
|
||||
Memimage *screenimage;
|
||||
int isfullscreen;
|
||||
ulong fullscreentime;
|
||||
|
||||
Point xy;
|
||||
int buttons;
|
||||
int kbuttons;
|
||||
|
||||
CGDataProviderRef provider;
|
||||
NSWindow *window;
|
||||
CGImageRef image;
|
||||
CGContextRef windowctx;
|
||||
|
||||
int needflush;
|
||||
QLock flushlock;
|
||||
int active;
|
||||
int infullscreen;
|
||||
int kalting; // last keystroke was Kalt
|
||||
} osx;
|
||||
|
||||
enum
|
||||
{
|
||||
WindowAttrs = NSClosableWindowMask |
|
||||
NSTitledWindowMask |
|
||||
NSMiniaturizableWindowMask |
|
||||
NSResizableWindowMask
|
||||
};
|
||||
|
||||
static void screenproc(void*);
|
||||
void eresized(int);
|
||||
void fullscreen(int);
|
||||
void seticon(void);
|
||||
static void activated(int);
|
||||
|
||||
enum
|
||||
{
|
||||
CmdFullScreen = 1,
|
||||
};
|
||||
|
||||
@interface P9View : NSView
|
||||
{}
|
||||
@end
|
||||
|
||||
@implementation P9View
|
||||
- (BOOL)acceptsFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
@end
|
||||
|
||||
void screeninit(void);
|
||||
void _flushmemscreen(Rectangle r);
|
||||
|
||||
Memimage*
|
||||
attachscreen(char *label, char *winsize)
|
||||
{
|
||||
if(label == nil)
|
||||
label = "gnot a label";
|
||||
osx.label = strdup(label);
|
||||
osx.winsize = winsize;
|
||||
if(osx.screenimage == nil){
|
||||
screeninit();
|
||||
if(osx.screenimage == nil)
|
||||
panic("cannot create OS X screen");
|
||||
}
|
||||
return osx.screenimage;
|
||||
}
|
||||
|
||||
void
|
||||
_screeninit(void)
|
||||
{
|
||||
CGRect cgr;
|
||||
NSRect or;
|
||||
Rectangle r;
|
||||
int havemin;
|
||||
|
||||
memimageinit();
|
||||
|
||||
cgr = CGDisplayBounds(CGMainDisplayID());
|
||||
osx.fullscreenr = Rect(0, 0, cgr.size.width, cgr.size.height);
|
||||
|
||||
// Create the window.
|
||||
r = Rect(0, 0, Dx(osx.fullscreenr)*2/3, Dy(osx.fullscreenr)*2/3);
|
||||
havemin = 0;
|
||||
if(osx.winsize && osx.winsize[0]){
|
||||
if(parsewinsize(osx.winsize, &r, &havemin) < 0)
|
||||
sysfatal("%r");
|
||||
}
|
||||
if(!havemin)
|
||||
r = rectaddpt(r, Pt((Dx(osx.fullscreenr)-Dx(r))/2, (Dy(osx.fullscreenr)-Dy(r))/2));
|
||||
or = NSMakeRect(r.min.x, r.min.y, r.max.x, r.max.y);
|
||||
osx.window = [[NSWindow alloc] initWithContentRect:or styleMask:WindowAttrs
|
||||
backing:NSBackingStoreBuffered defer:NO screen:[NSScreen mainScreen]];
|
||||
[osx.window setDelegate:[NSApp delegate]];
|
||||
[osx.window setAcceptsMouseMovedEvents:YES];
|
||||
|
||||
P9View *view = [[P9View alloc] initWithFrame:or];
|
||||
[osx.window setContentView:view];
|
||||
[view release];
|
||||
|
||||
setlabel(osx.label);
|
||||
seticon();
|
||||
|
||||
// Finally, put the window on the screen.
|
||||
eresized(0);
|
||||
[osx.window makeKeyAndOrderFront:nil];
|
||||
|
||||
[NSCursor unhide];
|
||||
}
|
||||
|
||||
static Rendez scr;
|
||||
static QLock slock;
|
||||
|
||||
void
|
||||
screeninit(void)
|
||||
{
|
||||
scr.l = &slock;
|
||||
qlock(scr.l);
|
||||
// proccreate(screenproc, nil, 256*1024);
|
||||
screenproc(NULL);
|
||||
while(osx.window == nil)
|
||||
rsleep(&scr);
|
||||
qunlock(scr.l);
|
||||
}
|
||||
|
||||
static void
|
||||
screenproc(void *v)
|
||||
{
|
||||
qlock(scr.l);
|
||||
_screeninit();
|
||||
rwakeup(&scr);
|
||||
qunlock(scr.l);
|
||||
}
|
||||
|
||||
static ulong
|
||||
msec(void)
|
||||
{
|
||||
return nsec()/1000000;
|
||||
}
|
||||
|
||||
//static void
|
||||
void
|
||||
mouseevent(NSEvent *event)
|
||||
{
|
||||
int wheel;
|
||||
NSPoint op;
|
||||
|
||||
op = [event locationInWindow];
|
||||
|
||||
osx.xy = subpt(Pt(op.x, op.y), osx.screenr.min);
|
||||
wheel = 0;
|
||||
|
||||
switch([event type]){
|
||||
case NSScrollWheel:;
|
||||
CGFloat delta = [event deltaY];
|
||||
if(delta > 0)
|
||||
wheel = 8;
|
||||
else
|
||||
wheel = 16;
|
||||
break;
|
||||
|
||||
case NSLeftMouseDown:
|
||||
case NSRightMouseDown:
|
||||
case NSOtherMouseDown:
|
||||
case NSLeftMouseUp:
|
||||
case NSRightMouseUp:
|
||||
case NSOtherMouseUp:;
|
||||
NSInteger but;
|
||||
NSUInteger mod;
|
||||
but = [event buttonNumber];
|
||||
mod = [event modifierFlags];
|
||||
|
||||
// OS X swaps button 2 and 3
|
||||
but = (but & ~6) | ((but & 4)>>1) | ((but&2)<<1);
|
||||
but = mouseswap(but);
|
||||
|
||||
// Apply keyboard modifiers and pretend it was a real mouse button.
|
||||
// (Modifiers typed while holding the button go into kbuttons,
|
||||
// but this one does not.)
|
||||
if(but == 1){
|
||||
if(mod & NSAlternateKeyMask) {
|
||||
// Take the ALT away from the keyboard handler.
|
||||
if(osx.kalting) {
|
||||
osx.kalting = 0;
|
||||
keystroke(Kalt);
|
||||
}
|
||||
but = 2;
|
||||
}
|
||||
else if(mod & NSCommandKeyMask)
|
||||
but = 4;
|
||||
}
|
||||
osx.buttons = but;
|
||||
break;
|
||||
|
||||
case NSMouseMoved:
|
||||
case NSLeftMouseDragged:
|
||||
case NSRightMouseDragged:
|
||||
case NSOtherMouseDragged:
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
mousetrack(osx.xy.x, osx.xy.y, osx.buttons|osx.kbuttons|wheel, msec());
|
||||
}
|
||||
|
||||
static int keycvt[] =
|
||||
{
|
||||
[QZ_IBOOK_ENTER] '\n',
|
||||
[QZ_RETURN] '\n',
|
||||
[QZ_ESCAPE] 27,
|
||||
[QZ_BACKSPACE] '\b',
|
||||
[QZ_LALT] Kalt,
|
||||
[QZ_LCTRL] Kctl,
|
||||
[QZ_LSHIFT] Kshift,
|
||||
[QZ_F1] KF+1,
|
||||
[QZ_F2] KF+2,
|
||||
[QZ_F3] KF+3,
|
||||
[QZ_F4] KF+4,
|
||||
[QZ_F5] KF+5,
|
||||
[QZ_F6] KF+6,
|
||||
[QZ_F7] KF+7,
|
||||
[QZ_F8] KF+8,
|
||||
[QZ_F9] KF+9,
|
||||
[QZ_F10] KF+10,
|
||||
[QZ_F11] KF+11,
|
||||
[QZ_F12] KF+12,
|
||||
[QZ_INSERT] Kins,
|
||||
[QZ_DELETE] 0x7F,
|
||||
[QZ_HOME] Khome,
|
||||
[QZ_END] Kend,
|
||||
[QZ_KP_PLUS] '+',
|
||||
[QZ_KP_MINUS] '-',
|
||||
[QZ_TAB] '\t',
|
||||
[QZ_PAGEUP] Kpgup,
|
||||
[QZ_PAGEDOWN] Kpgdown,
|
||||
[QZ_UP] Kup,
|
||||
[QZ_DOWN] Kdown,
|
||||
[QZ_LEFT] Kleft,
|
||||
[QZ_RIGHT] Kright,
|
||||
[QZ_KP_MULTIPLY] '*',
|
||||
[QZ_KP_DIVIDE] '/',
|
||||
[QZ_KP_ENTER] '\n',
|
||||
[QZ_KP_PERIOD] '.',
|
||||
[QZ_KP0] '0',
|
||||
[QZ_KP1] '1',
|
||||
[QZ_KP2] '2',
|
||||
[QZ_KP3] '3',
|
||||
[QZ_KP4] '4',
|
||||
[QZ_KP5] '5',
|
||||
[QZ_KP6] '6',
|
||||
[QZ_KP7] '7',
|
||||
[QZ_KP8] '8',
|
||||
[QZ_KP9] '9',
|
||||
};
|
||||
|
||||
//static void
|
||||
void
|
||||
kbdevent(NSEvent *event)
|
||||
{
|
||||
char ch;
|
||||
UInt32 code;
|
||||
UInt32 mod;
|
||||
int k;
|
||||
|
||||
ch = [[event characters] characterAtIndex:0];
|
||||
code = [event keyCode];
|
||||
mod = [event modifierFlags];
|
||||
|
||||
switch([event type]){
|
||||
case NSKeyDown:
|
||||
osx.kalting = 0;
|
||||
if(mod == NSCommandKeyMask){
|
||||
if(ch == 'F' || ch == 'f'){
|
||||
if(osx.isfullscreen && msec() - osx.fullscreentime > 500)
|
||||
fullscreen(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Pass most Cmd keys through as Kcmd + ch.
|
||||
// OS X interprets a few no matter what we do,
|
||||
// so it is useless to pass them through as keystrokes too.
|
||||
switch(ch) {
|
||||
case 'm': // minimize window
|
||||
case 'h': // hide window
|
||||
case 'H': // hide others
|
||||
case 'q': // quit
|
||||
return;
|
||||
}
|
||||
if(' ' <= ch && ch <= '~') {
|
||||
keystroke(Kcmd + ch);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
k = ch;
|
||||
if(code < nelem(keycvt) && keycvt[code])
|
||||
k = keycvt[code];
|
||||
if(k >= 0)
|
||||
keystroke(k);
|
||||
else{
|
||||
keystroke(ch);
|
||||
}
|
||||
break;
|
||||
|
||||
case NSFlagsChanged:
|
||||
if(!osx.buttons && !osx.kbuttons){
|
||||
if(mod == NSAlternateKeyMask) {
|
||||
osx.kalting = 1;
|
||||
keystroke(Kalt);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// If the mouse button is being held down, treat
|
||||
// changes in the keyboard modifiers as changes
|
||||
// in the mouse buttons.
|
||||
osx.kbuttons = 0;
|
||||
if(mod & NSAlternateKeyMask)
|
||||
osx.kbuttons |= 2;
|
||||
if(mod & NSCommandKeyMask)
|
||||
osx.kbuttons |= 4;
|
||||
mousetrack(osx.xy.x, osx.xy.y, osx.buttons|osx.kbuttons, msec());
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//static void
|
||||
void
|
||||
eresized(int new)
|
||||
{
|
||||
Memimage *m;
|
||||
NSRect or;
|
||||
ulong chan;
|
||||
Rectangle r;
|
||||
int bpl;
|
||||
CGDataProviderRef provider;
|
||||
CGImageRef image;
|
||||
CGColorSpaceRef cspace;
|
||||
|
||||
or = [[osx.window contentView] bounds];
|
||||
r = Rect(or.origin.x, or.origin.y, or.size.width, or.size.height);
|
||||
if(Dx(r) == Dx(osx.screenr) && Dy(r) == Dy(osx.screenr)){
|
||||
// No need to make new image.
|
||||
osx.screenr = r;
|
||||
return;
|
||||
}
|
||||
|
||||
chan = XBGR32;
|
||||
m = allocmemimage(Rect(0, 0, Dx(r), Dy(r)), chan);
|
||||
if(m == nil)
|
||||
panic("allocmemimage: %r");
|
||||
if(m->data == nil)
|
||||
panic("m->data == nil");
|
||||
bpl = bytesperline(r, 32);
|
||||
provider = CGDataProviderCreateWithData(0,
|
||||
m->data->bdata, Dy(r)*bpl, 0);
|
||||
//cspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
|
||||
cspace = CGColorSpaceCreateDeviceRGB();
|
||||
image = CGImageCreate(Dx(r), Dy(r), 8, 32, bpl,
|
||||
cspace,
|
||||
kCGImageAlphaNoneSkipLast,
|
||||
provider, 0, 0, kCGRenderingIntentDefault);
|
||||
CGColorSpaceRelease(cspace);
|
||||
CGDataProviderRelease(provider); // CGImageCreate did incref
|
||||
|
||||
mouserect = m->r;
|
||||
if(new){
|
||||
mouseresized = 1;
|
||||
mousetrack(osx.xy.x, osx.xy.y, osx.buttons|osx.kbuttons, msec());
|
||||
}
|
||||
// termreplacescreenimage(m);
|
||||
_drawreplacescreenimage(m); // frees old osx.screenimage if any
|
||||
if(osx.image)
|
||||
CGImageRelease(osx.image);
|
||||
osx.image = image;
|
||||
osx.screenimage = m;
|
||||
osx.screenr = r;
|
||||
}
|
||||
|
||||
void
|
||||
flushproc(void *v)
|
||||
{
|
||||
for(;;){
|
||||
if(osx.needflush && osx.windowctx && canqlock(&osx.flushlock)){
|
||||
if(osx.windowctx){
|
||||
CGContextFlush(osx.windowctx);
|
||||
osx.needflush = 0;
|
||||
}
|
||||
qunlock(&osx.flushlock);
|
||||
}
|
||||
usleep(33333);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_flushmemscreen(Rectangle r)
|
||||
{
|
||||
CGRect cgr;
|
||||
CGImageRef subimg;
|
||||
|
||||
qlock(&osx.flushlock);
|
||||
if(osx.windowctx == nil){
|
||||
osx.windowctx = [[osx.window graphicsContext] graphicsPort];
|
||||
// [osx.window flushWindow];
|
||||
// proccreate(flushproc, nil, 256*1024);
|
||||
}
|
||||
|
||||
cgr.origin.x = r.min.x;
|
||||
cgr.origin.y = r.min.y;
|
||||
cgr.size.width = Dx(r);
|
||||
cgr.size.height = Dy(r);
|
||||
subimg = CGImageCreateWithImageInRect(osx.image, cgr);
|
||||
cgr.origin.y = Dy(osx.screenr) - r.max.y; // XXX how does this make any sense?
|
||||
CGContextDrawImage(osx.windowctx, cgr, subimg);
|
||||
osx.needflush = 1;
|
||||
qunlock(&osx.flushlock);
|
||||
CGImageRelease(subimg);
|
||||
}
|
||||
|
||||
void
|
||||
activated(int active)
|
||||
{
|
||||
osx.active = active;
|
||||
}
|
||||
|
||||
void
|
||||
fullscreen(int wascmd)
|
||||
{
|
||||
NSView *view = [osx.window contentView];
|
||||
|
||||
if(osx.isfullscreen){
|
||||
[view exitFullScreenModeWithOptions:nil];
|
||||
osx.isfullscreen = 0;
|
||||
}else{
|
||||
[view enterFullScreenMode:[osx.window screen] withOptions:nil];
|
||||
osx.isfullscreen = 1;
|
||||
osx.fullscreentime = msec();
|
||||
}
|
||||
eresized(1);
|
||||
}
|
||||
|
||||
void
|
||||
setmouse(Point p)
|
||||
{
|
||||
CGPoint cgp;
|
||||
|
||||
cgp.x = p.x + osx.screenr.min.x;
|
||||
cgp.y = p.y + osx.screenr.min.y;
|
||||
CGWarpMouseCursorPosition(cgp);
|
||||
}
|
||||
|
||||
void
|
||||
setcursor(Cursor *c)
|
||||
{
|
||||
NSImage *image;
|
||||
NSBitmapImageRep *bitmap;
|
||||
NSCursor *nsc;
|
||||
unsigned char *planes[5];
|
||||
int i;
|
||||
|
||||
if(c == nil){
|
||||
[NSCursor pop];
|
||||
return;
|
||||
}
|
||||
|
||||
image = [[NSImage alloc] initWithSize:NSMakeSize(16.0, 16.0)];
|
||||
bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
|
||||
pixelsWide:16
|
||||
pixelsHigh:16
|
||||
bitsPerSample:1
|
||||
samplesPerPixel:2
|
||||
hasAlpha:YES
|
||||
isPlanar:YES
|
||||
colorSpaceName:NSCalibratedWhiteColorSpace
|
||||
bytesPerRow:2
|
||||
bitsPerPixel:1];
|
||||
|
||||
[bitmap getBitmapDataPlanes:planes];
|
||||
|
||||
for(i=0; i<16; i++){
|
||||
planes[0][i] = ((ushort*)c->set)[i];
|
||||
planes[1][i] = planes[0][i] | ((ushort*)c->clr)[i];
|
||||
}
|
||||
|
||||
[image addRepresentation:bitmap];
|
||||
|
||||
nsc = [[NSCursor alloc] initWithImage:image
|
||||
hotSpot:NSMakePoint(c->offset.x, c->offset.y)];
|
||||
[nsc push];
|
||||
|
||||
[image release];
|
||||
[bitmap release];
|
||||
[nsc release];
|
||||
}
|
||||
|
||||
void
|
||||
getcolor(ulong i, ulong *r, ulong *g, ulong *b)
|
||||
{
|
||||
ulong v;
|
||||
|
||||
v = 0;
|
||||
*r = (v>>16)&0xFF;
|
||||
*g = (v>>8)&0xFF;
|
||||
*b = v&0xFF;
|
||||
}
|
||||
|
||||
int
|
||||
setcolor(ulong i, ulong r, ulong g, ulong b)
|
||||
{
|
||||
/* no-op */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
hwdraw(Memdrawparam *p)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct {
|
||||
QLock lk;
|
||||
char buf[SnarfSize];
|
||||
Rune rbuf[SnarfSize];
|
||||
NSPasteboard *apple;
|
||||
} clip;
|
||||
|
||||
char*
|
||||
getsnarf(void)
|
||||
{
|
||||
char *s, *t;
|
||||
NSArray *types;
|
||||
NSString *string;
|
||||
NSData * data;
|
||||
NSUInteger ndata;
|
||||
|
||||
/* fprint(2, "applegetsnarf\n"); */
|
||||
qlock(&clip.lk);
|
||||
|
||||
clip.apple = [NSPasteboard generalPasteboard];
|
||||
types = [clip.apple types];
|
||||
|
||||
string = [clip.apple stringForType:NSStringPboardType];
|
||||
if(string == nil){
|
||||
fprint(2, "apple pasteboard get item type failed\n");
|
||||
qunlock(&clip.lk);
|
||||
return nil;
|
||||
}
|
||||
|
||||
data = [string dataUsingEncoding:NSUnicodeStringEncoding];
|
||||
if(data != nil){
|
||||
ndata = [data length];
|
||||
qunlock(&clip.lk);
|
||||
s = smprint("%.*S", ndata/2, (Rune*)[data bytes]);
|
||||
for(t=s; *t; t++)
|
||||
if(*t == '\r')
|
||||
*t = '\n';
|
||||
return s;
|
||||
}
|
||||
|
||||
qunlock(&clip.lk);
|
||||
return nil;
|
||||
}
|
||||
|
||||
void
|
||||
putsnarf(char *s)
|
||||
{
|
||||
NSArray *pboardTypes;
|
||||
NSString *string;
|
||||
|
||||
/* fprint(2, "appleputsnarf\n"); */
|
||||
|
||||
if(strlen(s) >= SnarfSize)
|
||||
return;
|
||||
qlock(&clip.lk);
|
||||
strcpy(clip.buf, s);
|
||||
runesnprint(clip.rbuf, nelem(clip.rbuf), "%s", s);
|
||||
|
||||
pboardTypes = [NSArray arrayWithObject:NSStringPboardType];
|
||||
|
||||
clip.apple = [NSPasteboard generalPasteboard];
|
||||
[clip.apple declareTypes:pboardTypes owner:nil];
|
||||
|
||||
assert(sizeof(clip.rbuf[0]) == 2);
|
||||
string = [NSString stringWithCharacters:clip.rbuf length:runestrlen(clip.rbuf)*2];
|
||||
if(string == nil){
|
||||
fprint(2, "apple pasteboard data create failed\n");
|
||||
qunlock(&clip.lk);
|
||||
return;
|
||||
}
|
||||
if(![clip.apple setString:string forType:NSStringPboardType]){
|
||||
fprint(2, "apple pasteboard putitem failed\n");
|
||||
qunlock(&clip.lk);
|
||||
return;
|
||||
}
|
||||
qunlock(&clip.lk);
|
||||
}
|
||||
|
||||
void
|
||||
setlabel(char *label)
|
||||
{
|
||||
CFStringRef cs;
|
||||
cs = CFStringCreateWithBytes(nil, (uchar*)label, strlen(osx.label), kCFStringEncodingUTF8, false);
|
||||
[osx.window setTitle:(NSString*)cs];
|
||||
CFRelease(cs);
|
||||
}
|
||||
|
||||
void
|
||||
kicklabel(char *label)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = strdup(label);
|
||||
if(p == nil)
|
||||
return;
|
||||
qlock(&osx.labellock);
|
||||
free(osx.label);
|
||||
osx.label = p;
|
||||
qunlock(&osx.labellock);
|
||||
|
||||
setlabel(label);
|
||||
}
|
||||
|
||||
// static void
|
||||
void
|
||||
seticon(void)
|
||||
{
|
||||
NSImage *im;
|
||||
NSData *d;
|
||||
|
||||
d = [[NSData alloc] initWithBytes:glenda_png length:(sizeof glenda_png)];
|
||||
im = [[NSImage alloc] initWithData:d];
|
||||
if(im){
|
||||
NSLog(@"here");
|
||||
[NSApp setApplicationIconImage:im];
|
||||
[[NSApp dockTile] setShowsApplicationBadge:YES];
|
||||
[[NSApp dockTile] display];
|
||||
}
|
||||
[d release];
|
||||
[im release];
|
||||
}
|
452
src/cmd/devdraw/osx-srv.m
Normal file
452
src/cmd/devdraw/osx-srv.m
Normal file
|
@ -0,0 +1,452 @@
|
|||
#define Point OSXPoint
|
||||
#define Rect OSXRect
|
||||
#define Cursor OSXCursor
|
||||
#import <AppKit/AppKit.h>
|
||||
#undef Rect
|
||||
#undef Point
|
||||
#undef Cursor
|
||||
|
||||
/*
|
||||
* Window system protocol server.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <errno.h>
|
||||
#include <sys/select.h>
|
||||
#include <libc.h>
|
||||
#include <draw.h>
|
||||
#include <memdraw.h>
|
||||
#include <memlayer.h>
|
||||
#include <keyboard.h>
|
||||
#include <mouse.h>
|
||||
#include <cursor.h>
|
||||
#include <drawfcall.h>
|
||||
#include "osx-screen.h"
|
||||
#include "devdraw.h"
|
||||
|
||||
AUTOFRAMEWORK(AppKit)
|
||||
|
||||
#import "osx-delegate.h"
|
||||
|
||||
#undef time
|
||||
|
||||
#define MouseMask (\
|
||||
ButtonPressMask|\
|
||||
ButtonReleaseMask|\
|
||||
PointerMotionMask|\
|
||||
Button1MotionMask|\
|
||||
Button2MotionMask|\
|
||||
Button3MotionMask)
|
||||
|
||||
#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask
|
||||
|
||||
typedef struct Kbdbuf Kbdbuf;
|
||||
typedef struct Mousebuf Mousebuf;
|
||||
typedef struct Fdbuf Fdbuf;
|
||||
typedef struct Tagbuf Tagbuf;
|
||||
|
||||
struct Kbdbuf
|
||||
{
|
||||
Rune r[32];
|
||||
int ri;
|
||||
int wi;
|
||||
int stall;
|
||||
};
|
||||
|
||||
struct Mousebuf
|
||||
{
|
||||
Mouse m[32];
|
||||
Mouse last;
|
||||
int ri;
|
||||
int wi;
|
||||
int stall;
|
||||
};
|
||||
|
||||
struct Tagbuf
|
||||
{
|
||||
int t[32];
|
||||
int ri;
|
||||
int wi;
|
||||
};
|
||||
|
||||
Kbdbuf kbd;
|
||||
Mousebuf mouse;
|
||||
Tagbuf kbdtags;
|
||||
Tagbuf mousetags;
|
||||
|
||||
void fdslide(Fdbuf*);
|
||||
void runmsg(Wsysmsg*);
|
||||
void replymsg(Wsysmsg*);
|
||||
void matchkbd(void);
|
||||
void matchmouse(void);
|
||||
int fdnoblock(int);
|
||||
Rectangle mouserect;
|
||||
int mouseresized;
|
||||
|
||||
|
||||
QLock lk;
|
||||
void
|
||||
zlock(void)
|
||||
{
|
||||
qlock(&lk);
|
||||
}
|
||||
|
||||
void
|
||||
zunlock(void)
|
||||
{
|
||||
qunlock(&lk);
|
||||
}
|
||||
|
||||
int chatty;
|
||||
int drawsleep;
|
||||
int trace;
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprint(2, "usage: devdraw (don't run directly)\n");
|
||||
exits("usage");
|
||||
}
|
||||
|
||||
void
|
||||
bell(void *v, char *msg)
|
||||
{
|
||||
if(strcmp(msg, "alarm") == 0)
|
||||
drawsleep = drawsleep ? 0 : 1000;
|
||||
noted(NCONT);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
NSAutoreleasePool *pool = nil;
|
||||
NSApplication *application = nil;
|
||||
|
||||
/*
|
||||
* Move the protocol off stdin/stdout so that
|
||||
* any inadvertent prints don't screw things up.
|
||||
*/
|
||||
dup(0, 3);
|
||||
dup(1, 4);
|
||||
close(0);
|
||||
close(1);
|
||||
open("/dev/null", OREAD);
|
||||
open("/dev/null", OWRITE);
|
||||
|
||||
trace = 1;
|
||||
fmtinstall('W', drawfcallfmt);
|
||||
|
||||
ARGBEGIN{
|
||||
case 'D':
|
||||
chatty++;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
}ARGEND
|
||||
|
||||
/*
|
||||
* Ignore arguments. They're only for good ps -a listings.
|
||||
*/
|
||||
|
||||
notify(bell);
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
application = [NSApplication sharedApplication];
|
||||
[application setDelegate:[[DevdrawDelegate alloc] init]];
|
||||
[application run];
|
||||
[application setDelegate:nil];
|
||||
[pool release];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
replyerror(Wsysmsg *m)
|
||||
{
|
||||
char err[256];
|
||||
|
||||
rerrstr(err, sizeof err);
|
||||
m->type = Rerror;
|
||||
m->error = err;
|
||||
replymsg(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a single wsysmsg.
|
||||
* Might queue for later (kbd, mouse read)
|
||||
*/
|
||||
void
|
||||
runmsg(Wsysmsg *m)
|
||||
{
|
||||
static uchar buf[65536];
|
||||
int n;
|
||||
Memimage *i;
|
||||
|
||||
switch(m->type){
|
||||
case Tinit:
|
||||
memimageinit();
|
||||
i = attachscreen(m->label, m->winsize);
|
||||
_initdisplaymemimage(i);
|
||||
replymsg(m);
|
||||
break;
|
||||
|
||||
case Trdmouse:
|
||||
// zlock();
|
||||
mousetags.t[mousetags.wi++] = m->tag;
|
||||
if(mousetags.wi == nelem(mousetags.t))
|
||||
mousetags.wi = 0;
|
||||
if(mousetags.wi == mousetags.ri)
|
||||
sysfatal("too many queued mouse reads");
|
||||
mouse.stall = 0;
|
||||
matchmouse();
|
||||
// zunlock();
|
||||
break;
|
||||
|
||||
case Trdkbd:
|
||||
zlock();
|
||||
kbdtags.t[kbdtags.wi++] = m->tag;
|
||||
if(kbdtags.wi == nelem(kbdtags.t))
|
||||
kbdtags.wi = 0;
|
||||
if(kbdtags.wi == kbdtags.ri)
|
||||
sysfatal("too many queued keyboard reads");
|
||||
kbd.stall = 0;
|
||||
matchkbd();
|
||||
zunlock();
|
||||
break;
|
||||
|
||||
case Tmoveto:
|
||||
setmouse(m->mouse.xy);
|
||||
replymsg(m);
|
||||
break;
|
||||
|
||||
case Tcursor:
|
||||
if(m->arrowcursor)
|
||||
setcursor(nil);
|
||||
else
|
||||
setcursor(&m->cursor);
|
||||
replymsg(m);
|
||||
break;
|
||||
|
||||
case Tbouncemouse:
|
||||
// _xbouncemouse(&m->mouse);
|
||||
replymsg(m);
|
||||
break;
|
||||
|
||||
case Tlabel:
|
||||
kicklabel(m->label);
|
||||
replymsg(m);
|
||||
break;
|
||||
|
||||
case Trdsnarf:
|
||||
m->snarf = getsnarf();
|
||||
replymsg(m);
|
||||
free(m->snarf);
|
||||
break;
|
||||
|
||||
case Twrsnarf:
|
||||
putsnarf(m->snarf);
|
||||
replymsg(m);
|
||||
break;
|
||||
|
||||
case Trddraw:
|
||||
n = m->count;
|
||||
if(n > sizeof buf)
|
||||
n = sizeof buf;
|
||||
n = _drawmsgread(buf, n);
|
||||
if(n < 0)
|
||||
replyerror(m);
|
||||
else{
|
||||
m->count = n;
|
||||
m->data = buf;
|
||||
replymsg(m);
|
||||
}
|
||||
break;
|
||||
|
||||
case Twrdraw:
|
||||
if(_drawmsgwrite(m->data, m->count) < 0)
|
||||
replyerror(m);
|
||||
else
|
||||
replymsg(m);
|
||||
break;
|
||||
|
||||
case Ttop:
|
||||
// _xtopwindow();
|
||||
replymsg(m);
|
||||
break;
|
||||
|
||||
case Tresize:
|
||||
// _xresizewindow(m->rect);
|
||||
replymsg(m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reply to m.
|
||||
*/
|
||||
QLock replylock;
|
||||
void
|
||||
replymsg(Wsysmsg *m)
|
||||
{
|
||||
int n;
|
||||
static uchar *mbuf;
|
||||
static int nmbuf;
|
||||
|
||||
/* T -> R msg */
|
||||
if(m->type%2 == 0)
|
||||
m->type++;
|
||||
|
||||
if(trace) fprint(2, "-> %W\n", m);
|
||||
/* copy to output buffer */
|
||||
n = sizeW2M(m);
|
||||
|
||||
qlock(&replylock);
|
||||
if(n > nmbuf){
|
||||
free(mbuf);
|
||||
mbuf = malloc(n);
|
||||
if(mbuf == nil)
|
||||
sysfatal("out of memory");
|
||||
nmbuf = n;
|
||||
}
|
||||
convW2M(m, mbuf, n);
|
||||
if(write(4, mbuf, n) != n)
|
||||
sysfatal("write: %r");
|
||||
qunlock(&replylock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Match queued kbd reads with queued kbd characters.
|
||||
*/
|
||||
void
|
||||
matchkbd(void)
|
||||
{
|
||||
Wsysmsg m;
|
||||
|
||||
if(kbd.stall)
|
||||
return;
|
||||
while(kbd.ri != kbd.wi && kbdtags.ri != kbdtags.wi){
|
||||
m.type = Rrdkbd;
|
||||
m.tag = kbdtags.t[kbdtags.ri++];
|
||||
if(kbdtags.ri == nelem(kbdtags.t))
|
||||
kbdtags.ri = 0;
|
||||
m.rune = kbd.r[kbd.ri++];
|
||||
if(kbd.ri == nelem(kbd.r))
|
||||
kbd.ri = 0;
|
||||
replymsg(&m);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Match queued mouse reads with queued mouse events.
|
||||
*/
|
||||
void
|
||||
matchmouse(void)
|
||||
{
|
||||
Wsysmsg m;
|
||||
|
||||
while(mouse.ri != mouse.wi && mousetags.ri != mousetags.wi){
|
||||
m.type = Rrdmouse;
|
||||
m.tag = mousetags.t[mousetags.ri++];
|
||||
if(mousetags.ri == nelem(mousetags.t))
|
||||
mousetags.ri = 0;
|
||||
m.mouse = mouse.m[mouse.ri];
|
||||
m.resized = mouseresized;
|
||||
/*
|
||||
if(m.resized)
|
||||
fprint(2, "sending resize\n");
|
||||
*/
|
||||
mouseresized = 0;
|
||||
mouse.ri++;
|
||||
if(mouse.ri == nelem(mouse.m))
|
||||
mouse.ri = 0;
|
||||
replymsg(&m);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mousetrack(int x, int y, int b, int ms)
|
||||
{
|
||||
Mouse *m;
|
||||
|
||||
if(x < mouserect.min.x)
|
||||
x = mouserect.min.x;
|
||||
if(x > mouserect.max.x)
|
||||
x = mouserect.max.x;
|
||||
if(y < mouserect.min.y)
|
||||
y = mouserect.min.y;
|
||||
if(y > mouserect.max.y)
|
||||
y = mouserect.max.y;
|
||||
|
||||
// zlock();
|
||||
// If reader has stopped reading, don't bother.
|
||||
// If reader is completely caught up, definitely queue.
|
||||
// Otherwise, queue only button change events.
|
||||
if(!mouse.stall)
|
||||
if(mouse.wi == mouse.ri || mouse.last.buttons != b){
|
||||
m = &mouse.last;
|
||||
m->xy.x = x;
|
||||
m->xy.y = y;
|
||||
m->buttons = b;
|
||||
m->msec = ms;
|
||||
|
||||
mouse.m[mouse.wi] = *m;
|
||||
if(++mouse.wi == nelem(mouse.m))
|
||||
mouse.wi = 0;
|
||||
if(mouse.wi == mouse.ri){
|
||||
mouse.stall = 1;
|
||||
mouse.ri = 0;
|
||||
mouse.wi = 1;
|
||||
mouse.m[0] = *m;
|
||||
}
|
||||
matchmouse();
|
||||
}
|
||||
// zunlock();
|
||||
}
|
||||
|
||||
void
|
||||
kputc(int c)
|
||||
{
|
||||
zlock();
|
||||
kbd.r[kbd.wi++] = c;
|
||||
if(kbd.wi == nelem(kbd.r))
|
||||
kbd.wi = 0;
|
||||
if(kbd.ri == kbd.wi)
|
||||
kbd.stall = 1;
|
||||
matchkbd();
|
||||
zunlock();
|
||||
}
|
||||
|
||||
void
|
||||
keystroke(int c)
|
||||
{
|
||||
static Rune k[10];
|
||||
static int alting, nk;
|
||||
int i;
|
||||
|
||||
if(c == Kalt){
|
||||
alting = !alting;
|
||||
return;
|
||||
}
|
||||
if(!alting){
|
||||
kputc(c);
|
||||
return;
|
||||
}
|
||||
if(nk >= nelem(k)) // should not happen
|
||||
nk = 0;
|
||||
k[nk++] = c;
|
||||
c = _latin1(k, nk);
|
||||
if(c > 0){
|
||||
alting = 0;
|
||||
kputc(c);
|
||||
nk = 0;
|
||||
return;
|
||||
}
|
||||
if(c == -1){
|
||||
alting = 0;
|
||||
for(i=0; i<nk; i++)
|
||||
kputc(k[i]);
|
||||
nk = 0;
|
||||
return;
|
||||
}
|
||||
// need more input
|
||||
return;
|
||||
}
|
Loading…
Reference in a new issue