github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/shiny/driver/windriver/window.go (about) 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 // +build windows 6 7 package windriver 8 9 // TODO: implement a back buffer. 10 11 import ( 12 "image" 13 "image/color" 14 "image/draw" 15 "sync" 16 "unsafe" 17 18 "golang.org/x/exp/shiny/driver/internal/pump" 19 "golang.org/x/exp/shiny/driver/internal/win32" 20 "golang.org/x/exp/shiny/screen" 21 "golang.org/x/image/math/f64" 22 "golang.org/x/mobile/event/key" 23 "golang.org/x/mobile/event/lifecycle" 24 "golang.org/x/mobile/event/mouse" 25 "golang.org/x/mobile/event/paint" 26 "golang.org/x/mobile/event/size" 27 ) 28 29 var ( 30 uploadsMu sync.Mutex 31 uploads = map[uintptr]upload{} 32 uploadID uintptr 33 ) 34 35 type windowImpl struct { 36 hwnd win32.HWND 37 pump pump.Pump 38 39 sz size.Event 40 lifecycleStage lifecycle.Stage 41 } 42 43 func (w *windowImpl) Release() { 44 win32.Release(w.hwnd) 45 w.pump.Release() 46 } 47 48 func (w *windowImpl) Events() <-chan interface{} { return w.pump.Events() } 49 func (w *windowImpl) Send(event interface{}) { w.pump.Send(event) } 50 51 func (w *windowImpl) Upload(dp image.Point, src screen.Buffer, sr image.Rectangle) { 52 completion := make(chan struct{}) 53 54 // Protect struct contents from being GCed 55 uploadsMu.Lock() 56 uploadID++ 57 id := uploadID 58 uploads[id] = upload{ 59 dp: dp, 60 src: src.(*bufferImpl), 61 sr: sr, 62 completion: completion, 63 } 64 uploadsMu.Unlock() 65 66 win32.SendMessage(w.hwnd, msgUpload, id, 0) 67 68 <-completion 69 } 70 71 type upload struct { 72 dp image.Point 73 src *bufferImpl 74 sr image.Rectangle 75 completion chan struct{} 76 } 77 78 func handleUpload(hwnd win32.HWND, uMsg uint32, wParam, lParam uintptr) { 79 id := wParam 80 uploadsMu.Lock() 81 u := uploads[id] 82 delete(uploads, id) 83 uploadsMu.Unlock() 84 85 dc, err := win32.GetDC(hwnd) 86 if err != nil { 87 panic(err) // TODO handle errors 88 } 89 defer win32.ReleaseDC(hwnd, dc) 90 91 u.src.preUpload(true) 92 93 // TODO: adjust if dp is outside dst bounds, or sr is outside src bounds. 94 err = blit(dc, _POINT{int32(u.dp.X), int32(u.dp.Y)}, u.src.hbitmap, &_RECT{ 95 Left: int32(u.sr.Min.X), 96 Top: int32(u.sr.Min.Y), 97 Right: int32(u.sr.Max.X), 98 Bottom: int32(u.sr.Max.Y), 99 }) 100 go func() { 101 u.src.postUpload() 102 close(u.completion) 103 }() 104 if err != nil { 105 panic(err) // TODO handle errors 106 } 107 } 108 109 func (w *windowImpl) Fill(dr image.Rectangle, src color.Color, op draw.Op) { 110 rect := _RECT{ 111 Left: int32(dr.Min.X), 112 Top: int32(dr.Min.Y), 113 Right: int32(dr.Max.X), 114 Bottom: int32(dr.Max.Y), 115 } 116 r, g, b, a := src.RGBA() 117 r >>= 8 118 g >>= 8 119 b >>= 8 120 a >>= 8 121 color := (a << 24) | (r << 16) | (g << 8) | b 122 msg := uint32(msgFillOver) 123 if op == draw.Src { 124 msg = msgFillSrc 125 } 126 // Note: this SendMessage won't return until after the fill 127 // completes, so using &rect is safe. 128 win32.SendMessage(w.hwnd, msg, uintptr(color), uintptr(unsafe.Pointer(&rect))) 129 } 130 131 func (w *windowImpl) Draw(src2dst f64.Aff3, src screen.Texture, sr image.Rectangle, op draw.Op, opts *screen.DrawOptions) { 132 // TODO 133 } 134 135 func (w *windowImpl) Publish() screen.PublishResult { 136 // TODO 137 return screen.PublishResult{} 138 } 139 140 func init() { 141 send := func(hwnd win32.HWND, e interface{}) { 142 theScreen.mu.Lock() 143 w := theScreen.windows[hwnd] 144 theScreen.mu.Unlock() 145 146 w.Send(e) 147 } 148 win32.MouseEvent = func(hwnd win32.HWND, e mouse.Event) { send(hwnd, e) } 149 win32.PaintEvent = func(hwnd win32.HWND, e paint.Event) { send(hwnd, e) } 150 win32.KeyEvent = func(hwnd win32.HWND, e key.Event) { send(hwnd, e) } 151 win32.LifecycleEvent = lifecycleEvent 152 win32.SizeEvent = sizeEvent 153 } 154 155 func lifecycleEvent(hwnd win32.HWND, to lifecycle.Stage) { 156 theScreen.mu.Lock() 157 w := theScreen.windows[hwnd] 158 theScreen.mu.Unlock() 159 160 if w.lifecycleStage == to { 161 return 162 } 163 w.Send(lifecycle.Event{ 164 From: w.lifecycleStage, 165 To: to, 166 }) 167 w.lifecycleStage = to 168 } 169 170 func sizeEvent(hwnd win32.HWND, e size.Event) { 171 theScreen.mu.Lock() 172 w := theScreen.windows[hwnd] 173 theScreen.mu.Unlock() 174 175 w.Send(e) 176 177 if e != w.sz { 178 w.sz = e 179 w.Send(paint.Event{}) 180 } 181 }