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  */