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  }