screen.go (11931B)
1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package screen provides interfaces for portable two-dimensional graphics and 6 // input events. 7 // 8 // Screens are not created directly. Instead, driver packages provide access to 9 // the screen through a Main function that is designed to be called by the 10 // program's main function. The golang.org/x/exp/shiny/driver package provides 11 // the default driver for the system, such as the X11 driver for desktop Linux, 12 // but other drivers, such as the OpenGL driver, can be explicitly invoked by 13 // calling that driver's Main function. To use the default driver: 14 // 15 // package main 16 // 17 // import ( 18 // "golang.org/x/exp/shiny/driver" 19 // "golang.org/x/exp/shiny/screen" 20 // "golang.org/x/mobile/event/lifecycle" 21 // ) 22 // 23 // func main() { 24 // driver.Main(func(s screen.Screen) { 25 // w, err := s.NewWindow(nil) 26 // if err != nil { 27 // handleError(err) 28 // return 29 // } 30 // defer w.Release() 31 // 32 // for { 33 // switch e := w.NextEvent().(type) { 34 // case lifecycle.Event: 35 // if e.To == lifecycle.StageDead { 36 // return 37 // } 38 // etc 39 // case etc: 40 // etc 41 // } 42 // } 43 // }) 44 // } 45 // 46 // Complete examples can be found in the shiny/example directory. 47 // 48 // Each driver package provides Screen, Buffer, Texture and Window 49 // implementations that work together. Such types are interface types because 50 // this package is driver-independent, but those interfaces aren't expected to 51 // be implemented outside of drivers. For example, a driver's Window 52 // implementation will generally work only with that driver's Buffer 53 // implementation, and will not work with an arbitrary type that happens to 54 // implement the Buffer methods. 55 package screen // import "golang.org/x/exp/shiny/screen" 56 57 import ( 58 "image" 59 "image/color" 60 "image/draw" 61 "unicode/utf8" 62 63 "golang.org/x/image/math/f64" 64 ) 65 66 // TODO: specify image format (Alpha or Gray, not just RGBA) for NewBuffer 67 // and/or NewTexture? 68 69 // Screen creates Buffers, Textures and Windows. 70 type Screen interface { 71 // NewBuffer returns a new Buffer for this screen. 72 NewBuffer(size image.Point) (Buffer, error) 73 74 // NewTexture returns a new Texture for this screen. 75 NewTexture(size image.Point) (Texture, error) 76 77 // NewWindow returns a new Window for this screen. 78 // 79 // A nil opts is valid and means to use the default option values. 80 NewWindow(opts *NewWindowOptions) (Window, error) 81 } 82 83 // TODO: rename Buffer to Image, to be less confusing with a Window's back and 84 // front buffers. 85 86 // Buffer is an in-memory pixel buffer. Its pixels can be modified by any Go 87 // code that takes an *image.RGBA, such as the standard library's image/draw 88 // package. A Buffer is essentially an *image.RGBA, but not all *image.RGBA 89 // values (including those returned by image.NewRGBA) are valid Buffers, as a 90 // driver may assume that the memory backing a Buffer's pixels are specially 91 // allocated. 92 // 93 // To see a Buffer's contents on a screen, upload it to a Texture (and then 94 // draw the Texture on a Window) or upload it directly to a Window. 95 // 96 // When specifying a sub-Buffer via Upload, a Buffer's top-left pixel is always 97 // (0, 0) in its own coordinate space. 98 type Buffer interface { 99 // Release releases the Buffer's resources, after all pending uploads and 100 // draws resolve. 101 // 102 // The behavior of the Buffer after Release, whether calling its methods or 103 // passing it as an argument, is undefined. 104 Release() 105 106 // Size returns the size of the Buffer's image. 107 Size() image.Point 108 109 // Bounds returns the bounds of the Buffer's image. It is equal to 110 // image.Rectangle{Max: b.Size()}. 111 Bounds() image.Rectangle 112 113 // RGBA returns the pixel buffer as an *image.RGBA. 114 // 115 // Its contents should not be accessed while the Buffer is uploading. 116 // 117 // The contents of the returned *image.RGBA's Pix field (of type []byte) 118 // can be modified at other times, but that Pix slice itself (i.e. its 119 // underlying pointer, length and capacity) should not be modified at any 120 // time. 121 // 122 // The following is valid: 123 // m := buffer.RGBA() 124 // if len(m.Pix) >= 4 { 125 // m.Pix[0] = 0xff 126 // m.Pix[1] = 0x00 127 // m.Pix[2] = 0x00 128 // m.Pix[3] = 0xff 129 // } 130 // or, equivalently: 131 // m := buffer.RGBA() 132 // m.SetRGBA(m.Rect.Min.X, m.Rect.Min.Y, color.RGBA{0xff, 0x00, 0x00, 0xff}) 133 // and using the standard library's image/draw package is also valid: 134 // dst := buffer.RGBA() 135 // draw.Draw(dst, dst.Bounds(), etc) 136 // but the following is invalid: 137 // m := buffer.RGBA() 138 // m.Pix = anotherByteSlice 139 // and so is this: 140 // *buffer.RGBA() = anotherImageRGBA 141 RGBA() *image.RGBA 142 } 143 144 // Texture is a pixel buffer, but not one that is directly accessible as a 145 // []byte. Conceptually, it could live on a GPU, in another process or even be 146 // across a network, instead of on a CPU in this process. 147 // 148 // Buffers can be uploaded to Textures, and Textures can be drawn on Windows. 149 // 150 // When specifying a sub-Texture via Draw, a Texture's top-left pixel is always 151 // (0, 0) in its own coordinate space. 152 type Texture interface { 153 // Release releases the Texture's resources, after all pending uploads and 154 // draws resolve. 155 // 156 // The behavior of the Texture after Release, whether calling its methods 157 // or passing it as an argument, is undefined. 158 Release() 159 160 // Size returns the size of the Texture's image. 161 Size() image.Point 162 163 // Bounds returns the bounds of the Texture's image. It is equal to 164 // image.Rectangle{Max: t.Size()}. 165 Bounds() image.Rectangle 166 167 Uploader 168 169 // TODO: also implement Drawer? If so, merge the Uploader and Drawer 170 // interfaces?? 171 } 172 173 // EventDeque is an infinitely buffered double-ended queue of events. 174 type EventDeque interface { 175 // Send adds an event to the end of the deque. They are returned by 176 // NextEvent in FIFO order. 177 Send(event interface{}) 178 179 // SendFirst adds an event to the start of the deque. They are returned by 180 // NextEvent in LIFO order, and have priority over events sent via Send. 181 SendFirst(event interface{}) 182 183 // NextEvent returns the next event in the deque. It blocks until such an 184 // event has been sent. 185 // 186 // Typical event types include: 187 // - lifecycle.Event 188 // - size.Event 189 // - paint.Event 190 // - key.Event 191 // - mouse.Event 192 // - touch.Event 193 // from the golang.org/x/mobile/event/... packages. Other packages may send 194 // events, of those types above or of other types, via Send or SendFirst. 195 NextEvent() interface{} 196 197 // TODO: LatestLifecycleEvent? Is that still worth it if the 198 // lifecycle.Event struct type loses its DrawContext field? 199 200 // TODO: LatestSizeEvent? 201 } 202 203 // Window is a top-level, double-buffered GUI window. 204 type Window interface { 205 // Release closes the window. 206 // 207 // The behavior of the Window after Release, whether calling its methods or 208 // passing it as an argument, is undefined. 209 Release() 210 211 EventDeque 212 213 Uploader 214 215 Drawer 216 217 // Publish flushes any pending Upload and Draw calls to the window, and 218 // swaps the back buffer to the front. 219 Publish() PublishResult 220 } 221 222 // PublishResult is the result of an Window.Publish call. 223 type PublishResult struct { 224 // BackBufferPreserved is whether the contents of the back buffer was 225 // preserved. If false, the contents are undefined. 226 BackBufferPreserved bool 227 } 228 229 // NewWindowOptions are optional arguments to NewWindow. 230 type NewWindowOptions struct { 231 // Width and Height specify the dimensions of the new window. If Width 232 // or Height are zero, a driver-dependent default will be used for each 233 // zero value dimension. 234 Width, Height int 235 236 // Title specifies the window title. 237 Title string 238 239 // TODO: fullscreen, icon, cursorHidden? 240 } 241 242 // GetTitle returns a sanitized form of o.Title. In particular, its length will 243 // not exceed 4096, and it may be further truncated so that it is valid UTF-8 244 // and will not contain the NUL byte. 245 // 246 // o may be nil, in which case "" is returned. 247 func (o *NewWindowOptions) GetTitle() string { 248 if o == nil { 249 return "" 250 } 251 return sanitizeUTF8(o.Title, 4096) 252 } 253 254 func sanitizeUTF8(s string, n int) string { 255 if n < len(s) { 256 s = s[:n] 257 } 258 i := 0 259 for i < len(s) { 260 r, n := utf8.DecodeRuneInString(s[i:]) 261 if r == 0 || (r == utf8.RuneError && n == 1) { 262 break 263 } 264 i += n 265 } 266 return s[:i] 267 } 268 269 // Uploader is something you can upload a Buffer to. 270 type Uploader interface { 271 // Upload uploads the sub-Buffer defined by src and sr to the destination 272 // (the method receiver), such that sr.Min in src-space aligns with dp in 273 // dst-space. The destination's contents are overwritten; the draw operator 274 // is implicitly draw.Src. 275 // 276 // It is valid to upload a Buffer while another upload of the same Buffer 277 // is in progress, but a Buffer's image.RGBA pixel contents should not be 278 // accessed while it is uploading. A Buffer is re-usable, in that its pixel 279 // contents can be further modified, once all outstanding calls to Upload 280 // have returned. 281 // 282 // TODO: make it optional that a Buffer's contents is preserved after 283 // Upload? Undoing a swizzle is a non-trivial amount of work, and can be 284 // redundant if the next paint cycle starts by clearing the buffer. 285 // 286 // When uploading to a Window, there will not be any visible effect until 287 // Publish is called. 288 Upload(dp image.Point, src Buffer, sr image.Rectangle) 289 290 // Fill fills that part of the destination (the method receiver) defined by 291 // dr with the given color. 292 // 293 // When filling a Window, there will not be any visible effect until 294 // Publish is called. 295 Fill(dr image.Rectangle, src color.Color, op draw.Op) 296 } 297 298 // TODO: have a Downloader interface? Not every graphical app needs to be 299 // interactive or involve a window. You could use the GPU for hardware- 300 // accelerated image manipulation: upload a buffer, do some texture ops, then 301 // download the result. 302 303 // Drawer is something you can draw Textures on. 304 // 305 // Draw is the most general purpose of this interface's methods. It supports 306 // arbitrary affine transformations, such as translations, scales and 307 // rotations. 308 // 309 // Copy and Scale are more specific versions of Draw. The affected dst pixels 310 // are an axis-aligned rectangle, quantized to the pixel grid. Copy copies 311 // pixels in a 1:1 manner, Scale is more general. They have simpler parameters 312 // than Draw, using ints instead of float64s. 313 // 314 // When drawing on a Window, there will not be any visible effect until Publish 315 // is called. 316 type Drawer interface { 317 // Draw draws the sub-Texture defined by src and sr to the destination (the 318 // method receiver). src2dst defines how to transform src coordinates to 319 // dst coordinates. For example, if src2dst is the matrix 320 // 321 // m00 m01 m02 322 // m10 m11 m12 323 // 324 // then the src-space point (sx, sy) maps to the dst-space point 325 // (m00*sx + m01*sy + m02, m10*sx + m11*sy + m12). 326 Draw(src2dst f64.Aff3, src Texture, sr image.Rectangle, op draw.Op, opts *DrawOptions) 327 328 // DrawUniform is like Draw except that the src is a uniform color instead 329 // of a Texture. 330 DrawUniform(src2dst f64.Aff3, src color.Color, sr image.Rectangle, op draw.Op, opts *DrawOptions) 331 332 // Copy copies the sub-Texture defined by src and sr to the destination 333 // (the method receiver), such that sr.Min in src-space aligns with dp in 334 // dst-space. 335 Copy(dp image.Point, src Texture, sr image.Rectangle, op draw.Op, opts *DrawOptions) 336 337 // Scale scales the sub-Texture defined by src and sr to the destination 338 // (the method receiver), such that sr in src-space is mapped to dr in 339 // dst-space. 340 Scale(dr image.Rectangle, src Texture, sr image.Rectangle, op draw.Op, opts *DrawOptions) 341 } 342 343 // These draw.Op constants are provided so that users of this package don't 344 // have to explicitly import "image/draw". 345 const ( 346 Over = draw.Over 347 Src = draw.Src 348 ) 349 350 // DrawOptions are optional arguments to Draw. 351 type DrawOptions struct { 352 // TODO: transparency in [0x0000, 0xffff]? 353 // TODO: scaler (nearest neighbor vs linear)? 354 }