github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/exp/shiny/driver/windriver/doc.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 // Package windriver provides the Windows driver for accessing a screen. 6 package windriver 7 8 /* 9 Implementation Details 10 11 On Windows, UI can run on any thread, but any windows created 12 on a thread must only be manipulated from that thread. You can send 13 "window messages" to any window; when you send a window 14 message to a window owned by another thread, Windows will 15 temporarily switch to that thread to dispatch the message. As such, 16 windows serve as the communication endpoints between threads 17 on Windows. In addition, each thread that hosts UI must handle 18 incoming window messages from the OS through a "message pump". 19 These messages include paint events and input events. 20 21 windriver designates the thread that calls Main as the UI thread. 22 It locks this thread, creates a special window to handle screen.Screen 23 calls, runs the function passed to Main on another goroutine, and 24 runs a message pump. 25 26 The window that handles screen.Screen functions is currently called 27 the "utility window". A better name can be chosen later. This window 28 handles creating screen.Windows/Buffers/Textures. As such, all shiny 29 Windows are owned by a single thread. 30 31 Each function in windriver, be it on screen.Screen or screen.Window, 32 is translated into a window message and sent to a window, namely 33 the utility window and the screen.Window window, respectively. 34 This is how windriver remains thread-safe. 35 36 (TODO(andlabs): actually move per-window messages to the window itself) 37 38 Presently, the actual Windows API work is implemented in C. This is 39 to encapsulate Windows's data structures, ensure properly handling 40 signed -> unsigned conversions in constants, handle pointer casts 41 cleanly, and properly handle the "last error", which I will describe 42 later. 43 44 Here is a demonstration of all of the above. When you call 45 screen.NewWindow(opts), the Go code calls the C function 46 createWindow, which is implemented as something similar to 47 48 HRESULT createWindow(newWindowOpts *opts, HWND *phwnd) { 49 return (HRESULT) SendMessageW(utilityWindow, 50 msgCreateWindow, 51 (WPARAM) opts, 52 (LPARAM) phwnd); 53 } 54 55 HRESULT is another type for errors in Windows; I will again describe 56 this later. This function tells the utility window to make a new window, 57 using the given options, storing the window's OS handle in phwnd, and 58 returning any error directly to us through SendMessageW. 59 60 This code is running on another goroutine, which will definitely be 61 run on another OS thread. As such, Windows will switch to the UI 62 thread to dispatch this new window message. The code for the 63 implementation of the utility window (called a "window procedure") 64 contains something like this: 65 66 case msgCreateWindow: 67 return utilCreateWindow((newWindowOpts *) wParam, 68 (HWND *) lParam); 69 70 and the utilCreateWindow function does the actual work: 71 72 LRESULT utilCreateWindow(newWindowOpts *opts, HWND *phwnd) { 73 *phwnd = CreateWindowExW(...); 74 if (*phwnd == NULL) { 75 return lastErrorAsLRESULT(); 76 } 77 return lS_OK; 78 } 79 80 When this returns, Windows switches back to the previous thread, 81 which can now use the window handle and error value. 82 83 Older Windows API functions return a Boolean flag to indicate if they 84 succeeded or failed, storing the actual reason for failure in what is 85 called the "last error". This is NOT contractual; functions are free to 86 fail without setting the last error, or free to clear the last error on 87 success. 88 89 To simplify error reporting, we instead convert all last errors to the 90 newer HRESULT error code system. The rules are simple: if the 91 function succeeded, we return the standard success code, S_OK. 92 If the function failed, we get the last error. If it's zero (no error), 93 we return the special value E_FAIL. Otherwise, we convert the last 94 error to an HRESULT (this is a well-defined operation that we can 95 reverse later when we're ready to report the error to the user). 96 This is all done by the C lastErrorToHRESULT function. Error 97 reporting on the Go side is handled by th winerror function. 98 99 Because window messages return LRESULTs, not HRESULTs, 100 the lastErrorToLRESULT and lS_OK macros are provided, which 101 automatically insert the necessary casts. An LRESULT (which is 102 pointer-sized) will always be either the same size as or larger than 103 an HRESULT (which is strictly 32 bits wide). 104 */