aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/devdraw
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/devdraw')
-rw-r--r--src/cmd/devdraw/bigarrow.h124
-rw-r--r--src/cmd/devdraw/cocoa-screen.h24
-rw-r--r--src/cmd/devdraw/cocoa-screen.m1674
-rw-r--r--src/cmd/devdraw/cocoa-srv.c427
-rw-r--r--src/cmd/devdraw/cocoa-thread.c35
-rw-r--r--src/cmd/devdraw/cocoa-thread.h34
-rw-r--r--src/cmd/devdraw/devdraw.c471
-rw-r--r--src/cmd/devdraw/devdraw.h235
-rw-r--r--src/cmd/devdraw/drawclient.c24
-rw-r--r--src/cmd/devdraw/latin1.c4
-rw-r--r--src/cmd/devdraw/mac-draw.c (renamed from src/cmd/devdraw/osx-draw.c)1
-rw-r--r--src/cmd/devdraw/mac-screen.m (renamed from src/cmd/devdraw/cocoa-screen-metal.m)990
-rw-r--r--src/cmd/devdraw/macargv.c90
-rw-r--r--src/cmd/devdraw/macargv.m3
-rw-r--r--src/cmd/devdraw/mkfile21
-rw-r--r--src/cmd/devdraw/mklatinkbd.c6
-rw-r--r--src/cmd/devdraw/mkwsysrules.sh21
-rw-r--r--src/cmd/devdraw/mouseswap.c7
-rw-r--r--src/cmd/devdraw/nowsys.c4
-rw-r--r--src/cmd/devdraw/osx-keycodes.h189
-rw-r--r--src/cmd/devdraw/snarf.c110
-rw-r--r--src/cmd/devdraw/srv.c521
-rw-r--r--src/cmd/devdraw/winsize.c5
-rw-r--r--src/cmd/devdraw/x11-alloc.c5
-rw-r--r--src/cmd/devdraw/x11-cload.c1
-rw-r--r--src/cmd/devdraw/x11-draw.c1
-rw-r--r--src/cmd/devdraw/x11-fill.c4
-rw-r--r--src/cmd/devdraw/x11-get.c7
-rw-r--r--src/cmd/devdraw/x11-inc.h2
-rw-r--r--src/cmd/devdraw/x11-init.c737
-rw-r--r--src/cmd/devdraw/x11-itrans.c741
-rw-r--r--src/cmd/devdraw/x11-keysym2ucs.c2
-rw-r--r--src/cmd/devdraw/x11-load.c1
-rw-r--r--src/cmd/devdraw/x11-memdraw.h66
-rw-r--r--src/cmd/devdraw/x11-pixelbits.c2
-rw-r--r--src/cmd/devdraw/x11-screen.c1759
-rw-r--r--src/cmd/devdraw/x11-srv.c638
-rw-r--r--src/cmd/devdraw/x11-unload.c1
-rw-r--r--src/cmd/devdraw/x11-wsys.c46
39 files changed, 3299 insertions, 5734 deletions
diff --git a/src/cmd/devdraw/bigarrow.h b/src/cmd/devdraw/bigarrow.h
index 1221ec8c..4bfe0245 100644
--- a/src/cmd/devdraw/bigarrow.h
+++ b/src/cmd/devdraw/bigarrow.h
@@ -14,70 +14,70 @@ Cursor bigarrow = {
Cursor2 bigarrow2 = {
{ -2, -2 },
- { 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF,
- 0xC0, 0x00, 0x00, 0x03,
- 0xC0, 0x00, 0x00, 0x07,
- 0xC0, 0x00, 0x00, 0x1E,
- 0xC0, 0x00, 0x00, 0x3C,
- 0xC0, 0x00, 0x00, 0xF0,
- 0xC0, 0x00, 0x03, 0xE0,
- 0xC0, 0x00, 0x0F, 0x80,
- 0xC0, 0x00, 0x0E, 0x00,
- 0xC0, 0x00, 0x07, 0x00,
- 0xC0, 0x00, 0x03, 0x80,
- 0xC0, 0x00, 0x01, 0xC0,
- 0xC0, 0x00, 0x00, 0xE0,
- 0xC0, 0x00, 0x00, 0x70,
- 0xC0, 0x00, 0x00, 0x38,
- 0xC0, 0x00, 0x00, 0x1C,
- 0xC0, 0x00, 0x00, 0x0E,
- 0xC0, 0x00, 0x00, 0x07,
- 0xC0, 0x00, 0x00, 0x03,
- 0xC0, 0xC0, 0x00, 0x07,
- 0xC0, 0xE0, 0x00, 0x0E,
- 0xC1, 0xF0, 0x00, 0x1C,
- 0xC1, 0xB8, 0x00, 0x38,
- 0xC3, 0x9C, 0x00, 0x70,
- 0xC3, 0x0E, 0x00, 0xE0,
- 0xC7, 0x07, 0x01, 0xC0,
- 0xCE, 0x03, 0x83, 0x80,
- 0xCC, 0x01, 0xC7, 0x00,
- 0xDC, 0x00, 0xEE, 0x00,
- 0xF8, 0x00, 0x7C, 0x00,
+ { 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xC0, 0x00, 0x00, 0x03,
+ 0xC0, 0x00, 0x00, 0x07,
+ 0xC0, 0x00, 0x00, 0x1E,
+ 0xC0, 0x00, 0x00, 0x3C,
+ 0xC0, 0x00, 0x00, 0xF0,
+ 0xC0, 0x00, 0x03, 0xE0,
+ 0xC0, 0x00, 0x0F, 0x80,
+ 0xC0, 0x00, 0x0E, 0x00,
+ 0xC0, 0x00, 0x07, 0x00,
+ 0xC0, 0x00, 0x03, 0x80,
+ 0xC0, 0x00, 0x01, 0xC0,
+ 0xC0, 0x00, 0x00, 0xE0,
+ 0xC0, 0x00, 0x00, 0x70,
+ 0xC0, 0x00, 0x00, 0x38,
+ 0xC0, 0x00, 0x00, 0x1C,
+ 0xC0, 0x00, 0x00, 0x0E,
+ 0xC0, 0x00, 0x00, 0x07,
+ 0xC0, 0x00, 0x00, 0x03,
+ 0xC0, 0xC0, 0x00, 0x07,
+ 0xC0, 0xE0, 0x00, 0x0E,
+ 0xC1, 0xF0, 0x00, 0x1C,
+ 0xC1, 0xB8, 0x00, 0x38,
+ 0xC3, 0x9C, 0x00, 0x70,
+ 0xC3, 0x0E, 0x00, 0xE0,
+ 0xC7, 0x07, 0x01, 0xC0,
+ 0xCE, 0x03, 0x83, 0x80,
+ 0xCC, 0x01, 0xC7, 0x00,
+ 0xDC, 0x00, 0xEE, 0x00,
+ 0xF8, 0x00, 0x7C, 0x00,
0xF0, 0x00, 0x38, 0x00,
},
- { 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x3F, 0xFF, 0xFF, 0xFC,
- 0x3F, 0xFF, 0xFF, 0xF8,
- 0x3F, 0xFF, 0xFF, 0xE0,
- 0x3F, 0xFF, 0xFF, 0xC0,
- 0x3F, 0xFF, 0xFF, 0x00,
- 0x3F, 0xFF, 0xFC, 0x00,
- 0x3F, 0xFF, 0xF0, 0x00,
- 0x3F, 0xFF, 0xF0, 0x00,
- 0x3F, 0xFF, 0xF8, 0x00,
- 0x3F, 0xFF, 0xFC, 0x00,
- 0x3F, 0xFF, 0xFE, 0x00,
- 0x3F, 0xFF, 0xFF, 0x00,
- 0x3F, 0xFF, 0xFF, 0x80,
- 0x3F, 0xFF, 0xFF, 0xC0,
- 0x3F, 0xFF, 0xFF, 0xE0,
- 0x3F, 0xFF, 0xFF, 0xF0,
- 0x3F, 0xFF, 0xFF, 0xF8,
- 0x3F, 0xFF, 0xFF, 0xFC,
- 0x3F, 0x3F, 0xFF, 0xF8,
- 0x3F, 0x1F, 0xFF, 0xF0,
- 0x3E, 0x0F, 0xFF, 0xE0,
- 0x3E, 0x07, 0xFF, 0xC0,
- 0x3C, 0x03, 0xFF, 0x80,
- 0x3C, 0x01, 0xFF, 0x00,
- 0x38, 0x00, 0xFE, 0x00,
- 0x30, 0x00, 0x7C, 0x00,
- 0x30, 0x00, 0x38, 0x00,
- 0x20, 0x00, 0x10, 0x00,
- 0x00, 0x00, 0x00, 0x00,
+ { 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x3F, 0xFF, 0xFF, 0xFC,
+ 0x3F, 0xFF, 0xFF, 0xF8,
+ 0x3F, 0xFF, 0xFF, 0xE0,
+ 0x3F, 0xFF, 0xFF, 0xC0,
+ 0x3F, 0xFF, 0xFF, 0x00,
+ 0x3F, 0xFF, 0xFC, 0x00,
+ 0x3F, 0xFF, 0xF0, 0x00,
+ 0x3F, 0xFF, 0xF0, 0x00,
+ 0x3F, 0xFF, 0xF8, 0x00,
+ 0x3F, 0xFF, 0xFC, 0x00,
+ 0x3F, 0xFF, 0xFE, 0x00,
+ 0x3F, 0xFF, 0xFF, 0x00,
+ 0x3F, 0xFF, 0xFF, 0x80,
+ 0x3F, 0xFF, 0xFF, 0xC0,
+ 0x3F, 0xFF, 0xFF, 0xE0,
+ 0x3F, 0xFF, 0xFF, 0xF0,
+ 0x3F, 0xFF, 0xFF, 0xF8,
+ 0x3F, 0xFF, 0xFF, 0xFC,
+ 0x3F, 0x3F, 0xFF, 0xF8,
+ 0x3F, 0x1F, 0xFF, 0xF0,
+ 0x3E, 0x0F, 0xFF, 0xE0,
+ 0x3E, 0x07, 0xFF, 0xC0,
+ 0x3C, 0x03, 0xFF, 0x80,
+ 0x3C, 0x01, 0xFF, 0x00,
+ 0x38, 0x00, 0xFE, 0x00,
+ 0x30, 0x00, 0x7C, 0x00,
+ 0x30, 0x00, 0x38, 0x00,
+ 0x20, 0x00, 0x10, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
}
};
diff --git a/src/cmd/devdraw/cocoa-screen.h b/src/cmd/devdraw/cocoa-screen.h
deleted file mode 100644
index b5e3c701..00000000
--- a/src/cmd/devdraw/cocoa-screen.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#define setcursor dsetcursor
-
-Memimage *attachscreen(char*, char*);
-void setmouse(Point);
-void setcursor(Cursor*, Cursor2*);
-void setlabel(char*);
-char* getsnarf(void);
-void putsnarf(char*);
-void topwin(void);
-
-void mousetrack(int, int, int, uint);
-void keystroke(int);
-void kicklabel(char*);
-
-void servep9p(void);
-void zlock(void);
-void zunlock(void);
-
-void resizeimg(void);
-
-Rectangle mouserect;
-
-int mouseresized;
-void resizewindow(Rectangle);
diff --git a/src/cmd/devdraw/cocoa-screen.m b/src/cmd/devdraw/cocoa-screen.m
deleted file mode 100644
index 9b404c67..00000000
--- a/src/cmd/devdraw/cocoa-screen.m
+++ /dev/null
@@ -1,1674 +0,0 @@
-/*
- * Cocoa's event loop must be in main thread.
- *
- * Unless otherwise stated, all coordinate systems
- * are bottom-left-based.
- */
-
-#define Cursor OSXCursor
-#define Point OSXPoint
-#define Rect OSXRect
-
-#import <Cocoa/Cocoa.h>
-
-#undef Cursor
-#undef Point
-#undef Rect
-
-#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 "bigarrow.h"
-#include "glendapng.h"
-
-// Use non-deprecated names.
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
-#define NSKeyDown NSEventTypeKeyDown
-#define NSShiftKeyMask NSEventModifierFlagShift
-#define NSAlternateKeyMask NSEventModifierFlagOption
-#define NSCommandKeyMask NSEventModifierFlagCommand
-#define NSResizableWindowMask NSWindowStyleMaskResizable
-#define NSLeftMouseDown NSEventTypeLeftMouseDown
-#define NSLeftMouseUp NSEventTypeLeftMouseUp
-#define NSRightMouseDown NSEventTypeRightMouseDown
-#define NSRightMouseUp NSEventTypeRightMouseUp
-#define NSOtherMouseDown NSEventTypeOtherMouseDown
-#define NSOtherMouseUp NSEventTypeOtherMouseUp
-#define NSScrollWheel NSEventTypeScrollWheel
-#define NSMouseMoved NSEventTypeMouseMoved
-#define NSLeftMouseDragged NSEventTypeLeftMouseDragged
-#define NSRightMouseDragged NSEventTypeRightMouseDragged
-#define NSOtherMouseDragged NSEventTypeOtherMouseDragged
-#define NSCompositeCopy NSCompositingOperationCopy
-#define NSCompositeSourceIn NSCompositingOperationSourceIn
-#define NSFlagsChanged NSEventTypeFlagsChanged
-#define NSTitledWindowMask NSWindowStyleMaskTitled
-#define NSClosableWindowMask NSWindowStyleMaskClosable
-#define NSMiniaturizableWindowMask NSWindowStyleMaskMiniaturizable
-#define NSBorderlessWindowMask NSWindowStyleMaskBorderless
-#endif
-
-AUTOFRAMEWORK(Cocoa)
-
-#define LOG if(0)NSLog
-#define panic sysfatal
-
-int usegestures = 0;
-int useliveresizing = 0;
-int useoldfullscreen = 1;
-int usebigarrow = 0;
-
-static void setprocname(const char*);
-
-/*
- * By default, devdraw uses retina displays.
- * Set devdrawretina=0 in the environment to override.
- */
-int devdrawretina = 1;
-
-void
-usage(void)
-{
- fprint(2, "usage: devdraw (don't run directly)\n");
- threadexitsall("usage");
-}
-
-@interface appdelegate : NSObject<NSApplicationDelegate,NSWindowDelegate> @end
-
-NSObject<NSApplicationDelegate,NSWindowDelegate> *myApp;
-
-void
-threadmain(int argc, char **argv)
-{
- char *envvar;
-
- /*
- * 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': /* for good ps -a listings */
- break;
- case 'f':
- useoldfullscreen = 1;
- break;
- case 'g':
- usegestures = 1;
- break;
- case 'b':
- usebigarrow = 1;
- break;
- default:
- usage();
- }ARGEND
-
- setprocname(argv0);
-
- if (envvar = getenv("devdrawretina"))
- devdrawretina = atoi(envvar) > 0;
-
- if(OSX_VERSION < 100700)
- [NSAutoreleasePool new];
-
- [NSApplication sharedApplication];
- [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
- myApp = [appdelegate new];
- [NSApp setDelegate:myApp];
- [NSApp run];
-}
-
-#define WIN win.ofs[win.isofs]
-
-struct
-{
- NSWindow *ofs[2]; /* ofs[1] for old fullscreen; ofs[0] else */
- int isofs;
- int isnfs;
- NSView *content;
- NSBitmapImageRep *img;
- int needimg;
- int deferflush;
- NSCursor *cursor;
- CGFloat topointscale;
- CGFloat topixelscale;
-} win;
-
-struct
-{
- NSCursor *bigarrow;
- int kbuttons;
- int mbuttons;
- NSPoint mpos;
- int mscroll;
- int willactivate;
-} in;
-
-static void hidebars(int);
-static void flushimg(NSRect);
-static void autoflushwin(int);
-static void flushwin(void);
-static void followzoombutton(NSRect);
-static void getmousepos(void);
-static void makeicon(void);
-static void makemenu(void);
-static void makewin(char*);
-static void sendmouse(void);
-static void kicklabel0(char*);
-static void setcursor0(Cursor*);
-static void togglefs(void);
-static void acceptresizing(int);
-
-static NSCursor* makecursor(Cursor*);
-
-static NSSize winsizepixels();
-static NSSize winsizepoints();
-static NSRect scalerect(NSRect, CGFloat);
-static NSPoint scalepoint(NSPoint, CGFloat);
-static NSRect dilate(NSRect);
-
-@implementation appdelegate
-- (void)applicationDidFinishLaunching:(id)arg
-{
- in.bigarrow = makecursor(&bigarrow);
- makeicon();
- makemenu();
- [NSApplication
- detachDrawingThread:@selector(callservep9p:)
- toTarget:[self class] withObject:nil];
-}
-
-- (void)windowDidBecomeKey:(id)arg
-{
- getmousepos();
- sendmouse();
-}
-- (void)windowDidResize:(id)arg
-{
- getmousepos();
- sendmouse();
-}
-- (void)windowWillStartLiveResize:(id)arg
-{
- if(useliveresizing == 0)
- [win.content setHidden:YES];
-}
-- (void)windowDidEndLiveResize:(id)arg
-{
- if(useliveresizing == 0)
- [win.content setHidden:NO];
-}
-- (void)windowDidChangeScreen:(id)arg
-{
- if(win.isnfs || win.isofs)
- hidebars(1);
- [win.ofs[1] setFrame:[[WIN screen] frame] display:YES];
-}
-- (BOOL)windowShouldZoom:(id)arg toFrame:(NSRect)r
-{
- followzoombutton(r);
- return YES;
-}
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(id)arg
-{
- return YES;
-}
-- (void)applicationDidBecomeActive:(id)arg{ in.willactivate = 0;}
-- (void)windowWillEnterFullScreen:(id)arg{ acceptresizing(1);}
-- (void)windowDidEnterFullScreen:(id)arg{ win.isnfs = 1; hidebars(1);}
-- (void)windowWillExitFullScreen:(id)arg{ win.isnfs = 0; hidebars(0);}
-- (void)windowDidExitFullScreen:(id)arg
-{
- NSButton *b;
-
- b = [WIN standardWindowButton:NSWindowMiniaturizeButton];
-
- if([b isEnabled] == 0){
- [b setEnabled:YES];
- hidebars(0);
- }
-}
-- (void)windowWillClose:(id)arg
-{
- autoflushwin(0); /* can crash otherwise */
-}
-
-+ (void)callservep9p:(id)arg
-{
- servep9p();
- [NSApp terminate:self];
-}
-- (void)plumbmanual:(id)arg
-{
- if(fork() != 0)
- return;
- execl("plumb", "plumb", "devdraw(1)", nil);
-}
-+ (void)callflushwin:(id)arg{ flushwin();}
-- (void)calltogglefs:(id)arg{ togglefs();}
-
-+ (void)callflushimg:(NSValue*)v{ flushimg([v rectValue]);}
-+ (void)callmakewin:(NSValue*)v{ makewin([v pointerValue]);}
-+ (void)callsetcursor0:(NSValue*)v{ setcursor0([v pointerValue]);}
-+ (void)callkicklabel0:(NSValue*)v{ kicklabel0([v pointerValue]);}
-@end
-
-static Memimage* initimg(void);
-
-Memimage*
-attachscreen(char *label, char *winsize)
-{
- static int first = 1;
-
- if(first)
- first = 0;
- else
- panic("attachscreen called twice");
-
- if(label == nil)
- label = "gnot a label";
- if(strcmp(label, "page") == 0)
- useliveresizing = 1;
-
- /*
- * Create window in main thread, else no cursor
- * change while resizing.
- */
- [appdelegate
- performSelectorOnMainThread:@selector(callmakewin:)
- withObject:[NSValue valueWithPointer:winsize]
- waitUntilDone:YES];
-// makewin(winsize);
-
- kicklabel(label);
- return initimg();
-}
-
-@interface appwin : NSWindow @end
-@interface contentview : NSView @end
-
-@implementation appwin
-- (NSTimeInterval)animationResizeTime:(NSRect)r
-{
- return 0;
-}
-- (BOOL)canBecomeKeyWindow
-{
- return YES; /* else no keyboard for old fullscreen */
-}
-- (void)makeKeyAndOrderFront:(id)arg
-{
- LOG(@"makeKeyAndOrderFront");
-
- autoflushwin(1);
- [win.content setHidden:NO];
- [super makeKeyAndOrderFront:arg];
-}
-- (void)miniaturize:(id)arg
-{
- [super miniaturize:arg];
- [NSApp hide:nil];
-
- [win.content setHidden:YES];
- autoflushwin(0);
-}
-- (void)deminiaturize:(id)arg
-{
- autoflushwin(1);
- [win.content setHidden:NO];
- [super deminiaturize:arg];
-}
-
-- (NSDragOperation)draggingEntered:(id)arg
-{
- NSPasteboard *b;
- NSDragOperation op;
-
- op = [arg draggingSourceOperationMask];
- b = [arg draggingPasteboard];
-
- if([[b types] containsObject:NSFilenamesPboardType])
- if(op&NSDragOperationLink)
- return NSDragOperationLink;
-
- return NSDragOperationNone;
-}
-
-- (BOOL)performDragOperation:(id)arg
-{
- NSPasteboard *b;
- NSArray *files;
- int i, n;
-
- b = [arg draggingPasteboard];
- if(![[b types] containsObject:NSFilenamesPboardType])
- return NO;
-
- files = [b propertyListForType:NSFilenamesPboardType];
- n = [files count];
- for(i=0; i<n; i++)
- if(fork() == 0)
- execl("macedit", "macedit", [[files objectAtIndex:i] UTF8String], nil);
-
- return YES;
-}
-
-@end
-
-double
-min(double a, double b)
-{
- return a<b? a : b;
-}
-
-enum
-{
- Winstyle = NSTitledWindowMask
- | NSClosableWindowMask
- | NSMiniaturizableWindowMask
- | NSResizableWindowMask
-};
-
-static void
-makewin(char *s)
-{
- NSRect r, sr;
- NSWindow *w;
- Rectangle wr;
- int i, set;
-
- sr = [[NSScreen mainScreen] frame];
- r = [[NSScreen mainScreen] visibleFrame];
-
- if(s && *s){
- if(parsewinsize(s, &wr, &set) < 0)
- sysfatal("%r");
- }else{
- wr = Rect(0, 0, sr.size.width*2/3, sr.size.height*2/3);
- set = 0;
- }
-
- r.origin.x = wr.min.x;
- r.origin.y = sr.size.height-wr.max.y; /* winsize is top-left-based */
- r.size.width = min(Dx(wr), r.size.width);
- r.size.height = min(Dy(wr), r.size.height);
- r = [NSWindow contentRectForFrameRect:r
- styleMask:Winstyle];
-
- w = [[appwin alloc]
- initWithContentRect:r
- styleMask:Winstyle
- backing:NSBackingStoreBuffered defer:NO];
- [w setTitle:@"devdraw"];
-
- if(!set)
- [w center];
-#if OSX_VERSION >= 100700
- [w setCollectionBehavior:
- NSWindowCollectionBehaviorFullScreenPrimary];
-#endif
- [w setContentMinSize:NSMakeSize(128,128)];
-
- [w registerForDraggedTypes:[NSArray arrayWithObjects:
- NSFilenamesPboardType, nil]];
-
- win.ofs[0] = w;
- win.ofs[1] = [[appwin alloc]
- initWithContentRect:sr
- styleMask:NSBorderlessWindowMask
- backing:NSBackingStoreBuffered defer:YES];
- for(i=0; i<2; i++){
- [win.ofs[i] setAcceptsMouseMovedEvents:YES];
- [win.ofs[i] setDelegate:myApp];
- [win.ofs[i] setDisplaysWhenScreenProfileChanges:NO];
- }
- win.isofs = 0;
- win.content = [contentview new];
- [WIN setContentView:win.content];
-
- topwin();
-}
-
-static Memimage*
-initimg(void)
-{
- Memimage *i;
- NSSize size, ptsize;
- Rectangle r;
-
- size = winsizepixels();
- LOG(@"initimg %.0f %.0f", size.width, size.height);
-
- r = Rect(0, 0, size.width, size.height);
- i = allocmemimage(r, XBGR32);
- if(i == nil)
- panic("allocmemimage: %r");
- if(i->data == nil)
- panic("i->data == nil");
-
- win.img = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:&i->data->bdata
- pixelsWide:Dx(r)
- pixelsHigh:Dy(r)
- bitsPerSample:8
- samplesPerPixel:3
- hasAlpha:NO
- isPlanar:NO
- colorSpaceName:NSDeviceRGBColorSpace
- bytesPerRow:bytesperline(r, 32)
- bitsPerPixel:32];
- ptsize = winsizepoints();
- [win.img setSize: ptsize];
- win.topixelscale = size.width / ptsize.width;
- win.topointscale = 1.0f / win.topixelscale;
-
- // NOTE: This is not really the display DPI.
- // On retina, topixelscale is 2; otherwise it is 1.
- // This formula gives us 220 for retina, 110 otherwise.
- // That's not quite right but it's close to correct.
- // http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density#Apple
- displaydpi = win.topixelscale * 110;
-
- return i;
-}
-
-void
-resizeimg(void)
-{
- [win.img release];
- _drawreplacescreenimage(initimg());
-
- mouseresized = 1;
- sendmouse();
-}
-
-static void
-waitimg(int msec)
-{
- NSDate *limit;
- int n;
-
- win.needimg = 1;
- win.deferflush = 0;
-
- n = 0;
- limit = [NSDate dateWithTimeIntervalSinceNow:msec/1000.0];
- do{
- [[NSRunLoop currentRunLoop]
- runMode:@"waiting image"
- beforeDate:limit];
- n++;
- }while(win.needimg && [(NSDate*)[NSDate date] compare:limit]<0);
-
- win.deferflush = win.needimg;
-
- LOG(@"waitimg %s (%d loop)", win.needimg?"defer":"ok", n);
-}
-
-void
-_flushmemscreen(Rectangle r)
-{
- static int n;
- NSRect rect;
-
- LOG(@"_flushmemscreen");
-
- if(n==0){
- n++;
- return; /* to skip useless white init rect */
- }else
- if(n==1){
- [WIN performSelectorOnMainThread:
- @selector(makeKeyAndOrderFront:)
- withObject:nil
- waitUntilDone:NO];
- n++;
- }else
- if([win.content canDraw] == 0)
- return;
-
- rect = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r));
-
- // This can get blocked behind responding to mouse events,
- // which need to acquire the zlock, so let go of it during
- // the flush. Perhaps the waitUntilDone:YES is wrong?
- zunlock();
- [appdelegate
- performSelectorOnMainThread:@selector(callflushimg:)
- withObject:[NSValue valueWithRect:rect]
- waitUntilDone:YES
- modes:[NSArray arrayWithObjects:
- NSRunLoopCommonModes,
- @"waiting image", nil]];
- zlock();
-}
-
-static void drawimg(NSRect, uint);
-static void drawresizehandle(void);
-
-enum
-{
- Pixel = 1,
- Barsize = 4*Pixel,
- Cornersize = 3*Pixel,
- Handlesize = 3*Barsize + 1*Pixel,
-};
-
-/*
- * |rect| is in pixel coordinates.
- */
-static void
-flushimg(NSRect rect)
-{
- NSRect dr, r;
-
- if([win.content lockFocusIfCanDraw] == 0)
- return;
-
- if(win.needimg){
- if(!NSEqualSizes(scalerect(rect, win.topointscale).size, [win.img size])){
- LOG(@"flushimg reject %.0f %.0f",
- rect.size.width, rect.size.height);
- [win.content unlockFocus];
- return;
- }
- win.needimg = 0;
- }else
- win.deferflush = 1;
-
- LOG(@"flushimg ok %.0f %.0f", rect.size.width, rect.size.height);
-
- /*
- * Unless we are inside "drawRect", we have to round
- * the corners ourselves, if this is the custom.
- * "NSCompositeSourceIn" can do that, but we don't
- * apply it to the whole rectangle, because this
- * slows down trackpad scrolling considerably in
- * Acme.
- */
- r = [win.content bounds];
- rect = dilate(scalerect(rect, win.topointscale));
- r.size.height -= Cornersize;
- dr = NSIntersectionRect(r, rect);
- LOG(@"r %.0f %.0f %.0f %.0f", r.origin.x, r.origin.y, rect.size.width, rect.size.height);
- LOG(@"rect in points %f %f %.0f %.0f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
- LOG(@"dr in points %f %f %.0f %.0f", dr.origin.x, dr.origin.y, dr.size.width, dr.size.height);
- drawimg(dr, NSCompositeCopy);
-
- r.origin.y = r.size.height;
- r.size = NSMakeSize(Cornersize, Cornersize);
- dr = NSIntersectionRect(r, rect);
- drawimg(dr, NSCompositeSourceIn);
-
- r.origin.x = [win.img size].width - Cornersize;
- dr = NSIntersectionRect(r, rect);
- drawimg(dr, NSCompositeSourceIn);
-
- r.size.width = r.origin.x - Cornersize;
- r.origin.x -= r.size.width;
- dr = NSIntersectionRect(r, rect);
- drawimg(dr, NSCompositeCopy);
-
- if(OSX_VERSION<100700 && win.isofs==0){
- r.origin.x = [win.img size].width - Handlesize;
- r.origin.y = [win.img size].height - Handlesize;
- r.size = NSMakeSize(Handlesize, Handlesize);
- if(NSIntersectsRect(r, rect))
- drawresizehandle();
- }
- [win.content unlockFocus];
-}
-
-static void
-autoflushwin(int set)
-{
- static NSTimer *t;
-
- if(set){
- if(t)
- return;
- /*
- * We need "NSRunLoopCommonModes", otherwise the
- * timer will not fire during live resizing.
- */
- t = [NSTimer
- timerWithTimeInterval:0.033
- target:[appdelegate class]
- selector:@selector(callflushwin:) userInfo:nil
- repeats:YES];
- [[NSRunLoop currentRunLoop] addTimer:t
- forMode:NSRunLoopCommonModes];
- }else{
- [t invalidate];
- t = nil;
- win.deferflush = 0;
- }
-}
-
-static void
-flushwin(void)
-{
- if(win.deferflush && win.needimg==0){
- [WIN flushWindow];
- win.deferflush = 0;
- }
-}
-
-/*
- * |dr| is sized in points. What if I make it pixels?
- */
-static void
-drawimg(NSRect dr, uint op)
-{
- CGContextRef c;
- CGImageRef i;
- NSRect sr;
-
- if(NSIsEmptyRect(dr))
- return;
-
- sr = [win.content convertRect:dr fromView:nil];
- LOG(@"before dr: %f %f %f %f\n", dr.origin.x, dr.origin.y, dr.size.width, dr.size.height);
- LOG(@"before sr: %f %f %f %f\n", sr.origin.x, sr.origin.y, sr.size.width, sr.size.height);
-
- dr = scalerect(dr, win.topixelscale);
- sr = scalerect(sr, win.topixelscale);
-
- LOG(@"dr: %f %f %f %f\n", dr.origin.x, dr.origin.y, dr.size.width, dr.size.height);
- LOG(@"sr: %f %f %f %f\n", sr.origin.x, sr.origin.y, sr.size.width, sr.size.height);
- if(OSX_VERSION >= 100800){
- i = CGImageCreateWithImageInRect([win.img CGImage], NSRectToCGRect(dr));
- c = [[WIN graphicsContext] graphicsPort];
-
- CGContextSaveGState(c);
- if(op == NSCompositeSourceIn)
- CGContextSetBlendMode(c, kCGBlendModeSourceIn);
- LOG(@"wim.img size %f %f\n", [win.img size].width, [win.img size].height);
- CGContextTranslateCTM(c, 0, [win.img size].height);
- CGContextScaleCTM(c, win.topointscale, -win.topointscale);
- CGContextDrawImage(c, NSRectToCGRect(sr), i);
- CGContextRestoreGState(c);
-
- CGImageRelease(i);
- }else{
- [win.img drawInRect:dr fromRect:sr
- operation:op fraction:1
- respectFlipped:YES hints:nil];
- }
-// NSFrameRect(dr);
-}
-
-static void
-drawresizehandle(void)
-{
- NSColor *color[Barsize];
- NSPoint a,b;
- Point c;
- int i,j;
-
- c = Pt([win.img size].width, [win.img size].height);
-
- [[WIN graphicsContext] setShouldAntialias:NO];
-
- color[0] = [NSColor clearColor];
- color[1] = [NSColor darkGrayColor];
- color[2] = [NSColor lightGrayColor];
- color[3] = [NSColor whiteColor];
-
- for(i=1; i+Barsize <= Handlesize; )
- for(j=0; j<Barsize; j++){
- [color[j] setStroke];
- i++;
- a = NSMakePoint(c.x-i, c.y-1);
- b = NSMakePoint(c.x-2, c.y+1-i);
- [NSBezierPath strokeLineFromPoint:a toPoint:b];
- }
-}
-
-static void getgesture(NSEvent*);
-static void getkeyboard(NSEvent*);
-static void getmouse(NSEvent*);
-static void gettouch(NSEvent*, int);
-static void updatecursor(void);
-
-@implementation contentview
-/*
- * "drawRect" is called each time Cocoa needs an
- * image, and each time we call "display". It is
- * preceded by background painting, and followed by
- * "flushWindow".
- */
-- (void)drawRect:(NSRect)r
-{
- static int first = 1;
-
- LOG(@"drawrect %.0f %.0f %.0f %.0f",
- r.origin.x, r.origin.y, r.size.width, r.size.height);
-
- if(first)
- first = 0;
- else
- resizeimg();
-
- if([WIN inLiveResize])
- waitimg(100);
- else
- waitimg(500);
-}
-- (BOOL)isFlipped
-{
- return YES; /* to make the content's origin top left */
-}
-- (BOOL)acceptsFirstResponder
-{
- return YES; /* else no keyboard */
-}
-- (id)initWithFrame:(NSRect)r
-{
- [super initWithFrame:r];
- [self setAcceptsTouchEvents:YES];
- [self setHidden:YES]; /* to avoid early "drawRect" call */
- return self;
-}
-- (void)setHidden:(BOOL)set
-{
- if(!set)
- [WIN makeFirstResponder:self]; /* for keyboard focus */
- [super setHidden:set];
-}
-- (void)cursorUpdate:(NSEvent*)e{ updatecursor();}
-
-- (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{ getgesture(e);}
-
-- (void)touchesBeganWithEvent:(NSEvent*)e
-{
- gettouch(e, NSTouchPhaseBegan);
-}
-- (void)touchesMovedWithEvent:(NSEvent*)e
-{
- gettouch(e, NSTouchPhaseMoved);
-}
-- (void)touchesEndedWithEvent:(NSEvent*)e
-{
- gettouch(e, NSTouchPhaseEnded);
-}
-- (void)touchesCancelledWithEvent:(NSEvent*)e
-{
- gettouch(e, NSTouchPhaseCancelled);
-}
-@end
-
-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',
-};
-
-@interface apptext : NSTextView @end
-
-@implementation apptext
-- (void)doCommandBySelector:(SEL)s{} /* Esc key beeps otherwise */
-- (void)insertText:(id)arg{} /* to avoid a latency after some time */
-@end
-
-static void
-interpretdeadkey(NSEvent *e)
-{
- static apptext *t;
-
- if(t == nil)
- t = [apptext new];
- [t interpretKeyEvents:[NSArray arrayWithObject:e]];
-}
-
-static void
-getkeyboard(NSEvent *e)
-{
- static int omod;
- NSString *s;
- char c;
- int k, m;
- uint code;
-
- m = [e modifierFlags];
-
- switch([e type]){
- case NSKeyDown:
- s = [e characters];
- c = [s UTF8String][0];
-
- interpretdeadkey(e);
-
- if(m & NSCommandKeyMask){
- if((m & NSShiftKeyMask) && 'a' <= c && c <= 'z')
- c += 'A' - 'a';
- if(' '<=c && c<='~')
- keystroke(Kcmd+c);
- break;
- }
- k = c;
- code = [e keyCode];
- if(code<nelem(keycvt) && keycvt[code])
- k = keycvt[code];
- if(k==0)
- break;
- if(k>0)
- keystroke(k);
- else
- keystroke([s characterAtIndex:0]);
- break;
-
- case NSFlagsChanged:
- if(in.mbuttons || in.kbuttons){
- in.kbuttons = 0;
- if(m & NSControlKeyMask)
- in.kbuttons |= 1;
- if(m & NSAlternateKeyMask)
- in.kbuttons |= 2;
- if(m & NSCommandKeyMask)
- in.kbuttons |= 4;
- sendmouse();
- }else
- if(m&NSAlternateKeyMask && (omod&NSAlternateKeyMask)==0)
- keystroke(Kalt);
- break;
-
- default:
- panic("getkey: unexpected event type");
- }
- omod = m;
-}
-
-/*
- * Devdraw does not use NSTrackingArea, that often
- * forgets to update the cursor on entering and on
- * leaving the area, and that sometimes stops sending
- * us MouseMove events, at least on OS X Lion.
- */
-static void
-updatecursor(void)
-{
- NSCursor *c;
- int isdown, isinside;
-
- isinside = NSPointInRect(in.mpos, [win.content bounds]);
- isdown = (in.mbuttons || in.kbuttons);
-
- if(win.cursor && (isinside || isdown))
- c = win.cursor;
- else if(isinside && usebigarrow)
- c = in.bigarrow;
- else
- c = [NSCursor arrowCursor];
- [c set];
-
- /*
- * Without this trick, we can come back from the dock
- * with a resize cursor.
- */
- if(OSX_VERSION >= 100700)
- [NSCursor unhide];
-}
-
-static void
-acceptresizing(int set)
-{
- uint old, style;
-
- old = [WIN styleMask];
-
- if((old | NSResizableWindowMask) != Winstyle)
- return; /* when entering new fullscreen */
-
- if(set)
- style = Winstyle;
- else
- style = Winstyle & ~NSResizableWindowMask;
-
- if(style != old)
- [WIN setStyleMask:style];
-}
-
-static void
-getmousepos(void)
-{
- NSPoint p, q;
-
- p = [WIN mouseLocationOutsideOfEventStream];
- q = [win.content convertPoint:p fromView:nil];
-
- /* q is in point coordinates. in.mpos is in pixels. */
- q = scalepoint(q, win.topixelscale);
-
- in.mpos.x = round(q.x);
- in.mpos.y = round(q.y);
-
- updatecursor();
-
- if(win.isnfs || win.isofs)
- hidebars(1);
- else if(OSX_VERSION>=100700 && [WIN inLiveResize]==0){
- if(p.x<12 && p.y<12 && p.x>2 && p.y>2)
- acceptresizing(0);
- else
- acceptresizing(1);
- }
-}
-
-static void
-getmouse(NSEvent *e)
-{
- float d;
- int b, m;
-
- if([WIN isKeyWindow] == 0)
- return;
-
- 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){
- abortcompose();
- b = 2;
- }else
- if(m & NSCommandKeyMask)
- b = 4;
- }
- in.mbuttons = b;
- break;
-
- case NSScrollWheel:
-#if OSX_VERSION >= 100700
- d = [e scrollingDeltaY];
-#else
- d = [e deltaY];
-#endif
- if(d>0)
- in.mscroll = 8;
- else
- if(d<0)
- in.mscroll = 16;
- break;
-
- case NSMouseMoved:
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSOtherMouseDragged:
- break;
-
- default:
- panic("getmouse: unexpected event type");
- }
- sendmouse();
-}
-
-#define Minpinch 0.02
-
-static void
-getgesture(NSEvent *e)
-{
- switch([e type]){
- case NSEventTypeMagnify:
- if(fabs([e magnification]) > Minpinch)
- togglefs();
- break;
- }
-}
-
-static void sendclick(int);
-
-static uint
-msec(void)
-{
- return nsec()/1000000;
-}
-
-static void
-gettouch(NSEvent *e, int type)
-{
- static int tapping;
- static uint taptime;
- NSSet *set;
- int p;
-
- switch(type){
- case NSTouchPhaseBegan:
- p = NSTouchPhaseTouching;
- set = [e touchesMatchingPhase:p inView:nil];
- if(set.count == 3){
- tapping = 1;
- taptime = msec();
- }else
- if(set.count > 3)
- tapping = 0;
- break;
-
- case NSTouchPhaseMoved:
- tapping = 0;
- break;
-
- case NSTouchPhaseEnded:
- p = NSTouchPhaseTouching;
- set = [e touchesMatchingPhase:p inView:nil];
- if(set.count == 0){
- if(tapping && msec()-taptime<400)
- sendclick(2);
- tapping = 0;
- }
- break;
-
- case NSTouchPhaseCancelled:
- break;
-
- default:
- panic("gettouch: unexpected event type");
- }
-}
-
-static void
-sendclick(int b)
-{
- in.mbuttons = b;
- sendmouse();
- in.mbuttons = 0;
- sendmouse();
-}
-
-static void
-sendmouse(void)
-{
- NSSize size;
- int b;
-
- size = winsizepixels();
- mouserect = Rect(0, 0, size.width, size.height);
-
- b = in.kbuttons | in.mbuttons | in.mscroll;
- mousetrack(in.mpos.x, in.mpos.y, b, msec());
- in.mscroll = 0;
-}
-
-/*
- * |p| is in pixels.
- */
-void
-setmouse(Point p)
-{
- NSPoint q;
- NSRect r;
-
- if([NSApp isActive]==0 && in.willactivate==0)
- return;
-
- if([WIN inLiveResize])
- return;
-
- in.mpos = scalepoint(NSMakePoint(p.x, p.y), win.topointscale); // race condition
-
- q = [win.content convertPoint:in.mpos toView:nil];
- q = [WIN convertRectToScreen:NSMakeRect(q.x, q.y, 0, 0)].origin;
-
- r = [[[NSScreen screens] objectAtIndex:0] frame];
- q.y = r.size.height - q.y; /* Quartz is top-left-based here */
-
- CGWarpMouseCursorPosition(NSPointToCGPoint(q));
- CGAssociateMouseAndMouseCursorPosition(true);
-}
-
-/*
- * |r| is in points.
- */
-static void
-followzoombutton(NSRect r)
-{
- NSRect wr;
- Point p;
- NSPoint pt;
-
- wr = [WIN frame];
- wr.origin.y += wr.size.height;
- r.origin.y += r.size.height;
-
- getmousepos();
- pt.x = in.mpos.x;
- pt.y = in.mpos.y;
- pt = scalepoint(pt, win.topointscale);
- pt.x = (r.origin.x - wr.origin.x) + pt.x;
- pt.y = -(r.origin.y - wr.origin.y) + pt.y;
- pt = scalepoint(pt, win.topixelscale);
-
- p.x = pt.x;
- p.y = pt.y;
-
- setmouse(p);
-}
-
-static void
-togglefs(void)
-{
- uint opt, tmp;
-
-#if OSX_VERSION >= 100700
- NSScreen *s, *s0;
-
- s = [WIN screen];
- s0 = [[NSScreen screens] objectAtIndex:0];
-
- if((s==s0 && useoldfullscreen==0) || win.isnfs) {
- [WIN toggleFullScreen:nil];
- return;
- }
-#endif
- [win.content retain];
- [WIN orderOut:nil];
- [WIN setContentView:nil];
-
- win.isofs = ! win.isofs;
- hidebars(win.isofs);
-
- /*
- * If we move the window from one space to another,
- * ofs[0] and ofs[1] can be on different spaces.
- * This "setCollectionBehavior" trick moves the
- * window to the active space.
- */
- opt = [WIN collectionBehavior];
- tmp = opt | NSWindowCollectionBehaviorCanJoinAllSpaces;
- [WIN setContentView:win.content];
- [WIN setCollectionBehavior:tmp];
- [WIN makeKeyAndOrderFront:nil];
- [WIN setCollectionBehavior:opt];
- [win.content release];
-}
-
-enum
-{
- Autohiddenbars = NSApplicationPresentationAutoHideDock
- | NSApplicationPresentationAutoHideMenuBar,
-
- Hiddenbars = NSApplicationPresentationHideDock
- | NSApplicationPresentationHideMenuBar,
-};
-
-static void
-hidebars(int set)
-{
- NSScreen *s,*s0;
- uint old, opt;
-
- s = [WIN screen];
- s0 = [[NSScreen screens] objectAtIndex:0];
- old = [NSApp presentationOptions];
-
-#if OSX_VERSION >= 100700
- /* This bit can get lost, resulting in dreadful bugs. */
- if(win.isnfs)
- old |= NSApplicationPresentationFullScreen;
-#endif
-
- if(set && s==s0)
- opt = (old & ~Autohiddenbars) | Hiddenbars;
- else
- opt = old & ~(Autohiddenbars | Hiddenbars);
-
- if(opt != old)
- [NSApp setPresentationOptions:opt];
-}
-
-static void
-makemenu(void)
-{
- NSMenu *m;
- NSMenuItem *i0,*i1;
-
- m = [NSMenu new];
- i0 = [m addItemWithTitle:@"app" action:NULL keyEquivalent:@""];
- i1 = [m addItemWithTitle:@"help" action:NULL keyEquivalent:@""];
- [NSApp setMainMenu:m];
- [m release];
-
- m = [[NSMenu alloc] initWithTitle:@"app"];
- [m addItemWithTitle:@"Full Screen"
- action:@selector(calltogglefs:)
- keyEquivalent:@"f"];
- [m addItemWithTitle:@"Hide"
- action:@selector(hide:)
- keyEquivalent:@"h"];
- [m addItemWithTitle:@"Quit"
- action:@selector(terminate:)
- keyEquivalent:@"q"];
- [i0 setSubmenu:m];
- [m release];
-
- m = [[NSMenu alloc] initWithTitle:@"help"];
- [m addItemWithTitle:@"Plumb devdraw(1)"
- action:@selector(plumbmanual:)
- keyEquivalent:@""];
- [i1 setSubmenu:m];
- [m release];
-}
-
-// FIXME: Introduce a high-resolution Glenda image.
-static void
-makeicon(void)
-{
- NSData *d;
- NSImage *i;
-
- d = [[NSData alloc]
- initWithBytes:glenda_png
- length:(sizeof glenda_png)];
-
- i = [[NSImage alloc] initWithData:d];
- [NSApp setApplicationIconImage:i];
- [[NSApp dockTile] display];
- [i release];
- [d release];
-}
-
-QLock snarfl;
-
-char*
-getsnarf(void)
-{
- NSPasteboard *pb;
- NSString *s;
-
- pb = [NSPasteboard generalPasteboard];
-
- qlock(&snarfl);
- s = [pb stringForType:NSPasteboardTypeString];
- qunlock(&snarfl);
-
- if(s)
- return strdup((char*)[s UTF8String]);
- else
- return nil;
-}
-
-void
-putsnarf(char *s)
-{
- NSArray *t;
- NSPasteboard *pb;
- NSString *str;
-
- if(strlen(s) >= SnarfSize)
- return;
-
- t = [NSArray arrayWithObject:NSPasteboardTypeString];
- pb = [NSPasteboard generalPasteboard];
- str = [[NSString alloc] initWithUTF8String:s];
-
- qlock(&snarfl);
- [pb declareTypes:t owner:nil];
- [pb setString:str forType:NSPasteboardTypeString];
- qunlock(&snarfl);
-
- [str release];
-}
-
-void
-kicklabel(char *label)
-{
- if(label == nil)
- return;
-
- [appdelegate
- performSelectorOnMainThread:@selector(callkicklabel0:)
- withObject:[NSValue valueWithPointer:label]
- waitUntilDone:YES];
-}
-
-static void
-kicklabel0(char *label) {
- NSString *s;
-
- s = [[NSString alloc] initWithUTF8String:label];
- [win.ofs[0] setTitle:s];
- [win.ofs[1] setTitle:s];
- [[NSApp dockTile] setBadgeLabel:s];
- [s release];
-}
-
-void
-setcursor(Cursor *c, Cursor2 *c2)
-{
- USED(c2);
-
- /*
- * No cursor change unless in main thread.
- */
- [appdelegate
- performSelectorOnMainThread:@selector(callsetcursor0:)
- withObject:[NSValue valueWithPointer:c]
- waitUntilDone:YES];
-}
-
-static void
-setcursor0(Cursor *c)
-{
- NSCursor *d;
-
- d = win.cursor;
-
- if(c)
- win.cursor = makecursor(c);
- else
- win.cursor = nil;
-
- updatecursor();
-
- if(d)
- [d release];
-}
-
-/*
- * Cursors will be scaled on retina display.
- */
-static NSCursor*
-makecursor(Cursor *c)
-{
- NSBitmapImageRep *r;
- NSCursor *d;
- NSImage *i;
- NSPoint p;
- int b;
- uchar *plane[5];
-
- r = [[NSBitmapImageRep alloc]
- initWithBitmapDataPlanes:nil
- pixelsWide:16
- pixelsHigh:16
- bitsPerSample:1
- samplesPerPixel:2
- hasAlpha:YES
- isPlanar:YES
- colorSpaceName:NSDeviceWhiteColorSpace
- bytesPerRow:2
- bitsPerPixel:1];
-
- [r getBitmapDataPlanes:plane];
-
- for(b=0; b<2*16; b++){
- plane[0][b] = ~c->set[b];
- plane[1][b] = c->clr[b];
- }
- p = NSMakePoint(-c->offset.x, -c->offset.y);
- i = [NSImage new];
- [i addRepresentation:r];
- [r release];
-
- d = [[NSCursor alloc] initWithImage:i hotSpot:p];
- [i release];
- return d;
-}
-
-void
-topwin(void)
-{
- [WIN performSelectorOnMainThread:
- @selector(makeKeyAndOrderFront:)
- withObject:nil
- waitUntilDone:NO];
-
- in.willactivate = 1;
- [NSApp activateIgnoringOtherApps:YES];
-}
-
-static NSSize
-winsizepoints()
-{
- return [win.content bounds].size;
-}
-
-static NSSize
-winsizepixels()
-{
-#if OSX_VERSION >= 100700
- if (OSX_VERSION >= 100700 && devdrawretina)
- return [win.content convertSizeToBacking: winsizepoints()];
- else
-#endif
- return winsizepoints();
-}
-
-static NSRect
-scalerect(NSRect r, CGFloat scale)
-{
- r.origin.x *= scale;
- r.origin.y *= scale;
- r.size.width *= scale;
- r.size.height *= scale;
- return r;
-}
-
-/*
- * Expands rectangle |r|'s bounds to more inclusive integer bounds to
- * eliminate 1 pixel gaps.
- */
-static NSRect
-dilate(NSRect r)
-{
- if(win.topixelscale > 1.0f){
- r.origin.x = floorf(r.origin.x);
- r.origin.y = floorf(r.origin.y);
- r.size.width = ceilf(r.size.width + 0.5);
- r.size.height = ceilf(r.size.height + 0.5);
- }
- return r;
-}
-
-static NSPoint
-scalepoint(NSPoint pt, CGFloat scale)
-{
- pt.x *= scale;
- pt.y *= scale;
- return pt;
-}
-
-static void
-setprocname(const char *s)
-{
- CFStringRef process_name;
-
- process_name = CFStringCreateWithBytes(nil, (uchar*)s, strlen(s), kCFStringEncodingUTF8, false);
-
- // Adapted from Chrome's mac_util.mm.
- // http://src.chromium.org/viewvc/chrome/trunk/src/base/mac/mac_util.mm
- //
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived from
- // this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- // Warning: here be dragons! This is SPI reverse-engineered from WebKit's
- // plugin host, and could break at any time (although realistically it's only
- // likely to break in a new major release).
- // When 10.7 is available, check that this still works, and update this
- // comment for 10.8.
-
- // Private CFType used in these LaunchServices calls.
- typedef CFTypeRef PrivateLSASN;
- typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
- typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
- CFStringRef,
- CFStringRef,
- CFDictionaryRef*);
-
- static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
- NULL;
- static LSSetApplicationInformationItemType
- ls_set_application_information_item_func = NULL;
- static CFStringRef ls_display_name_key = NULL;
-
- static bool did_symbol_lookup = false;
- if (!did_symbol_lookup) {
- did_symbol_lookup = true;
- CFBundleRef launch_services_bundle =
- CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
- if (!launch_services_bundle) {
- fprint(2, "Failed to look up LaunchServices bundle\n");
- return;
- }
-
- ls_get_current_application_asn_func =
- (LSGetCurrentApplicationASNType)(
- CFBundleGetFunctionPointerForName(
- launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
- if (!ls_get_current_application_asn_func)
- fprint(2, "Could not find _LSGetCurrentApplicationASN\n");
-
- ls_set_application_information_item_func =
- (LSSetApplicationInformationItemType)(
- CFBundleGetFunctionPointerForName(
- launch_services_bundle,
- CFSTR("_LSSetApplicationInformationItem")));
- if (!ls_set_application_information_item_func)
- fprint(2, "Could not find _LSSetApplicationInformationItem\n");
-
- CFStringRef* key_pointer = (CFStringRef*)(
- CFBundleGetDataPointerForName(launch_services_bundle,
- CFSTR("_kLSDisplayNameKey")));
- ls_display_name_key = key_pointer ? *key_pointer : NULL;
- if (!ls_display_name_key)
- fprint(2, "Could not find _kLSDisplayNameKey\n");
-
- // Internally, this call relies on the Mach ports that are started up by the
- // Carbon Process Manager. In debug builds this usually happens due to how
- // the logging layers are started up; but in release, it isn't started in as
- // much of a defined order. So if the symbols had to be loaded, go ahead
- // and force a call to make sure the manager has been initialized and hence
- // the ports are opened.
- ProcessSerialNumber psn;
- GetCurrentProcess(&psn);
- }
- if (!ls_get_current_application_asn_func ||
- !ls_set_application_information_item_func ||
- !ls_display_name_key) {
- return;
- }
-
- PrivateLSASN asn = ls_get_current_application_asn_func();
- // Constant used by WebKit; what exactly it means is unknown.
- const int magic_session_constant = -2;
- OSErr err =
- ls_set_application_information_item_func(magic_session_constant, asn,
- ls_display_name_key,
- process_name,
- NULL /* optional out param */);
- if(err != noErr)
- fprint(2, "Call to set process name failed\n");
-}
-
-void
-resizewindow(Rectangle r)
-{
- USED(r);
-}
diff --git a/src/cmd/devdraw/cocoa-srv.c b/src/cmd/devdraw/cocoa-srv.c
deleted file mode 100644
index c1cf5983..00000000
--- a/src/cmd/devdraw/cocoa-srv.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * 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[256];
- int ri;
- int wi;
- int stall;
-};
-
-struct Mousebuf
-{
- Mouse m[256];
- Mouse last;
- int ri;
- int wi;
- int stall;
-};
-
-struct Tagbuf
-{
- int t[256];
- 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);
-
- 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, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &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, nil);
- else
- setcursor(&m->cursor, nil);
- replymsg(m);
- break;
-
- case Tcursor2:
- if(m->arrowcursor)
- setcursor(nil, nil);
- else
- setcursor(&m->cursor, &m->cursor2);
- 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:
- zlock();
- 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);
- }
- zunlock();
- break;
-
- case Twrdraw:
- zlock();
- if(_drawmsgwrite(m->data, m->count) < 0)
- replyerror(m);
- else
- replymsg(m);
- zunlock();
- break;
-
- case Ttop:
- topwin();
- replymsg(m);
- break;
-
- case Tresize:
- resizewindow(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, "%ud [%d] -> %W\n", nsec()/1000000, threadid(), 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;
- mouseresized = 0;
- /*
- if(m.resized)
- fprint(2, "sending resize\n");
- */
- mouse.ri++;
- if(mouse.ri == nelem(mouse.m))
- mouse.ri = 0;
- replymsg(&m);
- }
-}
-
-void
-mousetrack(int x, int y, int b, uint 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();
-}
-
-static int alting;
-
-void
-abortcompose(void)
-{
- if(alting)
- keystroke(Kalt);
-}
-
-void
-keystroke(int c)
-{
- static Rune k[10];
- static int nk;
- int i;
-
- if(c == Kalt){
- alting = !alting;
- nk = 0;
- return;
- }
- if(c == Kcmd+'r') {
- if(forcedpi)
- forcedpi = 0;
- else if(displaydpi >= 200)
- forcedpi = 100;
- else
- forcedpi = 225;
- resizeimg();
- 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;
-}
diff --git a/src/cmd/devdraw/cocoa-thread.c b/src/cmd/devdraw/cocoa-thread.c
deleted file mode 100644
index 92b92d2c..00000000
--- a/src/cmd/devdraw/cocoa-thread.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include "cocoa-thread.h"
-
-#ifndef TRY_LIBTHREAD
-
-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);
-}
-
-int
-threadid(void)
-{
- return pthread_mach_thread_np(pthread_self());
-}
-
-#endif
diff --git a/src/cmd/devdraw/cocoa-thread.h b/src/cmd/devdraw/cocoa-thread.h
deleted file mode 100644
index d5793f0a..00000000
--- a/src/cmd/devdraw/cocoa-thread.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * I am too ignorant to know if Cocoa and Libthread
- * can coexist: if I try to include thread.h, now
- * that Devdraw uses Cocoa's threads (and timers), it
- * crashes immediately; when Devdraw was using
- * proccreate(), it could run a little while before to
- * crash; the origin of those crashes is hard to
- * ascertain, because other programs using Libthread
- * (such as 9term, Acme, Plumber, and Sam) currently
- * don't run when compiled with Xcode 4.1.
- */
-//#define TRY_LIBTHREAD
-
-#ifdef TRY_LIBTHREAD
- #include <thread.h>
-#else
- #define QLock DQLock
- #define qlock dqlock
- #define qunlock dqunlock
- #define threadexitsall exits
- #define threadmain main
-
- typedef struct QLock QLock;
-
- struct QLock
- {
- int init;
- pthread_mutex_t m;
- };
-
- void qlock(QLock*);
- void qunlock(QLock*);
- int threadid(void);
-#endif
diff --git a/src/cmd/devdraw/devdraw.c b/src/cmd/devdraw/devdraw.c
index 7f0bff21..086574ef 100644
--- a/src/cmd/devdraw/devdraw.c
+++ b/src/cmd/devdraw/devdraw.c
@@ -8,181 +8,60 @@
#include <draw.h>
#include <memdraw.h>
#include <memlayer.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <keyboard.h>
+#include <drawfcall.h>
#include "devdraw.h"
-extern void _flushmemscreen(Rectangle);
-int forcedpi = 0;
-int displaydpi = 100;
-
-#define NHASH (1<<5)
-#define HASHMASK (NHASH-1)
-
-typedef struct Client Client;
-typedef struct Draw Draw;
-typedef struct DImage DImage;
-typedef struct DScreen DScreen;
-typedef struct CScreen CScreen;
-typedef struct FChar FChar;
-typedef struct Refresh Refresh;
-typedef struct Refx Refx;
-typedef struct DName DName;
-
-struct Draw
-{
- QLock lk;
- int clientid;
- int nclient;
- Client* client[1];
- int nname;
- DName* name;
- int vers;
- int softscreen;
-};
-
-struct Client
-{
- /*Ref r;*/
- DImage* dimage[NHASH];
- CScreen* cscreen;
- Refresh* refresh;
- Rendez refrend;
- uchar* readdata;
- int nreaddata;
- int busy;
- int clientid;
- int slot;
- int refreshme;
- int infoid;
- int op;
-};
-
-struct Refresh
-{
- DImage* dimage;
- Rectangle r;
- Refresh* next;
-};
-
-struct Refx
-{
- Client* client;
- DImage* dimage;
-};
-
-struct DName
-{
- char *name;
- Client *client;
- DImage* dimage;
- int vers;
-};
-
-struct FChar
-{
- int minx; /* left edge of bits */
- int maxx; /* right edge of bits */
- uchar miny; /* first non-zero scan-line */
- uchar maxy; /* last non-zero scan-line + 1 */
- schar left; /* offset of baseline */
- uchar width; /* width of baseline */
-};
-
-/*
- * Reference counts in DImages:
- * one per open by original client
- * one per screen image or fill
- * one per image derived from this one by name
- */
-struct DImage
-{
- int id;
- int ref;
- char *name;
- int vers;
- Memimage* image;
- int ascent;
- int nfchar;
- FChar* fchar;
- DScreen* dscreen; /* 0 if not a window */
- DImage* fromname; /* image this one is derived from, by name */
- DImage* next;
-};
-
-struct CScreen
-{
- DScreen* dscreen;
- CScreen* next;
-};
-
-struct DScreen
-{
- int id;
- int public;
- int ref;
- DImage *dimage;
- DImage *dfill;
- Memscreen* screen;
- Client* owner;
- DScreen* next;
-};
-
-static Draw sdraw;
-static Client *client0;
-static Memimage *screenimage;
-static Rectangle flushrect;
-static int waste;
-static DScreen* dscreen;
static int drawuninstall(Client*, int);
static Memimage* drawinstall(Client*, int, Memimage*, DScreen*);
-static void drawfreedimage(DImage*);
+static void drawfreedimage(Client*, DImage*);
void
-_initdisplaymemimage(Memimage *m)
+draw_initdisplaymemimage(Client *c, Memimage *m)
{
- screenimage = m;
+ c->screenimage = m;
m->screenref = 1;
- client0 = mallocz(sizeof(Client), 1);
- if(client0 == nil){
- fprint(2, "initdraw: allocating client0: out of memory");
- abort();
- }
- client0->slot = 0;
- client0->clientid = ++sdraw.clientid;
- client0->op = SoverD;
- sdraw.client[0] = client0;
- sdraw.nclient = 1;
- sdraw.softscreen = 1;
+ c->slot = 0;
+ c->clientid = 1;
+ c->op = SoverD;
}
+// gfx_replacescreenimage replaces c's screen image with m.
+// It is called by the host driver on the main host thread.
void
-_drawreplacescreenimage(Memimage *m)
+gfx_replacescreenimage(Client *c, Memimage *m)
{
/*
* Replace the screen image because the screen
* was resized.
- *
+ *
* In theory there should only be one reference
* to the current screen image, and that's through
* client0's image 0, installed a few lines above.
- * Once the client drops the image, the underlying backing
+ * Once the client drops the image, the underlying backing
* store freed properly. The client is being notified
* about the resize through external means, so all we
* need to do is this assignment.
*/
Memimage *om;
- qlock(&sdraw.lk);
- om = screenimage;
- screenimage = m;
+ qlock(&c->drawlk);
+ om = c->screenimage;
+ c->screenimage = m;
m->screenref = 1;
if(om && --om->screenref == 0){
_freememimage(om);
}
- qunlock(&sdraw.lk);
+ qunlock(&c->drawlk);
+
+ qlock(&c->eventlk);
+ c->mouse.resized = 1;
+ qunlock(&c->eventlk);
}
-static
-void
+static void
drawrefreshscreen(DImage *l, Client *client)
{
while(l != nil && l->dscreen == nil)
@@ -191,8 +70,7 @@ drawrefreshscreen(DImage *l, Client *client)
l->dscreen->owner->refreshme = 1;
}
-static
-void
+static void
drawrefresh(Memimage *m, Rectangle r, void *v)
{
Refx *x;
@@ -222,57 +100,65 @@ drawrefresh(Memimage *m, Rectangle r, void *v)
}
static void
-addflush(Rectangle r)
+addflush(Client *c, Rectangle r)
{
int abb, ar, anbb;
- Rectangle nbb;
+ Rectangle nbb, fr;
- if(sdraw.softscreen==0 || !rectclip(&r, screenimage->r))
+ if(/*sdraw.softscreen==0 ||*/ !rectclip(&r, c->screenimage->r))
return;
- if(flushrect.min.x >= flushrect.max.x){
- flushrect = r;
- waste = 0;
+ if(c->flushrect.min.x >= c->flushrect.max.x){
+ c->flushrect = r;
+ c->waste = 0;
return;
}
- nbb = flushrect;
+ nbb = c->flushrect;
combinerect(&nbb, r);
ar = Dx(r)*Dy(r);
- abb = Dx(flushrect)*Dy(flushrect);
+ abb = Dx(c->flushrect)*Dy(c->flushrect);
anbb = Dx(nbb)*Dy(nbb);
/*
* Area of new waste is area of new bb minus area of old bb,
* less the area of the new segment, which we assume is not waste.
* This could be negative, but that's OK.
*/
- waste += anbb-abb - ar;
- if(waste < 0)
- waste = 0;
+ c->waste += anbb-abb - ar;
+ if(c->waste < 0)
+ c->waste = 0;
/*
* absorb if:
* total area is small
* waste is less than half total area
* rectangles touch
*/
- if(anbb<=1024 || waste*2<anbb || rectXrect(flushrect, r)){
- flushrect = nbb;
+ if(anbb<=1024 || c->waste*2<anbb || rectXrect(c->flushrect, r)){
+ c->flushrect = nbb;
return;
}
/* emit current state */
- if(flushrect.min.x < flushrect.max.x)
- _flushmemscreen(flushrect);
- flushrect = r;
- waste = 0;
+ fr = c->flushrect;
+ c->flushrect = r;
+ c->waste = 0;
+ if(fr.min.x < fr.max.x) {
+ // Unlock drawlk because rpc_flush may want to run on gfx thread,
+ // and gfx thread might be blocked on drawlk trying to install a new screen
+ // during a resize.
+ rpc_gfxdrawunlock();
+ qunlock(&c->drawlk);
+ rpc_flush(c, fr);
+ qlock(&c->drawlk);
+ rpc_gfxdrawlock();
+ }
}
-static
-void
-dstflush(int dstid, Memimage *dst, Rectangle r)
+static void
+dstflush(Client *c, int dstid, Memimage *dst, Rectangle r)
{
Memlayer *l;
if(dstid == 0){
- combinerect(&flushrect, r);
+ combinerect(&c->flushrect, r);
return;
}
/* how can this happen? -rsc, dec 12 2002 */
@@ -284,25 +170,34 @@ dstflush(int dstid, Memimage *dst, Rectangle r)
if(l == nil)
return;
do{
- if(l->screen->image->data != screenimage->data)
+ if(l->screen->image->data != c->screenimage->data)
return;
r = rectaddpt(r, l->delta);
l = l->screen->image->layer;
}while(l);
- addflush(r);
+ addflush(c, r);
}
-static
-void
-drawflush(void)
+static void
+drawflush(Client *c)
{
- if(flushrect.min.x < flushrect.max.x)
- _flushmemscreen(flushrect);
- flushrect = Rect(10000, 10000, -10000, -10000);
+ Rectangle r;
+
+ r = c->flushrect;
+ c->flushrect = Rect(10000, 10000, -10000, -10000);
+ if(r.min.x < r.max.x) {
+ // Unlock drawlk because rpc_flush may want to run on gfx thread,
+ // and gfx thread might be blocked on drawlk trying to install a new screen
+ // during a resize.
+ rpc_gfxdrawunlock();
+ qunlock(&c->drawlk);
+ rpc_flush(c, r);
+ qlock(&c->drawlk);
+ rpc_gfxdrawlock();
+ }
}
-static
-int
+static int
drawcmp(char *a, char *b, int n)
{
if(strlen(a) != n)
@@ -310,41 +205,38 @@ drawcmp(char *a, char *b, int n)
return memcmp(a, b, n);
}
-static
-DName*
-drawlookupname(int n, char *str)
+static DName*
+drawlookupname(Client *client, int n, char *str)
{
DName *name, *ename;
- name = sdraw.name;
- ename = &name[sdraw.nname];
+ name = client->name;
+ ename = &name[client->nname];
for(; name<ename; name++)
if(drawcmp(name->name, str, n) == 0)
return name;
return 0;
}
-static
-int
-drawgoodname(DImage *d)
+static int
+drawgoodname(Client *client, DImage *d)
{
DName *n;
/* if window, validate the screen's own images */
if(d->dscreen)
- if(drawgoodname(d->dscreen->dimage) == 0
- || drawgoodname(d->dscreen->dfill) == 0)
+ if(drawgoodname(client, d->dscreen->dimage) == 0
+ || drawgoodname(client, d->dscreen->dfill) == 0)
return 0;
if(d->name == nil)
return 1;
- n = drawlookupname(strlen(d->name), d->name);
+ n = drawlookupname(client, strlen(d->name), d->name);
if(n==nil || n->vers!=d->vers)
return 0;
return 1;
}
-static
-DImage*
+static DImage*
drawlookup(Client *client, int id, int checkname)
{
DImage *d;
@@ -356,7 +248,7 @@ drawlookup(Client *client, int id, int checkname)
* BUG: should error out but too hard.
* Return 0 instead.
*/
- if(checkname && !drawgoodname(d))
+ if(checkname && !drawgoodname(client, d))
return 0;
return d;
}
@@ -365,13 +257,12 @@ drawlookup(Client *client, int id, int checkname)
return 0;
}
-static
-DScreen*
-drawlookupdscreen(int id)
+static DScreen*
+drawlookupdscreen(Client *c, int id)
{
DScreen *s;
- s = dscreen;
+ s = c->dscreen;
while(s){
if(s->id == id)
return s;
@@ -380,8 +271,7 @@ drawlookupdscreen(int id)
return 0;
}
-static
-DScreen*
+static DScreen*
drawlookupscreen(Client *client, int id, CScreen **cs)
{
CScreen *s;
@@ -398,8 +288,7 @@ drawlookupscreen(Client *client, int id, CScreen **cs)
return 0;
}
-static
-Memimage*
+static Memimage*
drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
{
DImage *d;
@@ -423,8 +312,7 @@ drawinstall(Client *client, int id, Memimage *i, DScreen *dscreen)
return i;
}
-static
-Memscreen*
+static Memscreen*
drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *dfill, int public)
{
Memscreen *s;
@@ -466,9 +354,9 @@ drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *df
d->id = id;
d->screen = s;
d->public = public;
- d->next = dscreen;
+ d->next = client->dscreen;
d->owner = client;
- dscreen = d;
+ client->dscreen = d;
}
c->dscreen = d;
d->ref++;
@@ -477,20 +365,18 @@ drawinstallscreen(Client *client, DScreen *d, int id, DImage *dimage, DImage *df
return d->screen;
}
-static
-void
-drawdelname(DName *name)
+static void
+drawdelname(Client *client, DName *name)
{
int i;
- i = name-sdraw.name;
- memmove(name, name+1, (sdraw.nname-(i+1))*sizeof(DName));
- sdraw.nname--;
+ i = name-client->name;
+ memmove(name, name+1, (client->nname-(i+1))*sizeof(DName));
+ client->nname--;
}
-static
-void
-drawfreedscreen(DScreen *this)
+static void
+drawfreedscreen(Client *client, DScreen *this)
{
DScreen *ds, *next;
@@ -499,9 +385,9 @@ drawfreedscreen(DScreen *this)
fprint(2, "negative ref in drawfreedscreen\n");
if(this->ref > 0)
return;
- ds = dscreen;
+ ds = client->dscreen;
if(ds == this){
- dscreen = this->next;
+ client->dscreen = this->next;
goto Found;
}
while(next = ds->next){ /* assign = */
@@ -518,16 +404,15 @@ drawfreedscreen(DScreen *this)
Found:
if(this->dimage)
- drawfreedimage(this->dimage);
+ drawfreedimage(client, this->dimage);
if(this->dfill)
- drawfreedimage(this->dfill);
+ drawfreedimage(client, this->dfill);
free(this->screen);
free(this);
}
-static
-void
-drawfreedimage(DImage *dimage)
+static void
+drawfreedimage(Client *client, DImage *dimage)
{
int i;
Memimage *l;
@@ -540,13 +425,13 @@ drawfreedimage(DImage *dimage)
return;
/* any names? */
- for(i=0; i<sdraw.nname; )
- if(sdraw.name[i].dimage == dimage)
- drawdelname(sdraw.name+i);
+ for(i=0; i<client->nname; )
+ if(client->name[i].dimage == dimage)
+ drawdelname(client, client->name+i);
else
i++;
if(dimage->fromname){ /* acquired by name; owned by someone else*/
- drawfreedimage(dimage->fromname);
+ drawfreedimage(client, dimage->fromname);
goto Return;
}
ds = dimage->dscreen;
@@ -554,16 +439,16 @@ drawfreedimage(DImage *dimage)
dimage->dscreen = nil; /* paranoia */
dimage->image = nil;
if(ds){
- if(l->data == screenimage->data)
- addflush(l->layer->screenr);
+ if(l->data == client->screenimage->data)
+ addflush(client, l->layer->screenr);
if(l->layer->refreshfn == drawrefresh) /* else true owner will clean up */
free(l->layer->refreshptr);
l->layer->refreshptr = nil;
- if(drawgoodname(dimage))
+ if(drawgoodname(client, dimage))
memldelete(l);
else
memlfree(l);
- drawfreedscreen(ds);
+ drawfreedscreen(client, ds);
}else{
if(l->screenref==0)
freememimage(l);
@@ -575,8 +460,7 @@ drawfreedimage(DImage *dimage)
free(dimage);
}
-static
-void
+static void
drawuninstallscreen(Client *client, CScreen *this)
{
CScreen *cs, *next;
@@ -584,14 +468,14 @@ drawuninstallscreen(Client *client, CScreen *this)
cs = client->cscreen;
if(cs == this){
client->cscreen = this->next;
- drawfreedscreen(this->dscreen);
+ drawfreedscreen(client, this->dscreen);
free(this);
return;
}
while(next = cs->next){ /* assign = */
if(next == this){
cs->next = this->next;
- drawfreedscreen(this->dscreen);
+ drawfreedscreen(client, this->dscreen);
free(this);
return;
}
@@ -599,8 +483,7 @@ drawuninstallscreen(Client *client, CScreen *this)
}
}
-static
-int
+static int
drawuninstall(Client *client, int id)
{
DImage *d, **l;
@@ -608,28 +491,27 @@ drawuninstall(Client *client, int id)
for(l=&client->dimage[id&HASHMASK]; (d=*l) != nil; l=&d->next){
if(d->id == id){
*l = d->next;
- drawfreedimage(d);
+ drawfreedimage(client, d);
return 0;
}
}
return -1;
}
-static
-int
+static int
drawaddname(Client *client, DImage *di, int n, char *str, char **err)
{
DName *name, *ename, *new, *t;
char *ns;
- name = sdraw.name;
- ename = &name[sdraw.nname];
+ name = client->name;
+ ename = &name[client->nname];
for(; name<ename; name++)
if(drawcmp(name->name, str, n) == 0){
*err = "image name in use";
return -1;
}
- t = mallocz((sdraw.nname+1)*sizeof(DName), 1);
+ t = mallocz((client->nname+1)*sizeof(DName), 1);
ns = malloc(n+1);
if(t == nil || ns == nil){
free(t);
@@ -637,16 +519,16 @@ drawaddname(Client *client, DImage *di, int n, char *str, char **err)
*err = "out of memory";
return -1;
}
- memmove(t, sdraw.name, sdraw.nname*sizeof(DName));
- free(sdraw.name);
- sdraw.name = t;
- new = &sdraw.name[sdraw.nname++];
+ memmove(t, client->name, client->nname*sizeof(DName));
+ free(client->name);
+ client->name = t;
+ new = &client->name[client->nname++];
new->name = ns;
memmove(new->name, str, n);
new->name[n] = 0;
new->dimage = di;
new->client = client;
- new->vers = ++sdraw.vers;
+ new->vers = ++client->namevers;
return 0;
}
@@ -660,8 +542,7 @@ drawclientop(Client *cl)
return op;
}
-static
-Memimage*
+static Memimage*
drawimage(Client *client, uchar *a)
{
DImage *d;
@@ -672,8 +553,7 @@ drawimage(Client *client, uchar *a)
return d->image;
}
-static
-void
+static void
drawrectangle(Rectangle *r, uchar *a)
{
r->min.x = BGLONG(a+0*4);
@@ -682,16 +562,14 @@ drawrectangle(Rectangle *r, uchar *a)
r->max.y = BGLONG(a+3*4);
}
-static
-void
+static void
drawpoint(Point *p, uchar *a)
{
p->x = BGLONG(a+0*4);
p->y = BGLONG(a+1*4);
}
-static
-Point
+static Point
drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int index, int op)
{
FChar *fc;
@@ -711,8 +589,7 @@ drawchar(Memimage *dst, Point p, Memimage *src, Point *sp, DImage *font, int ind
return p;
}
-static
-uchar*
+static uchar*
drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
{
int b, x;
@@ -738,12 +615,9 @@ drawcoord(uchar *p, uchar *maxp, int oldx, int *newx)
}
int
-_drawmsgread(void *a, int n)
+draw_dataread(Client *cl, void *a, int n)
{
- Client *cl;
-
- qlock(&sdraw.lk);
- cl = client0;
+ qlock(&cl->drawlk);
if(cl->readdata == nil){
werrstr("no draw data");
goto err;
@@ -756,23 +630,22 @@ _drawmsgread(void *a, int n)
memmove(a, cl->readdata, cl->nreaddata);
free(cl->readdata);
cl->readdata = nil;
- qunlock(&sdraw.lk);
+ qunlock(&cl->drawlk);
return n;
err:
- qunlock(&sdraw.lk);
+ qunlock(&cl->drawlk);
return -1;
}
int
-_drawmsgwrite(void *v, int n)
+draw_datawrite(Client *client, void *v, int n)
{
char cbuf[40], *err, ibuf[12*12+1], *s;
int c, ci, doflush, dstid, e0, e1, esize, j, m;
- int ni, nw, oesize, oldn, op, ox, oy, repl, scrnid, y;
+ int ni, nw, oesize, oldn, op, ox, oy, repl, scrnid, y;
uchar *a, refresh, *u;
u32int chan, value;
- Client *client;
CScreen *cs;
DImage *di, *ddst, *dsrc, *font, *ll;
DName *dn;
@@ -786,11 +659,11 @@ _drawmsgwrite(void *v, int n)
Refreshfn reffn;
Refx *refx;
- qlock(&sdraw.lk);
+ qlock(&client->drawlk);
+ rpc_gfxdrawlock();
a = v;
m = 0;
oldn = n;
- client = client0;
while((n-=m) > 0){
a += m;
@@ -844,7 +717,7 @@ _drawmsgwrite(void *v, int n)
l = memlalloc(scrn, r, reffn, 0, value);
if(l == 0)
goto Edrawmem;
- addflush(l->layer->screenr);
+ addflush(client, l->layer->screenr);
l->clipr = clipr;
rectclip(&l->clipr, r);
if(drawinstall(client, dstid, l, dscrn) == 0){
@@ -891,7 +764,7 @@ _drawmsgwrite(void *v, int n)
dstid = BGLONG(a+1);
if(dstid == 0)
goto Ebadarg;
- if(drawlookupdscreen(dstid))
+ if(drawlookupdscreen(client, dstid))
goto Escreenexists;
ddst = drawlookup(client, BGLONG(a+5), 1);
dsrc = drawlookup(client, BGLONG(a+9), 1);
@@ -935,7 +808,7 @@ _drawmsgwrite(void *v, int n)
drawpoint(&q, a+37);
op = drawclientop(client);
memdraw(dst, r, src, p, mask, q, op);
- dstflush(dstid, dst, r);
+ dstflush(client, dstid, dst, r);
continue;
/* toggle debugging: 'D' val[1] */
@@ -969,7 +842,7 @@ _drawmsgwrite(void *v, int n)
err = "negative ellipse thickness";
goto error;
}
-
+
drawpoint(&sp, a+29);
c = j;
if(*a == 'E')
@@ -984,7 +857,7 @@ _drawmsgwrite(void *v, int n)
memarc(dst, p, e0, e1, c, src, sp, ox, oy, op);
}else
memellipse(dst, p, e0, e1, c, src, sp, op);
- dstflush(dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
+ dstflush(client, dstid, dst, Rect(p.x-e0-j, p.y-e1-j, p.x+e0+j+1, p.y+e1+j+1));
continue;
/* free: 'f' id[4] */
@@ -1049,7 +922,7 @@ _drawmsgwrite(void *v, int n)
goto Eshortdraw;
if(drawlookup(client, 0, 0))
goto Eimageexists;
- drawinstall(client, 0, screenimage, 0);
+ drawinstall(client, 0, client->screenimage, 0);
client->infoid = 0;
continue;
@@ -1061,7 +934,7 @@ _drawmsgwrite(void *v, int n)
if(client->infoid < 0)
goto Enodrawimage;
if(client->infoid == 0){
- i = screenimage;
+ i = client->screenimage;
if(i == nil)
goto Enodrawimage;
}else{
@@ -1073,11 +946,11 @@ _drawmsgwrite(void *v, int n)
ni = sprint(ibuf, "%11d %11d %11s %11d %11d %11d %11d %11d"
" %11d %11d %11d %11d ",
client->clientid,
- client->infoid,
+ client->infoid,
chantostr(cbuf, i->chan),
(i->flags&Frepl)==Frepl,
i->r.min.x, i->r.min.y, i->r.max.x, i->r.max.y,
- i->clipr.min.x, i->clipr.min.y,
+ i->clipr.min.x, i->clipr.min.y,
i->clipr.max.x, i->clipr.max.y);
free(client->readdata);
client->readdata = malloc(ni);
@@ -1087,7 +960,7 @@ _drawmsgwrite(void *v, int n)
client->nreaddata = ni;
client->infoid = -1;
continue;
-
+
/* query: 'Q' n[1] queryspec[n] */
case 'q':
if(n < 2)
@@ -1102,10 +975,10 @@ _drawmsgwrite(void *v, int n)
err = "unknown query";
goto error;
case 'd': /* dpi */
- if(forcedpi)
- fmtprint(&fmt, "%11d ", forcedpi);
+ if(client->forcedpi)
+ fmtprint(&fmt, "%11d ", client->forcedpi);
else
- fmtprint(&fmt, "%11d ", displaydpi);
+ fmtprint(&fmt, "%11d ", client->displaydpi);
break;
}
}
@@ -1169,7 +1042,7 @@ _drawmsgwrite(void *v, int n)
if(dstid==0 || dst->layer!=nil){
/* BUG: this is terribly inefficient: update maximal containing rect*/
r = memlinebbox(p, q, e0, e1, j);
- dstflush(dstid, dst, insetrect(r, -(1+1+j)));
+ dstflush(client, dstid, dst, insetrect(r, -(1+1+j)));
}
continue;
@@ -1198,7 +1071,7 @@ _drawmsgwrite(void *v, int n)
dstid = BGLONG(a+1);
if(drawlookup(client, dstid, 0))
goto Eimageexists;
- dn = drawlookupname(j, (char*)a+6);
+ dn = drawlookupname(client, j, (char*)a+6);
if(dn == nil)
goto Enoname;
s = malloc(j+1);
@@ -1239,12 +1112,12 @@ _drawmsgwrite(void *v, int n)
if(drawaddname(client, di, j, (char*)a+7, &err) < 0)
goto error;
else{
- dn = drawlookupname(j, (char*)a+7);
+ dn = drawlookupname(client, j, (char*)a+7);
if(dn == nil)
goto Enoname;
if(dn->dimage != di)
goto Ewrongname;
- drawdelname(dn);
+ drawdelname(client, dn);
}
continue;
@@ -1266,8 +1139,8 @@ _drawmsgwrite(void *v, int n)
goto error;
}
if(ni > 0){
- addflush(r);
- addflush(dst->layer->screenr);
+ addflush(client, r);
+ addflush(client, dst->layer->screenr);
ll = drawlookup(client, BGLONG(a+1), 1);
drawrefreshscreen(ll, client);
}
@@ -1316,7 +1189,7 @@ _drawmsgwrite(void *v, int n)
if(pp == nil)
goto Enomem;
doflush = 0;
- if(dstid==0 || (dst->layer && dst->layer->screen->image->data == screenimage->data))
+ if(dstid==0 || (dst->layer && dst->layer->screen->image->data == client->screenimage->data))
doflush = 1; /* simplify test in loop */
ox = oy = 0;
esize = 0;
@@ -1353,12 +1226,12 @@ _drawmsgwrite(void *v, int n)
combinerect(&r, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
}
if(rectclip(&r, dst->clipr)) /* should perhaps be an arg to dstflush */
- dstflush(dstid, dst, r);
+ dstflush(client, dstid, dst, r);
}
pp[y] = p;
}
if(y == 1)
- dstflush(dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
+ dstflush(client, dstid, dst, Rect(p.x-esize, p.y-esize, p.x+esize+1, p.y+esize+1));
op = drawclientop(client);
if(*a == 'p')
mempoly(dst, pp, ni, e0, e1, j, src, sp, op);
@@ -1462,7 +1335,7 @@ _drawmsgwrite(void *v, int n)
}
dst->clipr = clipr;
p.y -= font->ascent;
- dstflush(dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
+ dstflush(client, dstid, dst, Rect(p.x, p.y, q.x, p.y+Dy(font->image->r)));
continue;
/* use public screen: 'S' id[4] chan[4] */
@@ -1473,7 +1346,7 @@ _drawmsgwrite(void *v, int n)
dstid = BGLONG(a+1);
if(dstid == 0)
goto Ebadarg;
- dscrn = drawlookupdscreen(dstid);
+ dscrn = drawlookupdscreen(client, dstid);
if(dscrn==0 || (dscrn->public==0 && dscrn->owner!=client))
goto Enodrawscreen;
if(dscrn->screen->image->chan != BGLONG(a+5)){
@@ -1522,9 +1395,9 @@ _drawmsgwrite(void *v, int n)
memltofrontn(lp, nw);
else
memltorearn(lp, nw);
- if(lp[0]->layer->screen->image->data == screenimage->data)
+ if(lp[0]->layer->screen->image->data == client->screenimage->data)
for(j=0; j<nw; j++)
- addflush(lp[j]->layer->screenr);
+ addflush(client, lp[j]->layer->screenr);
free(lp);
ll = drawlookup(client, BGLONG(a+1+1+2), 1);
drawrefreshscreen(ll, client);
@@ -1533,7 +1406,7 @@ _drawmsgwrite(void *v, int n)
/* visible: 'v' */
case 'v':
m = 1;
- drawflush();
+ drawflush(client);
continue;
/* write: 'y' id[4] R[4*4] data[x*1] */
@@ -1555,12 +1428,13 @@ _drawmsgwrite(void *v, int n)
err = "bad writeimage call";
goto error;
}
- dstflush(dstid, dst, r);
+ dstflush(client, dstid, dst, r);
m += y;
continue;
}
}
- qunlock(&sdraw.lk);
+ rpc_gfxdrawunlock();
+ qunlock(&client->drawlk);
return oldn - n;
Enodrawimage:
@@ -1630,8 +1504,7 @@ Ebadarg:
error:
werrstr("%s", err);
- qunlock(&sdraw.lk);
+ rpc_gfxdrawunlock();
+ qunlock(&client->drawlk);
return -1;
}
-
-
diff --git a/src/cmd/devdraw/devdraw.h b/src/cmd/devdraw/devdraw.h
index f768735f..4980ed90 100644
--- a/src/cmd/devdraw/devdraw.h
+++ b/src/cmd/devdraw/devdraw.h
@@ -1,10 +1,229 @@
-int _drawmsgread(void*, int);
-int _drawmsgwrite(void*, int);
-void _initdisplaymemimage(Memimage*);
-int _latin1(Rune*, int);
-int parsewinsize(char*, Rectangle*, int*);
+
+#define NHASH (1<<5)
+#define HASHMASK (NHASH-1)
+
+typedef struct Kbdbuf Kbdbuf;
+typedef struct Mousebuf Mousebuf;
+typedef struct Tagbuf Tagbuf;
+
+typedef struct Client Client;
+typedef struct DImage DImage;
+typedef struct DScreen DScreen;
+typedef struct CScreen CScreen;
+typedef struct FChar FChar;
+typedef struct Refresh Refresh;
+typedef struct Refx Refx;
+typedef struct DName DName;
+
+struct Kbdbuf
+{
+ Rune r[256];
+ int ri;
+ int wi;
+ int stall;
+ int alting;
+ Rune k[10];
+ int nk;
+};
+
+struct Mousebuf
+{
+ Mouse m[256];
+ Mouse last;
+ int ri;
+ int wi;
+ int stall;
+ int resized;
+};
+
+struct Tagbuf
+{
+ int t[256];
+ int ri;
+ int wi;
+};
+
+struct Client
+{
+ int rfd;
+
+ // wfdlk protects writes to wfd, which can be issued from either
+ // the RPC thread or the graphics thread.
+ QLock wfdlk;
+ int wfd;
+ uchar* mbuf;
+ int nmbuf;
+
+ char* wsysid;
+
+ // drawlk protects the draw data structures.
+ // It can be acquired by an RPC thread or a graphics thread
+ // but must not be held on one thread while waiting for the other.
+ QLock drawlk;
+ /*Ref r;*/
+ DImage* dimage[NHASH];
+ CScreen* cscreen;
+ Refresh* refresh;
+ Rendez refrend;
+ uchar* readdata;
+ int nreaddata;
+ int busy;
+ int clientid;
+ int slot;
+ int refreshme;
+ int infoid;
+ int op;
+ int displaydpi;
+ int forcedpi;
+ int waste;
+ Rectangle flushrect;
+ Memimage *screenimage;
+ DScreen* dscreen;
+ int nname;
+ DName* name;
+ int namevers;
+
+ // Only accessed/modified by the graphics thread.
+ const void* view;
+
+ // eventlk protects the keyboard and mouse events.
+ QLock eventlk;
+ Kbdbuf kbd;
+ Mousebuf mouse;
+ Tagbuf kbdtags;
+ Tagbuf mousetags;
+ Rectangle mouserect;
+};
+
+struct Refresh
+{
+ DImage* dimage;
+ Rectangle r;
+ Refresh* next;
+};
+
+struct Refx
+{
+ Client* client;
+ DImage* dimage;
+};
+
+struct DName
+{
+ char *name;
+ Client *client;
+ DImage* dimage;
+ int vers;
+};
+
+struct FChar
+{
+ int minx; /* left edge of bits */
+ int maxx; /* right edge of bits */
+ uchar miny; /* first non-zero scan-line */
+ uchar maxy; /* last non-zero scan-line + 1 */
+ schar left; /* offset of baseline */
+ uchar width; /* width of baseline */
+};
+
+/*
+ * Reference counts in DImages:
+ * one per open by original client
+ * one per screen image or fill
+ * one per image derived from this one by name
+ */
+struct DImage
+{
+ int id;
+ int ref;
+ char *name;
+ int vers;
+ Memimage* image;
+ int ascent;
+ int nfchar;
+ FChar* fchar;
+ DScreen* dscreen; /* 0 if not a window */
+ DImage* fromname; /* image this one is derived from, by name */
+ DImage* next;
+};
+
+struct CScreen
+{
+ DScreen* dscreen;
+ CScreen* next;
+};
+
+struct DScreen
+{
+ int id;
+ int public;
+ int ref;
+ DImage *dimage;
+ DImage *dfill;
+ Memscreen* screen;
+ Client* owner;
+ DScreen* next;
+};
+
+// For the most part, the graphics driver-specific code in files
+// like mac-screen.m runs in the graphics library's main thread,
+// while the RPC service code in srv.c runs on the RPC service thread.
+// The exceptions in each file, which are called by the other,
+// are marked with special prefixes: gfx_* indicates code that
+// is in srv.c but nonetheless runs on the main graphics thread,
+// while rpc_* indicates code that is in, say, mac-screen.m but
+// nonetheless runs on the RPC service thread.
+//
+// The gfx_* and rpc_* calls typically synchronize with the other
+// code in the file by acquiring a lock (or running a callback on the
+// target thread, which amounts to the same thing).
+// To avoid deadlock, callers of those routines must not hold any locks.
+
+// gfx_* routines are called on the graphics thread,
+// invoked from graphics driver callbacks to do RPC work.
+// No locks are held on entry.
+void gfx_abortcompose(Client*);
+void gfx_keystroke(Client*, int);
+void gfx_main(void);
+void gfx_mousetrack(Client*, int, int, int, uint);
+void gfx_replacescreenimage(Client*, Memimage*);
+void gfx_started(void);
+
+// rpc_* routines are called on the RPC thread,
+// invoked by the RPC server code to do graphics work.
+// No locks are held on entry.
+Memimage *rpc_attach(Client*, char*, char*);
+char* rpc_getsnarf(void);
+void rpc_putsnarf(char*);
+void rpc_resizeimg(Client*);
+void rpc_resizewindow(Client*, Rectangle);
+void rpc_serve(Client*);
+void rpc_setcursor(Client*, Cursor*, Cursor2*);
+void rpc_setlabel(Client*, char*);
+void rpc_setmouse(Client*, Point);
+void rpc_shutdown(void);
+void rpc_topwin(Client*);
+void rpc_main(void);
+void rpc_bouncemouse(Client*, Mouse);
+void rpc_flush(Client*, Rectangle);
+
+// rpc_gfxdrawlock and rpc_gfxdrawunlock
+// are called around drawing operations to lock and unlock
+// access to the graphics display, for systems where the
+// individual memdraw operations use the graphics display (X11, not macOS).
+void rpc_gfxdrawlock(void);
+void rpc_gfxdrawunlock(void);
+
+// draw* routines are called on the RPC thread,
+// invoked by the RPC server to do pixel pushing.
+// No locks are held on entry.
+int draw_dataread(Client*, void*, int);
+int draw_datawrite(Client*, void*, int);
+void draw_initdisplaymemimage(Client*, Memimage*);
+
+// utility routines
+int latin1(Rune*, int);
int mouseswap(int);
-void abortcompose(void);
+int parsewinsize(char*, Rectangle*, int*);
-extern int displaydpi;
-extern int forcedpi;
+extern Client *client0; // set in single-client mode
diff --git a/src/cmd/devdraw/drawclient.c b/src/cmd/devdraw/drawclient.c
index 87df3f18..71c7142d 100644
--- a/src/cmd/devdraw/drawclient.c
+++ b/src/cmd/devdraw/drawclient.c
@@ -4,7 +4,7 @@
#include <draw.h>
#include <mouse.h>
#include <cursor.h>
-#include <drawsrv.h>
+#include <drawfcall.h>
typedef struct Cmd Cmd;
struct Cmd {
@@ -20,7 +20,7 @@ void
startsrv(void)
{
int pid, p[2];
-
+
if(pipe(p) < 0)
sysfatal("pipe");
if((pid=fork()) < 0)
@@ -29,7 +29,7 @@ startsrv(void)
close(p[0]);
dup(p[1], 0);
dup(p[1], 1);
- execl("o.drawsrv", "o.drawsrv", "-D", nil);
+ execl("./o.devdraw", "o.devdraw", "-D", nil);
sysfatal("exec: %r");
}
close(p[1]);
@@ -47,7 +47,7 @@ fprint(2, "write %d to %d\n", n, fd);
n = readwsysmsg(fd, buf, sizeof buf);
nn = convM2W(buf, n, m);
assert(nn == n);
- if(m->op == Rerror)
+ if(m->type == Rerror)
return -1;
return 0;
}
@@ -56,12 +56,11 @@ void
cmdinit(int argc, char **argv)
{
Wsysmsg m;
-
+
memset(&m, 0, sizeof m);
- m.op = Tinit;
+ m.type = Tinit;
m.winsize = "100x100";
m.label = "label";
- m.font = "";
if(domsg(&m) < 0)
sysfatal("domsg");
}
@@ -70,9 +69,9 @@ void
cmdmouse(int argc, char **argv)
{
Wsysmsg m;
-
+
memset(&m, 0, sizeof m);
- m.op = Trdmouse;
+ m.type = Trdmouse;
if(domsg(&m) < 0)
sysfatal("domsg");
print("%c %d %d %d\n",
@@ -86,12 +85,12 @@ void
cmdkbd(int argc, char **argv)
{
Wsysmsg m;
-
+
memset(&m, 0, sizeof m);
- m.op = Trdkbd;
+ m.type = Trdkbd;
if(domsg(&m) < 0)
sysfatal("domsg");
- print("%s\n", m.runes);
+ print("%d\n", m.rune);
}
Cmd cmdtab[] = {
@@ -125,4 +124,3 @@ fprint(2, "%s...\n", p);
}
exits(0);
}
-
diff --git a/src/cmd/devdraw/latin1.c b/src/cmd/devdraw/latin1.c
index 09c67523..a3d13a08 100644
--- a/src/cmd/devdraw/latin1.c
+++ b/src/cmd/devdraw/latin1.c
@@ -46,7 +46,7 @@ unicode(Rune *k)
* is minus the required n.
*/
int
-_latin1(Rune *k, int n)
+latin1(Rune *k, int n)
{
struct cvlist *l;
int c;
@@ -58,7 +58,7 @@ _latin1(Rune *k, int n)
else
return -5;
}
-
+
for(l=latintab; l->ld!=0; l++)
if(k[0] == l->ld[0]){
if(n == 1)
diff --git a/src/cmd/devdraw/osx-draw.c b/src/cmd/devdraw/mac-draw.c
index d3f08331..fdf7acec 100644
--- a/src/cmd/devdraw/osx-draw.c
+++ b/src/cmd/devdraw/mac-draw.c
@@ -56,4 +56,3 @@ unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
{
return _unloadmemimage(i, r, data, ndata);
}
-
diff --git a/src/cmd/devdraw/cocoa-screen-metal.m b/src/cmd/devdraw/mac-screen.m
index 984ede03..e02a2524 100644
--- a/src/cmd/devdraw/cocoa-screen-metal.m
+++ b/src/cmd/devdraw/mac-screen.m
@@ -12,13 +12,14 @@
#include <u.h>
#include <libc.h>
-#include "cocoa-thread.h"
+#include <thread.h>
#include <draw.h>
#include <memdraw.h>
-#include <keyboard.h>
+#include <memlayer.h>
+#include <mouse.h>
#include <cursor.h>
-#include "cocoa-screen.h"
-#include "osx-keycodes.h"
+#include <keyboard.h>
+#include <drawfcall.h>
#include "devdraw.h"
#include "bigarrow.h"
#include "glendapng.h"
@@ -26,78 +27,29 @@
AUTOFRAMEWORK(Cocoa)
AUTOFRAMEWORK(Metal)
AUTOFRAMEWORK(QuartzCore)
+AUTOFRAMEWORK(CoreFoundation)
#define LOG if(0)NSLog
+// TODO: Maintain list of views for dock menu.
+
static void setprocname(const char*);
static uint keycvt(uint);
static uint msec(void);
-static Memimage* initimg(void);
-void
-usage(void)
-{
- fprint(2, "usage: devdraw (don't run directly)\n");
- threadexitsall("usage");
-}
+@class DrawView;
+@class DrawLayer;
-@interface AppDelegate : NSObject<NSApplicationDelegate,NSWindowDelegate>
-+ (void)callservep9p:(id)arg;
-+ (void)makewin:(NSValue *)v;
-+ (void)callkicklabel:(NSString *)v;
-+ (void)callsetNeedsDisplayInRect:(NSValue *)v;
-+ (void)callsetcursor:(NSValue *)v;
-@end
-@interface DevDrawView : NSView<NSTextInputClient>
-- (void)clearInput;
-- (void)getmouse:(NSEvent *)e;
-- (void)sendmouse:(NSUInteger)b;
-- (void)resetLastInputRect;
-- (void)enlargeLastInputRect:(NSRect)r;
-@end
-@interface DrawLayer : CAMetalLayer
+@interface AppDelegate : NSObject<NSApplicationDelegate>
@end
static AppDelegate *myApp = NULL;
-static DevDrawView *myContent = NULL;
-static NSWindow *win = NULL;
-static NSCursor *currentCursor = NULL;
-
-static DrawLayer *layer;
-static id<MTLDevice> device;
-static id<MTLCommandQueue> commandQueue;
-static id<MTLTexture> texture;
-
-static Memimage *img = NULL;
-
-static QLock snarfl;
void
-threadmain(int argc, char **argv)
+gfx_main(void)
{
- /*
- * 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': /* for good ps -a listings */
- break;
- case 'f': /* fall through for backward compatibility */
- case 'g':
- case 'b':
- break;
- default:
- usage();
- }ARGEND
-
- setprocname(argv0);
+ if(client0)
+ setprocname(argv0);
@autoreleasepool{
[NSApplication sharedApplication];
@@ -108,16 +60,157 @@ threadmain(int argc, char **argv)
}
}
+
+void
+rpc_shutdown(void)
+{
+ [NSApp terminate:myApp];
+}
+
@implementation AppDelegate
+- (void)applicationDidFinishLaunching:(id)arg
+{
+ NSMenu *m, *sm;
+ NSData *d;
+ NSImage *i;
+
+ LOG(@"applicationDidFinishLaunching");
+
+ sm = [NSMenu new];
+ [sm addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
+ [sm addItemWithTitle:@"Hide" action:@selector(hide:) keyEquivalent:@"h"];
+ [sm addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
+ m = [NSMenu new];
+ [m addItemWithTitle:@"DEVDRAW" action:NULL keyEquivalent:@""];
+ [m setSubmenu:sm forItem:[m itemWithTitle:@"DEVDRAW"]];
+ [NSApp setMainMenu:m];
+
+ d = [[NSData alloc] initWithBytes:glenda_png length:(sizeof glenda_png)];
+ i = [[NSImage alloc] initWithData:d];
+ [NSApp setApplicationIconImage:i];
+ [[NSApp dockTile] display];
+
+ gfx_started();
+}
+
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
+ return client0 != nil;
+}
+@end
+
+@interface DrawLayer : CAMetalLayer
+@property (nonatomic, retain) id<MTLCommandQueue> cmd;
+@property (nonatomic, retain) id<MTLTexture> texture;
+@end
+
+@implementation DrawLayer
+- (void)display
+{
+ LOG(@"display");
+ LOG(@"display query drawable");
+
+ @autoreleasepool{
+ id<CAMetalDrawable> drawable = [self nextDrawable];
+ if(!drawable){
+ LOG(@"display couldn't get drawable");
+ [self setNeedsDisplay];
+ return;
+ }
+
+ LOG(@"display got drawable");
+
+ id<MTLCommandBuffer> cbuf = [self.cmd commandBuffer];
+ id<MTLBlitCommandEncoder> blit = [cbuf blitCommandEncoder];
+ [blit copyFromTexture:self.texture
+ sourceSlice:0
+ sourceLevel:0
+ sourceOrigin:MTLOriginMake(0, 0, 0)
+ sourceSize:MTLSizeMake(self.texture.width, self.texture.height, self.texture.depth)
+ toTexture:drawable.texture
+ destinationSlice:0
+ destinationLevel:0
+ destinationOrigin:MTLOriginMake(0, 0, 0)];
+ [blit endEncoding];
+
+ [cbuf presentDrawable:drawable];
+ drawable = nil;
+ [cbuf addCompletedHandler:^(id<MTLCommandBuffer> cmdBuff){
+ if(cmdBuff.error){
+ NSLog(@"command buffer finished with error: %@",
+ cmdBuff.error.localizedDescription);
+ }else
+ LOG(@"command buffer finishes present drawable");
+ }];
+ [cbuf commit];
+ }
+ LOG(@"display commit");
+}
+@end
+
+@interface DrawView : NSView<NSTextInputClient,NSWindowDelegate>
+@property (nonatomic, assign) Client *client;
+@property (nonatomic, retain) DrawLayer *dlayer;
+@property (nonatomic, retain) NSWindow *win;
+@property (nonatomic, retain) NSCursor *currentCursor;
+@property (nonatomic, assign) Memimage *img;
+
+- (id)attach:(Client*)client winsize:(char*)winsize label:(char*)label;
+- (void)topwin;
+- (void)setlabel:(char*)label;
+- (void)setcursor:(Cursor*)c cursor2:(Cursor2*)c2;
+- (void)setmouse:(Point)p;
+- (void)clearInput;
+- (void)getmouse:(NSEvent*)e;
+- (void)sendmouse:(NSUInteger)b;
+- (void)resetLastInputRect;
+- (void)enlargeLastInputRect:(NSRect)r;
+@end
-+ (void)callservep9p:(id)arg
+@implementation DrawView
{
- servep9p();
- [NSApp terminate:self];
+ NSMutableString *_tmpText;
+ NSRange _markedRange;
+ NSRange _selectedRange;
+ NSRect _lastInputRect; // The view is flipped, this is not.
+ BOOL _tapping;
+ NSUInteger _tapFingers;
+ NSUInteger _tapTime;
}
-+ (void)makewin:(NSValue *)v
+- (id)init
{
+ LOG(@"View init");
+ self = [super init];
+ [self setAllowedTouchTypes:NSTouchTypeMaskDirect|NSTouchTypeMaskIndirect];
+ _tmpText = [[NSMutableString alloc] initWithCapacity:2];
+ _markedRange = NSMakeRange(NSNotFound, 0);
+ _selectedRange = NSMakeRange(0, 0);
+ return self;
+}
+
+- (CALayer*)makeBackingLayer { return [DrawLayer layer]; }
+- (BOOL)wantsUpdateLayer { return YES; }
+- (BOOL)isOpaque { return YES; }
+- (BOOL)isFlipped { return YES; }
+- (BOOL)acceptsFirstResponder { return YES; }
+
+// rpc_attach allocates a new screen window with the given label and size
+// and attaches it to client c (by setting c->view).
+Memimage*
+rpc_attach(Client *c, char *label, char *winsize)
+{
+ LOG(@"attachscreen(%s, %s)", label, winsize);
+
+ dispatch_sync(dispatch_get_main_queue(), ^(void) {
+ @autoreleasepool {
+ DrawView *view = [[DrawView new] attach:c winsize:winsize label:label];
+ [view initimg];
+ }
+ });
+ return ((__bridge DrawView*)c->view).img;
+}
+
+- (id)attach:(Client*)client winsize:(char*)winsize label:(char*)label {
NSRect r, sr;
Rectangle wr;
int set;
@@ -129,15 +222,12 @@ threadmain(int argc, char **argv)
| NSWindowStyleMaskMiniaturizable
| NSWindowStyleMaskResizable;
+ s = winsize;
sr = [[NSScreen mainScreen] frame];
r = [[NSScreen mainScreen] visibleFrame];
- s = [v pointerValue];
LOG(@"makewin(%s)", s);
- if(s && *s){
- if(parsewinsize(s, &wr, &set) < 0)
- sysfatal("%r");
- }else{
+ if(s == nil || *s == '\0' || parsewinsize(s, &wr, &set) < 0) {
wr = Rect(0, 0, sr.size.width*2/3, sr.size.height*2/3);
set = 0;
}
@@ -148,7 +238,7 @@ threadmain(int argc, char **argv)
r.size.height = fmin(Dy(wr), r.size.height);
r = [NSWindow contentRectForFrameRect:r styleMask:Winstyle];
- win = [[NSWindow alloc]
+ NSWindow *win = [[NSWindow alloc]
initWithContentRect:r
styleMask:Winstyle
backing:NSBackingStoreBuffered defer:NO];
@@ -161,14 +251,17 @@ threadmain(int argc, char **argv)
[win setOpaque:YES];
[win setRestorable:NO];
[win setAcceptsMouseMovedEvents:YES];
- [win setDelegate:myApp];
-
- myContent = [DevDrawView new];
- [win setContentView:myContent];
- [myContent setWantsLayer:YES];
- [myContent setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
-
- device = nil;
+
+ client->view = CFBridgingRetain(self);
+ self.client = client;
+ self.win = win;
+ self.currentCursor = nil;
+ [win setContentView:self];
+ [win setDelegate:self];
+ [self setWantsLayer:YES];
+ [self setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
+
+ id<MTLDevice> device = nil;
allDevices = MTLCopyAllDevices();
for(id mtlDevice in allDevices) {
if ([mtlDevice isLowPower] && ![mtlDevice isRemovable]) {
@@ -179,17 +272,19 @@ threadmain(int argc, char **argv)
if(!device)
device = MTLCreateSystemDefaultDevice();
- commandQueue = [device newCommandQueue];
-
- layer = (DrawLayer *)[myContent layer];
+ DrawLayer *layer = (DrawLayer*)[self layer];
+ self.dlayer = layer;
layer.device = device;
+ layer.cmd = [device newCommandQueue];
layer.pixelFormat = MTLPixelFormatBGRA8Unorm;
layer.framebufferOnly = YES;
layer.opaque = YES;
// We use a default transparent layer on top of the CAMetalLayer.
// This seems to make fullscreen applications behave.
- {
+ // Specifically, without this code if you enter full screen with Cmd-F,
+ // the screen goes black until the first mouse click.
+ if(1) {
CALayer *stub = [CALayer layer];
stub.frame = CGRectMake(0, 0, 1, 1);
[stub setNeedsDisplay];
@@ -198,61 +293,78 @@ threadmain(int argc, char **argv)
[NSEvent setMouseCoalescingEnabled:NO];
- topwin();
+ [self topwin];
+ [self setlabel:label];
+ [self setcursor:nil cursor2:nil];
+
+ return self;
}
-+ (void)callkicklabel:(NSString *)s
+// rpc_topwin moves the window to the top of the desktop.
+// Called from an RPC thread with no client lock held.
+void
+rpc_topwin(Client *c)
{
- LOG(@"callkicklabel(%@)", s);
- [win setTitle:s];
- [[NSApp dockTile] setBadgeLabel:s];
+ DrawView *view = (__bridge DrawView*)c->view;
+ dispatch_sync(dispatch_get_main_queue(), ^(void) {
+ [view topwin];
+ });
}
+- (void)topwin {
+ [self.win makeKeyAndOrderFront:nil];
+ [NSApp activateIgnoringOtherApps:YES];
+}
-+ (void)callsetNeedsDisplayInRect:(NSValue *)v
+// rpc_setlabel updates the client window's label.
+// If label == nil, the call is a no-op.
+// Called from an RPC thread with no client lock held.
+void
+rpc_setlabel(Client *client, char *label)
{
- NSRect r;
- dispatch_time_t time;
-
- r = [v rectValue];
- LOG(@"callsetNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height);
- r = [win convertRectFromBacking:r];
- LOG(@"setNeedsDisplayInRect(%g, %g, %g, %g)", r.origin.x, r.origin.y, r.size.width, r.size.height);
- [layer setNeedsDisplayInRect:r];
-
- time = dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC);
- dispatch_after(time, dispatch_get_main_queue(), ^(void){
- [layer setNeedsDisplayInRect:r];
+ DrawView *view = (__bridge DrawView*)client->view;
+ dispatch_sync(dispatch_get_main_queue(), ^(void){
+ [view setlabel:label];
});
-
- [myContent enlargeLastInputRect:r];
}
-typedef struct Cursors Cursors;
-struct Cursors {
- Cursor *c;
- Cursor2 *c2;
-};
+- (void)setlabel:(char*)label {
+ LOG(@"setlabel(%s)", label);
+ if(label == nil)
+ return;
+
+ @autoreleasepool{
+ NSString *s = [[NSString alloc] initWithUTF8String:label];
+ [self.win setTitle:s];
+ if(client0)
+ [[NSApp dockTile] setBadgeLabel:s];
+ }
+}
-+ (void)callsetcursor:(NSValue *)v
+// rpc_setcursor updates the client window's cursor image.
+// Either c and c2 are both non-nil, or they are both nil to use the default arrow.
+// Called from an RPC thread with no client lock held.
+void
+rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2)
{
- Cursors *cs;
- Cursor *c;
- Cursor2 *c2;
+ DrawView *view = (__bridge DrawView*)client->view;
+ dispatch_sync(dispatch_get_main_queue(), ^(void){
+ [view setcursor:c cursor2:c2];
+ });
+}
+
+- (void)setcursor:(Cursor*)c cursor2:(Cursor2*)c2 {
+ if(!c) {
+ c = &bigarrow;
+ c2 = &bigarrow2;
+ }
+
NSBitmapImageRep *r, *r2;
NSImage *i;
NSPoint p;
uchar *plane[5], *plane2[5];
uint b;
- cs = [v pointerValue];
- c = cs->c;
- if(!c)
- c = &bigarrow;
- c2 = cs->c2;
- if(!c2)
- c2 = &bigarrow2;
-
r = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:nil
pixelsWide:16
@@ -287,128 +399,166 @@ struct Cursors {
plane2[1][b] = c2->set[b] | c2->clr[b];
}
- // For checking out the cursor bitmap image
-/*
- static BOOL saveimg = YES;
- if(saveimg){
+ static BOOL debug = NO;
+ if(debug){
NSData *data = [r representationUsingType: NSBitmapImageFileTypeBMP properties: @{}];
[data writeToFile: @"/tmp/r.bmp" atomically: NO];
data = [r2 representationUsingType: NSBitmapImageFileTypeBMP properties: @{}];
[data writeToFile: @"/tmp/r2.bmp" atomically: NO];
- saveimg = NO;
+ debug = NO;
}
-*/
i = [[NSImage alloc] initWithSize:NSMakeSize(16, 16)];
[i addRepresentation:r2];
[i addRepresentation:r];
p = NSMakePoint(-c->offset.x, -c->offset.y);
- currentCursor = [[NSCursor alloc] initWithImage:i hotSpot:p];
+ self.currentCursor = [[NSCursor alloc] initWithImage:i hotSpot:p];
+ [self.win invalidateCursorRectsForView:self];
+}
- [win invalidateCursorRectsForView:myContent];
+- (void)initimg {
+ @autoreleasepool {
+ CGFloat scale;
+ NSSize size;
+ MTLTextureDescriptor *textureDesc;
+
+ size = [self convertSizeToBacking:[self bounds].size];
+ self.client->mouserect = Rect(0, 0, size.width, size.height);
+
+ LOG(@"initimg %.0f %.0f", size.width, size.height);
+
+ self.img = allocmemimage(self.client->mouserect, XRGB32);
+ if(self.img == nil)
+ panic("allocmemimage: %r");
+ if(self.img->data == nil)
+ panic("img->data == nil");
+
+ textureDesc = [MTLTextureDescriptor
+ texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
+ width:size.width
+ height:size.height
+ mipmapped:NO];
+ textureDesc.allowGPUOptimizedContents = YES;
+ textureDesc.usage = MTLTextureUsageShaderRead;
+ textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
+ self.dlayer.texture = [self.dlayer.device newTextureWithDescriptor:textureDesc];
+
+ scale = [self.win backingScaleFactor];
+ [self.dlayer setDrawableSize:size];
+ [self.dlayer setContentsScale:scale];
+
+ // NOTE: This is not really the display DPI.
+ // On retina, scale is 2; otherwise it is 1.
+ // This formula gives us 220 for retina, 110 otherwise.
+ // That's not quite right but it's close to correct.
+ // https://en.wikipedia.org/wiki/Retina_display#Models
+ self.client->displaydpi = scale * 110;
+ }
}
-- (void)applicationDidFinishLaunching:(id)arg
+// rpc_flush flushes changes to view.img's rectangle r
+// to the on-screen window, making them visible.
+// Called from an RPC thread with no client lock held.
+void
+rpc_flush(Client *client, Rectangle r)
{
- NSMenu *m, *sm;
- NSData *d;
- NSImage *i;
-
- LOG(@"applicationDidFinishLaunching");
-
- sm = [NSMenu new];
- [sm addItemWithTitle:@"Toggle Full Screen" action:@selector(toggleFullScreen:) keyEquivalent:@"f"];
- [sm addItemWithTitle:@"Hide" action:@selector(hide:) keyEquivalent:@"h"];
- [sm addItemWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
- m = [NSMenu new];
- [m addItemWithTitle:@"DEVDRAW" action:NULL keyEquivalent:@""];
- [m setSubmenu:sm forItem:[m itemWithTitle:@"DEVDRAW"]];
- [NSApp setMainMenu:m];
+ DrawView *view = (__bridge DrawView*)client->view;
+ dispatch_async(dispatch_get_main_queue(), ^(void){
+ [view flush:r];
+ });
+}
- d = [[NSData alloc] initWithBytes:glenda_png length:(sizeof glenda_png)];
- i = [[NSImage alloc] initWithData:d];
- [NSApp setApplicationIconImage:i];
- [[NSApp dockTile] display];
+- (void)flush:(Rectangle)r {
+ @autoreleasepool{
+ if(!rectclip(&r, Rect(0, 0, self.dlayer.texture.width, self.dlayer.texture.height)) || !rectclip(&r, self.img->r))
+ return;
+
+ // self.client->drawlk protects the pixel data in self.img.
+ // In addition to avoiding a technical data race,
+ // the lock avoids drawing partial updates, which makes
+ // animations like sweeping windows much less flickery.
+ qlock(&self.client->drawlk);
+ [self.dlayer.texture
+ replaceRegion:MTLRegionMake2D(r.min.x, r.min.y, Dx(r), Dy(r))
+ mipmapLevel:0
+ withBytes:byteaddr(self.img, Pt(r.min.x, r.min.y))
+ bytesPerRow:self.img->width*sizeof(u32int)];
+ qunlock(&self.client->drawlk);
- [NSThread
- detachNewThreadSelector:@selector(callservep9p:)
- toTarget:[self class] withObject:nil];
-}
+ NSRect nr = NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r));
+ dispatch_time_t time;
-- (NSApplicationPresentationOptions)window:(id)arg
- willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions {
- NSApplicationPresentationOptions o;
- o = proposedOptions;
- o &= ~(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar);
- o |= NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar;
- return o;
-}
+ LOG(@"callsetNeedsDisplayInRect(%g, %g, %g, %g)", nr.origin.x, nr.origin.y, nr.size.width, nr.size.height);
+ nr = [self.win convertRectFromBacking:nr];
+ LOG(@"setNeedsDisplayInRect(%g, %g, %g, %g)", nr.origin.x, nr.origin.y, nr.size.width, nr.size.height);
+ [self.dlayer setNeedsDisplayInRect:nr];
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
- return YES;
-}
+ time = dispatch_time(DISPATCH_TIME_NOW, 16 * NSEC_PER_MSEC);
+ dispatch_after(time, dispatch_get_main_queue(), ^(void){
+ [self.dlayer setNeedsDisplayInRect:nr];
+ });
-- (void)windowDidResize:(NSNotification *)notification
-{
- if(![myContent inLiveResize] && img) {
- resizeimg();
+ [self enlargeLastInputRect:nr];
}
}
-- (void)windowDidBecomeKey:(id)arg
+// rpc_resizeimg forces the client window to discard its current window and make a new one.
+// It is called when the user types Cmd-R to toggle whether retina mode is forced.
+// Called from an RPC thread with no client lock held.
+void
+rpc_resizeimg(Client *c)
{
- [myContent sendmouse:0];
+ DrawView *view = (__bridge DrawView*)c->view;
+ dispatch_sync(dispatch_get_main_queue(), ^(void){
+ [view resizeimg];
+ });
}
-@end
-
-@implementation DevDrawView
-{
- NSMutableString *_tmpText;
- NSRange _markedRange;
- NSRange _selectedRange;
- NSRect _lastInputRect; // The view is flipped, this is not.
- BOOL _tapping;
- NSUInteger _tapFingers;
- NSUInteger _tapTime;
+- (void)resizeimg {
+ [self initimg];
+ gfx_replacescreenimage(self.client, self.img);
+ [self sendmouse:0];
}
-- (id)init
-{
- LOG(@"View init");
- self = [super init];
- [self setAllowedTouchTypes:NSTouchTypeMaskDirect|NSTouchTypeMaskIndirect];
- _tmpText = [[NSMutableString alloc] initWithCapacity:2];
- _markedRange = NSMakeRange(NSNotFound, 0);
- _selectedRange = NSMakeRange(0, 0);
- return self;
+- (void)windowDidResize:(NSNotification *)notification {
+ if(![self inLiveResize] && self.img) {
+ [self resizeimg];
+ }
}
-
-- (CALayer *)makeBackingLayer
+- (void)viewDidEndLiveResize
{
- LOG(@"makeBackingLayer");
- return [DrawLayer layer];
+ [super viewDidEndLiveResize];
+ if(self.img)
+ [self resizeimg];
}
-- (BOOL)wantsUpdateLayer
+- (void)viewDidChangeBackingProperties
{
- return YES;
+ [super viewDidChangeBackingProperties];
+ if(self.img)
+ [self resizeimg];
}
-- (BOOL)isOpaque
+// rpc_resizewindow asks for the client window to be resized to size r.
+// Called from an RPC thread with no client lock held.
+void
+rpc_resizewindow(Client *c, Rectangle r)
{
- return YES;
-}
+ DrawView *view = (__bridge DrawView*)c->view;
-- (BOOL)isFlipped
-{
- return YES;
+ LOG(@"resizewindow %d %d %d %d", r.min.x, r.min.y, Dx(r), Dy(r));
+ dispatch_async(dispatch_get_main_queue(), ^(void){
+ NSSize s;
+
+ s = [view convertSizeFromBacking:NSMakeSize(Dx(r), Dy(r))];
+ [view.win setContentSize:s];
+ });
}
-- (BOOL)acceptsFirstResponder
-{
- return YES;
+
+- (void)windowDidBecomeKey:(id)arg {
+ [self sendmouse:0];
}
- (void)mouseMoved:(NSEvent*)e{ [self getmouse:e];}
@@ -462,7 +612,7 @@ struct Cursors {
b |= 4;
[self sendmouse:b];
}else if(m & ~omod & NSEventModifierFlagOption)
- keystroke(Kalt);
+ gfx_keystroke(self.client, Kalt);
omod = m;
}
@@ -519,7 +669,7 @@ struct Cursors {
if(b == 1){
m = [e modifierFlags];
if(m & NSEventModifierFlagOption){
- abortcompose();
+ gfx_abortcompose(self.client);
b = 2;
}else
if(m & NSEventModifierFlagCommand)
@@ -534,48 +684,60 @@ struct Cursors {
p = [self.window convertPointToBacking:
[self.window mouseLocationOutsideOfEventStream]];
- p.y = Dy(mouserect) - p.y;
+ p.y = Dy(self.client->mouserect) - p.y;
// LOG(@"(%g, %g) <- sendmouse(%d)", p.x, p.y, (uint)b);
- mousetrack(p.x, p.y, b, msec());
+ gfx_mousetrack(self.client, p.x, p.y, b, msec());
if(b && _lastInputRect.size.width && _lastInputRect.size.height)
[self resetLastInputRect];
}
-- (void)resetCursorRects {
- [super resetCursorRects];
- [self addCursorRect:self.bounds cursor:currentCursor];
+// rpc_setmouse moves the mouse cursor.
+// Called from an RPC thread with no client lock held.
+void
+rpc_setmouse(Client *c, Point p)
+{
+ DrawView *view = (__bridge DrawView*)c->view;
+ dispatch_async(dispatch_get_main_queue(), ^(void){
+ [view setmouse:p];
+ });
}
-- (void)viewDidEndLiveResize
-{
- [super viewDidEndLiveResize];
- if(img)
- resizeimg();
+- (void)setmouse:(Point)p {
+ @autoreleasepool{
+ NSPoint q;
+
+ LOG(@"setmouse(%d,%d)", p.x, p.y);
+ q = [self.win convertPointFromBacking:NSMakePoint(p.x, p.y)];
+ LOG(@"(%g, %g) <- fromBacking", q.x, q.y);
+ q = [self convertPoint:q toView:nil];
+ LOG(@"(%g, %g) <- toWindow", q.x, q.y);
+ q = [self.win convertPointToScreen:q];
+ LOG(@"(%g, %g) <- toScreen", q.x, q.y);
+ // Quartz has the origin of the "global display
+ // coordinate space" at the top left of the primary
+ // screen with y increasing downward, while Cocoa has
+ // the origin at the bottom left of the primary screen
+ // with y increasing upward. We flip the coordinate
+ // with a negative sign and shift upward by the height
+ // of the primary screen.
+ q.y = NSScreen.screens[0].frame.size.height - q.y;
+ LOG(@"(%g, %g) <- setmouse", q.x, q.y);
+ CGWarpMouseCursorPosition(NSPointToCGPoint(q));
+ CGAssociateMouseAndMouseCursorPosition(true);
+ }
}
-- (void)viewDidChangeBackingProperties
-{
- [super viewDidChangeBackingProperties];
- if(img)
- resizeimg();
+
+- (void)resetCursorRects {
+ [super resetCursorRects];
+ [self addCursorRect:self.bounds cursor:self.currentCursor];
}
// conforms to protocol NSTextInputClient
-- (BOOL)hasMarkedText
-{
- LOG(@"hasMarkedText");
- return _markedRange.location != NSNotFound;
-}
-- (NSRange)markedRange
-{
- LOG(@"markedRange");
- return _markedRange;
-}
-- (NSRange)selectedRange
-{
- LOG(@"selectedRange");
- return _selectedRange;
-}
+- (BOOL)hasMarkedText { return _markedRange.location != NSNotFound; }
+- (NSRange)markedRange { return _markedRange; }
+- (NSRange)selectedRange { return _selectedRange; }
+
- (void)setMarkedText:(id)string
selectedRange:(NSRange)sRange
replacementRange:(NSRange)rRange
@@ -616,49 +778,50 @@ struct Cursors {
LOG(@"text length %ld", _tmpText.length);
for(i = 0; i <= _tmpText.length; ++i){
if(i == _markedRange.location)
- keystroke('[');
+ gfx_keystroke(self.client, '[');
if(_selectedRange.length){
if(i == _selectedRange.location)
- keystroke('{');
+ gfx_keystroke(self.client, '{');
if(i == NSMaxRange(_selectedRange))
- keystroke('}');
+ gfx_keystroke(self.client, '}');
}
if(i == NSMaxRange(_markedRange))
- keystroke(']');
+ gfx_keystroke(self.client, ']');
if(i < _tmpText.length)
- keystroke([_tmpText characterAtIndex:i]);
+ gfx_keystroke(self.client, [_tmpText characterAtIndex:i]);
}
int l;
l = 1 + _tmpText.length - NSMaxRange(_selectedRange)
+ (_selectedRange.length > 0);
LOG(@"move left %d", l);
for(i = 0; i < l; ++i)
- keystroke(Kleft);
+ gfx_keystroke(self.client, Kleft);
}
LOG(@"text: \"%@\" (%ld,%ld) (%ld,%ld)", _tmpText,
_markedRange.location, _markedRange.length,
_selectedRange.location, _selectedRange.length);
}
-- (void)unmarkText
-{
+
+- (void)unmarkText {
//NSUInteger i;
NSUInteger len;
LOG(@"unmarkText");
len = [_tmpText length];
//for(i = 0; i < len; ++i)
- // keystroke([_tmpText characterAtIndex:i]);
+ // gfx_keystroke(self.client, [_tmpText characterAtIndex:i]);
[_tmpText deleteCharactersInRange:NSMakeRange(0, len)];
_markedRange = NSMakeRange(NSNotFound, 0);
_selectedRange = NSMakeRange(0, 0);
}
-- (NSArray<NSAttributedStringKey> *)validAttributesForMarkedText
-{
+
+- (NSArray<NSAttributedStringKey>*)validAttributesForMarkedText {
LOG(@"validAttributesForMarkedText");
return @[];
}
-- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)r
+
+- (NSAttributedString*)attributedSubstringForProposedRange:(NSRange)r
actualRange:(NSRangePointer)actualRange
{
NSRange sr;
@@ -671,15 +834,15 @@ struct Cursors {
if(actualRange)
*actualRange = sr;
LOG(@"use range: %ld, %ld", sr.location, sr.length);
+ s = nil;
if(sr.length)
s = [[NSAttributedString alloc]
initWithString:[_tmpText substringWithRange:sr]];
LOG(@" return %@", s);
return s;
}
-- (void)insertText:(id)s
- replacementRange:(NSRange)r
-{
+
+- (void)insertText:(id)s replacementRange:(NSRange)r {
NSUInteger i;
NSUInteger len;
@@ -689,27 +852,27 @@ struct Cursors {
len = [s length];
for(i = 0; i < len; ++i)
- keystroke([s characterAtIndex:i]);
+ gfx_keystroke(self.client, [s characterAtIndex:i]);
[_tmpText deleteCharactersInRange:NSMakeRange(0, _tmpText.length)];
_markedRange = NSMakeRange(NSNotFound, 0);
_selectedRange = NSMakeRange(0, 0);
}
+
- (NSUInteger)characterIndexForPoint:(NSPoint)point
{
LOG(@"characterIndexForPoint: %g, %g", point.x, point.y);
return 0;
}
-- (NSRect)firstRectForCharacterRange:(NSRange)r
- actualRange:(NSRangePointer)actualRange
-{
+
+- (NSRect)firstRectForCharacterRange:(NSRange)r actualRange:(NSRangePointer)actualRange {
LOG(@"firstRectForCharacterRange: (%ld, %ld) (%ld, %ld)",
r.location, r.length, actualRange->location, actualRange->length);
if(actualRange)
*actualRange = r;
return [[self window] convertRectToScreen:_lastInputRect];
}
-- (void)doCommandBySelector:(SEL)s
-{
+
+- (void)doCommandBySelector:(SEL)s {
NSEvent *e;
NSEventModifierFlags m;
uint c, k;
@@ -729,12 +892,11 @@ struct Cursors {
k += Kcmd;
}
if(k>0)
- keystroke(k);
+ gfx_keystroke(self.client, k);
}
// Helper for managing input rect approximately
-- (void)resetLastInputRect
-{
+- (void)resetLastInputRect {
LOG(@"resetLastInputRect");
_lastInputRect.origin.x = 0.0;
_lastInputRect.origin.y = 0.0;
@@ -742,8 +904,7 @@ struct Cursors {
_lastInputRect.size.height = 0.0;
}
-- (void)enlargeLastInputRect:(NSRect)r
-{
+- (void)enlargeLastInputRect:(NSRect)r {
r.origin.y = [self bounds].size.height - r.origin.y - r.size.height;
_lastInputRect = NSUnionRect(_lastInputRect, r);
LOG(@"update last input rect (%g, %g, %g, %g)",
@@ -751,8 +912,7 @@ struct Cursors {
_lastInputRect.size.width, _lastInputRect.size.height);
}
-- (void)clearInput
-{
+- (void)clearInput {
if(_tmpText.length){
uint i;
int l;
@@ -760,68 +920,35 @@ struct Cursors {
+ (_selectedRange.length > 0);
LOG(@"move right %d", l);
for(i = 0; i < l; ++i)
- keystroke(Kright);
+ gfx_keystroke(self.client, Kright);
l = _tmpText.length+2+2*(_selectedRange.length > 0);
LOG(@"backspace %d", l);
for(uint i = 0; i < l; ++i)
- keystroke(Kbs);
+ gfx_keystroke(self.client, Kbs);
}
}
-@end
-
-@implementation DrawLayer
-
-- (void)display
-{
- id<MTLCommandBuffer> cbuf;
- id<MTLBlitCommandEncoder> blit;
-
- LOG(@"display");
-
- cbuf = [commandQueue commandBuffer];
-
- LOG(@"display query drawable");
-
-@autoreleasepool{
- id<CAMetalDrawable> drawable;
-
- drawable = [layer nextDrawable];
- if(!drawable){
- LOG(@"display couldn't get drawable");
- [self setNeedsDisplay];
- return;
- }
-
- LOG(@"display got drawable");
-
- blit = [cbuf blitCommandEncoder];
- [blit copyFromTexture:texture
- sourceSlice:0
- sourceLevel:0
- sourceOrigin:MTLOriginMake(0, 0, 0)
- sourceSize:MTLSizeMake(texture.width, texture.height, texture.depth)
- toTexture:drawable.texture
- destinationSlice:0
- destinationLevel:0
- destinationOrigin:MTLOriginMake(0, 0, 0)];
- [blit endEncoding];
-
- [cbuf presentDrawable:drawable];
- drawable = nil;
+- (NSApplicationPresentationOptions)window:(id)arg
+ willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions {
+ NSApplicationPresentationOptions o;
+ o = proposedOptions;
+ o &= ~(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar);
+ o |= NSApplicationPresentationHideDock | NSApplicationPresentationHideMenuBar;
+ return o;
}
- [cbuf addCompletedHandler:^(id<MTLCommandBuffer> cmdBuff){
- if(cmdBuff.error){
- NSLog(@"command buffer finished with error: %@",
- cmdBuff.error.localizedDescription);
- }else
- LOG(@"command buffer finishes present drawable");
- }];
- [cbuf commit];
- LOG(@"display commit");
+- (void)windowWillEnterFullScreen:(NSNotification*)notification {
+ // TODO: This should only be done if the window
+ // is on the screen with the dock.
+ // But how can you tell which window has the dock?
+ [[NSApplication sharedApplication]
+ setPresentationOptions:NSApplicationPresentationHideMenuBar | NSApplicationPresentationHideDock];
}
+- (void)windowDidExitFullScreen:(NSNotification*)notification {
+ [[NSApplication sharedApplication]
+ setPresentationOptions:NSApplicationPresentationDefault];
+}
@end
static uint
@@ -912,221 +1039,62 @@ keycvt(uint code)
}
}
-Memimage*
-attachscreen(char *label, char *winsize)
-{
- LOG(@"attachscreen(%s, %s)", label, winsize);
- [AppDelegate
- performSelectorOnMainThread:@selector(makewin:)
- withObject:[NSValue valueWithPointer:winsize]
- waitUntilDone:YES];
- kicklabel(label);
- setcursor(nil, nil);
- mouseresized = 0;
- return initimg();
-}
-
-static Memimage*
-initimg(void)
-{
-@autoreleasepool{
- CGFloat scale;
- NSSize size;
- MTLTextureDescriptor *textureDesc;
-
- size = [myContent convertSizeToBacking:[myContent bounds].size];
- mouserect = Rect(0, 0, size.width, size.height);
-
- LOG(@"initimg %.0f %.0f", size.width, size.height);
-
- img = allocmemimage(mouserect, XRGB32);
- if(img == nil)
- panic("allocmemimage: %r");
- if(img->data == nil)
- panic("img->data == nil");
-
- textureDesc = [MTLTextureDescriptor
- texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
- width:size.width
- height:size.height
- mipmapped:NO];
- textureDesc.allowGPUOptimizedContents = YES;
- textureDesc.usage = MTLTextureUsageShaderRead;
- textureDesc.cpuCacheMode = MTLCPUCacheModeWriteCombined;
- texture = [device newTextureWithDescriptor:textureDesc];
-
- scale = [win backingScaleFactor];
- [layer setDrawableSize:size];
- [layer setContentsScale:scale];
-
- // NOTE: This is not really the display DPI.
- // On retina, scale is 2; otherwise it is 1.
- // This formula gives us 220 for retina, 110 otherwise.
- // That's not quite right but it's close to correct.
- // https://en.wikipedia.org/wiki/Retina_display#Models
- displaydpi = scale * 110;
-}
- LOG(@"initimg return");
-
- return img;
-}
-
-void
-_flushmemscreen(Rectangle r)
-{
- LOG(@"_flushmemscreen(%d,%d,%d,%d)", r.min.x, r.min.y, Dx(r), Dy(r));
- if(!rectinrect(r, Rect(0, 0, texture.width, texture.height))){
- LOG(@"Rectangle is out of bounds, return.");
- return;
- }
-
- @autoreleasepool{
- [texture
- replaceRegion:MTLRegionMake2D(r.min.x, r.min.y, Dx(r), Dy(r))
- mipmapLevel:0
- withBytes:byteaddr(img, Pt(r.min.x, r.min.y))
- bytesPerRow:img->width*sizeof(u32int)];
- [AppDelegate
- performSelectorOnMainThread:@selector(callsetNeedsDisplayInRect:)
- withObject:[NSValue valueWithRect:NSMakeRect(r.min.x, r.min.y, Dx(r), Dy(r))]
- waitUntilDone:NO];
- }
-}
-
-void
-setmouse(Point p)
-{
- @autoreleasepool{
- NSPoint q;
-
- LOG(@"setmouse(%d,%d)", p.x, p.y);
- q = [win convertPointFromBacking:NSMakePoint(p.x, p.y)];
- LOG(@"(%g, %g) <- fromBacking", q.x, q.y);
- q = [myContent convertPoint:q toView:nil];
- LOG(@"(%g, %g) <- toWindow", q.x, q.y);
- q = [win convertPointToScreen:q];
- LOG(@"(%g, %g) <- toScreen", q.x, q.y);
- // Quartz has the origin of the "global display
- // coordinate space" at the top left of the primary
- // screen with y increasing downward, while Cocoa has
- // the origin at the bottom left of the primary screen
- // with y increasing upward. We flip the coordinate
- // with a negative sign and shift upward by the height
- // of the primary screen.
- q.y = NSScreen.screens[0].frame.size.height - q.y;
- LOG(@"(%g, %g) <- setmouse", q.x, q.y);
- CGWarpMouseCursorPosition(NSPointToCGPoint(q));
- CGAssociateMouseAndMouseCursorPosition(true);
- }
-}
-
+// rpc_getsnarf reads the current pasteboard as a plain text string.
+// Called from an RPC thread with no client lock held.
char*
-getsnarf(void)
+rpc_getsnarf(void)
{
- NSPasteboard *pb;
- NSString *s;
-
- @autoreleasepool{
- pb = [NSPasteboard generalPasteboard];
-
- qlock(&snarfl);
- s = [pb stringForType:NSPasteboardTypeString];
- qunlock(&snarfl);
-
- if(s)
- return strdup((char *)[s UTF8String]);
- else
- return nil;
- }
-}
-
-void
-putsnarf(char *s)
-{
- NSArray *t;
- NSPasteboard *pb;
- NSString *str;
-
- if(strlen(s) >= SnarfSize)
- return;
-
- @autoreleasepool{
- t = [NSArray arrayWithObject:NSPasteboardTypeString];
- pb = [NSPasteboard generalPasteboard];
- str = [[NSString alloc] initWithUTF8String:s];
-
- qlock(&snarfl);
- [pb declareTypes:t owner:nil];
- [pb setString:str forType:NSPasteboardTypeString];
- qunlock(&snarfl);
- }
+ char __block *ret;
+
+ ret = nil;
+ dispatch_sync(dispatch_get_main_queue(), ^(void) {
+ @autoreleasepool {
+ NSPasteboard *pb = [NSPasteboard generalPasteboard];
+ NSString *s = [pb stringForType:NSPasteboardTypeString];
+ if(s)
+ ret = strdup((char*)[s UTF8String]);
+ }
+ });
+ return ret;
}
+// rpc_putsnarf writes the given text to the pasteboard.
+// Called from an RPC thread with no client lock held.
void
-kicklabel(char *label)
+rpc_putsnarf(char *s)
{
- NSString *s;
-
- LOG(@"kicklabel(%s)", label);
- if(label == nil)
+ if(s == nil || strlen(s) >= SnarfSize)
return;
- @autoreleasepool{
- s = [[NSString alloc] initWithUTF8String:label];
- [AppDelegate
- performSelectorOnMainThread:@selector(callkicklabel:)
- withObject:s
- waitUntilDone:NO];
- }
-}
-
-void
-setcursor(Cursor *c, Cursor2 *c2)
-{
- Cursors cs;
-
- cs.c = c;
- cs.c2 = c2;
-
- [AppDelegate
- performSelectorOnMainThread:@selector(callsetcursor:)
- withObject:[NSValue valueWithPointer:&cs]
- waitUntilDone:YES];
+ dispatch_sync(dispatch_get_main_queue(), ^(void) {
+ @autoreleasepool{
+ NSArray *t = [NSArray arrayWithObject:NSPasteboardTypeString];
+ NSPasteboard *pb = [NSPasteboard generalPasteboard];
+ NSString *str = [[NSString alloc] initWithUTF8String:s];
+ [pb declareTypes:t owner:nil];
+ [pb setString:str forType:NSPasteboardTypeString];
+ }
+ });
}
+// rpc_bouncemouse is for sending a mouse event
+// back to the X11 window manager rio(1).
+// Does not apply here.
void
-topwin(void)
+rpc_bouncemouse(Client *c, Mouse m)
{
- [win
- performSelectorOnMainThread:
- @selector(makeKeyAndOrderFront:)
- withObject:nil
- waitUntilDone:YES];
-
- [NSApp activateIgnoringOtherApps:YES];
}
+// We don't use the graphics thread state during memimagedraw,
+// so rpc_gfxdrawlock and rpc_gfxdrawunlock are no-ops.
void
-resizeimg(void)
+rpc_gfxdrawlock(void)
{
- zlock();
- _drawreplacescreenimage(initimg());
-
- mouseresized = 1;
- zunlock();
- [myContent sendmouse:0];
}
void
-resizewindow(Rectangle r)
+rpc_gfxdrawunlock(void)
{
- LOG(@"resizewindow %d %d %d %d", r.min.x, r.min.y, Dx(r), Dy(r));
- dispatch_async(dispatch_get_main_queue(), ^(void){
- NSSize s;
-
- s = [myContent convertSizeFromBacking:NSMakeSize(Dx(r), Dy(r))];
- [win setContentSize:s];
- });
}
static void
diff --git a/src/cmd/devdraw/macargv.c b/src/cmd/devdraw/macargv.c
deleted file mode 100644
index a5ea1ade..00000000
--- a/src/cmd/devdraw/macargv.c
+++ /dev/null
@@ -1,90 +0,0 @@
-#include <u.h>
-#include <stdio.h>
-#include <Carbon/Carbon.h>
-
-AUTOFRAMEWORK(Carbon)
-
-static OSErr Handler(const AppleEvent *event, AppleEvent *reply, long handlerRefcon);
-
-int
-main(void)
-{
- AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, Handler, 0, false);
- RunApplicationEventLoop();
- return 0;
-}
-
-static OSErr
-GetFullPathname(FSSpec *fss, char *path, int len)
-{
- FSRef fsr;
- OSErr err;
-
- *path = '\0';
- err = FSpMakeFSRef(fss, &fsr);
- if (err == fnfErr) {
- /* FSSpecs can point to non-existing files, fsrefs can't. */
- FSSpec fss2;
- int tocopy;
-
- err = FSMakeFSSpec(fss->vRefNum, fss->parID,
- (unsigned char*)"", &fss2);
- if (err)
- return err;
- err = FSpMakeFSRef(&fss2, &fsr);
- if (err)
- return err;
- err = (OSErr)FSRefMakePath(&fsr, (unsigned char*)path, len-1);
- if (err)
- return err;
- /* This part is not 100% safe: we append the filename part, but
- ** I'm not sure that we don't run afoul of the various 8bit
- ** encodings here. Will have to look this up at some point...
- */
- strcat(path, "/");
- tocopy = fss->name[0];
- if ((strlen(path) + tocopy) >= len)
- tocopy = len - strlen(path) - 1;
- if (tocopy > 0)
- strncat(path, (char*)fss->name+1, tocopy);
- }
- else {
- if (err)
- return err;
- err = (OSErr)FSRefMakePath(&fsr, (unsigned char*)path, len);
- if (err)
- return err;
- }
- return 0;
-}
-
-static void
-chk(int err)
-{
- if(err != 0) {
- printf("err %d\n", err);
- exit(1);
- }
-}
-
-static OSErr
-Handler(const AppleEvent *event, AppleEvent *reply, long handlerRefcon)
-{
- AEDesc list;
- DescType type;
- FSSpec f;
- AEKeyword keyword;
- Size actual;
- long len;
- char s[1000];
-
- chk(AEGetParamDesc(event, keyDirectObject, typeAEList, &list));
- chk(AECountItems(&list, &len));
- chk(AEGetNthPtr(&list, 1, typeFSS, &keyword, &type, (Ptr*)&f, sizeof(FSSpec), &actual));
- chk(GetFullPathname(&f, s, sizeof s));
- printf("%s\n", s);
- fflush(stdout);
-
- // uncomment to keep handling more open events
- exit(0);
-}
diff --git a/src/cmd/devdraw/macargv.m b/src/cmd/devdraw/macargv.m
index 8db56be7..92df2a6f 100644
--- a/src/cmd/devdraw/macargv.m
+++ b/src/cmd/devdraw/macargv.m
@@ -12,9 +12,6 @@ AUTOFRAMEWORK(Cocoa)
void
main(void)
{
- if(OSX_VERSION < 100700)
- [NSAutoreleasePool new];
-
[NSApplication sharedApplication];
NSObject<NSApplicationDelegate> *delegate = [appdelegate new];
[NSApp setDelegate:delegate];
diff --git a/src/cmd/devdraw/mkfile b/src/cmd/devdraw/mkfile
index 7f0c2a20..6bcf1890 100644
--- a/src/cmd/devdraw/mkfile
+++ b/src/cmd/devdraw/mkfile
@@ -9,6 +9,7 @@ WSYSOFILES=\
devdraw.$O\
latin1.$O\
mouseswap.$O\
+ srv.$O\
winsize.$O\
<|sh ./mkwsysrules.sh
@@ -16,14 +17,15 @@ WSYSOFILES=\
OFILES=$WSYSOFILES
HFILES=\
+ bigarrow.h\
devdraw.h\
+ glendapng.h\
+ latin1.h\
+ $WSYSHFILES\
<$PLAN9/src/mkone
-$O.drawclient: drawclient.$O drawfcall.$O
- $LD -o $target $prereq
-
-$O.snarf: x11-alloc.$O x11-cload.$O x11-draw.$O x11-fill.$O x11-get.$O x11-init.$O x11-itrans.$O x11-keysym2ucs.$O x11-load.$O x11-pixelbits.$O x11-unload.$O x11-wsys.$O snarf.$O latin1.$O devdraw.$O
+$O.drawclient: drawclient.$O
$LD -o $target $prereq
$O.mklatinkbd: mklatinkbd.$O
@@ -37,16 +39,13 @@ latin1.h: $PLAN9/lib/keyboard $O.mklatinkbd
$O.macargv: $MACARGV
$LD -o $target $prereq
-cocoa-screen-metal-objc.$O: cocoa-screen-metal.m
- $CC $CFLAGS $OBJCFLAGS -o $target cocoa-screen-metal.m
-
-%-objc.$O: %.m
- $CC $CFLAGS -o $target $stem.m
+%.$O: %.m
+ $CC $CFLAGS $OBJCFLAGS -fobjc-arc -o $target $stem.m
-CLEANFILES=$O.macargv $O.mklatinkbd latin1.h
+CLEANFILES=$O.devdraw $O.macargv $O.drawclient $O.mklatinkbd latin1.h
install: mklatinkbd.install
-install:Q:
+install:Q:
if [ $MACARGV ]; then
mk $MKFLAGS macargv.install
fi
diff --git a/src/cmd/devdraw/mklatinkbd.c b/src/cmd/devdraw/mklatinkbd.c
index abd202fb..db34b6ec 100644
--- a/src/cmd/devdraw/mklatinkbd.c
+++ b/src/cmd/devdraw/mklatinkbd.c
@@ -132,7 +132,7 @@ printtrie(Biobuf *b, Trie *t)
printtrie(b, t->link[i]);
if(t->n == 0)
return;
-
+
if(xflag) {
for(i=0; i<256; i++) {
if(t->r[i] == 0)
@@ -142,7 +142,7 @@ printtrie(Biobuf *b, Trie *t)
Bprint(b, " %k", *p);
Bprint(b, " %k : \"%C\" U%04X\n", i, t->r[i], t->r[i]);
}
- return;
+ return;
}
Bprint(b, "\t\"");
@@ -315,5 +315,3 @@ kfmt(Fmt *f)
return fmtprint(f, "<%s>", xkey[i].s);
return fmtprint(f, "<%c>", c);
}
-
-
diff --git a/src/cmd/devdraw/mkwsysrules.sh b/src/cmd/devdraw/mkwsysrules.sh
index e94afbd3..122e9123 100644
--- a/src/cmd/devdraw/mkwsysrules.sh
+++ b/src/cmd/devdraw/mkwsysrules.sh
@@ -22,13 +22,11 @@ fi
if [ "x$WSYSTYPE" = "x" ]; then
if [ "x`uname`" = "xDarwin" ]; then
- if sw_vers | grep 'ProductVersion: 10\.[0-5]\.' >/dev/null; then
- echo 1>&2 'OS X 10.5 and older are not supported'
+ if sw_vers | egrep 'ProductVersion: (10\.[0-9]\.|10\.1[012])$' >/dev/null; then
+ echo 1>&2 'OS X 10.12 and older are not supported'
exit 1
- else
- #echo 1>&2 'WARNING: OS X Lion is not working. Copy binaries from a Snow Leopard system.'
- WSYSTYPE=osx-cocoa
fi
+ WSYSTYPE=mac
elif [ -d "$X11" ]; then
WSYSTYPE=x11
else
@@ -53,14 +51,11 @@ if [ $WSYSTYPE = x11 ]; then
echo 'HFILES=$HFILES $XHFILES'
XO=`ls x11-*.c 2>/dev/null | sed 's/\.c$/.o/'`
echo 'WSYSOFILES=$WSYSOFILES '$XO
-elif [ $WSYSTYPE = osx-cocoa ]; then
- if sw_vers|awk '/ProductVersion/{split($2,a,".");exit(a[2]<14)}' >/dev/null; then # 0 is true in sh.
- echo 'OBJCFLAGS=$OBJCFLAGS -fobjc-arc'
- echo 'WSYSOFILES=$WSYSOFILES osx-draw.o cocoa-screen-metal-objc.o cocoa-srv.o cocoa-thread.o'
- else
- echo 'WSYSOFILES=$WSYSOFILES osx-draw.o cocoa-screen-objc.o cocoa-srv.o cocoa-thread.o'
- fi
- echo 'MACARGV=macargv-objc.o'
+ echo 'WSYSHFILES=x11-inc.h x11-keysym2ucs.h x11-memdraw.h'
+elif [ $WSYSTYPE = mac ]; then
+ echo 'WSYSOFILES=$WSYSOFILES mac-draw.o mac-screen.o'
+ echo 'WSYSHFILES='
+ echo 'MACARGV=macargv.o'
elif [ $WSYSTYPE = nowsys ]; then
echo 'WSYSOFILES=nowsys.o'
fi
diff --git a/src/cmd/devdraw/mouseswap.c b/src/cmd/devdraw/mouseswap.c
index e6ece333..d2dea666 100644
--- a/src/cmd/devdraw/mouseswap.c
+++ b/src/cmd/devdraw/mouseswap.c
@@ -2,6 +2,11 @@
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
+#include <memlayer.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <keyboard.h>
+#include <drawfcall.h>
#include "devdraw.h"
enum
@@ -51,7 +56,7 @@ mouseswap(int but)
if(!map.init)
initmap();
-
+
nbut = 0;
for(i=0; i<Nbutton; i++)
if((but&(1<<i)) && map.b[i] >= 0)
diff --git a/src/cmd/devdraw/nowsys.c b/src/cmd/devdraw/nowsys.c
index fd8b7ee1..08e0521f 100644
--- a/src/cmd/devdraw/nowsys.c
+++ b/src/cmd/devdraw/nowsys.c
@@ -18,14 +18,14 @@ main(int argc, char **argv)
int n;
uchar buf[1024*1024];
Wsysmsg m;
-
+
ARGBEGIN{
case 'D':
break;
default:
usage();
}ARGEND
-
+
if(argc != 0)
usage();
diff --git a/src/cmd/devdraw/osx-keycodes.h b/src/cmd/devdraw/osx-keycodes.h
deleted file mode 100644
index 52328ace..00000000
--- a/src/cmd/devdraw/osx-keycodes.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/* 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/cmd/devdraw/snarf.c b/src/cmd/devdraw/snarf.c
deleted file mode 100644
index 1e7a93a1..00000000
--- a/src/cmd/devdraw/snarf.c
+++ /dev/null
@@ -1,110 +0,0 @@
-#include <u.h>
-#include <sys/select.h>
-#include <errno.h>
-#include "x11-inc.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 "x11-memdraw.h"
-#include "devdraw.h"
-
-#undef time
-
-#define MouseMask (\
- ButtonPressMask|\
- ButtonReleaseMask|\
- PointerMotionMask|\
- Button1MotionMask|\
- Button2MotionMask|\
- Button3MotionMask)
-
-#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|EnterWindowMask|LeaveWindowMask
-
-void runxevent(XEvent*);
-
-void
-usage(void)
-{
- fprint(2, "usage: snarf [-a] [-o | text]\n");
- exits("usage");
-}
-
-void
-main(int argc, char **argv)
-{
- int apple;
- int out;
-
- apple = 0;
- out = 0;
-
- ARGBEGIN{
- case 'a':
- apple = 1;
- break;
- case 'o':
- out = 1;
- break;
- default:
- usage();
- }ARGEND
-
- if(out && argc != 0)
- usage();
- if(!out && argc != 1)
- usage();
-
- _x.fd = -1;
-
- memimageinit();
- _xattach("snarf", "20x20");
-
- XSelectInput(_x.display, _x.drawable, Mask);
- XFlush(_x.display);
-
- if(out){
- char *s;
- if(apple)
- s = _applegetsnarf();
- else
- s = _xgetsnarf();
- write(1, s, strlen(s));
- write(1, "\n", 1);
- exits(0);
- }else{
- _xputsnarf(argv[0]);
- for(;;){
- XEvent event;
- XNextEvent(_x.display, &event);
- runxevent(&event);
- }
- }
-}
-
-/*
- * Handle an incoming X event.
- */
-void
-runxevent(XEvent *xev)
-{
- switch(xev->type){
- case Expose:
- _xexpose(xev);
- break;
-
- case DestroyNotify:
- if(_xdestroy(xev))
- exits(0);
- break;
-
- case SelectionRequest:
- _xselect(xev);
- break;
- }
-}
-
diff --git a/src/cmd/devdraw/srv.c b/src/cmd/devdraw/srv.c
new file mode 100644
index 00000000..bfeb7c38
--- /dev/null
+++ b/src/cmd/devdraw/srv.c
@@ -0,0 +1,521 @@
+/*
+ * Window system protocol server.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <memlayer.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <drawfcall.h>
+#include "devdraw.h"
+
+static void runmsg(Client*, Wsysmsg*);
+static void replymsg(Client*, Wsysmsg*);
+static void matchkbd(Client*);
+static void matchmouse(Client*);
+static void serveproc(void*);
+static void listenproc(void*);
+Client *client0;
+
+int trace = 0;
+static char *srvname;
+static int afd;
+static char adir[40];
+
+static void
+usage(void)
+{
+ fprint(2, "usage: devdraw (don't run directly)\n");
+ threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+ ARGBEGIN{
+ case 'D': /* for good ps -a listings */
+ break;
+ case 'f': /* fall through for backward compatibility */
+ case 'g':
+ case 'b':
+ break;
+ case 's':
+ // TODO: Update usage, man page.
+ srvname = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(srvname == nil) {
+ client0 = mallocz(sizeof(Client), 1);
+ if(client0 == nil){
+ fprint(2, "initdraw: allocating client0: out of memory");
+ abort();
+ }
+ client0->displaydpi = 100;
+ client0->rfd = 3;
+ client0->wfd = 4;
+
+ /*
+ * 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);
+ }
+
+ fmtinstall('W', drawfcallfmt);
+ gfx_main();
+}
+
+void
+gfx_started(void)
+{
+ char *addr;
+
+ if(srvname == nil) {
+ // Legacy mode: serving single client on pipes.
+ proccreate(serveproc, client0, 0);
+ return;
+ }
+
+ // Server mode.
+ addr = smprint("unix!%s/%s", getns(), srvname);
+ if(addr == nil)
+ sysfatal("out of memory");
+
+ if((afd = announce(addr, adir)) < 0)
+ sysfatal("announce %s: %r", addr);
+
+ proccreate(listenproc, nil, 0);
+}
+
+static void
+listenproc(void *v)
+{
+ Client *c;
+ int fd;
+ char dir[40];
+
+ USED(v);
+
+ for(;;) {
+ fd = listen(adir, dir);
+ if(fd < 0)
+ sysfatal("listen: %r");
+ c = mallocz(sizeof(Client), 1);
+ if(c == nil){
+ fprint(2, "initdraw: allocating client0: out of memory");
+ abort();
+ }
+ c->displaydpi = 100;
+ c->rfd = fd;
+ c->wfd = fd;
+ proccreate(serveproc, c, 0);
+ }
+}
+
+static void
+serveproc(void *v)
+{
+ Client *c;
+ uchar buf[4], *mbuf;
+ int nmbuf, n, nn;
+ Wsysmsg m;
+
+ c = v;
+ mbuf = nil;
+ nmbuf = 0;
+ while((n = read(c->rfd, buf, 4)) == 4){
+ GET(buf, n);
+ if(n > nmbuf){
+ free(mbuf);
+ mbuf = malloc(4+n);
+ if(mbuf == nil)
+ sysfatal("out of memory");
+ nmbuf = n;
+ }
+ memmove(mbuf, buf, 4);
+ nn = readn(c->rfd, mbuf+4, n-4);
+ if(nn != n-4) {
+ fprint(2, "serveproc: eof during message\n");
+ break;
+ }
+
+ /* pick off messages one by one */
+ if(convM2W(mbuf, nn+4, &m) <= 0) {
+ fprint(2, "serveproc: cannot convert message\n");
+ break;
+ }
+ if(trace) fprint(2, "%ud [%d] <- %W\n", nsec()/1000000, threadid(), &m);
+ runmsg(c, &m);
+ }
+
+ if(c == client0) {
+ rpc_shutdown();
+ threadexitsall(nil);
+ }
+}
+
+static void
+replyerror(Client *c, Wsysmsg *m)
+{
+ char err[256];
+
+ rerrstr(err, sizeof err);
+ m->type = Rerror;
+ m->error = err;
+ replymsg(c, m);
+}
+
+/*
+ * Handle a single wsysmsg.
+ * Might queue for later (kbd, mouse read)
+ */
+static void
+runmsg(Client *c, Wsysmsg *m)
+{
+ static uchar buf[65536];
+ int n;
+ Memimage *i;
+
+ switch(m->type){
+ case Tctxt:
+ c->wsysid = strdup(m->id);
+ replymsg(c, m);
+ break;
+
+ case Tinit:
+ memimageinit();
+ i = rpc_attach(c, m->label, m->winsize);
+ draw_initdisplaymemimage(c, i);
+ replymsg(c, m);
+ break;
+
+ case Trdmouse:
+ qlock(&c->eventlk);
+ if((c->mousetags.wi+1)%nelem(c->mousetags.t) == c->mousetags.ri) {
+ qunlock(&c->eventlk);
+ werrstr("too many queued mouse reads");
+ replyerror(c, m);
+ break;
+ }
+ c->mousetags.t[c->mousetags.wi++] = m->tag;
+ if(c->mousetags.wi == nelem(c->mousetags.t))
+ c->mousetags.wi = 0;
+ c->mouse.stall = 0;
+ matchmouse(c);
+ qunlock(&c->eventlk);
+ break;
+
+ case Trdkbd:
+ qlock(&c->eventlk);
+ if((c->kbdtags.wi+1)%nelem(c->kbdtags.t) == c->kbdtags.ri) {
+ qunlock(&c->eventlk);
+ werrstr("too many queued keyboard reads");
+ replyerror(c, m);
+ break;
+ }
+ c->kbdtags.t[c->kbdtags.wi++] = m->tag;
+ if(c->kbdtags.wi == nelem(c->kbdtags.t))
+ c->kbdtags.wi = 0;
+ c->kbd.stall = 0;
+ matchkbd(c);
+ qunlock(&c->eventlk);
+ break;
+
+ case Tmoveto:
+ rpc_setmouse(c, m->mouse.xy);
+ replymsg(c, m);
+ break;
+
+ case Tcursor:
+ if(m->arrowcursor)
+ rpc_setcursor(c, nil, nil);
+ else {
+ scalecursor(&m->cursor2, &m->cursor);
+ rpc_setcursor(c, &m->cursor, &m->cursor2);
+ }
+ replymsg(c, m);
+ break;
+
+ case Tcursor2:
+ if(m->arrowcursor)
+ rpc_setcursor(c, nil, nil);
+ else
+ rpc_setcursor(c, &m->cursor, &m->cursor2);
+ replymsg(c, m);
+ break;
+
+ case Tbouncemouse:
+ rpc_bouncemouse(c, m->mouse);
+ replymsg(c, m);
+ break;
+
+ case Tlabel:
+ rpc_setlabel(c, m->label);
+ replymsg(c, m);
+ break;
+
+ case Trdsnarf:
+ m->snarf = rpc_getsnarf();
+ replymsg(c, m);
+ free(m->snarf);
+ break;
+
+ case Twrsnarf:
+ rpc_putsnarf(m->snarf);
+ replymsg(c, m);
+ break;
+
+ case Trddraw:
+ n = m->count;
+ if(n > sizeof buf)
+ n = sizeof buf;
+ n = draw_dataread(c, buf, n);
+ if(n < 0)
+ replyerror(c, m);
+ else{
+ m->count = n;
+ m->data = buf;
+ replymsg(c, m);
+ }
+ break;
+
+ case Twrdraw:
+ if(draw_datawrite(c, m->data, m->count) < 0)
+ replyerror(c, m);
+ else
+ replymsg(c, m);
+ break;
+
+ case Ttop:
+ rpc_topwin(c);
+ replymsg(c, m);
+ break;
+
+ case Tresize:
+ rpc_resizewindow(c, m->rect);
+ replymsg(c, m);
+ break;
+ }
+}
+
+/*
+ * Reply to m.
+ */
+static void
+replymsg(Client *c, Wsysmsg *m)
+{
+ int n;
+
+ /* T -> R msg */
+ if(m->type%2 == 0)
+ m->type++;
+
+ if(trace) fprint(2, "%ud [%d] -> %W\n", nsec()/1000000, threadid(), m);
+ /* copy to output buffer */
+ n = sizeW2M(m);
+
+ qlock(&c->wfdlk);
+ if(n > c->nmbuf){
+ free(c->mbuf);
+ c->mbuf = malloc(n);
+ if(c->mbuf == nil)
+ sysfatal("out of memory");
+ c->nmbuf = n;
+ }
+ convW2M(m, c->mbuf, n);
+ if(write(c->wfd, c->mbuf, n) != n)
+ fprint(2, "client write: %r\n");
+ qunlock(&c->wfdlk);
+}
+
+/*
+ * Match queued kbd reads with queued kbd characters.
+ */
+static void
+matchkbd(Client *c)
+{
+ Wsysmsg m;
+
+ if(c->kbd.stall)
+ return;
+ while(c->kbd.ri != c->kbd.wi && c->kbdtags.ri != c->kbdtags.wi){
+ m.type = Rrdkbd;
+ m.tag = c->kbdtags.t[c->kbdtags.ri++];
+ if(c->kbdtags.ri == nelem(c->kbdtags.t))
+ c->kbdtags.ri = 0;
+ m.rune = c->kbd.r[c->kbd.ri++];
+ if(c->kbd.ri == nelem(c->kbd.r))
+ c->kbd.ri = 0;
+ replymsg(c, &m);
+ }
+}
+
+// matchmouse matches queued mouse reads with queued mouse events.
+// It must be called with c->eventlk held.
+static void
+matchmouse(Client *c)
+{
+ Wsysmsg m;
+
+ if(canqlock(&c->eventlk)) {
+ fprint(2, "misuse of matchmouse\n");
+ abort();
+ }
+
+ while(c->mouse.ri != c->mouse.wi && c->mousetags.ri != c->mousetags.wi){
+ m.type = Rrdmouse;
+ m.tag = c->mousetags.t[c->mousetags.ri++];
+ if(c->mousetags.ri == nelem(c->mousetags.t))
+ c->mousetags.ri = 0;
+ m.mouse = c->mouse.m[c->mouse.ri];
+ m.resized = c->mouse.resized;
+ c->mouse.resized = 0;
+ /*
+ if(m.resized)
+ fprint(2, "sending resize\n");
+ */
+ c->mouse.ri++;
+ if(c->mouse.ri == nelem(c->mouse.m))
+ c->mouse.ri = 0;
+ replymsg(c, &m);
+ }
+}
+
+void
+gfx_mousetrack(Client *c, int x, int y, int b, uint ms)
+{
+ Mouse *m;
+
+ qlock(&c->eventlk);
+ if(x < c->mouserect.min.x)
+ x = c->mouserect.min.x;
+ if(x > c->mouserect.max.x)
+ x = c->mouserect.max.x;
+ if(y < c->mouserect.min.y)
+ y = c->mouserect.min.y;
+ if(y > c->mouserect.max.y)
+ y = c->mouserect.max.y;
+
+ // If reader has stopped reading, don't bother.
+ // If reader is completely caught up, definitely queue.
+ // Otherwise, queue only button change events.
+ if(!c->mouse.stall)
+ if(c->mouse.wi == c->mouse.ri || c->mouse.last.buttons != b){
+ m = &c->mouse.last;
+ m->xy.x = x;
+ m->xy.y = y;
+ m->buttons = b;
+ m->msec = ms;
+
+ c->mouse.m[c->mouse.wi] = *m;
+ if(++c->mouse.wi == nelem(c->mouse.m))
+ c->mouse.wi = 0;
+ if(c->mouse.wi == c->mouse.ri){
+ c->mouse.stall = 1;
+ c->mouse.ri = 0;
+ c->mouse.wi = 1;
+ c->mouse.m[0] = *m;
+ }
+ matchmouse(c);
+ }
+ qunlock(&c->eventlk);
+}
+
+// kputc adds ch to the keyboard buffer.
+// It must be called with c->eventlk held.
+static void
+kputc(Client *c, int ch)
+{
+ if(canqlock(&c->eventlk)) {
+ fprint(2, "misuse of kputc\n");
+ abort();
+ }
+
+ c->kbd.r[c->kbd.wi++] = ch;
+ if(c->kbd.wi == nelem(c->kbd.r))
+ c->kbd.wi = 0;
+ if(c->kbd.ri == c->kbd.wi)
+ c->kbd.stall = 1;
+ matchkbd(c);
+}
+
+// gfx_abortcompose stops any pending compose sequence,
+// because a mouse button has been clicked.
+// It is called from the graphics thread with no locks held.
+void
+gfx_abortcompose(Client *c)
+{
+ qlock(&c->eventlk);
+ if(c->kbd.alting) {
+ c->kbd.alting = 0;
+ c->kbd.nk = 0;
+ }
+ qunlock(&c->eventlk);
+}
+
+// gfx_keystroke records a single-rune keystroke.
+// It is called from the graphics thread with no locks held.
+void
+gfx_keystroke(Client *c, int ch)
+{
+ int i;
+
+ qlock(&c->eventlk);
+ if(ch == Kalt){
+ c->kbd.alting = !c->kbd.alting;
+ c->kbd.nk = 0;
+ qunlock(&c->eventlk);
+ return;
+ }
+ if(ch == Kcmd+'r') {
+ if(c->forcedpi)
+ c->forcedpi = 0;
+ else if(c->displaydpi >= 200)
+ c->forcedpi = 100;
+ else
+ c->forcedpi = 225;
+ qunlock(&c->eventlk);
+ rpc_resizeimg(c);
+ return;
+ }
+ if(!c->kbd.alting){
+ kputc(c, ch);
+ qunlock(&c->eventlk);
+ return;
+ }
+ if(c->kbd.nk >= nelem(c->kbd.k)) // should not happen
+ c->kbd.nk = 0;
+ c->kbd.k[c->kbd.nk++] = ch;
+ ch = latin1(c->kbd.k, c->kbd.nk);
+ if(ch > 0){
+ c->kbd.alting = 0;
+ kputc(c, ch);
+ c->kbd.nk = 0;
+ qunlock(&c->eventlk);
+ return;
+ }
+ if(ch == -1){
+ c->kbd.alting = 0;
+ for(i=0; i<c->kbd.nk; i++)
+ kputc(c, c->kbd.k[i]);
+ c->kbd.nk = 0;
+ qunlock(&c->eventlk);
+ return;
+ }
+ // need more input
+ qunlock(&c->eventlk);
+ return;
+}
diff --git a/src/cmd/devdraw/winsize.c b/src/cmd/devdraw/winsize.c
index 375401bf..7d0a7b70 100644
--- a/src/cmd/devdraw/winsize.c
+++ b/src/cmd/devdraw/winsize.c
@@ -2,6 +2,11 @@
#include <libc.h>
#include <draw.h>
#include <memdraw.h>
+#include <memlayer.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <keyboard.h>
+#include <drawfcall.h>
#include "devdraw.h"
int
diff --git a/src/cmd/devdraw/x11-alloc.c b/src/cmd/devdraw/x11-alloc.c
index a465f998..cee93064 100644
--- a/src/cmd/devdraw/x11-alloc.c
+++ b/src/cmd/devdraw/x11-alloc.c
@@ -21,7 +21,7 @@ _xallocmemimage(Rectangle r, u32int chan, int pixmap)
m = _allocmemimage(r, chan);
if(chan != GREY1 && chan != _x.chan)
return m;
- if(_x.display == 0)
+ if(_x.display == 0 || _x.windows == nil)
return m;
/*
@@ -49,7 +49,7 @@ _xallocmemimage(Rectangle r, u32int chan, int pixmap)
if(pixmap != PMundef)
xm->pixmap = pixmap;
else
- xm->pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), d);
+ xm->pixmap = XCreatePixmap(_x.display, _x.windows->drawable, Dx(r), Dy(r), d);
/*
* We want to align pixels on word boundaries.
@@ -121,4 +121,3 @@ freememimage(Memimage *m)
}
_freememimage(m);
}
-
diff --git a/src/cmd/devdraw/x11-cload.c b/src/cmd/devdraw/x11-cload.c
index 33e3170a..1666eced 100644
--- a/src/cmd/devdraw/x11-cload.c
+++ b/src/cmd/devdraw/x11-cload.c
@@ -15,4 +15,3 @@ cloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
_xputxdata(i, r);
return n;
}
-
diff --git a/src/cmd/devdraw/x11-draw.c b/src/cmd/devdraw/x11-draw.c
index 685ad88a..f3b6a689 100644
--- a/src/cmd/devdraw/x11-draw.c
+++ b/src/cmd/devdraw/x11-draw.c
@@ -147,4 +147,3 @@ xdraw(Memdrawparam *par)
*/
return 0;
}
-
diff --git a/src/cmd/devdraw/x11-fill.c b/src/cmd/devdraw/x11-fill.c
index fc43a684..adead1ea 100644
--- a/src/cmd/devdraw/x11-fill.c
+++ b/src/cmd/devdraw/x11-fill.c
@@ -23,7 +23,7 @@ _xfillcolor(Memimage *m, Rectangle r, u32int v)
Point p;
Xmem *xm;
XGC gc;
-
+
xm = m->X;
assert(xm != nil);
@@ -52,5 +52,3 @@ _xfillcolor(Memimage *m, Rectangle r, u32int v)
p = subpt(r.min, m->r.min);
XFillRectangle(_x.display, xm->pixmap, gc, p.x, p.y, Dx(r), Dy(r));
}
-
-
diff --git a/src/cmd/devdraw/x11-get.c b/src/cmd/devdraw/x11-get.c
index 1a47be01..61913f18 100644
--- a/src/cmd/devdraw/x11-get.c
+++ b/src/cmd/devdraw/x11-get.c
@@ -21,7 +21,7 @@ _xgetxdata(Memimage *m, Rectangle r)
uchar *p;
Point tp, xdelta, delta;
Xmem *xm;
-
+
xm = m->X;
if(xm == nil)
return nil;
@@ -83,7 +83,7 @@ _xputxdata(Memimage *m, Rectangle r)
XPutImage(_x.display, xm->pixmap, gc, xi, xdelta.x, xdelta.y, delta.x, delta.y,
Dx(r), Dy(r));
-
+
if(_x.usetable && m->chan==CMAP8){
for(y=r.min.y; y<r.max.y; y++)
for(x=r.min.x, p=byteaddr(m, Pt(x,y)); x<r.max.x; x++, p++)
@@ -103,6 +103,3 @@ _xdirtyxdata(Memimage *m, Rectangle r)
xm->dirty = 1;
addrect(&xm->dirtyr, r);
}
-
-
-
diff --git a/src/cmd/devdraw/x11-inc.h b/src/cmd/devdraw/x11-inc.h
index 1ac27d65..dca3ebcd 100644
--- a/src/cmd/devdraw/x11-inc.h
+++ b/src/cmd/devdraw/x11-inc.h
@@ -31,5 +31,3 @@
#undef Screen
#undef Visual
#undef Window
-
-void sendalt(void);
diff --git a/src/cmd/devdraw/x11-init.c b/src/cmd/devdraw/x11-init.c
deleted file mode 100644
index f09963dc..00000000
--- a/src/cmd/devdraw/x11-init.c
+++ /dev/null
@@ -1,737 +0,0 @@
-/*
- * Some of the stuff in this file is not X-dependent and should be elsewhere.
- */
-#include <u.h>
-#include "x11-inc.h"
-#include <libc.h>
-#include <draw.h>
-#include <memdraw.h>
-#include <keyboard.h>
-#include <mouse.h>
-#include <cursor.h>
-#include "x11-memdraw.h"
-#include "devdraw.h"
-
-static void plan9cmap(void);
-static int setupcmap(XWindow);
-static XGC xgc(XDrawable, int, int);
-
-Xprivate _x;
-
-static int
-xerror(XDisplay *d, XErrorEvent *e)
-{
- char buf[200];
-
- if(e->request_code == 42) /* XSetInputFocus */
- return 0;
- if(e->request_code == 18) /* XChangeProperty */
- return 0;
- /*
- * BadDrawable happens in apps that get resized a LOT,
- * e.g. when KDE is configured to resize continuously
- * during a window drag.
- */
- if(e->error_code == 9) /* BadDrawable */
- return 0;
-
- fprint(2, "X error: error_code=%d, request_code=%d, minor=%d disp=%p\n",
- e->error_code, e->request_code, e->minor_code, d);
- XGetErrorText(d, e->error_code, buf, sizeof buf);
- fprint(2, "%s\n", buf);
- return 0;
-}
-
-static int
-xioerror(XDisplay *d)
-{
- /*print("X I/O error\n"); */
- exit(0);
- /*sysfatal("X I/O error\n");*/
- abort();
- return -1;
-}
-
-
-Memimage*
-_xattach(char *label, char *winsize)
-{
- char *argv[2], *disp;
- int i, havemin, height, mask, n, width, x, xrootid, y;
- Rectangle r;
- XClassHint classhint;
- XDrawable pmid;
- XPixmapFormatValues *pfmt;
- XScreen *xscreen;
- XSetWindowAttributes attr;
- XSizeHints normalhint;
- XTextProperty name;
- XVisualInfo xvi;
- XWindow xrootwin;
- XWindowAttributes wattr;
- XWMHints hint;
- Atom atoms[2];
-
- /*
- if(XInitThreads() == 0){
- fprint(2, "XInitThreads failed\n");
- abort();
- }
- */
-
- /*
- * Connect to X server.
- */
- _x.display = XOpenDisplay(NULL);
- if(_x.display == nil){
- disp = getenv("DISPLAY");
- werrstr("XOpenDisplay %s: %r", disp ? disp : ":0");
- free(disp);
- return nil;
- }
- _x.fd = ConnectionNumber(_x.display);
- XSetErrorHandler(xerror);
- XSetIOErrorHandler(xioerror);
- xrootid = DefaultScreen(_x.display);
- xrootwin = DefaultRootWindow(_x.display);
-
- /*
- * Figure out underlying screen format.
- */
- if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi)
- || XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){
- _x.vis = xvi.visual;
- _x.depth = 24;
- }
- else
- if(XMatchVisualInfo(_x.display, xrootid, 16, TrueColor, &xvi)
- || XMatchVisualInfo(_x.display, xrootid, 16, DirectColor, &xvi)){
- _x.vis = xvi.visual;
- _x.depth = 16;
- }
- else
- if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi)
- || XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){
- _x.vis = xvi.visual;
- _x.depth = 15;
- }
- else
- if(XMatchVisualInfo(_x.display, xrootid, 8, PseudoColor, &xvi)
- || XMatchVisualInfo(_x.display, xrootid, 8, StaticColor, &xvi)){
- if(_x.depth > 8){
- werrstr("can't deal with colormapped depth %d screens",
- _x.depth);
- goto err0;
- }
- _x.vis = xvi.visual;
- _x.depth = 8;
- }
- else{
- _x.depth = DefaultDepth(_x.display, xrootid);
- if(_x.depth != 8){
- werrstr("can't understand depth %d screen", _x.depth);
- goto err0;
- }
- _x.vis = DefaultVisual(_x.display, xrootid);
- }
-
- if(DefaultDepth(_x.display, xrootid) == _x.depth)
- _x.usetable = 1;
-
- /*
- * _x.depth is only the number of significant pixel bits,
- * not the total number of pixel bits. We need to walk the
- * display list to find how many actual bits are used
- * per pixel.
- */
- _x.chan = 0;
- pfmt = XListPixmapFormats(_x.display, &n);
- for(i=0; i<n; i++){
- if(pfmt[i].depth == _x.depth){
- switch(pfmt[i].bits_per_pixel){
- case 1: /* untested */
- _x.chan = GREY1;
- break;
- case 2: /* untested */
- _x.chan = GREY2;
- break;
- case 4: /* untested */
- _x.chan = GREY4;
- break;
- case 8:
- _x.chan = CMAP8;
- break;
- case 15:
- _x.chan = RGB15;
- break;
- case 16: /* how to tell RGB15? */
- _x.chan = RGB16;
- break;
- case 24: /* untested (impossible?) */
- _x.chan = RGB24;
- break;
- case 32:
- _x.chan = XRGB32;
- break;
- }
- }
- }
- XFree(pfmt);
- if(_x.chan == 0){
- werrstr("could not determine screen pixel format");
- goto err0;
- }
-
- /*
- * Set up color map if necessary.
- */
- xscreen = DefaultScreenOfDisplay(_x.display);
- _x.cmap = DefaultColormapOfScreen(xscreen);
- if(_x.vis->class != StaticColor){
- plan9cmap();
- setupcmap(xrootwin);
- }
-
- /*
- * We get to choose the initial rectangle size.
- * This is arbitrary. In theory we should read the
- * command line and allow the traditional X options.
- */
- mask = 0;
- x = 0;
- y = 0;
- if(winsize && winsize[0]){
- if(parsewinsize(winsize, &r, &havemin) < 0)
- sysfatal("%r");
- }else{
- /*
- * Parse the various X resources. Thanks to Peter Canning.
- */
- char *screen_resources, *display_resources, *geom,
- *geomrestype, *home, *file, *dpitype;
- XrmDatabase database;
- XrmValue geomres, dpires;
-
- database = XrmGetDatabase(_x.display);
- screen_resources = XScreenResourceString(xscreen);
- if(screen_resources != nil){
- XrmCombineDatabase(XrmGetStringDatabase(screen_resources), &database, False);
- XFree(screen_resources);
- }
-
- display_resources = XResourceManagerString(_x.display);
- if(display_resources == nil){
- home = getenv("HOME");
- if(home!=nil && (file=smprint("%s/.Xdefaults", home)) != nil){
- XrmCombineFileDatabase(file, &database, False);
- free(file);
- }
- free(home);
- }else
- XrmCombineDatabase(XrmGetStringDatabase(display_resources), &database, False);
-
- if (XrmGetResource(database, "Xft.dpi", "String", &dpitype, &dpires) == True) {
- if (dpires.addr) {
- displaydpi=atoi(dpires.addr);
- }
- }
- geom = smprint("%s.geometry", label);
- if(geom && XrmGetResource(database, geom, nil, &geomrestype, &geomres))
- mask = XParseGeometry(geomres.addr, &x, &y, (uint*)&width, (uint*)&height);
- XrmDestroyDatabase(database);
- free(geom);
-
- if((mask & WidthValue) && (mask & HeightValue)){
- r = Rect(0, 0, width, height);
- }else{
- r = Rect(0, 0, WidthOfScreen(xscreen)*3/4,
- HeightOfScreen(xscreen)*3/4);
- if(Dx(r) > Dy(r)*3/2)
- r.max.x = r.min.x + Dy(r)*3/2;
- if(Dy(r) > Dx(r)*3/2)
- r.max.y = r.min.y + Dx(r)*3/2;
- }
- if(mask & XNegative){
- x += WidthOfScreen(xscreen);
- }
- if(mask & YNegative){
- y += HeightOfScreen(xscreen);
- }
- havemin = 0;
- }
- screenrect = Rect(0, 0, WidthOfScreen(xscreen), HeightOfScreen(xscreen));
- windowrect = r;
-
- memset(&attr, 0, sizeof attr);
- attr.colormap = _x.cmap;
- attr.background_pixel = ~0;
- attr.border_pixel = 0;
- _x.drawable = XCreateWindow(
- _x.display, /* display */
- xrootwin, /* parent */
- x, /* x */
- y, /* y */
- Dx(r), /* width */
- Dy(r), /* height */
- 0, /* border width */
- _x.depth, /* depth */
- InputOutput, /* class */
- _x.vis, /* visual */
- /* valuemask */
- CWBackPixel|CWBorderPixel|CWColormap,
- &attr /* attributes (the above aren't?!) */
- );
-
- /*
- * Label and other properties required by ICCCCM.
- */
- memset(&name, 0, sizeof name);
- if(label == nil)
- label = "pjw-face-here";
- name.value = (uchar*)label;
- name.encoding = XA_STRING;
- name.format = 8;
- name.nitems = strlen((char*)name.value);
-
- memset(&normalhint, 0, sizeof normalhint);
- normalhint.flags = PSize|PMaxSize;
- if(winsize && winsize[0]){
- normalhint.flags &= ~PSize;
- normalhint.flags |= USSize;
- normalhint.width = Dx(r);
- normalhint.height = Dy(r);
- }else{
- if((mask & WidthValue) && (mask & HeightValue)){
- normalhint.flags &= ~PSize;
- normalhint.flags |= USSize;
- normalhint.width = width;
- normalhint.height = height;
- }
- if((mask & WidthValue) && (mask & HeightValue)){
- normalhint.flags |= USPosition;
- normalhint.x = x;
- normalhint.y = y;
- }
- }
-
- normalhint.max_width = WidthOfScreen(xscreen);
- normalhint.max_height = HeightOfScreen(xscreen);
-
- memset(&hint, 0, sizeof hint);
- hint.flags = InputHint|StateHint;
- hint.input = 1;
- hint.initial_state = NormalState;
-
- memset(&classhint, 0, sizeof classhint);
- classhint.res_name = label;
- classhint.res_class = label;
-
- argv[0] = label;
- argv[1] = nil;
-
- XSetWMProperties(
- _x.display, /* display */
- _x.drawable, /* window */
- &name, /* XA_WM_NAME property */
- &name, /* XA_WM_ICON_NAME property */
- argv, /* XA_WM_COMMAND */
- 1, /* argc */
- &normalhint, /* XA_WM_NORMAL_HINTS */
- &hint, /* XA_WM_HINTS */
- &classhint /* XA_WM_CLASSHINTS */
- );
- XFlush(_x.display);
-
- if(havemin){
- XWindowChanges ch;
-
- memset(&ch, 0, sizeof ch);
- ch.x = r.min.x;
- ch.y = r.min.y;
- XConfigureWindow(_x.display, _x.drawable, CWX|CWY, &ch);
- /*
- * Must pretend origin is 0,0 for X.
- */
- r = Rect(0,0,Dx(r),Dy(r));
- }
- /*
- * Look up clipboard atom.
- */
- _x.clipboard = XInternAtom(_x.display, "CLIPBOARD", False);
- _x.utf8string = XInternAtom(_x.display, "UTF8_STRING", False);
- _x.targets = XInternAtom(_x.display, "TARGETS", False);
- _x.text = XInternAtom(_x.display, "TEXT", False);
- _x.compoundtext = XInternAtom(_x.display, "COMPOUND_TEXT", False);
- _x.takefocus = XInternAtom(_x.display, "WM_TAKE_FOCUS", False);
- _x.losefocus = XInternAtom(_x.display, "_9WM_LOSE_FOCUS", False);
- _x.wmprotos = XInternAtom(_x.display, "WM_PROTOCOLS", False);
-
- atoms[0] = _x.takefocus;
- atoms[1] = _x.losefocus;
- XChangeProperty(_x.display, _x.drawable, _x.wmprotos, XA_ATOM, 32,
- PropModeReplace, (uchar*)atoms, 2);
-
- /*
- * Put the window on the screen, check to see what size we actually got.
- */
- XMapWindow(_x.display, _x.drawable);
- XSync(_x.display, False);
-
- if(!XGetWindowAttributes(_x.display, _x.drawable, &wattr))
- fprint(2, "XGetWindowAttributes failed\n");
- else if(wattr.width && wattr.height){
- if(wattr.width != Dx(r) || wattr.height != Dy(r)){
- r.max.x = wattr.width;
- r.max.y = wattr.height;
- }
- }else
- fprint(2, "XGetWindowAttributes: bad attrs\n");
-
- /*
- * Allocate our local backing store.
- */
- _x.screenr = r;
- _x.screenpm = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth);
- _x.nextscreenpm = _x.screenpm;
- _x.screenimage = _xallocmemimage(r, _x.chan, _x.screenpm);
-
- /*
- * Allocate some useful graphics contexts for the future.
- */
- _x.gcfill = xgc(_x.screenpm, FillSolid, -1);
- _x.gccopy = xgc(_x.screenpm, -1, -1);
- _x.gcsimplesrc = xgc(_x.screenpm, FillStippled, -1);
- _x.gczero = xgc(_x.screenpm, -1, -1);
- _x.gcreplsrc = xgc(_x.screenpm, FillTiled, -1);
-
- pmid = XCreatePixmap(_x.display, _x.drawable, 1, 1, 1);
- _x.gcfill0 = xgc(pmid, FillSolid, 0);
- _x.gccopy0 = xgc(pmid, -1, -1);
- _x.gcsimplesrc0 = xgc(pmid, FillStippled, -1);
- _x.gczero0 = xgc(pmid, -1, -1);
- _x.gcreplsrc0 = xgc(pmid, FillTiled, -1);
- XFreePixmap(_x.display, pmid);
-
- return _x.screenimage;
-
-err0:
- /*
- * Should do a better job of cleaning up here.
- */
- XCloseDisplay(_x.display);
- return nil;
-}
-
-int
-_xsetlabel(char *label)
-{
- XTextProperty name;
-
- /*
- * Label and other properties required by ICCCCM.
- */
- memset(&name, 0, sizeof name);
- if(label == nil)
- label = "pjw-face-here";
- name.value = (uchar*)label;
- name.encoding = XA_STRING;
- name.format = 8;
- name.nitems = strlen((char*)name.value);
-
- XSetWMProperties(
- _x.display, /* display */
- _x.drawable, /* window */
- &name, /* XA_WM_NAME property */
- &name, /* XA_WM_ICON_NAME property */
- nil, /* XA_WM_COMMAND */
- 0, /* argc */
- nil, /* XA_WM_NORMAL_HINTS */
- nil, /* XA_WM_HINTS */
- nil /* XA_WM_CLASSHINTS */
- );
- XFlush(_x.display);
- return 0;
-}
-
-/*
- * Create a GC with a particular fill style and XXX.
- * Disable generation of GraphicsExpose/NoExpose events in the GC.
- */
-static XGC
-xgc(XDrawable d, int fillstyle, int foreground)
-{
- XGC gc;
- XGCValues v;
-
- memset(&v, 0, sizeof v);
- v.function = GXcopy;
- v.graphics_exposures = False;
- gc = XCreateGC(_x.display, d, GCFunction|GCGraphicsExposures, &v);
- if(fillstyle != -1)
- XSetFillStyle(_x.display, gc, fillstyle);
- if(foreground != -1)
- XSetForeground(_x.display, gc, 0);
- return gc;
-}
-
-
-/*
- * Initialize map with the Plan 9 rgbv color map.
- */
-static void
-plan9cmap(void)
-{
- int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7;
- static int once;
-
- if(once)
- return;
- once = 1;
-
- for(r=0; r!=4; r++)
- for(g = 0; g != 4; g++)
- for(b = 0; b!=4; b++)
- for(v = 0; v!=4; v++){
- den=r;
- if(g > den)
- den=g;
- if(b > den)
- den=b;
- /* divide check -- pick grey shades */
- if(den==0)
- cr=cg=cb=v*17;
- else {
- num=17*(4*den+v);
- cr=r*num/den;
- cg=g*num/den;
- cb=b*num/den;
- }
- idx = r*64 + v*16 + ((g*4 + b + v - r) & 15);
- _x.map[idx].red = cr*0x0101;
- _x.map[idx].green = cg*0x0101;
- _x.map[idx].blue = cb*0x0101;
- _x.map[idx].pixel = idx;
- _x.map[idx].flags = DoRed|DoGreen|DoBlue;
-
- v7 = v >> 1;
- idx7 = r*32 + v7*16 + g*4 + b;
- if((v & 1) == v7){
- _x.map7to8[idx7][0] = idx;
- if(den == 0) { /* divide check -- pick grey shades */
- cr = ((255.0/7.0)*v7)+0.5;
- cg = cr;
- cb = cr;
- }
- else {
- num=17*15*(4*den+v7*2)/14;
- cr=r*num/den;
- cg=g*num/den;
- cb=b*num/den;
- }
- _x.map7[idx7].red = cr*0x0101;
- _x.map7[idx7].green = cg*0x0101;
- _x.map7[idx7].blue = cb*0x0101;
- _x.map7[idx7].pixel = idx7;
- _x.map7[idx7].flags = DoRed|DoGreen|DoBlue;
- }
- else
- _x.map7to8[idx7][1] = idx;
- }
-}
-
-/*
- * Initialize and install the rgbv color map as a private color map
- * for this application. It gets the best colors when it has the
- * cursor focus.
- *
- * We always choose the best depth possible, but that might not
- * be the default depth. On such "suboptimal" systems, we have to allocate an
- * empty color map anyway, according to Axel Belinfante.
- */
-static int
-setupcmap(XWindow w)
-{
- char buf[30];
- int i;
- u32int p, pp;
- XColor c;
-
- if(_x.depth <= 1)
- return 0;
-
- if(_x.depth >= 24) {
- if(_x.usetable == 0)
- _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
-
- /*
- * The pixel value returned from XGetPixel needs to
- * be converted to RGB so we can call rgb2cmap()
- * to translate between 24 bit X and our color. Unfortunately,
- * the return value appears to be display server endian
- * dependant. Therefore, we run some heuristics to later
- * determine how to mask the int value correctly.
- * Yeah, I know we can look at _x.vis->byte_order but
- * some displays say MSB even though they run on LSB.
- * Besides, this is more anal.
- */
- c = _x.map[19]; /* known to have different R, G, B values */
- if(!XAllocColor(_x.display, _x.cmap, &c)){
- werrstr("XAllocColor: %r");
- return -1;
- }
- p = c.pixel;
- pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff);
- if(pp != _x.map[19].pixel) {
- /* check if endian is other way */
- pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
- if(pp != _x.map[19].pixel){
- werrstr("cannot detect X server byte order");
- return -1;
- }
-
- switch(_x.chan){
- case RGB24:
- _x.chan = BGR24;
- break;
- case XRGB32:
- _x.chan = XBGR32;
- break;
- default:
- werrstr("cannot byteswap channel %s",
- chantostr(buf, _x.chan));
- break;
- }
- }
- }else if(_x.vis->class == TrueColor || _x.vis->class == DirectColor){
- /*
- * Do nothing. We have no way to express a
- * mixed-endian 16-bit screen, so pretend they don't exist.
- */
- if(_x.usetable == 0)
- _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
- }else if(_x.vis->class == PseudoColor){
- if(_x.usetable == 0){
- _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocAll);
- XStoreColors(_x.display, _x.cmap, _x.map, 256);
- for(i = 0; i < 256; i++){
- _x.tox11[i] = i;
- _x.toplan9[i] = i;
- }
- }else{
- for(i = 0; i < 128; i++){
- c = _x.map7[i];
- if(!XAllocColor(_x.display, _x.cmap, &c)){
- werrstr("can't allocate colors in 7-bit map");
- return -1;
- }
- _x.tox11[_x.map7to8[i][0]] = c.pixel;
- _x.tox11[_x.map7to8[i][1]] = c.pixel;
- _x.toplan9[c.pixel] = _x.map7to8[i][0];
- }
- }
- }else{
- werrstr("unsupported visual class %d", _x.vis->class);
- return -1;
- }
- return 0;
-}
-
-void
-_flushmemscreen(Rectangle r)
-{
- if(_x.nextscreenpm != _x.screenpm){
- qlock(&_x.screenlock);
- XSync(_x.display, False);
- XFreePixmap(_x.display, _x.screenpm);
- _x.screenpm = _x.nextscreenpm;
- qunlock(&_x.screenlock);
- }
-
- if(r.min.x >= r.max.x || r.min.y >= r.max.y)
- return;
- XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
- Dx(r), Dy(r), r.min.x, r.min.y);
- XFlush(_x.display);
-}
-
-void
-_xexpose(XEvent *e)
-{
- XExposeEvent *xe;
- Rectangle r;
-
- qlock(&_x.screenlock);
- if(_x.screenpm != _x.nextscreenpm){
- qunlock(&_x.screenlock);
- return;
- }
- xe = (XExposeEvent*)e;
- r.min.x = xe->x;
- r.min.y = xe->y;
- r.max.x = xe->x+xe->width;
- r.max.y = xe->y+xe->height;
- XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
- Dx(r), Dy(r), r.min.x, r.min.y);
- XSync(_x.display, False);
- qunlock(&_x.screenlock);
-}
-
-int
-_xdestroy(XEvent *e)
-{
- XDestroyWindowEvent *xe;
-
- xe = (XDestroyWindowEvent*)e;
- if(xe->window == _x.drawable){
- _x.destroyed = 1;
- return 1;
- }
- return 0;
-}
-
-int
-_xconfigure(XEvent *e)
-{
- Rectangle r;
- XConfigureEvent *xe = (XConfigureEvent*)e;
-
- if(!fullscreen){
- int rx, ry;
- XWindow w;
- if(XTranslateCoordinates(_x.display, _x.drawable, DefaultRootWindow(_x.display), 0, 0, &rx, &ry, &w))
- windowrect = Rect(rx, ry, rx+xe->width, ry+xe->height);
- }
-
- if(xe->width == Dx(_x.screenr) && xe->height == Dy(_x.screenr))
- return 0;
- r = Rect(0, 0, xe->width, xe->height);
-
- qlock(&_x.screenlock);
- if(_x.screenpm != _x.nextscreenpm){
- XCopyArea(_x.display, _x.screenpm, _x.drawable, _x.gccopy, r.min.x, r.min.y,
- Dx(r), Dy(r), r.min.x, r.min.y);
- XSync(_x.display, False);
- }
- qunlock(&_x.screenlock);
- _x.newscreenr = r;
- return 1;
-}
-
-int
-_xreplacescreenimage(void)
-{
- Memimage *m;
- XDrawable pixmap;
- Rectangle r;
-
- r = _x.newscreenr;
-
- pixmap = XCreatePixmap(_x.display, _x.drawable, Dx(r), Dy(r), _x.depth);
- m = _xallocmemimage(r, _x.chan, pixmap);
- if(_x.nextscreenpm != _x.screenpm)
- XFreePixmap(_x.display, _x.nextscreenpm);
- _x.nextscreenpm = pixmap;
- _x.screenr = r;
- _drawreplacescreenimage(m);
- return 1;
-}
diff --git a/src/cmd/devdraw/x11-itrans.c b/src/cmd/devdraw/x11-itrans.c
deleted file mode 100644
index 729f2647..00000000
--- a/src/cmd/devdraw/x11-itrans.c
+++ /dev/null
@@ -1,741 +0,0 @@
-/* input event and data structure translation */
-
-#include <u.h>
-#include "x11-inc.h"
-#ifdef __APPLE__
-#define APPLESNARF
-#define Boolean AppleBoolean
-#define Rect AppleRect
-#define EventMask AppleEventMask
-#define Point ApplePoint
-#define Cursor AppleCursor
-#include <Carbon/Carbon.h>
-AUTOFRAMEWORK(Carbon)
-#undef Boolean
-#undef Rect
-#undef EventMask
-#undef Point
-#undef Cursor
-#endif
-#include <libc.h>
-#include <draw.h>
-#include <memdraw.h>
-#include <mouse.h>
-#include <cursor.h>
-#include <keyboard.h>
-#include "x11-memdraw.h"
-#include "x11-keysym2ucs.h"
-#undef time
-
-static KeySym
-__xtoplan9kbd(XEvent *e)
-{
- KeySym k;
-
- if(e->xany.type != KeyPress)
- return -1;
- needstack(64*1024); /* X has some *huge* buffers in openobject */
- /* and they're even bigger on SuSE */
- XLookupString((XKeyEvent*)e,NULL,0,&k,NULL);
- if(k == NoSymbol)
- return -1;
-
- if(k&0xFF00){
- switch(k){
- case XK_BackSpace:
- case XK_Tab:
- case XK_Escape:
- case XK_Delete:
- case XK_KP_0:
- case XK_KP_1:
- case XK_KP_2:
- case XK_KP_3:
- case XK_KP_4:
- case XK_KP_5:
- case XK_KP_6:
- case XK_KP_7:
- case XK_KP_8:
- case XK_KP_9:
- case XK_KP_Divide:
- case XK_KP_Multiply:
- case XK_KP_Subtract:
- case XK_KP_Add:
- case XK_KP_Decimal:
- k &= 0x7F;
- break;
- case XK_Linefeed:
- k = '\r';
- break;
- case XK_KP_Space:
- k = ' ';
- break;
- case XK_Home:
- case XK_KP_Home:
- k = Khome;
- break;
- case XK_Left:
- case XK_KP_Left:
- k = Kleft;
- break;
- case XK_Up:
- case XK_KP_Up:
- k = Kup;
- break;
- case XK_Down:
- case XK_KP_Down:
- k = Kdown;
- break;
- case XK_Right:
- case XK_KP_Right:
- k = Kright;
- break;
- case XK_Page_Down:
- case XK_KP_Page_Down:
- k = Kpgdown;
- break;
- case XK_End:
- case XK_KP_End:
- k = Kend;
- break;
- case XK_Page_Up:
- case XK_KP_Page_Up:
- k = Kpgup;
- break;
- case XK_Insert:
- case XK_KP_Insert:
- k = Kins;
- break;
- case XK_KP_Enter:
- case XK_Return:
- k = '\n';
- break;
- case XK_Alt_L:
- case XK_Meta_L: /* Shift Alt on PCs */
- case XK_Alt_R:
- case XK_Meta_R: /* Shift Alt on PCs */
- case XK_Multi_key:
- return -1;
- default: /* not ISO-1 or tty control */
- if(k>0xff) {
- k = _p9keysym2ucs(k);
- if(k==-1) return -1;
- }
- }
- }
-
- /* Compensate for servers that call a minus a hyphen */
- if(k == XK_hyphen)
- k = XK_minus;
- /* Do control mapping ourselves if translator doesn't */
- if(e->xkey.state&ControlMask)
- k &= 0x9f;
- if(k == NoSymbol) {
- return -1;
- }
-
- return k+0;
-}
-
-int alting;
-
-void
-abortcompose(void)
-{
- alting = 0;
-}
-
-static Rune* sendrune(Rune);
-
-extern int _latin1(Rune*, int);
-static Rune*
-xtoplan9latin1(XEvent *e)
-{
- Rune r;
-
- r = __xtoplan9kbd(e);
- if(r == -1)
- return nil;
- return sendrune(r);
-}
-
-void
-sendalt(void)
-{
- sendrune(Kalt);
-}
-
-static Rune*
-sendrune(Rune r)
-{
- static Rune k[10];
- static int nk;
- int n;
-
- if(alting){
- /*
- * Kludge for Mac's X11 3-button emulation.
- * It treats Command+Button as button 3, but also
- * ends up sending XK_Meta_L twice.
- */
- if(r == Kalt){
- alting = 0;
- return nil;
- }
- k[nk++] = r;
- n = _latin1(k, nk);
- if(n > 0){
- alting = 0;
- k[0] = n;
- k[1] = 0;
- return k;
- }
- if(n == -1){
- alting = 0;
- k[nk] = 0;
- return k;
- }
- /* n < -1, need more input */
- return nil;
- }else if(r == Kalt){
- alting = 1;
- nk = 0;
- return nil;
- }else{
- k[0] = r;
- k[1] = 0;
- return k;
- }
-}
-
-int
-_xtoplan9kbd(XEvent *e)
-{
- static Rune *r;
-
- if(e == (XEvent*)-1){
- assert(r);
- r--;
- return 0;
- }
- if(e)
- r = xtoplan9latin1(e);
- if(r && *r)
- return *r++;
- return -1;
-}
-
-int
-_xtoplan9mouse(XEvent *e, Mouse *m)
-{
- int s;
- XButtonEvent *be;
- XMotionEvent *me;
-
- if(_x.putsnarf != _x.assertsnarf){
- _x.assertsnarf = _x.putsnarf;
- XSetSelectionOwner(_x.display, XA_PRIMARY, _x.drawable, CurrentTime);
- if(_x.clipboard != None)
- XSetSelectionOwner(_x.display, _x.clipboard, _x.drawable, CurrentTime);
- XFlush(_x.display);
- }
-
- switch(e->type){
- case ButtonPress:
- be = (XButtonEvent*)e;
-
- /*
- * Fake message, just sent to make us announce snarf.
- * Apparently state and button are 16 and 8 bits on
- * the wire, since they are truncated by the time they
- * get to us.
- */
- if(be->send_event
- && (~be->state&0xFFFF)==0
- && (~be->button&0xFF)==0)
- return -1;
- /* BUG? on mac need to inherit these from elsewhere? */
- m->xy.x = be->x;
- m->xy.y = be->y;
- s = be->state;
- m->msec = be->time;
- switch(be->button){
- case 1:
- s |= Button1Mask;
- break;
- case 2:
- s |= Button2Mask;
- break;
- case 3:
- s |= Button3Mask;
- break;
- case 4:
- s |= Button4Mask;
- break;
- case 5:
- s |= Button5Mask;
- break;
- }
- break;
- case ButtonRelease:
- be = (XButtonEvent*)e;
- m->xy.x = be->x;
- m->xy.y = be->y;
- s = be->state;
- m->msec = be->time;
- switch(be->button){
- case 1:
- s &= ~Button1Mask;
- break;
- case 2:
- s &= ~Button2Mask;
- break;
- case 3:
- s &= ~Button3Mask;
- break;
- case 4:
- s &= ~Button4Mask;
- break;
- case 5:
- s &= ~Button5Mask;
- break;
- }
- break;
-
- case MotionNotify:
- me = (XMotionEvent*)e;
- s = me->state;
- m->xy.x = me->x;
- m->xy.y = me->y;
- m->msec = me->time;
- return 0; // do not set buttons
-
- default:
- return -1;
- }
-
- m->buttons = 0;
- if(s & Button1Mask)
- m->buttons |= 1;
- if(s & Button2Mask)
- m->buttons |= 2;
- if(s & Button3Mask)
- m->buttons |= 4;
- if(s & Button4Mask)
- m->buttons |= 8;
- if(s & Button5Mask)
- m->buttons |= 16;
- return 0;
-}
-
-void
-_xmoveto(Point p)
-{
- XWarpPointer(_x.display, None, _x.drawable, 0, 0, 0, 0, p.x, p.y);
- XFlush(_x.display);
-}
-
-static int
-revbyte(int b)
-{
- int r;
-
- r = 0;
- r |= (b&0x01) << 7;
- r |= (b&0x02) << 5;
- r |= (b&0x04) << 3;
- r |= (b&0x08) << 1;
- r |= (b&0x10) >> 1;
- r |= (b&0x20) >> 3;
- r |= (b&0x40) >> 5;
- r |= (b&0x80) >> 7;
- return r;
-}
-
-static void
-xcursorarrow(void)
-{
- if(_x.cursor != 0){
- XFreeCursor(_x.display, _x.cursor);
- _x.cursor = 0;
- }
- XUndefineCursor(_x.display, _x.drawable);
- XFlush(_x.display);
-}
-
-
-void
-_xsetcursor(Cursor *c)
-{
- XColor fg, bg;
- XCursor xc;
- Pixmap xsrc, xmask;
- int i;
- uchar src[2*16], mask[2*16];
-
- if(c == nil){
- xcursorarrow();
- return;
- }
- for(i=0; i<2*16; i++){
- src[i] = revbyte(c->set[i]);
- mask[i] = revbyte(c->set[i] | c->clr[i]);
- }
-
- fg = _x.map[0];
- bg = _x.map[255];
- xsrc = XCreateBitmapFromData(_x.display, _x.drawable, (char*)src, 16, 16);
- xmask = XCreateBitmapFromData(_x.display, _x.drawable, (char*)mask, 16, 16);
- xc = XCreatePixmapCursor(_x.display, xsrc, xmask, &fg, &bg, -c->offset.x, -c->offset.y);
- if(xc != 0) {
- XDefineCursor(_x.display, _x.drawable, xc);
- if(_x.cursor != 0)
- XFreeCursor(_x.display, _x.cursor);
- _x.cursor = xc;
- }
- XFreePixmap(_x.display, xsrc);
- XFreePixmap(_x.display, xmask);
- XFlush(_x.display);
-}
-
-struct {
- QLock lk;
- char buf[SnarfSize];
-#ifdef APPLESNARF
- Rune rbuf[SnarfSize];
- PasteboardRef apple;
-#endif
-} clip;
-
-static uchar*
-_xgetsnarffrom(XWindow w, Atom clipboard, Atom target, int timeout0, int timeout)
-{
- Atom prop, type;
- ulong len, lastlen, dummy;
- int fmt, i;
- uchar *data, *xdata;
-
- /*
- * We should be waiting for SelectionNotify here, but it might never
- * come, and we have no way to time out. Instead, we will clear
- * local property #1, request our buddy to fill it in for us, and poll
- * until he's done or we get tired of waiting.
- */
- prop = 1;
- XChangeProperty(_x.display, _x.drawable, prop, target, 8, PropModeReplace, (uchar*)"", 0);
- XConvertSelection(_x.display, clipboard, target, prop, _x.drawable, CurrentTime);
- XFlush(_x.display);
- lastlen = 0;
- timeout0 = (timeout0 + 9)/10;
- timeout = (timeout + 9)/10;
- for(i=0; i<timeout0 || (lastlen!=0 && i<timeout); i++){
- usleep(10*1000);
- XGetWindowProperty(_x.display, _x.drawable, prop, 0, 0, 0, AnyPropertyType,
- &type, &fmt, &dummy, &len, &xdata);
- if(lastlen == len && len > 0){
- XFree(xdata);
- break;
- }
- lastlen = len;
- XFree(xdata);
- }
- if(len == 0)
- return nil;
-
- /* get the property */
- xdata = nil;
- XGetWindowProperty(_x.display, _x.drawable, prop, 0, SnarfSize/sizeof(ulong), 0,
- AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
- if((type != target && type != XA_STRING && type != _x.utf8string) || len == 0){
- if(xdata)
- XFree(xdata);
- return nil;
- }
- if(xdata){
- data = (uchar*)strdup((char*)xdata);
- XFree(xdata);
- return data;
- }
- return nil;
-}
-
-char*
-_xgetsnarf(void)
-{
- uchar *data;
- Atom clipboard;
- XWindow w;
-
- qlock(&clip.lk);
- /*
- * Have we snarfed recently and the X server hasn't caught up?
- */
- if(_x.putsnarf != _x.assertsnarf)
- goto mine;
-
- /*
- * Is there a primary selection (highlighted text in an xterm)?
- */
- clipboard = XA_PRIMARY;
- w = XGetSelectionOwner(_x.display, XA_PRIMARY);
- if(w == _x.drawable){
- mine:
- data = (uchar*)strdup(clip.buf);
- goto out;
- }
-
- /*
- * If not, is there a clipboard selection?
- */
- if(w == None && _x.clipboard != None){
- clipboard = _x.clipboard;
- w = XGetSelectionOwner(_x.display, _x.clipboard);
- if(w == _x.drawable)
- goto mine;
- }
-
- /*
- * If not, give up.
- */
- if(w == None){
- data = nil;
- goto out;
- }
-
- if((data = _xgetsnarffrom(w, clipboard, _x.utf8string, 10, 100)) == nil)
- if((data = _xgetsnarffrom(w, clipboard, XA_STRING, 10, 100)) == nil){
- /* nothing left to do */
- }
-
-out:
- qunlock(&clip.lk);
- return (char*)data;
-}
-
-void
-__xputsnarf(char *data)
-{
- XButtonEvent e;
-
- if(strlen(data) >= SnarfSize)
- return;
- qlock(&clip.lk);
- strcpy(clip.buf, data);
- /* leave note for mouse proc to assert selection ownership */
- _x.putsnarf++;
-
- /* send mouse a fake event so snarf is announced */
- memset(&e, 0, sizeof e);
- e.type = ButtonPress;
- e.window = _x.drawable;
- e.state = ~0;
- e.button = ~0;
- XSendEvent(_x.display, _x.drawable, True, ButtonPressMask, (XEvent*)&e);
- XFlush(_x.display);
- qunlock(&clip.lk);
-}
-
-int
-_xselect(XEvent *e)
-{
- char *name;
- XEvent r;
- XSelectionRequestEvent *xe;
- Atom a[4];
-
- memset(&r, 0, sizeof r);
- xe = (XSelectionRequestEvent*)e;
-if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d (sizeof atom=%d)\n",
- xe->target, xe->requestor, xe->property, xe->selection, sizeof a[0]);
- r.xselection.property = xe->property;
- if(xe->target == _x.targets){
- a[0] = _x.utf8string;
- a[1] = XA_STRING;
- a[2] = _x.text;
- a[3] = _x.compoundtext;
- XChangeProperty(_x.display, xe->requestor, xe->property, XA_ATOM,
- 32, PropModeReplace, (uchar*)a, nelem(a));
- }else if(xe->target == XA_STRING
- || xe->target == _x.utf8string
- || xe->target == _x.text
- || xe->target == _x.compoundtext
- || ((name = XGetAtomName(_x.display, xe->target)) && strcmp(name, "text/plain;charset=UTF-8") == 0)){
- /* text/plain;charset=UTF-8 seems nonstandard but is used by Synergy */
- /* if the target is STRING we're supposed to reply with Latin1 XXX */
- qlock(&clip.lk);
- XChangeProperty(_x.display, xe->requestor, xe->property, xe->target,
- 8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
- qunlock(&clip.lk);
- }else{
- if(strcmp(name, "TIMESTAMP") != 0)
- fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);
- r.xselection.property = None;
- }
-
- r.xselection.display = xe->display;
- /* r.xselection.property filled above */
- r.xselection.target = xe->target;
- r.xselection.type = SelectionNotify;
- r.xselection.requestor = xe->requestor;
- r.xselection.time = xe->time;
- r.xselection.send_event = True;
- r.xselection.selection = xe->selection;
- XSendEvent(_x.display, xe->requestor, False, 0, &r);
- XFlush(_x.display);
- return 0;
-}
-
-#ifdef APPLESNARF
-char*
-_applegetsnarf(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);
- 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
-_appleputsnarf(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);
- if(clip.apple == nil){
- if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){
- fprint(2, "apple pasteboard create failed\n");
- qunlock(&clip.lk);
- return;
- }
- }
- 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);
-}
-#endif /* APPLESNARF */
-
-void
-_xputsnarf(char *data)
-{
-#ifdef APPLESNARF
- _appleputsnarf(data);
-#endif
- __xputsnarf(data);
-}
-
-/*
- * Send the mouse event back to the window manager.
- * So that 9term can tell rio to pop up its button3 menu.
- */
-void
-_xbouncemouse(Mouse *m)
-{
- XButtonEvent e;
- XWindow dw;
-
- e.type = ButtonPress;
- e.state = 0;
- e.button = 0;
- if(m->buttons&1)
- e.button = 1;
- else if(m->buttons&2)
- e.button = 2;
- else if(m->buttons&4)
- e.button = 3;
- e.same_screen = 1;
- XTranslateCoordinates(_x.display, _x.drawable,
- DefaultRootWindow(_x.display),
- m->xy.x, m->xy.y, &e.x_root, &e.y_root, &dw);
- e.root = DefaultRootWindow(_x.display);
- e.window = e.root;
- e.subwindow = None;
- e.x = e.x_root;
- e.y = e.y_root;
-#undef time
- e.time = CurrentTime;
- XUngrabPointer(_x.display, m->msec);
- XSendEvent(_x.display, e.root, True, ButtonPressMask, (XEvent*)&e);
- XFlush(_x.display);
-}
diff --git a/src/cmd/devdraw/x11-keysym2ucs.c b/src/cmd/devdraw/x11-keysym2ucs.c
index 108f153c..853fa552 100644
--- a/src/cmd/devdraw/x11-keysym2ucs.c
+++ b/src/cmd/devdraw/x11-keysym2ucs.c
@@ -34,7 +34,7 @@
*/
#ifndef KEYSYM2UCS_INCLUDED
-
+
#include "x11-keysym2ucs.h"
#define VISIBLE /* */
diff --git a/src/cmd/devdraw/x11-load.c b/src/cmd/devdraw/x11-load.c
index a7446f37..895e1109 100644
--- a/src/cmd/devdraw/x11-load.c
+++ b/src/cmd/devdraw/x11-load.c
@@ -15,4 +15,3 @@ loadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
_xputxdata(i, r);
return n;
}
-
diff --git a/src/cmd/devdraw/x11-memdraw.h b/src/cmd/devdraw/x11-memdraw.h
index d2cab13b..0c78b9b6 100644
--- a/src/cmd/devdraw/x11-memdraw.h
+++ b/src/cmd/devdraw/x11-memdraw.h
@@ -4,6 +4,7 @@
typedef struct Xmem Xmem;
typedef struct Xprivate Xprivate;
+typedef struct Xwin Xwin;
enum
{
@@ -26,7 +27,6 @@ struct Xprivate {
XDisplay *display;
int fd; /* of display */
int depth; /* of screen */
- XDrawable drawable;
XColor map[256];
XColor map7[128];
uchar map7to8[128][2];
@@ -50,12 +50,6 @@ struct Xprivate {
u32int gczeropixmap;
XGC gczero0;
u32int gczero0pixmap;
- Rectangle newscreenr;
- Memimage* screenimage;
- QLock screenlock;
- XDrawable screenpm;
- XDrawable nextscreenpm;
- Rectangle screenr;
int toplan9[256];
int tox11[256];
int usetable;
@@ -70,9 +64,35 @@ struct Xprivate {
Atom wmprotos;
uint putsnarf;
uint assertsnarf;
+ int kbuttons;
+ int kstate;
+ int altdown;
+
+ Xwin* windows;
+};
+
+struct Client;
+
+struct Xwin
+{
+ XDrawable drawable;
+ struct Client* client;
+
+ Rectangle newscreenr;
+ Memimage* screenimage;
+ XDrawable screenpm;
+ XDrawable nextscreenpm;
+ Rectangle screenr;
+ Rectangle screenrect;
+ Rectangle windowrect;
+ int fullscreen;
int destroyed;
+
+ Xwin* next;
};
+void xlock(void);
+void xunlock(void);
extern Xprivate _x;
extern Memimage *_xallocmemimage(Rectangle, u32int, int);
@@ -83,35 +103,3 @@ extern void _xfreexdata(Memimage*);
extern XImage *_xgetxdata(Memimage*, Rectangle);
extern void _xputxdata(Memimage*, Rectangle);
-struct Mouse;
-extern int _xtoplan9mouse(XEvent*, struct Mouse*);
-extern int _xtoplan9kbd(XEvent*);
-extern void _xexpose(XEvent*);
-extern int _xselect(XEvent*);
-extern int _xconfigure(XEvent*);
-extern int _xdestroy(XEvent*);
-extern void _flushmemscreen(Rectangle);
-extern void _xmoveto(Point);
-struct Cursor;
-extern void _xsetcursor(struct Cursor*);
-extern void _xbouncemouse(Mouse*);
-extern int _xsetlabel(char*);
-extern Memimage* _xattach(char*, char*);
-extern char* _xgetsnarf(void);
-extern void _xputsnarf(char *data);
-extern void _xtopwindow(void);
-extern void _xresizewindow(Rectangle);
-extern void _xmovewindow(Rectangle);
-extern int _xreplacescreenimage(void);
-
-#define MouseMask (\
- ButtonPressMask|\
- ButtonReleaseMask|\
- PointerMotionMask|\
- Button1MotionMask|\
- Button2MotionMask|\
- Button3MotionMask)
-
-extern Rectangle screenrect;
-extern Rectangle windowrect;
-extern int fullscreen;
diff --git a/src/cmd/devdraw/x11-pixelbits.c b/src/cmd/devdraw/x11-pixelbits.c
index 5cbdded8..5227f39b 100644
--- a/src/cmd/devdraw/x11-pixelbits.c
+++ b/src/cmd/devdraw/x11-pixelbits.c
@@ -12,5 +12,3 @@ pixelbits(Memimage *m, Point p)
_xgetxdata(m, Rect(p.x, p.y, p.x+1, p.y+1));
return _pixelbits(m, p);
}
-
-
diff --git a/src/cmd/devdraw/x11-screen.c b/src/cmd/devdraw/x11-screen.c
new file mode 100644
index 00000000..8026e1e6
--- /dev/null
+++ b/src/cmd/devdraw/x11-screen.c
@@ -0,0 +1,1759 @@
+#include <u.h>
+#include "x11-inc.h"
+#include "x11-keysym2ucs.h"
+#include <errno.h>
+#include <libc.h>
+#include <draw.h>
+#include <memdraw.h>
+#include <memlayer.h>
+#include <keyboard.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <thread.h>
+#include "x11-memdraw.h"
+#include "devdraw.h"
+
+#undef time
+
+static void plan9cmap(void);
+static int setupcmap(XWindow);
+static XGC xgc(XDrawable, int, int);
+#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask|EnterWindowMask|LeaveWindowMask|FocusChangeMask
+
+#define MouseMask (\
+ ButtonPressMask|\
+ ButtonReleaseMask|\
+ PointerMotionMask|\
+ Button1MotionMask|\
+ Button2MotionMask|\
+ Button3MotionMask)
+
+Xprivate _x;
+
+static void runxevent(XEvent *xev);
+static int _xconfigure(Xwin *w, XEvent *e);
+static int _xdestroy(Xwin *w, XEvent *e);
+static void _xexpose(Xwin *w, XEvent *e);
+static int _xreplacescreenimage(Client *client);
+static int _xtoplan9mouse(Xwin *w, XEvent *e, Mouse *m);
+static void _xmovewindow(Xwin *w, Rectangle r);
+static int _xtoplan9kbd(XEvent *e);
+static int _xselect(XEvent *e);
+
+static Xwin*
+newxwin(Client *c)
+{
+ Xwin *w;
+
+ w = mallocz(sizeof *w, 1);
+ if(w == nil)
+ sysfatal("out of memory");
+ w->client = c;
+ w->next = _x.windows;
+ _x.windows = w;
+ c->view = w;
+ return w;
+}
+
+static Xwin*
+findxwin(XDrawable d)
+{
+ Xwin *w, **l;
+
+ for(l=&_x.windows; (w=*l) != nil; l=&w->next) {
+ if(w->drawable == d) {
+ /* move to front */
+ *l = w->next;
+ w->next = _x.windows;
+ _x.windows = w;
+ return w;
+ }
+ }
+ return nil;
+}
+
+static int
+xerror(XDisplay *d, XErrorEvent *e)
+{
+ char buf[200];
+
+ if(e->request_code == 42) /* XSetInputFocus */
+ return 0;
+ if(e->request_code == 18) /* XChangeProperty */
+ return 0;
+ /*
+ * BadDrawable happens in apps that get resized a LOT,
+ * e.g. when KDE is configured to resize continuously
+ * during a window drag.
+ */
+ if(e->error_code == 9) /* BadDrawable */
+ return 0;
+
+ fprint(2, "X error: error_code=%d, request_code=%d, minor=%d disp=%p\n",
+ e->error_code, e->request_code, e->minor_code, d);
+ XGetErrorText(d, e->error_code, buf, sizeof buf);
+ fprint(2, "%s\n", buf);
+ return 0;
+}
+
+static int
+xioerror(XDisplay *d)
+{
+ /*print("X I/O error\n"); */
+ exit(0);
+ /*sysfatal("X I/O error\n");*/
+ abort();
+ return -1;
+}
+
+static void xloop(void);
+
+static QLock xlk;
+
+void
+xlock(void)
+{
+ qlock(&xlk);
+}
+
+void
+xunlock(void)
+{
+ qunlock(&xlk);
+}
+
+void
+gfx_main(void)
+{
+ char *disp;
+ int i, n, xrootid;
+ XPixmapFormatValues *pfmt;
+ XScreen *xscreen;
+ XVisualInfo xvi;
+ XWindow xrootwin;
+
+ /*
+ if(XInitThreads() == 0)
+ sysfatal("XInitThread: %r");
+ */
+
+ /*
+ * Connect to X server.
+ */
+ _x.display = XOpenDisplay(NULL);
+ if(_x.display == nil){
+ disp = getenv("DISPLAY");
+ werrstr("XOpenDisplay %s: %r", disp ? disp : ":0");
+ free(disp);
+ sysfatal("%r");
+ }
+ _x.fd = ConnectionNumber(_x.display);
+ XSetErrorHandler(xerror);
+ XSetIOErrorHandler(xioerror);
+ xrootid = DefaultScreen(_x.display);
+ xrootwin = DefaultRootWindow(_x.display);
+
+ /*
+ * Figure out underlying screen format.
+ */
+ if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi)
+ || XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){
+ _x.vis = xvi.visual;
+ _x.depth = 24;
+ }
+ else
+ if(XMatchVisualInfo(_x.display, xrootid, 16, TrueColor, &xvi)
+ || XMatchVisualInfo(_x.display, xrootid, 16, DirectColor, &xvi)){
+ _x.vis = xvi.visual;
+ _x.depth = 16;
+ }
+ else
+ if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi)
+ || XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){
+ _x.vis = xvi.visual;
+ _x.depth = 15;
+ }
+ else
+ if(XMatchVisualInfo(_x.display, xrootid, 8, PseudoColor, &xvi)
+ || XMatchVisualInfo(_x.display, xrootid, 8, StaticColor, &xvi)){
+ if(_x.depth > 8){
+ werrstr("can't deal with colormapped depth %d screens",
+ _x.depth);
+ goto err0;
+ }
+ _x.vis = xvi.visual;
+ _x.depth = 8;
+ }
+ else{
+ _x.depth = DefaultDepth(_x.display, xrootid);
+ if(_x.depth != 8){
+ werrstr("can't understand depth %d screen", _x.depth);
+ goto err0;
+ }
+ _x.vis = DefaultVisual(_x.display, xrootid);
+ }
+
+ if(DefaultDepth(_x.display, xrootid) == _x.depth)
+ _x.usetable = 1;
+
+ /*
+ * _x.depth is only the number of significant pixel bits,
+ * not the total number of pixel bits. We need to walk the
+ * display list to find how many actual bits are used
+ * per pixel.
+ */
+ _x.chan = 0;
+ pfmt = XListPixmapFormats(_x.display, &n);
+ for(i=0; i<n; i++){
+ if(pfmt[i].depth == _x.depth){
+ switch(pfmt[i].bits_per_pixel){
+ case 1: /* untested */
+ _x.chan = GREY1;
+ break;
+ case 2: /* untested */
+ _x.chan = GREY2;
+ break;
+ case 4: /* untested */
+ _x.chan = GREY4;
+ break;
+ case 8:
+ _x.chan = CMAP8;
+ break;
+ case 15:
+ _x.chan = RGB15;
+ break;
+ case 16: /* how to tell RGB15? */
+ _x.chan = RGB16;
+ break;
+ case 24: /* untested (impossible?) */
+ _x.chan = RGB24;
+ break;
+ case 32:
+ _x.chan = XRGB32;
+ break;
+ }
+ }
+ }
+ XFree(pfmt);
+ if(_x.chan == 0){
+ werrstr("could not determine screen pixel format");
+ goto err0;
+ }
+
+ /*
+ * Set up color map if necessary.
+ */
+ xscreen = DefaultScreenOfDisplay(_x.display);
+ _x.cmap = DefaultColormapOfScreen(xscreen);
+ if(_x.vis->class != StaticColor){
+ plan9cmap();
+ setupcmap(xrootwin);
+ }
+ gfx_started();
+ xloop();
+
+err0:
+ XCloseDisplay(_x.display);
+ sysfatal("%r");
+}
+
+static void
+xloop(void)
+{
+ fd_set rd, wr, xx;
+ XEvent event;
+
+ xlock();
+ _x.fd = ConnectionNumber(_x.display);
+ for(;;) {
+ FD_ZERO(&rd);
+ FD_ZERO(&wr);
+ FD_ZERO(&xx);
+ FD_SET(_x.fd, &rd);
+ FD_SET(_x.fd, &xx);
+ if(_x.windows != nil)
+ XSelectInput(_x.display, _x.windows->drawable, Mask); // TODO: when is this needed?
+ XFlush(_x.display);
+ xunlock();
+
+ again:
+ if(select(_x.fd+1, &rd, &wr, &xx, nil) < 0) {
+ if(errno == EINTR)
+ goto again;
+ sysfatal("select: %r"); // TODO: quiet exit?
+ }
+
+ xlock();
+ while(XPending(_x.display)) {
+ XNextEvent(_x.display, &event);
+ runxevent(&event);
+ }
+ }
+}
+
+/*
+ * Handle an incoming X event.
+ */
+static void
+runxevent(XEvent *xev)
+{
+ int c;
+ KeySym k;
+ static Mouse m;
+ XButtonEvent *be;
+ XKeyEvent *ke;
+ Xwin *w;
+
+#ifdef SHOWEVENT
+ static int first = 1;
+ if(first){
+ dup(create("/tmp/devdraw.out", OWRITE, 0666), 1);
+ setbuf(stdout, 0);
+ first = 0;
+ }
+#endif
+
+ if(xev == 0)
+ return;
+
+#ifdef SHOWEVENT
+ print("\n");
+ ShowEvent(xev);
+#endif
+
+ w = nil;
+ switch(xev->type){
+ case Expose:
+ w = findxwin(((XExposeEvent*)xev)->window);
+ break;
+ case DestroyNotify:
+ w = findxwin(((XDestroyWindowEvent*)xev)->window);
+ break;
+ case ConfigureNotify:
+ w = findxwin(((XConfigureEvent*)xev)->window);
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ w = findxwin(((XButtonEvent*)xev)->window);
+ break;
+ case MotionNotify:
+ w = findxwin(((XMotionEvent*)xev)->window);
+ break;
+ case KeyRelease:
+ case KeyPress:
+ w = findxwin(((XKeyEvent*)xev)->window);
+ break;
+ case FocusOut:
+ w = findxwin(((XFocusChangeEvent*)xev)->window);
+ break;
+ }
+ if(w == nil)
+ w = _x.windows;
+
+ switch(xev->type){
+ case Expose:
+ _xexpose(w, xev);
+ break;
+
+ case DestroyNotify:
+ if(_xdestroy(w, xev))
+ threadexitsall(nil);
+ break;
+
+ case ConfigureNotify:
+ if(_xconfigure(w, xev))
+ _xreplacescreenimage(w->client);
+ break;
+
+ case ButtonPress:
+ be = (XButtonEvent*)xev;
+ if(be->button == 1) {
+ if(_x.kstate & ControlMask)
+ be->button = 2;
+ else if(_x.kstate & Mod1Mask)
+ be->button = 3;
+ }
+ // fall through
+ case ButtonRelease:
+ _x.altdown = 0;
+ // fall through
+ case MotionNotify:
+ if(_xtoplan9mouse(w, xev, &m) < 0)
+ return;
+ gfx_mousetrack(w->client, m.xy.x, m.xy.y, m.buttons|_x.kbuttons, m.msec);
+ break;
+
+ case KeyRelease:
+ case KeyPress:
+ ke = (XKeyEvent*)xev;
+ XLookupString(ke, NULL, 0, &k, NULL);
+ c = ke->state;
+ switch(k) {
+ case XK_Alt_L:
+ case XK_Meta_L: /* Shift Alt on PCs */
+ case XK_Alt_R:
+ case XK_Meta_R: /* Shift Alt on PCs */
+ case XK_Multi_key:
+ if(xev->type == KeyPress)
+ _x.altdown = 1;
+ else if(_x.altdown) {
+ _x.altdown = 0;
+ gfx_keystroke(w->client, Kalt);
+ }
+ break;
+ }
+
+ switch(k) {
+ case XK_Control_L:
+ if(xev->type == KeyPress)
+ c |= ControlMask;
+ else
+ c &= ~ControlMask;
+ goto kbutton;
+ case XK_Alt_L:
+ case XK_Shift_L:
+ if(xev->type == KeyPress)
+ c |= Mod1Mask;
+ else
+ c &= ~Mod1Mask;
+ kbutton:
+ _x.kstate = c;
+ if(m.buttons || _x.kbuttons) {
+ _x.altdown = 0; // used alt
+ _x.kbuttons = 0;
+ if(c & ControlMask)
+ _x.kbuttons |= 2;
+ if(c & Mod1Mask)
+ _x.kbuttons |= 4;
+ gfx_mousetrack(w->client, m.xy.x, m.xy.y, m.buttons|_x.kbuttons, m.msec);
+ break;
+ }
+ }
+
+ if(xev->type != KeyPress)
+ break;
+ if(k == XK_F11){
+ w->fullscreen = !w->fullscreen;
+ _xmovewindow(w, w->fullscreen ? w->screenrect : w->windowrect);
+ return;
+ }
+ if((c = _xtoplan9kbd(xev)) < 0)
+ return;
+ gfx_keystroke(w->client, c);
+ break;
+
+ case FocusOut:
+ /*
+ * Some key combinations (e.g. Alt-Tab) can cause us
+ * to see the key down event without the key up event,
+ * so clear out the keyboard state when we lose the focus.
+ */
+ _x.kstate = 0;
+ _x.altdown = 0;
+ gfx_abortcompose(w->client);
+ break;
+
+ case SelectionRequest:
+ _xselect(xev);
+ break;
+ }
+}
+
+
+static Memimage*
+xattach(Client *client, char *label, char *winsize)
+{
+ char *argv[2];
+ int havemin, height, mask, width, x, y;
+ Rectangle r;
+ XClassHint classhint;
+ XDrawable pmid;
+ XScreen *xscreen;
+ XSetWindowAttributes attr;
+ XSizeHints normalhint;
+ XTextProperty name;
+ XWindow xrootwin;
+ XWindowAttributes wattr;
+ XWMHints hint;
+ Atom atoms[2];
+ Xwin *w;
+
+ USED(client);
+ xscreen = DefaultScreenOfDisplay(_x.display);
+ xrootwin = DefaultRootWindow(_x.display);
+
+ /*
+ * We get to choose the initial rectangle size.
+ * This is arbitrary. In theory we should read the
+ * command line and allow the traditional X options.
+ */
+ mask = 0;
+ x = 0;
+ y = 0;
+ if(winsize && winsize[0]){
+ if(parsewinsize(winsize, &r, &havemin) < 0)
+ sysfatal("%r");
+ }else{
+ /*
+ * Parse the various X resources. Thanks to Peter Canning.
+ */
+ char *screen_resources, *display_resources, *geom,
+ *geomrestype, *home, *file, *dpitype;
+ XrmDatabase database;
+ XrmValue geomres, dpires;
+
+ database = XrmGetDatabase(_x.display);
+ screen_resources = XScreenResourceString(xscreen);
+ if(screen_resources != nil){
+ XrmCombineDatabase(XrmGetStringDatabase(screen_resources), &database, False);
+ XFree(screen_resources);
+ }
+
+ display_resources = XResourceManagerString(_x.display);
+ if(display_resources == nil){
+ home = getenv("HOME");
+ if(home!=nil && (file=smprint("%s/.Xdefaults", home)) != nil){
+ XrmCombineFileDatabase(file, &database, False);
+ free(file);
+ }
+ free(home);
+ }else
+ XrmCombineDatabase(XrmGetStringDatabase(display_resources), &database, False);
+
+ if (XrmGetResource(database, "Xft.dpi", "String", &dpitype, &dpires) == True) {
+ if (dpires.addr) {
+ client->displaydpi = atoi(dpires.addr);
+ }
+ }
+ geom = smprint("%s.geometry", label);
+ if(geom && XrmGetResource(database, geom, nil, &geomrestype, &geomres))
+ mask = XParseGeometry(geomres.addr, &x, &y, (uint*)&width, (uint*)&height);
+ XrmDestroyDatabase(database);
+ free(geom);
+
+ if((mask & WidthValue) && (mask & HeightValue)){
+ r = Rect(0, 0, width, height);
+ }else{
+ r = Rect(0, 0, WidthOfScreen(xscreen)*3/4,
+ HeightOfScreen(xscreen)*3/4);
+ if(Dx(r) > Dy(r)*3/2)
+ r.max.x = r.min.x + Dy(r)*3/2;
+ if(Dy(r) > Dx(r)*3/2)
+ r.max.y = r.min.y + Dx(r)*3/2;
+ }
+ if(mask & XNegative){
+ x += WidthOfScreen(xscreen);
+ }
+ if(mask & YNegative){
+ y += HeightOfScreen(xscreen);
+ }
+ havemin = 0;
+ }
+ w = newxwin(client);
+ w->screenrect = Rect(0, 0, WidthOfScreen(xscreen), HeightOfScreen(xscreen));
+ w->windowrect = r;
+
+ memset(&attr, 0, sizeof attr);
+ attr.colormap = _x.cmap;
+ attr.background_pixel = ~0;
+ attr.border_pixel = 0;
+ w->drawable = XCreateWindow(
+ _x.display, /* display */
+ xrootwin, /* parent */
+ x, /* x */
+ y, /* y */
+ Dx(r), /* width */
+ Dy(r), /* height */
+ 0, /* border width */
+ _x.depth, /* depth */
+ InputOutput, /* class */
+ _x.vis, /* visual */
+ /* valuemask */
+ CWBackPixel|CWBorderPixel|CWColormap,
+ &attr /* attributes (the above aren't?!) */
+ );
+
+ /*
+ * Label and other properties required by ICCCCM.
+ */
+ memset(&name, 0, sizeof name);
+ if(label == nil)
+ label = "pjw-face-here";
+ name.value = (uchar*)label;
+ name.encoding = XA_STRING;
+ name.format = 8;
+ name.nitems = strlen((char*)name.value);
+
+ memset(&normalhint, 0, sizeof normalhint);
+ normalhint.flags = PSize|PMaxSize;
+ if(winsize && winsize[0]){
+ normalhint.flags &= ~PSize;
+ normalhint.flags |= USSize;
+ normalhint.width = Dx(r);
+ normalhint.height = Dy(r);
+ }else{
+ if((mask & WidthValue) && (mask & HeightValue)){
+ normalhint.flags &= ~PSize;
+ normalhint.flags |= USSize;
+ normalhint.width = width;
+ normalhint.height = height;
+ }
+ if((mask & WidthValue) && (mask & HeightValue)){
+ normalhint.flags |= USPosition;
+ normalhint.x = x;
+ normalhint.y = y;
+ }
+ }
+
+ normalhint.max_width = WidthOfScreen(xscreen);
+ normalhint.max_height = HeightOfScreen(xscreen);
+
+ memset(&hint, 0, sizeof hint);
+ hint.flags = InputHint|StateHint;
+ hint.input = 1;
+ hint.initial_state = NormalState;
+
+ memset(&classhint, 0, sizeof classhint);
+ classhint.res_name = label;
+ classhint.res_class = label;
+
+ argv[0] = label;
+ argv[1] = nil;
+
+ XSetWMProperties(
+ _x.display, /* display */
+ w->drawable, /* window */
+ &name, /* XA_WM_NAME property */
+ &name, /* XA_WM_ICON_NAME property */
+ argv, /* XA_WM_COMMAND */
+ 1, /* argc */
+ &normalhint, /* XA_WM_NORMAL_HINTS */
+ &hint, /* XA_WM_HINTS */
+ &classhint /* XA_WM_CLASSHINTS */
+ );
+ XFlush(_x.display);
+
+ if(havemin){
+ XWindowChanges ch;
+
+ memset(&ch, 0, sizeof ch);
+ ch.x = r.min.x;
+ ch.y = r.min.y;
+ XConfigureWindow(_x.display, w->drawable, CWX|CWY, &ch);
+ /*
+ * Must pretend origin is 0,0 for X.
+ */
+ r = Rect(0,0,Dx(r),Dy(r));
+ }
+ /*
+ * Look up clipboard atom.
+ */
+ if(_x.clipboard == 0) {
+ _x.clipboard = XInternAtom(_x.display, "CLIPBOARD", False);
+ _x.utf8string = XInternAtom(_x.display, "UTF8_STRING", False);
+ _x.targets = XInternAtom(_x.display, "TARGETS", False);
+ _x.text = XInternAtom(_x.display, "TEXT", False);
+ _x.compoundtext = XInternAtom(_x.display, "COMPOUND_TEXT", False);
+ _x.takefocus = XInternAtom(_x.display, "WM_TAKE_FOCUS", False);
+ _x.losefocus = XInternAtom(_x.display, "_9WM_LOSE_FOCUS", False);
+ _x.wmprotos = XInternAtom(_x.display, "WM_PROTOCOLS", False);
+ }
+
+ atoms[0] = _x.takefocus;
+ atoms[1] = _x.losefocus;
+ XChangeProperty(_x.display, w->drawable, _x.wmprotos, XA_ATOM, 32,
+ PropModeReplace, (uchar*)atoms, 2);
+
+ /*
+ * Put the window on the screen, check to see what size we actually got.
+ */
+ XMapWindow(_x.display, w->drawable);
+ XSync(_x.display, False);
+
+ if(!XGetWindowAttributes(_x.display, w->drawable, &wattr))
+ fprint(2, "XGetWindowAttributes failed\n");
+ else if(wattr.width && wattr.height){
+ if(wattr.width != Dx(r) || wattr.height != Dy(r)){
+ r.max.x = wattr.width;
+ r.max.y = wattr.height;
+ }
+ }else
+ fprint(2, "XGetWindowAttributes: bad attrs\n");
+
+ /*
+ * Allocate our local backing store.
+ */
+ w->screenr = r;
+ w->screenpm = XCreatePixmap(_x.display, w->drawable, Dx(r), Dy(r), _x.depth);
+ w->nextscreenpm = w->screenpm;
+ w->screenimage = _xallocmemimage(r, _x.chan, w->screenpm);
+ client->mouserect = r;
+
+ /*
+ * Allocate some useful graphics contexts for the future.
+ * These can be used with any drawable matching w->drawable's
+ * pixel format (which is all the drawables we create).
+ */
+ if(_x.gcfill == 0) {
+ _x.gcfill = xgc(w->screenpm, FillSolid, -1);
+ _x.gccopy = xgc(w->screenpm, -1, -1);
+ _x.gcsimplesrc = xgc(w->screenpm, FillStippled, -1);
+ _x.gczero = xgc(w->screenpm, -1, -1);
+ _x.gcreplsrc = xgc(w->screenpm, FillTiled, -1);
+
+ pmid = XCreatePixmap(_x.display, w->drawable, 1, 1, 1);
+ _x.gcfill0 = xgc(pmid, FillSolid, 0);
+ _x.gccopy0 = xgc(pmid, -1, -1);
+ _x.gcsimplesrc0 = xgc(pmid, FillStippled, -1);
+ _x.gczero0 = xgc(pmid, -1, -1);
+ _x.gcreplsrc0 = xgc(pmid, FillTiled, -1);
+ XFreePixmap(_x.display, pmid);
+ }
+
+ return w->screenimage;
+}
+
+Memimage*
+rpc_attach(Client *client, char *label, char *winsize)
+{
+ Memimage *m;
+
+ xlock();
+ m = xattach(client, label, winsize);
+ xunlock();
+ return m;
+}
+
+void
+rpc_setlabel(Client *client, char *label)
+{
+ Xwin *w = (Xwin*)client->view;
+ XTextProperty name;
+
+ /*
+ * Label and other properties required by ICCCCM.
+ */
+ xlock();
+ memset(&name, 0, sizeof name);
+ if(label == nil)
+ label = "pjw-face-here";
+ name.value = (uchar*)label;
+ name.encoding = XA_STRING;
+ name.format = 8;
+ name.nitems = strlen((char*)name.value);
+
+ XSetWMProperties(
+ _x.display, /* display */
+ w->drawable, /* window */
+ &name, /* XA_WM_NAME property */
+ &name, /* XA_WM_ICON_NAME property */
+ nil, /* XA_WM_COMMAND */
+ 0, /* argc */
+ nil, /* XA_WM_NORMAL_HINTS */
+ nil, /* XA_WM_HINTS */
+ nil /* XA_WM_CLASSHINTS */
+ );
+ XFlush(_x.display);
+ xunlock();
+}
+
+/*
+ * Create a GC with a particular fill style and XXX.
+ * Disable generation of GraphicsExpose/NoExpose events in the GC.
+ */
+static XGC
+xgc(XDrawable d, int fillstyle, int foreground)
+{
+ XGC gc;
+ XGCValues v;
+
+ memset(&v, 0, sizeof v);
+ v.function = GXcopy;
+ v.graphics_exposures = False;
+ gc = XCreateGC(_x.display, d, GCFunction|GCGraphicsExposures, &v);
+ if(fillstyle != -1)
+ XSetFillStyle(_x.display, gc, fillstyle);
+ if(foreground != -1)
+ XSetForeground(_x.display, gc, 0);
+ return gc;
+}
+
+
+/*
+ * Initialize map with the Plan 9 rgbv color map.
+ */
+static void
+plan9cmap(void)
+{
+ int r, g, b, cr, cg, cb, v, num, den, idx, v7, idx7;
+ static int once;
+
+ if(once)
+ return;
+ once = 1;
+
+ for(r=0; r!=4; r++)
+ for(g = 0; g != 4; g++)
+ for(b = 0; b!=4; b++)
+ for(v = 0; v!=4; v++){
+ den=r;
+ if(g > den)
+ den=g;
+ if(b > den)
+ den=b;
+ /* divide check -- pick grey shades */
+ if(den==0)
+ cr=cg=cb=v*17;
+ else {
+ num=17*(4*den+v);
+ cr=r*num/den;
+ cg=g*num/den;
+ cb=b*num/den;
+ }
+ idx = r*64 + v*16 + ((g*4 + b + v - r) & 15);
+ _x.map[idx].red = cr*0x0101;
+ _x.map[idx].green = cg*0x0101;
+ _x.map[idx].blue = cb*0x0101;
+ _x.map[idx].pixel = idx;
+ _x.map[idx].flags = DoRed|DoGreen|DoBlue;
+
+ v7 = v >> 1;
+ idx7 = r*32 + v7*16 + g*4 + b;
+ if((v & 1) == v7){
+ _x.map7to8[idx7][0] = idx;
+ if(den == 0) { /* divide check -- pick grey shades */
+ cr = ((255.0/7.0)*v7)+0.5;
+ cg = cr;
+ cb = cr;
+ }
+ else {
+ num=17*15*(4*den+v7*2)/14;
+ cr=r*num/den;
+ cg=g*num/den;
+ cb=b*num/den;
+ }
+ _x.map7[idx7].red = cr*0x0101;
+ _x.map7[idx7].green = cg*0x0101;
+ _x.map7[idx7].blue = cb*0x0101;
+ _x.map7[idx7].pixel = idx7;
+ _x.map7[idx7].flags = DoRed|DoGreen|DoBlue;
+ }
+ else
+ _x.map7to8[idx7][1] = idx;
+ }
+}
+
+/*
+ * Initialize and install the rgbv color map as a private color map
+ * for this application. It gets the best colors when it has the
+ * cursor focus.
+ *
+ * We always choose the best depth possible, but that might not
+ * be the default depth. On such "suboptimal" systems, we have to allocate an
+ * empty color map anyway, according to Axel Belinfante.
+ */
+static int
+setupcmap(XWindow w)
+{
+ char buf[30];
+ int i;
+ u32int p, pp;
+ XColor c;
+
+ if(_x.depth <= 1)
+ return 0;
+
+ if(_x.depth >= 24) {
+ if(_x.usetable == 0)
+ _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
+
+ /*
+ * The pixel value returned from XGetPixel needs to
+ * be converted to RGB so we can call rgb2cmap()
+ * to translate between 24 bit X and our color. Unfortunately,
+ * the return value appears to be display server endian
+ * dependant. Therefore, we run some heuristics to later
+ * determine how to mask the int value correctly.
+ * Yeah, I know we can look at _x.vis->byte_order but
+ * some displays say MSB even though they run on LSB.
+ * Besides, this is more anal.
+ */
+ c = _x.map[19]; /* known to have different R, G, B values */
+ if(!XAllocColor(_x.display, _x.cmap, &c)){
+ werrstr("XAllocColor: %r");
+ return -1;
+ }
+ p = c.pixel;
+ pp = rgb2cmap((p>>16)&0xff,(p>>8)&0xff,p&0xff);
+ if(pp != _x.map[19].pixel) {
+ /* check if endian is other way */
+ pp = rgb2cmap(p&0xff,(p>>8)&0xff,(p>>16)&0xff);
+ if(pp != _x.map[19].pixel){
+ werrstr("cannot detect X server byte order");
+ return -1;
+ }
+
+ switch(_x.chan){
+ case RGB24:
+ _x.chan = BGR24;
+ break;
+ case XRGB32:
+ _x.chan = XBGR32;
+ break;
+ default:
+ werrstr("cannot byteswap channel %s",
+ chantostr(buf, _x.chan));
+ break;
+ }
+ }
+ }else if(_x.vis->class == TrueColor || _x.vis->class == DirectColor){
+ /*
+ * Do nothing. We have no way to express a
+ * mixed-endian 16-bit screen, so pretend they don't exist.
+ */
+ if(_x.usetable == 0)
+ _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocNone);
+ }else if(_x.vis->class == PseudoColor){
+ if(_x.usetable == 0){
+ _x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocAll);
+ XStoreColors(_x.display, _x.cmap, _x.map, 256);
+ for(i = 0; i < 256; i++){
+ _x.tox11[i] = i;
+ _x.toplan9[i] = i;
+ }
+ }else{
+ for(i = 0; i < 128; i++){
+ c = _x.map7[i];
+ if(!XAllocColor(_x.display, _x.cmap, &c)){
+ werrstr("can't allocate colors in 7-bit map");
+ return -1;
+ }
+ _x.tox11[_x.map7to8[i][0]] = c.pixel;
+ _x.tox11[_x.map7to8[i][1]] = c.pixel;
+ _x.toplan9[c.pixel] = _x.map7to8[i][0];
+ }
+ }
+ }else{
+ werrstr("unsupported visual class %d", _x.vis->class);
+ return -1;
+ }
+ return 0;
+}
+
+void
+rpc_shutdown(void)
+{
+}
+
+void
+rpc_flush(Client *client, Rectangle r)
+{
+ Xwin *w = (Xwin*)client->view;
+
+ xlock();
+ if(w->nextscreenpm != w->screenpm){
+ XSync(_x.display, False);
+ XFreePixmap(_x.display, w->screenpm);
+ w->screenpm = w->nextscreenpm;
+ }
+
+ if(r.min.x >= r.max.x || r.min.y >= r.max.y) {
+ xunlock();
+ return;
+ }
+
+ XCopyArea(_x.display, w->screenpm, w->drawable, _x.gccopy, r.min.x, r.min.y,
+ Dx(r), Dy(r), r.min.x, r.min.y);
+ XFlush(_x.display);
+ xunlock();
+}
+
+static void
+_xexpose(Xwin *w, XEvent *e)
+{
+ XExposeEvent *xe;
+ Rectangle r;
+
+ if(w->screenpm != w->nextscreenpm)
+ return;
+ xe = (XExposeEvent*)e;
+ r.min.x = xe->x;
+ r.min.y = xe->y;
+ r.max.x = xe->x+xe->width;
+ r.max.y = xe->y+xe->height;
+ XCopyArea(_x.display, w->screenpm, w->drawable, _x.gccopy, r.min.x, r.min.y,
+ Dx(r), Dy(r), r.min.x, r.min.y);
+ XSync(_x.display, False);
+}
+
+static int
+_xdestroy(Xwin *w, XEvent *e)
+{
+ XDestroyWindowEvent *xe;
+
+ xe = (XDestroyWindowEvent*)e;
+ if(xe->window == w->drawable){
+ w->destroyed = 1;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+_xconfigure(Xwin *w, XEvent *e)
+{
+ Rectangle r;
+ XConfigureEvent *xe = (XConfigureEvent*)e;
+
+ if(!w->fullscreen){
+ int rx, ry;
+ XWindow xw;
+ if(XTranslateCoordinates(_x.display, w->drawable, DefaultRootWindow(_x.display), 0, 0, &rx, &ry, &xw))
+ w->windowrect = Rect(rx, ry, rx+xe->width, ry+xe->height);
+ }
+
+ if(xe->width == Dx(w->screenr) && xe->height == Dy(w->screenr))
+ return 0;
+ r = Rect(0, 0, xe->width, xe->height);
+
+ if(w->screenpm != w->nextscreenpm){
+ XCopyArea(_x.display, w->screenpm, w->drawable, _x.gccopy, r.min.x, r.min.y,
+ Dx(r), Dy(r), r.min.x, r.min.y);
+ XSync(_x.display, False);
+ }
+ w->newscreenr = r;
+ return 1;
+}
+
+static int
+_xreplacescreenimage(Client *client)
+{
+ Memimage *m;
+ XDrawable pixmap;
+ Rectangle r;
+ Xwin *w;
+
+ w = (Xwin*)client->view;
+ r = w->newscreenr;
+ pixmap = XCreatePixmap(_x.display, w->drawable, Dx(r), Dy(r), _x.depth);
+ m = _xallocmemimage(r, _x.chan, pixmap);
+ if(w->nextscreenpm != w->screenpm)
+ XFreePixmap(_x.display, w->nextscreenpm);
+ w->nextscreenpm = pixmap;
+ w->screenr = r;
+ client->mouserect = r;
+ gfx_replacescreenimage(client, m);
+ return 1;
+}
+
+void
+rpc_resizeimg(Client *client)
+{
+ xlock();
+ _xreplacescreenimage(client);
+ xunlock();
+}
+
+void
+rpc_gfxdrawlock(void)
+{
+ xlock();
+}
+
+void
+rpc_gfxdrawunlock(void)
+{
+ xunlock();
+}
+void
+rpc_topwin(Client *client)
+{
+ Xwin *w = (Xwin*)client->view;
+
+ xlock();
+ XMapRaised(_x.display, w->drawable);
+ XSetInputFocus(_x.display, w->drawable, RevertToPointerRoot,
+ CurrentTime);
+ XFlush(_x.display);
+ xunlock();
+}
+
+void
+rpc_resizewindow(Client *client, Rectangle r)
+{
+ Xwin *w = (Xwin*)client->view;
+ XWindowChanges e;
+ int value_mask;
+
+ xlock();
+ memset(&e, 0, sizeof e);
+ value_mask = CWX|CWY|CWWidth|CWHeight;
+ e.width = Dx(r);
+ e.height = Dy(r);
+ XConfigureWindow(_x.display, w->drawable, value_mask, &e);
+ XFlush(_x.display);
+ xunlock();
+}
+
+static void
+_xmovewindow(Xwin *w, Rectangle r)
+{
+ XWindowChanges e;
+ int value_mask;
+
+ memset(&e, 0, sizeof e);
+ value_mask = CWX|CWY|CWWidth|CWHeight;
+ e.x = r.min.x;
+ e.y = r.min.y;
+ e.width = Dx(r);
+ e.height = Dy(r);
+ XConfigureWindow(_x.display, w->drawable, value_mask, &e);
+ XFlush(_x.display);
+}
+
+static int
+_xtoplan9kbd(XEvent *e)
+{
+ KeySym k;
+
+ if(e->xany.type != KeyPress)
+ return -1;
+ needstack(64*1024); /* X has some *huge* buffers in openobject */
+ /* and they're even bigger on SuSE */
+ XLookupString((XKeyEvent*)e,NULL,0,&k,NULL);
+ if(k == NoSymbol)
+ return -1;
+
+ if(k&0xFF00){
+ switch(k){
+ case XK_BackSpace:
+ case XK_Tab:
+ case XK_Escape:
+ case XK_Delete:
+ case XK_KP_0:
+ case XK_KP_1:
+ case XK_KP_2:
+ case XK_KP_3:
+ case XK_KP_4:
+ case XK_KP_5:
+ case XK_KP_6:
+ case XK_KP_7:
+ case XK_KP_8:
+ case XK_KP_9:
+ case XK_KP_Divide:
+ case XK_KP_Multiply:
+ case XK_KP_Subtract:
+ case XK_KP_Add:
+ case XK_KP_Decimal:
+ k &= 0x7F;
+ break;
+ case XK_Linefeed:
+ k = '\r';
+ break;
+ case XK_KP_Space:
+ k = ' ';
+ break;
+ case XK_Home:
+ case XK_KP_Home:
+ k = Khome;
+ break;
+ case XK_Left:
+ case XK_KP_Left:
+ k = Kleft;
+ break;
+ case XK_Up:
+ case XK_KP_Up:
+ k = Kup;
+ break;
+ case XK_Down:
+ case XK_KP_Down:
+ k = Kdown;
+ break;
+ case XK_Right:
+ case XK_KP_Right:
+ k = Kright;
+ break;
+ case XK_Page_Down:
+ case XK_KP_Page_Down:
+ k = Kpgdown;
+ break;
+ case XK_End:
+ case XK_KP_End:
+ k = Kend;
+ break;
+ case XK_Page_Up:
+ case XK_KP_Page_Up:
+ k = Kpgup;
+ break;
+ case XK_Insert:
+ case XK_KP_Insert:
+ k = Kins;
+ break;
+ case XK_KP_Enter:
+ case XK_Return:
+ k = '\n';
+ break;
+ case XK_Alt_L:
+ case XK_Meta_L: /* Shift Alt on PCs */
+ case XK_Alt_R:
+ case XK_Meta_R: /* Shift Alt on PCs */
+ case XK_Multi_key:
+ return -1;
+ default: /* not ISO-1 or tty control */
+ if(k>0xff) {
+ k = _p9keysym2ucs(k);
+ if(k==-1) return -1;
+ }
+ }
+ }
+
+ /* Compensate for servers that call a minus a hyphen */
+ if(k == XK_hyphen)
+ k = XK_minus;
+ /* Do control mapping ourselves if translator doesn't */
+ if(e->xkey.state&ControlMask)
+ k &= 0x9f;
+ if(k == NoSymbol) {
+ return -1;
+ }
+
+ return k+0;
+}
+
+static int
+_xtoplan9mouse(Xwin *w, XEvent *e, Mouse *m)
+{
+ int s;
+ XButtonEvent *be;
+ XMotionEvent *me;
+
+ if(_x.putsnarf != _x.assertsnarf){
+ _x.assertsnarf = _x.putsnarf;
+ XSetSelectionOwner(_x.display, XA_PRIMARY, w->drawable, CurrentTime);
+ if(_x.clipboard != None)
+ XSetSelectionOwner(_x.display, _x.clipboard, w->drawable, CurrentTime);
+ XFlush(_x.display);
+ }
+
+ switch(e->type){
+ case ButtonPress:
+ be = (XButtonEvent*)e;
+
+ /*
+ * Fake message, just sent to make us announce snarf.
+ * Apparently state and button are 16 and 8 bits on
+ * the wire, since they are truncated by the time they
+ * get to us.
+ */
+ if(be->send_event
+ && (~be->state&0xFFFF)==0
+ && (~be->button&0xFF)==0)
+ return -1;
+ /* BUG? on mac need to inherit these from elsewhere? */
+ m->xy.x = be->x;
+ m->xy.y = be->y;
+ s = be->state;
+ m->msec = be->time;
+ switch(be->button){
+ case 1:
+ s |= Button1Mask;
+ break;
+ case 2:
+ s |= Button2Mask;
+ break;
+ case 3:
+ s |= Button3Mask;
+ break;
+ case 4:
+ s |= Button4Mask;
+ break;
+ case 5:
+ s |= Button5Mask;
+ break;
+ }
+ break;
+ case ButtonRelease:
+ be = (XButtonEvent*)e;
+ m->xy.x = be->x;
+ m->xy.y = be->y;
+ s = be->state;
+ m->msec = be->time;
+ switch(be->button){
+ case 1:
+ s &= ~Button1Mask;
+ break;
+ case 2:
+ s &= ~Button2Mask;
+ break;
+ case 3:
+ s &= ~Button3Mask;
+ break;
+ case 4:
+ s &= ~Button4Mask;
+ break;
+ case 5:
+ s &= ~Button5Mask;
+ break;
+ }
+ break;
+
+ case MotionNotify:
+ me = (XMotionEvent*)e;
+ s = me->state;
+ m->xy.x = me->x;
+ m->xy.y = me->y;
+ m->msec = me->time;
+ return 0; // do not set buttons
+
+ default:
+ return -1;
+ }
+
+ m->buttons = 0;
+ if(s & Button1Mask)
+ m->buttons |= 1;
+ if(s & Button2Mask)
+ m->buttons |= 2;
+ if(s & Button3Mask)
+ m->buttons |= 4;
+ if(s & Button4Mask)
+ m->buttons |= 8;
+ if(s & Button5Mask)
+ m->buttons |= 16;
+ return 0;
+}
+
+void
+rpc_setmouse(Client *client, Point p)
+{
+ Xwin *w = (Xwin*)client->view;
+
+ xlock();
+ XWarpPointer(_x.display, None, w->drawable, 0, 0, 0, 0, p.x, p.y);
+ XFlush(_x.display);
+ xunlock();
+}
+
+static int
+revbyte(int b)
+{
+ int r;
+
+ r = 0;
+ r |= (b&0x01) << 7;
+ r |= (b&0x02) << 5;
+ r |= (b&0x04) << 3;
+ r |= (b&0x08) << 1;
+ r |= (b&0x10) >> 1;
+ r |= (b&0x20) >> 3;
+ r |= (b&0x40) >> 5;
+ r |= (b&0x80) >> 7;
+ return r;
+}
+
+static void
+xcursorarrow(Xwin *w)
+{
+ if(_x.cursor != 0){
+ XFreeCursor(_x.display, _x.cursor);
+ _x.cursor = 0;
+ }
+ XUndefineCursor(_x.display, w->drawable);
+ XFlush(_x.display);
+}
+
+
+void
+rpc_setcursor(Client *client, Cursor *c, Cursor2 *c2)
+{
+ Xwin *w = (Xwin*)client->view;
+ XColor fg, bg;
+ XCursor xc;
+ Pixmap xsrc, xmask;
+ int i;
+ uchar src[2*16], mask[2*16];
+
+ USED(c2);
+
+ xlock();
+ if(c == nil){
+ xcursorarrow(w);
+ xunlock();
+ return;
+ }
+ for(i=0; i<2*16; i++){
+ src[i] = revbyte(c->set[i]);
+ mask[i] = revbyte(c->set[i] | c->clr[i]);
+ }
+
+ fg = _x.map[0];
+ bg = _x.map[255];
+ xsrc = XCreateBitmapFromData(_x.display, w->drawable, (char*)src, 16, 16);
+ xmask = XCreateBitmapFromData(_x.display, w->drawable, (char*)mask, 16, 16);
+ xc = XCreatePixmapCursor(_x.display, xsrc, xmask, &fg, &bg, -c->offset.x, -c->offset.y);
+ if(xc != 0) {
+ XDefineCursor(_x.display, w->drawable, xc);
+ if(_x.cursor != 0)
+ XFreeCursor(_x.display, _x.cursor);
+ _x.cursor = xc;
+ }
+ XFreePixmap(_x.display, xsrc);
+ XFreePixmap(_x.display, xmask);
+ XFlush(_x.display);
+ xunlock();
+}
+
+struct {
+ QLock lk;
+ char buf[SnarfSize];
+#ifdef APPLESNARF
+ Rune rbuf[SnarfSize];
+ PasteboardRef apple;
+#endif
+} clip;
+
+static uchar*
+_xgetsnarffrom(Xwin *w, XWindow xw, Atom clipboard, Atom target, int timeout0, int timeout)
+{
+ Atom prop, type;
+ ulong len, lastlen, dummy;
+ int fmt, i;
+ uchar *data, *xdata;
+
+ /*
+ * We should be waiting for SelectionNotify here, but it might never
+ * come, and we have no way to time out. Instead, we will clear
+ * local property #1, request our buddy to fill it in for us, and poll
+ * until he's done or we get tired of waiting.
+ */
+ prop = 1;
+ XChangeProperty(_x.display, w->drawable, prop, target, 8, PropModeReplace, (uchar*)"", 0);
+ XConvertSelection(_x.display, clipboard, target, prop, w->drawable, CurrentTime);
+ XFlush(_x.display);
+ lastlen = 0;
+ timeout0 = (timeout0 + 9)/10;
+ timeout = (timeout + 9)/10;
+ for(i=0; i<timeout0 || (lastlen!=0 && i<timeout); i++){
+ usleep(10*1000);
+ XGetWindowProperty(_x.display, w->drawable, prop, 0, 0, 0, AnyPropertyType,
+ &type, &fmt, &dummy, &len, &xdata);
+ if(lastlen == len && len > 0){
+ XFree(xdata);
+ break;
+ }
+ lastlen = len;
+ XFree(xdata);
+ }
+ if(len == 0)
+ return nil;
+
+ /* get the property */
+ xdata = nil;
+ XGetWindowProperty(_x.display, w->drawable, prop, 0, SnarfSize/sizeof(ulong), 0,
+ AnyPropertyType, &type, &fmt, &len, &dummy, &xdata);
+ if((type != target && type != XA_STRING && type != _x.utf8string) || len == 0){
+ if(xdata)
+ XFree(xdata);
+ return nil;
+ }
+ if(xdata){
+ data = (uchar*)strdup((char*)xdata);
+ XFree(xdata);
+ return data;
+ }
+ return nil;
+}
+
+char*
+rpc_getsnarf(void)
+{
+ uchar *data;
+ Atom clipboard;
+ XWindow xw;
+ Xwin *w;
+
+ qlock(&clip.lk);
+ xlock();
+ w = _x.windows;
+ /*
+ * Have we snarfed recently and the X server hasn't caught up?
+ */
+ if(_x.putsnarf != _x.assertsnarf)
+ goto mine;
+
+ /*
+ * Is there a primary selection (highlighted text in an xterm)?
+ */
+ clipboard = XA_PRIMARY;
+ xw = XGetSelectionOwner(_x.display, XA_PRIMARY);
+ // TODO check more
+ if(xw == w->drawable){
+ mine:
+ data = (uchar*)strdup(clip.buf);
+ goto out;
+ }
+
+ /*
+ * If not, is there a clipboard selection?
+ */
+ if(xw == None && _x.clipboard != None){
+ clipboard = _x.clipboard;
+ xw = XGetSelectionOwner(_x.display, _x.clipboard);
+ if(xw == w->drawable)
+ goto mine;
+ }
+
+ /*
+ * If not, give up.
+ */
+ if(xw == None){
+ data = nil;
+ goto out;
+ }
+
+ if((data = _xgetsnarffrom(w, xw, clipboard, _x.utf8string, 10, 100)) == nil)
+ if((data = _xgetsnarffrom(w, xw, clipboard, XA_STRING, 10, 100)) == nil){
+ /* nothing left to do */
+ }
+
+out:
+ xunlock();
+ qunlock(&clip.lk);
+ return (char*)data;
+}
+
+void
+__xputsnarf(char *data)
+{
+ XButtonEvent e;
+ Xwin *w;
+
+ if(strlen(data) >= SnarfSize)
+ return;
+ qlock(&clip.lk);
+ xlock();
+ w = _x.windows;
+ strcpy(clip.buf, data);
+ /* leave note for mouse proc to assert selection ownership */
+ _x.putsnarf++;
+
+ /* send mouse a fake event so snarf is announced */
+ memset(&e, 0, sizeof e);
+ e.type = ButtonPress;
+ e.window = w->drawable;
+ e.state = ~0;
+ e.button = ~0;
+ XSendEvent(_x.display, w->drawable, True, ButtonPressMask, (XEvent*)&e);
+ XFlush(_x.display);
+ xunlock();
+ qunlock(&clip.lk);
+}
+
+static int
+_xselect(XEvent *e)
+{
+ char *name;
+ XEvent r;
+ XSelectionRequestEvent *xe;
+ Atom a[4];
+
+ memset(&r, 0, sizeof r);
+ xe = (XSelectionRequestEvent*)e;
+if(0) fprint(2, "xselect target=%d requestor=%d property=%d selection=%d (sizeof atom=%d)\n",
+ xe->target, xe->requestor, xe->property, xe->selection, sizeof a[0]);
+ r.xselection.property = xe->property;
+ if(xe->target == _x.targets){
+ a[0] = _x.utf8string;
+ a[1] = XA_STRING;
+ a[2] = _x.text;
+ a[3] = _x.compoundtext;
+ XChangeProperty(_x.display, xe->requestor, xe->property, XA_ATOM,
+ 32, PropModeReplace, (uchar*)a, nelem(a));
+ }else if(xe->target == XA_STRING
+ || xe->target == _x.utf8string
+ || xe->target == _x.text
+ || xe->target == _x.compoundtext
+ || ((name = XGetAtomName(_x.display, xe->target)) && strcmp(name, "text/plain;charset=UTF-8") == 0)){
+ /* text/plain;charset=UTF-8 seems nonstandard but is used by Synergy */
+ /* if the target is STRING we're supposed to reply with Latin1 XXX */
+ qlock(&clip.lk);
+ XChangeProperty(_x.display, xe->requestor, xe->property, xe->target,
+ 8, PropModeReplace, (uchar*)clip.buf, strlen(clip.buf));
+ qunlock(&clip.lk);
+ }else{
+ if(strcmp(name, "TIMESTAMP") != 0)
+ fprint(2, "%s: cannot handle selection request for '%s' (%d)\n", argv0, name, (int)xe->target);
+ r.xselection.property = None;
+ }
+
+ r.xselection.display = xe->display;
+ /* r.xselection.property filled above */
+ r.xselection.target = xe->target;
+ r.xselection.type = SelectionNotify;
+ r.xselection.requestor = xe->requestor;
+ r.xselection.time = xe->time;
+ r.xselection.send_event = True;
+ r.xselection.selection = xe->selection;
+ XSendEvent(_x.display, xe->requestor, False, 0, &r);
+ XFlush(_x.display);
+ return 0;
+}
+
+#ifdef APPLESNARF
+char*
+_applegetsnarf(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);
+ 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
+_appleputsnarf(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);
+ if(clip.apple == nil){
+ if(PasteboardCreate(kPasteboardClipboard, &clip.apple) != noErr){
+ fprint(2, "apple pasteboard create failed\n");
+ qunlock(&clip.lk);
+ return;
+ }
+ }
+ 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);
+}
+#endif /* APPLESNARF */
+
+void
+rpc_putsnarf(char *data)
+{
+#ifdef APPLESNARF
+ _appleputsnarf(data);
+#endif
+ __xputsnarf(data);
+}
+
+/*
+ * Send the mouse event back to the window manager.
+ * So that 9term can tell rio to pop up its button3 menu.
+ */
+void
+rpc_bouncemouse(Client *c, Mouse m)
+{
+ Xwin *w = (Xwin*)c->view;
+ XButtonEvent e;
+ XWindow dw;
+
+ xlock();
+ e.type = ButtonPress;
+ e.state = 0;
+ e.button = 0;
+ if(m.buttons&1)
+ e.button = 1;
+ else if(m.buttons&2)
+ e.button = 2;
+ else if(m.buttons&4)
+ e.button = 3;
+ e.same_screen = 1;
+ XTranslateCoordinates(_x.display, w->drawable,
+ DefaultRootWindow(_x.display),
+ m.xy.x, m.xy.y, &e.x_root, &e.y_root, &dw);
+ e.root = DefaultRootWindow(_x.display);
+ e.window = e.root;
+ e.subwindow = None;
+ e.x = e.x_root;
+ e.y = e.y_root;
+#undef time
+ e.time = CurrentTime;
+ XUngrabPointer(_x.display, m.msec);
+ XSendEvent(_x.display, e.root, True, ButtonPressMask, (XEvent*)&e);
+ XFlush(_x.display);
+ xunlock();
+}
diff --git a/src/cmd/devdraw/x11-srv.c b/src/cmd/devdraw/x11-srv.c
deleted file mode 100644
index 81416482..00000000
--- a/src/cmd/devdraw/x11-srv.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/*
- * Window system protocol server.
- * Use select and a single proc and single stack
- * to avoid aggravating the X11 library, which is
- * subtle and quick to anger.
- */
-
-// #define SHOWEVENT
-
-#include <u.h>
-#include <sys/select.h>
-#include <errno.h>
-#ifdef SHOWEVENT
-#include <stdio.h>
-#endif
-#include "x11-inc.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 "x11-memdraw.h"
-#include "devdraw.h"
-
-#undef time
-
-#define MouseMask (\
- ButtonPressMask|\
- ButtonReleaseMask|\
- PointerMotionMask|\
- Button1MotionMask|\
- Button2MotionMask|\
- Button3MotionMask)
-
-#define Mask MouseMask|ExposureMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask|EnterWindowMask|LeaveWindowMask|FocusChangeMask
-
-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];
- int ri;
- int wi;
- int stall;
- int resized;
-};
-
-struct Tagbuf
-{
- int t[32];
- int ri;
- int wi;
-};
-
-struct Fdbuf
-{
- uchar buf[2*MAXWMSG];
- uchar *rp;
- uchar *wp;
- uchar *ep;
-};
-
-Kbdbuf kbd;
-Mousebuf mouse;
-Fdbuf fdin;
-Fdbuf fdout;
-Tagbuf kbdtags;
-Tagbuf mousetags;
-
-void fdslide(Fdbuf*);
-void runmsg(Wsysmsg*);
-void replymsg(Wsysmsg*);
-void runxevent(XEvent*);
-void matchkbd(void);
-void matchmouse(void);
-int fdnoblock(int);
-
-int chatty;
-int drawsleep;
-int fullscreen;
-
-Rectangle windowrect;
-Rectangle screenrect;
-
-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);
-}
-
-void
-main(int argc, char **argv)
-{
- int n, top, firstx;
- fd_set rd, wr, xx;
- Wsysmsg m;
- XEvent event;
-
- /*
- * 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);
-
- /* reopens stdout if debugging */
- runxevent(0);
-
- fmtinstall('W', drawfcallfmt);
-
- ARGBEGIN{
- case 'D':
- chatty++;
- break;
- default:
- usage();
- }ARGEND
-
- /*
- * Ignore arguments. They're only for good ps -a listings.
- */
-
- notify(bell);
-
- fdin.rp = fdin.wp = fdin.buf;
- fdin.ep = fdin.buf+sizeof fdin.buf;
-
- fdout.rp = fdout.wp = fdout.buf;
- fdout.ep = fdout.buf+sizeof fdout.buf;
-
- fdnoblock(3);
- fdnoblock(4);
-
- firstx = 1;
- _x.fd = -1;
- for(;;){
- /* set up file descriptors */
- FD_ZERO(&rd);
- FD_ZERO(&wr);
- FD_ZERO(&xx);
- /*
- * Don't read unless there's room *and* we haven't
- * already filled the output buffer too much.
- */
- if(fdout.wp < fdout.buf+MAXWMSG && fdin.wp < fdin.ep)
- FD_SET(3, &rd);
- if(fdout.wp > fdout.rp)
- FD_SET(4, &wr);
- FD_SET(3, &xx);
- FD_SET(4, &xx);
- top = 4;
- if(_x.fd >= 0){
- if(firstx){
- firstx = 0;
- XSelectInput(_x.display, _x.drawable, Mask);
- }
- FD_SET(_x.fd, &rd);
- FD_SET(_x.fd, &xx);
- XFlush(_x.display);
- if(_x.fd > top)
- top = _x.fd;
- }
-
- if(chatty)
- fprint(2, "select %d...\n", top+1);
- /* wait for something to happen */
- again:
- if(select(top+1, &rd, &wr, &xx, NULL) < 0){
- if(errno == EINTR)
- goto again;
- if(chatty)
- fprint(2, "select failure\n");
- exits(0);
- }
- if(chatty)
- fprint(2, "got select...\n");
-
- {
- /* read what we can */
- n = 1;
- while(fdin.wp < fdin.ep && (n = read(3, fdin.wp, fdin.ep-fdin.wp)) > 0)
- fdin.wp += n;
- if(n == 0){
- if(chatty)
- fprint(2, "eof\n");
- exits(0);
- }
- if(n < 0 && errno != EAGAIN)
- sysfatal("reading wsys msg: %r");
-
- /* pick off messages one by one */
- while((n = convM2W(fdin.rp, fdin.wp-fdin.rp, &m)) > 0){
- /* fprint(2, "<- %W\n", &m); */
- runmsg(&m);
- fdin.rp += n;
- }
-
- /* slide data to beginning of buf */
- fdslide(&fdin);
- }
- {
- /* write what we can */
- n = 1;
- while(fdout.rp < fdout.wp && (n = write(4, fdout.rp, fdout.wp-fdout.rp)) > 0)
- fdout.rp += n;
- if(n == 0)
- sysfatal("short write writing wsys");
- if(n < 0 && errno != EAGAIN)
- sysfatal("writing wsys msg: %r");
-
- /* slide data to beginning of buf */
- fdslide(&fdout);
- }
- {
- /*
- * Read an X message if we can.
- * (XPending actually calls select to make sure
- * the display's fd is readable and then reads
- * in any waiting data before declaring whether
- * there are events on the queue.)
- */
- while(XPending(_x.display)){
- XNextEvent(_x.display, &event);
- runxevent(&event);
- }
- }
- }
-}
-
-int
-fdnoblock(int fd)
-{
- return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL)|O_NONBLOCK);
-}
-
-void
-fdslide(Fdbuf *fb)
-{
- int n;
-
- n = fb->wp - fb->rp;
- if(n > 0)
- memmove(fb->buf, fb->rp, n);
- fb->rp = fb->buf;
- fb->wp = fb->rp+n;
-}
-
-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)
-{
- uchar buf[65536];
- int n;
- Memimage *i;
-
- switch(m->type){
- case Tinit:
- memimageinit();
- i = _xattach(m->label, m->winsize);
- _initdisplaymemimage(i);
- replymsg(m);
- break;
-
- case Trdmouse:
- 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");
- /* fprint(2, "mouse unstall\n"); */
- mouse.stall = 0;
- matchmouse();
- break;
-
- case Trdkbd:
- 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();
- break;
-
- case Tmoveto:
- _xmoveto(m->mouse.xy);
- replymsg(m);
- break;
-
- case Tcursor:
- case Tcursor2:
- if(m->arrowcursor)
- _xsetcursor(nil);
- else
- _xsetcursor(&m->cursor);
- replymsg(m);
- break;
-
- case Tbouncemouse:
- _xbouncemouse(&m->mouse);
- replymsg(m);
- break;
-
- case Tlabel:
- _xsetlabel(m->label);
- replymsg(m);
- break;
-
- case Trdsnarf:
- m->snarf = _xgetsnarf();
- replymsg(m);
- free(m->snarf);
- break;
-
- case Twrsnarf:
- _xputsnarf(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.
- */
-void
-replymsg(Wsysmsg *m)
-{
- int n;
-
- /* T -> R msg */
- if(m->type%2 == 0)
- m->type++;
-
- /* fprint(2, "-> %W\n", m); */
- /* copy to output buffer */
- n = sizeW2M(m);
- if(fdout.wp+n > fdout.ep)
- sysfatal("out of space for reply message");
- convW2M(m, fdout.wp, n);
- fdout.wp += n;
-}
-
-/*
- * 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 = mouse.resized;
- /*
- if(m.resized)
- fprint(2, "sending resize\n");
- */
- mouse.resized = 0;
- mouse.ri++;
- if(mouse.ri == nelem(mouse.m))
- mouse.ri = 0;
- replymsg(&m);
- }
-}
-
-static int kbuttons;
-static int altdown;
-static int kstate;
-
-static void
-sendmouse(Mouse m)
-{
- m.buttons |= kbuttons;
- mouse.m[mouse.wi] = m;
- mouse.wi++;
- 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;
- /* fprint(2, "mouse stall\n"); */
- }
- matchmouse();
-}
-
-/*
- * Handle an incoming X event.
- */
-void
-runxevent(XEvent *xev)
-{
- int c;
- KeySym k;
- static Mouse m;
- XButtonEvent *be;
- XKeyEvent *ke;
-
-#ifdef SHOWEVENT
- static int first = 1;
- if(first){
- dup(create("/tmp/devdraw.out", OWRITE, 0666), 1);
- setbuf(stdout, 0);
- first = 0;
- }
-#endif
-
- if(xev == 0)
- return;
-
-#ifdef SHOWEVENT
- print("\n");
- ShowEvent(xev);
-#endif
-
- switch(xev->type){
- case Expose:
- _xexpose(xev);
- break;
-
- case DestroyNotify:
- if(_xdestroy(xev))
- exits(0);
- break;
-
- case ConfigureNotify:
- if(_xconfigure(xev)){
- mouse.resized = 1;
- _xreplacescreenimage();
- sendmouse(m);
- }
- break;
-
- case ButtonPress:
- be = (XButtonEvent*)xev;
- if(be->button == 1) {
- if(kstate & ControlMask)
- be->button = 2;
- else if(kstate & Mod1Mask)
- be->button = 3;
- }
- // fall through
- case ButtonRelease:
- altdown = 0;
- // fall through
- case MotionNotify:
- if(mouse.stall)
- return;
- if(_xtoplan9mouse(xev, &m) < 0)
- return;
- sendmouse(m);
- break;
-
- case KeyRelease:
- case KeyPress:
- ke = (XKeyEvent*)xev;
- XLookupString(ke, NULL, 0, &k, NULL);
- c = ke->state;
- switch(k) {
- case XK_Alt_L:
- case XK_Meta_L: /* Shift Alt on PCs */
- case XK_Alt_R:
- case XK_Meta_R: /* Shift Alt on PCs */
- case XK_Multi_key:
- if(xev->type == KeyPress)
- altdown = 1;
- else if(altdown) {
- altdown = 0;
- sendalt();
- }
- break;
- }
-
- switch(k) {
- case XK_Control_L:
- if(xev->type == KeyPress)
- c |= ControlMask;
- else
- c &= ~ControlMask;
- goto kbutton;
- case XK_Alt_L:
- case XK_Shift_L:
- if(xev->type == KeyPress)
- c |= Mod1Mask;
- else
- c &= ~Mod1Mask;
- kbutton:
- kstate = c;
- if(m.buttons || kbuttons) {
- altdown = 0; // used alt
- kbuttons = 0;
- if(c & ControlMask)
- kbuttons |= 2;
- if(c & Mod1Mask)
- kbuttons |= 4;
- sendmouse(m);
- break;
- }
- }
-
- if(xev->type != KeyPress)
- break;
- if(k == XK_F11){
- fullscreen = !fullscreen;
- _xmovewindow(fullscreen ? screenrect : windowrect);
- return;
- }
- if(kbd.stall)
- return;
- if((c = _xtoplan9kbd(xev)) < 0)
- return;
- kbd.r[kbd.wi++] = c;
- if(kbd.wi == nelem(kbd.r))
- kbd.wi = 0;
- if(kbd.ri == kbd.wi)
- kbd.stall = 1;
- matchkbd();
- break;
-
- case FocusOut:
- /*
- * Some key combinations (e.g. Alt-Tab) can cause us
- * to see the key down event without the key up event,
- * so clear out the keyboard state when we lose the focus.
- */
- kstate = 0;
- altdown = 0;
- abortcompose();
- break;
-
- case SelectionRequest:
- _xselect(xev);
- break;
- }
-}
-
diff --git a/src/cmd/devdraw/x11-unload.c b/src/cmd/devdraw/x11-unload.c
index d01a232f..2f6241ba 100644
--- a/src/cmd/devdraw/x11-unload.c
+++ b/src/cmd/devdraw/x11-unload.c
@@ -12,4 +12,3 @@ unloadmemimage(Memimage *i, Rectangle r, uchar *data, int ndata)
_xgetxdata(i, r);
return _unloadmemimage(i, r, data, ndata);
}
-
diff --git a/src/cmd/devdraw/x11-wsys.c b/src/cmd/devdraw/x11-wsys.c
deleted file mode 100644
index 9095c950..00000000
--- a/src/cmd/devdraw/x11-wsys.c
+++ /dev/null
@@ -1,46 +0,0 @@
-#include <u.h>
-#include "x11-inc.h"
-#include <libc.h>
-#include <draw.h>
-#include <memdraw.h>
-#include "x11-memdraw.h"
-
-void
-_xtopwindow(void)
-{
- XMapRaised(_x.display, _x.drawable);
- XSetInputFocus(_x.display, _x.drawable, RevertToPointerRoot,
- CurrentTime);
- XFlush(_x.display);
-}
-
-void
-_xresizewindow(Rectangle r)
-{
- XWindowChanges e;
- int value_mask;
-
- memset(&e, 0, sizeof e);
- value_mask = CWX|CWY|CWWidth|CWHeight;
- e.width = Dx(r);
- e.height = Dy(r);
- XConfigureWindow(_x.display, _x.drawable, value_mask, &e);
- XFlush(_x.display);
-}
-
-void
-_xmovewindow(Rectangle r)
-{
- XWindowChanges e;
- int value_mask;
-
- memset(&e, 0, sizeof e);
- value_mask = CWX|CWY|CWWidth|CWHeight;
- e.x = r.min.x;
- e.y = r.min.y;
- e.width = Dx(r);
- e.height = Dy(r);
- XConfigureWindow(_x.display, _x.drawable, value_mask, &e);
- XFlush(_x.display);
-}
-