]> Cypherpunks repositories - gostls13.git/commitdiff
final Native Client package - av
authorRuss Cox <rsc@golang.org>
Fri, 2 Oct 2009 20:25:26 +0000 (13:25 -0700)
committerRuss Cox <rsc@golang.org>
Fri, 2 Oct 2009 20:25:26 +0000 (13:25 -0700)
R=r
DELTA=894  (887 added, 0 deleted, 7 changed)
OCL=35115
CL=35286

usr/rsc/nacl/av/Makefile [new file with mode: 0644]
usr/rsc/nacl/av/av.go [new file with mode: 0644]
usr/rsc/nacl/av/event.go [new file with mode: 0644]
usr/rsc/nacl/av/image.go [new file with mode: 0644]
usr/rsc/nacl/srpc/server.go

diff --git a/usr/rsc/nacl/av/Makefile b/usr/rsc/nacl/av/Makefile
new file mode 100644 (file)
index 0000000..523a9ff
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright 2009 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+include $(GOROOT)/src/Make.$(GOARCH)
+
+TARG=nacl/av
+GOFILES=\
+       av.go\
+       event.go\
+       image.go\
+
+include $(GOROOT)/src/Make.pkg
diff --git a/usr/rsc/nacl/av/av.go b/usr/rsc/nacl/av/av.go
new file mode 100644 (file)
index 0000000..8433cda
--- /dev/null
@@ -0,0 +1,308 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Native Client audio/video
+
+// Package av implements audio and video access for Native Client
+// binaries running standalone or embedded in a web browser window.
+package av
+
+import (
+       "bytes";
+       "draw";
+       "log";
+       "nacl/srpc";
+       "os";
+       "syscall";
+       "unsafe";
+)
+
+var srpcEnabled = srpc.Enabled();
+
+// native_client/src/trusted/service_runtime/include/sys/audio_video.h
+
+// Subsystem values for Init.
+const (
+       SubsystemVideo = 1<<iota;
+       SubsystemAudio;
+       SubsystemEmbed;
+)
+//     SubsystemRawEvents;
+
+// Audio formats.
+const (
+       AudioFormatStereo44K = iota;
+       AudioFormatStereo48K;
+)
+
+// A Window represents a connection to the Native Client window.
+// It implements draw.Context.
+type Window struct {
+       Embedded bool;  // running as part of a web page?
+       *Image;         // screen image
+
+       mousec chan draw.Mouse;
+       kbdc chan int;
+       quitc chan bool;
+       resizec chan bool;
+}
+
+// *Window implements draw.Context
+var _ draw.Context = (*Window)(nil)
+
+func (w *Window) KeyboardChan() <-chan int {
+       return w.kbdc;
+}
+
+func (w *Window) MouseChan() <-chan draw.Mouse {
+       return w.mousec;
+}
+
+func (w *Window) QuitChan() <-chan bool {
+       return w.quitc;
+}
+
+func (w *Window) ResizeChan() <-chan bool {
+       return w.resizec;
+}
+
+func (w *Window) Screen() draw.Image {
+       return w.Image;
+}
+
+// Init initializes the Native Client subsystems specified by subsys.
+// Init must be called before using any of the other functions
+// in this package, and it must be called only once.
+//
+// If the SubsystemVideo flag is set, Init requests a window of size dx×dy.
+// When embedded in a web page, the web page's window specification
+// overrides the parameters to Init, so the returned Window may have
+// a different size than requested.
+//
+// If the SubsystemAudio flag is set, Init requests a connection to the
+// audio device carrying 44 kHz 16-bit stereo PCM audio samples.
+func Init(subsys int, dx, dy int) (*Window, os.Error) {
+       xsubsys := subsys;
+       if srpcEnabled {
+               waitBridge();
+               xsubsys &^= SubsystemVideo|SubsystemEmbed;
+       }
+
+       if xsubsys & SubsystemEmbed != 0 {
+               return nil, os.NewError("not embedded");
+       }
+
+       w := new(Window);
+       err := multimediaInit(xsubsys);
+       if err != nil {
+               return nil, err;
+       }
+
+       if subsys&SubsystemVideo != 0 {
+               if dx, dy, err = videoInit(dx, dy); err != nil {
+                       return nil, err;
+               }
+               w.Image = newImage(dx, dy, bridge.pixel);
+               w.resizec = make(chan bool, 64);
+               w.kbdc = make(chan int, 64);
+               w.mousec = make(chan draw.Mouse, 64);
+               w.quitc = make(chan bool);
+       }
+
+       if subsys&SubsystemAudio != 0 {
+               var n int;
+               if n, err = audioInit(AudioFormatStereo44K, 2048); err != nil {
+                       return nil, err;
+               }
+               println("audio", n);
+       }
+
+       if subsys&SubsystemVideo != 0 {
+               go w.readEvents();
+       }
+
+       return w, nil;
+}
+
+func (w *Window) FlushImage() {
+       if w.Image == nil {
+               return;
+       }
+       videoUpdate(w.Image.Linear);
+}
+
+func multimediaInit(subsys int) (err os.Error) {
+       return os.NewSyscallError("multimedia_init", syscall.MultimediaInit(subsys));
+}
+
+func videoInit(dx, dy int) (ndx, ndy int, err os.Error) {
+       if srpcEnabled {
+               bridge.share.ready = 1;
+               return int(bridge.share.width), int(bridge.share.height), nil;
+       }
+       if e := syscall.VideoInit(dx, dy); e != 0 {
+               return 0, 0, os.NewSyscallError("video_init", int(e));
+       }
+       return dx, dy, nil;
+}
+
+func videoUpdate(data []Color) (err os.Error) {
+       if srpcEnabled {
+               bridge.flushRPC.Call("upcall", nil);
+               return;
+       }
+       return os.NewSyscallError("video_update", syscall.VideoUpdate((*uint32)(&data[0])));
+}
+
+var noEvents = os.NewError("no events");
+
+func videoPollEvent(ev []byte) (err os.Error) {
+       if srpcEnabled {
+               r := bridge.share.eq.ri;
+               if r == bridge.share.eq.wi {
+                       return noEvents;
+               }
+               bytes.Copy(ev, &bridge.share.eq.event[r]);
+               bridge.share.eq.ri = (r+1) % eqsize;
+               return nil;
+       }
+       return os.NewSyscallError("video_poll_event", syscall.VideoPollEvent(&ev[0]));
+}
+
+func audioInit(fmt int, want int) (got int, err os.Error) {
+       var x int;
+       e := syscall.AudioInit(fmt, want, &x);
+       if e == 0 {
+               return x, nil;
+       }
+       return 0, os.NewSyscallError("audio_init", e);
+}
+
+var audioSize uintptr
+
+// AudioStream provides access to the audio device.
+// Each call to AudioStream writes the given data,
+// which should be a slice of 16-bit stereo PCM audio samples,
+// and returns the number of samples required by the next
+// call to AudioStream.
+//
+// To find out the initial number of samples to write, call AudioStream(nil).
+//
+func AudioStream(data []uint16) (nextSize int, err os.Error) {
+       if audioSize == 0 {
+               e := os.NewSyscallError("audio_stream", syscall.AudioStream(nil, &audioSize));
+               return int(audioSize), e;
+       }
+       if data == nil {
+               return int(audioSize), nil;
+       }
+       if uintptr(len(data))*2 != audioSize {
+               log.Stdoutf("invalid audio size want %d got %d", audioSize, len(data));
+       }
+       e := os.NewSyscallError("audio_stream", syscall.AudioStream(&data[0], &audioSize));
+       return int(audioSize), e;
+}
+
+// Synchronization structure to wait for bridge to become ready.
+var bridge struct {
+       c chan bool;
+       displayFd int;
+       rpcFd int;
+       share *videoShare;
+       pixel []Color;
+       client *srpc.Client;
+       flushRPC *srpc.RPC;
+}
+
+// Wait for bridge to become ready.
+// When chan is first created, there is nothing in it,
+// so this blocks.  Once the bridge is ready, multimediaBridge.Run
+// will drop a value into the channel.  Then any calls
+// to waitBridge will finish, taking the value out and immediately putting it back.
+func waitBridge() {
+       bridge.c <- <-bridge.c;
+}
+
+const eqsize = 64;
+
+// Data structure shared with host via mmap.
+type videoShare struct {
+       revision int32; // definition below is rev 100 unless noted
+       mapSize int32;
+
+       // event queue
+       eq struct {
+               ri uint32;      // read index [0,eqsize)
+               wi uint32;      // write index [0,eqsize)
+               eof int32;
+               event [eqsize][64]byte;
+       };
+
+       // now unused
+       _, _, _, _ int32;
+
+       // video backing store information
+       width, height, _, size int32;
+       ready int32;    // rev 0x101
+}
+
+// The frame buffer data is videoShareSize bytes after
+// the videoShare begins.
+const videoShareSize = 16*1024
+
+type multimediaBridge struct{}
+
+// If using SRPC, the runtime will call this method to pass in two file descriptors,
+// one to mmap to get the display memory, and another to use for SRPCs back
+// to the main process.
+func (multimediaBridge) Run(arg, ret []interface{}, size []int) srpc.Errno {
+       bridge.displayFd = arg[0].(int);
+       bridge.rpcFd = arg[1].(int);
+
+       var st syscall.Stat_t;
+       if errno := syscall.Fstat(bridge.displayFd, &st); errno != 0 {
+               log.Exitf("mmbridge stat display: %s", os.Errno(errno));
+       }
+
+       addr, _, errno := syscall.Syscall6(syscall.SYS_MMAP,
+               0,
+               uintptr(st.Size),
+               syscall.PROT_READ|syscall.PROT_WRITE,
+               syscall.MAP_SHARED,
+               uintptr(bridge.displayFd),
+               0);
+       if errno != 0 {
+               log.Exitf("mmap display: %s", os.Errno(errno));
+       }
+
+       bridge.share = (*videoShare)(unsafe.Pointer(addr));
+
+       // Overestimate frame buffer size
+       // (must use a compile-time constant)
+       // and then reslice.  256 megapixels (1 GB) should be enough.
+       fb := (*[256*1024*1024]Color)(unsafe.Pointer(addr+videoShareSize));
+       bridge.pixel = fb[0:(st.Size - videoShareSize)/4];
+
+       // Configure RPC connection back to client.
+       var err os.Error;
+       bridge.client, err = srpc.NewClient(bridge.rpcFd);
+       if err != nil {
+               log.Exitf("NewClient: %s", err);
+       }
+       bridge.flushRPC = bridge.client.NewRPC(nil);
+
+       // Notify waiters that the bridge is ready.
+       println("bridged", bridge.share.revision);
+       bridge.c <- true;
+
+       return srpc.OK;
+}
+
+func init() {
+       bridge.c = make(chan bool, 1);
+       if srpcEnabled {
+               srpc.Add("nacl_multimedia_bridge", "hh:", multimediaBridge{});
+       }
+}
+
diff --git a/usr/rsc/nacl/av/event.go b/usr/rsc/nacl/av/event.go
new file mode 100644 (file)
index 0000000..62ecbc6
--- /dev/null
@@ -0,0 +1,471 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// NaCl GUI events.
+// Clients do not have raw access to the event stream
+// (only filtered through the lens of package draw)
+// but perhaps they will.
+
+package av
+
+import (
+       "bytes";
+       "debug/binary";
+       "draw";
+       "log";
+       "os";
+       "time";
+)
+
+// An eventType identifies the type of a Native Client Event.
+type eventType uint8;
+const (
+       eventActive = 1+iota;
+       eventExpose;
+       eventKeyDown;
+       eventKeyUp;
+       eventMouseMotion;
+       eventMouseButtonDown;
+       eventMouseButtonUp;
+       eventQuit;
+       eventUnsupported;
+)
+
+// A key represents a key on a keyboard.
+type key uint16
+const (
+       keyUnknown      = 0;
+       keyFirst        = 0;
+       keyBackspace    = 8;
+       keyTab          = 9;
+       keyClear        = 12;
+       keyReturn       = 13;
+       keyPause        = 19;
+       keyEscape       = 27;
+       keySpace        = 32;
+       keyExclaim      = 33;
+       keyQuotedbl     = 34;
+       keyHash         = 35;
+       keyDollar       = 36;
+       keyAmpersand    = 38;
+       keyQuote        = 39;
+       keyLeftparen    = 40;
+       keyRightparen   = 41;
+       keyAsterisk     = 42;
+       keyPlus         = 43;
+       keyComma        = 44;
+       keyMinus        = 45;
+       keyPeriod       = 46;
+       keySlash        = 47;
+       key0            = 48;
+       key1            = 49;
+       key2            = 50;
+       key3            = 51;
+       key4            = 52;
+       key5            = 53;
+       key6            = 54;
+       key7            = 55;
+       key8            = 56;
+       key9            = 57;
+       keyColon        = 58;
+       keySemicolon    = 59;
+       keyLess         = 60;
+       keyEquals       = 61;
+       keyGreater      = 62;
+       keyQuestion     = 63;
+       keyAt           = 64;
+       keyLeftbracket  = 91;
+       keyBackslash    = 92;
+       keyRightbracket = 93;
+       keyCaret        = 94;
+       keyUnderscore   = 95;
+       keyBackquote    = 96;
+       keyA            = 97;
+       keyB            = 98;
+       keyC            = 99;
+       keyD            = 100;
+       keyE            = 101;
+       keyF            = 102;
+       keyG            = 103;
+       keyH            = 104;
+       keyI            = 105;
+       keyJ            = 106;
+       keyK            = 107;
+       keyL            = 108;
+       keyM            = 109;
+       keyN            = 110;
+       keyO            = 111;
+       keyP            = 112;
+       keyQ            = 113;
+       keyR            = 114;
+       keyS            = 115;
+       keyT            = 116;
+       keyU            = 117;
+       keyV            = 118;
+       keyW            = 119;
+       keyX            = 120;
+       keyY            = 121;
+       keyZ            = 122;
+       keyDelete       = 127;
+       keyWorld0      = 160;
+       keyWorld1      = 161;
+       keyWorld2      = 162;
+       keyWorld3      = 163;
+       keyWorld4      = 164;
+       keyWorld5      = 165;
+       keyWorld6      = 166;
+       keyWorld7      = 167;
+       keyWorld8      = 168;
+       keyWorld9      = 169;
+       keyWorld10     = 170;
+       keyWorld11     = 171;
+       keyWorld12     = 172;
+       keyWorld13     = 173;
+       keyWorld14     = 174;
+       keyWorld15     = 175;
+       keyWorld16     = 176;
+       keyWorld17     = 177;
+       keyWorld18     = 178;
+       keyWorld19     = 179;
+       keyWorld20     = 180;
+       keyWorld21     = 181;
+       keyWorld22     = 182;
+       keyWorld23     = 183;
+       keyWorld24     = 184;
+       keyWorld25     = 185;
+       keyWorld26     = 186;
+       keyWorld27     = 187;
+       keyWorld28     = 188;
+       keyWorld29     = 189;
+       keyWorld30     = 190;
+       keyWorld31     = 191;
+       keyWorld32     = 192;
+       keyWorld33     = 193;
+       keyWorld34     = 194;
+       keyWorld35     = 195;
+       keyWorld36     = 196;
+       keyWorld37     = 197;
+       keyWorld38     = 198;
+       keyWorld39     = 199;
+       keyWorld40     = 200;
+       keyWorld41     = 201;
+       keyWorld42     = 202;
+       keyWorld43     = 203;
+       keyWorld44     = 204;
+       keyWorld45     = 205;
+       keyWorld46     = 206;
+       keyWorld47     = 207;
+       keyWorld48     = 208;
+       keyWorld49     = 209;
+       keyWorld50     = 210;
+       keyWorld51     = 211;
+       keyWorld52     = 212;
+       keyWorld53     = 213;
+       keyWorld54     = 214;
+       keyWorld55     = 215;
+       keyWorld56     = 216;
+       keyWorld57     = 217;
+       keyWorld58     = 218;
+       keyWorld59     = 219;
+       keyWorld60     = 220;
+       keyWorld61     = 221;
+       keyWorld62     = 222;
+       keyWorld63     = 223;
+       keyWorld64     = 224;
+       keyWorld65     = 225;
+       keyWorld66     = 226;
+       keyWorld67     = 227;
+       keyWorld68     = 228;
+       keyWorld69     = 229;
+       keyWorld70     = 230;
+       keyWorld71     = 231;
+       keyWorld72     = 232;
+       keyWorld73     = 233;
+       keyWorld74     = 234;
+       keyWorld75     = 235;
+       keyWorld76     = 236;
+       keyWorld77     = 237;
+       keyWorld78     = 238;
+       keyWorld79     = 239;
+       keyWorld80     = 240;
+       keyWorld81     = 241;
+       keyWorld82     = 242;
+       keyWorld83     = 243;
+       keyWorld84     = 244;
+       keyWorld85     = 245;
+       keyWorld86     = 246;
+       keyWorld87     = 247;
+       keyWorld88     = 248;
+       keyWorld89     = 249;
+       keyWorld90     = 250;
+       keyWorld91     = 251;
+       keyWorld92     = 252;
+       keyWorld93     = 253;
+       keyWorld94     = 254;
+       keyWorld95     = 255;
+
+       // Numeric keypad
+       keyKp0          = 256;
+       keyKp1          = 257;
+       keyKp2          = 258;
+       keyKp3          = 259;
+       keyKp4          = 260;
+       keyKp5          = 261;
+       keyKp6          = 262;
+       keyKp7          = 263;
+       keyKp8          = 264;
+       keyKp9          = 265;
+       keyKpPeriod    = 266;
+       keyKpDivide    = 267;
+       keyKpMultiply  = 268;
+       keyKpMinus     = 269;
+       keyKpPlus      = 270;
+       keyKpEnter     = 271;
+       keyKpEquals    = 272;
+
+       // Arrow & insert/delete pad
+       keyUp           = 273;
+       keyDown         = 274;
+       keyRight        = 275;
+       keyLeft         = 276;
+       keyInsert       = 277;
+       keyHome         = 278;
+       keyEnd          = 279;
+       keyPageup       = 280;
+       keyPagedown     = 281;
+
+       // Function keys
+       keyF1           = 282;
+       keyF2           = 283;
+       keyF3           = 284;
+       keyF4           = 285;
+       keyF5           = 286;
+       keyF6           = 287;
+       keyF7           = 288;
+       keyF8           = 289;
+       keyF9           = 290;
+       keyF10          = 291;
+       keyF11          = 292;
+       keyF12          = 293;
+       keyF13          = 294;
+       keyF14          = 295;
+       keyF15          = 296;
+
+       // Modifier keys
+       keyNumlock      = 300;
+       keyCapslock     = 301;
+       keyScrollock    = 302;
+       keyRshift       = 303;
+       keyLshift       = 304;
+       keyRctrl        = 305;
+       keyLctrl        = 306;
+       keyRalt         = 307;
+       keyLalt         = 308;
+       keyRmeta        = 309;
+       keyLmeta        = 310;
+       keyLsuper       = 311;
+       keyRsuper       = 312;
+       keyMode         = 313;
+       keyCompose      = 314;
+
+       // Misc keys
+       keyHelp         = 315;
+       keyPrint        = 316;
+       keySysreq       = 317;
+       keyBreak        = 318;
+       keyMenu         = 319;
+       keyPower        = 320;
+       keyEuro         = 321;
+       keyUndo         = 322;
+
+       // Add any other keys here
+       keyLast
+)
+
+// A keymod is a set of bit flags
+type keymod uint16
+const (
+       keymodNone  = 0x0000;
+       keymodLshift= 0x0001;
+       keymodRshift= 0x0002;
+       keymodLctrl = 0x0040;
+       keymodRctrl = 0x0080;
+       keymodLalt  = 0x0100;
+       keymodRalt  = 0x0200;
+       keymodLmeta = 0x0400;
+       keymodRmeta = 0x0800;
+       keymodNum   = 0x1000;
+       keymodCaps  = 0x2000;
+       keymodMode  = 0x4000;
+       keymodReserved = 0x8000
+)
+
+const (
+       mouseButtonLeft = 1;
+       mouseButtonMiddle = 2;
+       mouseButtonRight = 3;
+       mouseScrollUp = 4;
+       mouseScrollDown = 5
+)
+
+const (
+       mouseStateLeftButtonPressed = 1;
+       mouseStateMiddleButtonPressed = 2;
+       mouseStateRightButtonPressed = 4
+)
+
+const (
+       activeMouse = 1;        //  mouse leaving/entering
+       activeInputFocus = 2;  // input focus lost/restored
+       activeApplication = 4   // application minimized/restored
+)
+
+const maxEventBytes = 64
+
+type activeEvent struct {
+       EventType eventType;
+       Gain uint8;
+       State uint8;
+}
+
+type exposeEvent struct {
+       EventType eventType;
+}
+
+type keyboardEvent struct {
+       EventType eventType;
+       Device uint8;
+       State uint8;
+       Pad uint8;
+       ScanCode uint8;
+       Pad1 uint8;
+       Key key;
+       Mod keymod;
+       Unicode uint16;
+}
+
+type mouseMotionEvent struct {
+       EventType eventType;
+       Device uint8;
+       Buttons uint8;
+       Pad uint8;
+       X uint16;
+       Y uint16;
+       Xrel int16;
+       Yrel int16;
+}
+
+type mouseButtonEvent struct {
+       EventType eventType;
+       Device uint8;
+       Button uint8;
+       State uint8;
+       X uint16;
+       Y uint16;
+}
+
+type quitEvent struct {
+       EventType eventType;
+}
+
+type syncEvent struct {
+}
+
+type event interface {
+}
+
+type reader []byte
+func (r *reader) Read(p []byte) (n int, err os.Error) {
+       b := *r;
+       if len(b) == 0 && len(p) > 0 {
+               return 0, os.EOF;
+       }
+       n = bytes.Copy(p, b);
+       *r = b[n:len(b)];
+       return;
+}
+
+func (w *Window) readEvents() {
+       buf := make([]byte, maxEventBytes);
+       clean := false;
+       var (
+               ea *activeEvent;
+               ee *exposeEvent;
+               ke *keyboardEvent;
+               mme *mouseMotionEvent;
+               mbe *mouseButtonEvent;
+               qe *quitEvent;
+       )
+       var m draw.Mouse;
+       for {
+               if err := videoPollEvent(buf); err != nil {
+                       if !clean {
+                               clean = w.resizec <- false;
+                       }
+                       time.Sleep(10e6);       // 10ms
+                       continue;
+               }
+               clean = false;
+               var e event;
+               switch buf[0] {
+               default:
+                       log.Stdout("unsupported event type", buf[0]);
+                       continue;
+               case eventActive:
+                       ea = new(activeEvent);
+                       e = ea;
+               case eventExpose:
+                       ee = new(exposeEvent);
+                       e = ee;
+               case eventKeyDown, eventKeyUp:
+                       ke = new(keyboardEvent);
+                       e = ke;
+               case eventMouseMotion:
+                       mme = new(mouseMotionEvent);
+                       e = mme;
+               case eventMouseButtonDown, eventMouseButtonUp:
+                       mbe = new(mouseButtonEvent);
+                       e = mbe;
+               case eventQuit:
+                       qe = new(quitEvent);
+                       e = qe;
+               }
+               r := reader(buf);
+               if err := binary.Read(&r, binary.LittleEndian, e); err != nil {
+                       log.Stdout("unpacking %T event: %s", e, err);
+                       continue;
+               }
+               // log.Stdoutf("%#v\n", e);
+               switch buf[0] {
+               case eventExpose:
+                       w.resizec <- true
+               case eventKeyDown:
+                       w.kbdc <- int(ke.Key);
+               case eventKeyUp:
+                       w.kbdc <- -int(ke.Key);
+               case eventMouseMotion:
+                       m.X = int(mme.X);
+                       m.Y = int(mme.Y);
+                       m.Buttons = int(mme.Buttons);
+                       m.Nsec = time.Nanoseconds();
+                       _ = w.mousec <- m;
+               case eventMouseButtonDown:
+                       m.X = int(mbe.X);
+                       m.Y = int(mbe.Y);
+                       // TODO(rsc): Remove uint cast once 8g bug is fixed.
+                       m.Buttons |= 1<<uint(mbe.Button-1);
+                       m.Nsec = time.Nanoseconds();
+                       _ = w.mousec <- m;
+               case eventMouseButtonUp:
+                       m.X = int(mbe.X);
+                       m.Y = int(mbe.Y);
+                       // TODO(rsc): Remove uint cast once 8g bug is fixed.
+                       m.Buttons &^= 1<<uint(mbe.Button-1);
+                       m.Nsec = time.Nanoseconds();
+                       _ = w.mousec <- m;
+               case eventQuit:
+                       w.quitc <- true;
+               }
+       }
+}
diff --git a/usr/rsc/nacl/av/image.go b/usr/rsc/nacl/av/image.go
new file mode 100644 (file)
index 0000000..3aee3ca
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright 2009 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package av
+
+import (
+       "image";
+)
+
+// Native Client image format:
+// a single linear array of 32-bit ARGB as packed uint32s.
+
+// An Image represents a Native Client frame buffer.
+// The pixels in the image can be accessed as a single
+// linear slice or as a two-dimensional slice of slices.
+// Image implements image.Image.
+type Image struct {
+       Linear []Color;
+       Pixel [][]Color;
+}
+
+var _ image.Image = (*Image)(nil);
+
+func (m *Image) ColorModel() image.ColorModel {
+       return ColorModel;
+}
+
+func (m *Image) Width() int {
+       if len(m.Pixel) == 0 {
+               return 0;
+       }
+       return len(m.Pixel[0]);
+}
+
+func (m *Image) Height() int {
+       return len(m.Pixel);
+}
+
+func (m *Image) At(x, y int) image.Color {
+       return m.Pixel[y][x];
+}
+
+func (m *Image) Set(x, y int, color image.Color) {
+       if c, ok := color.(Color); ok {
+               m.Pixel[y][x] = c;
+       }
+       m.Pixel[y][x] = makeColor(color.RGBA());
+}
+
+func newImage(dx, dy int, linear []Color) *Image {
+       if linear == nil {
+               linear = make([]Color, dx*dy);
+       }
+       pix := make([][]Color, dy);
+       for i := range pix {
+               pix[i] = linear[dx*i : dx*(i+1)];
+       }
+       return &Image{linear, pix};
+}
+
+// A Color represents a Native Client color value,
+// a 32-bit R, G, B, A value packed as 0xAARRGGBB.
+type Color uint32
+func (p Color) RGBA() (r, g, b, a uint32) {
+       x := uint32(p);
+       a = x>>24;
+       a |= a<<8;
+       a |= a<<16;
+       r = (x>>16) & 0xFF;
+       r |= r<<8;
+       r |= r<<16;
+       g = (x>>8) & 0xFF;
+       g |= g<<8;
+       g |= g<<16;
+       b = x & 0xFF;
+       b |= b<<8;
+       b |= b<<16;
+       return;
+}
+
+func makeColor(r, g, b, a uint32) Color {
+       return Color(a>>24<<24 | r>>24<<16 | g>>24<<8 | b>>24);
+}
+
+func toColor(color image.Color) image.Color {
+       if c, ok := color.(Color); ok {
+               return c;
+       }
+       return makeColor(color.RGBA());
+}
+
+// ColorModel is the color model corresponding to the Native Client Color.
+var ColorModel = image.ColorModelFunc(toColor);
+
index 4fd778d635930a4510b6a35ee06ac0fb8d5ffb15..c4dc0a6c7dfcb2d21cc06200d4adcbaff5ae3a65 100644 (file)
@@ -19,10 +19,10 @@ import (
 // The explicit interface is a way to attach state.
 
 // A Handler is a handler for an SRPC method.
-// It reads arguments from m.Arg, checks m.Size for array limits,
-// writes return values to m.Ret, and returns an Errno status code.
+// It reads arguments from arg, checks size for array limits,
+// writes return values to ret, and returns an Errno status code.
 type Handler interface {
-       Run(m *msg) Errno
+       Run(arg, ret []interface{}, size []int) Errno
 }
 
 type method struct {
@@ -149,7 +149,7 @@ func serveMsg(m *msg, c chan<- *msg) {
                return;
        }
 
-       m.status = meth.handler.Run(m);
+       m.status = meth.handler.Run(m.Arg, m.Ret, m.Size);
        c <- m;
 }
 
@@ -183,7 +183,7 @@ func Enabled() bool {
 // and their argument formats.
 type serviceDiscovery struct{}
 
-func (serviceDiscovery) Run(m *msg) Errno {
+func (serviceDiscovery) Run(arg, ret []interface{}, size []int) Errno {
        var b bytes.Buffer;
        for _, m := range rpcMethod {
                b.WriteString(m.name);
@@ -191,10 +191,10 @@ func (serviceDiscovery) Run(m *msg) Errno {
                b.WriteString(m.fmt);
                b.WriteByte('\n');
        }
-       if b.Len() > m.Size[0] {
+       if b.Len() > size[0] {
                return ErrNoMemory;
        }
-       m.Ret[0] = b.Bytes();
+       ret[0] = b.Bytes();
        return OK;
 }