diff --git a/shiny/driver/gldriver/cocoa.go b/shiny/driver/gldriver/cocoa.go
index e13ac8027..edd8d101e 100644
--- a/shiny/driver/gldriver/cocoa.go
+++ b/shiny/driver/gldriver/cocoa.go
@@ -22,6 +22,7 @@ void stopDriver();
 void makeCurrentContext(uintptr_t ctx);
 void flushContext(uintptr_t ctx);
 uintptr_t doNewWindow(int width, int height, char* title);
+void doSetTitle(uintptr_t id, char* title);
 void doShowWindow(uintptr_t id);
 void doCloseWindow(uintptr_t id);
 uint64_t threadID();
@@ -81,6 +82,13 @@ func showWindow(w *windowImpl) {
 	C.doShowWindow(C.uintptr_t(w.id))
 }
 
+func setTitle(id uintptr, title string) {
+	ctitle := C.CString(title)
+	defer C.free(unsafe.Pointer(ctitle))
+
+	C.doSetTitle(C.uintptr_t(id), ctitle)
+}
+
 //export preparedOpenGL
 func preparedOpenGL(id, ctx, vba uintptr) {
 	theScreen.mu.Lock()
diff --git a/shiny/driver/gldriver/cocoa.m b/shiny/driver/gldriver/cocoa.m
index 2c8fd8376..89855246d 100644
--- a/shiny/driver/gldriver/cocoa.m
+++ b/shiny/driver/gldriver/cocoa.m
@@ -302,6 +302,14 @@ uintptr_t doNewWindow(int width, int height, char* title) {
 	return (uintptr_t)view;
 }
 
+void doSetTitle(uintptr_t viewID, char* title) {
+	ScreenGLView* view = (ScreenGLView*)viewID;
+	NSString* name = [[NSString alloc] initWithUTF8String:title];
+	dispatch_async(dispatch_get_main_queue(), ^{
+		[view.window setTitle:name];
+	});
+}
+
 void doShowWindow(uintptr_t viewID) {
 	ScreenGLView* view = (ScreenGLView*)viewID;
 	dispatch_async(dispatch_get_main_queue(), ^{
diff --git a/shiny/driver/gldriver/other.go b/shiny/driver/gldriver/other.go
index 0a0442545..49132814f 100644
--- a/shiny/driver/gldriver/other.go
+++ b/shiny/driver/gldriver/other.go
@@ -24,10 +24,11 @@ var errUnsupported = fmt.Errorf("gldriver: unsupported GOOS/GOARCH %s/%s or cgo
 
 func newWindow(opts *screen.NewWindowOptions) (uintptr, error) { return 0, errUnsupported }
 
-func initWindow(id *windowImpl) {}
-func showWindow(id *windowImpl) {}
-func closeWindow(id uintptr)    {}
-func drawLoop(w *windowImpl)    {}
+func initWindow(id *windowImpl)         {}
+func showWindow(id *windowImpl)         {}
+func closeWindow(id uintptr)            {}
+func drawLoop(w *windowImpl)            {}
+func setTitle(id uintptr, title string) {}
 
 func surfaceCreate() error             { return errUnsupported }
 func main(f func(screen.Screen)) error { return errUnsupported }
diff --git a/shiny/driver/gldriver/win32.go b/shiny/driver/gldriver/win32.go
index 8ece242f5..d019ac847 100755
--- a/shiny/driver/gldriver/win32.go
+++ b/shiny/driver/gldriver/win32.go
@@ -89,6 +89,10 @@ func showWindow(w *windowImpl) {
 
 func closeWindow(id uintptr) {} // TODO
 
+func setTitle(id uintptr, title string) {
+	_ = win32.SetWindowTitle(syscall.Handle(id), title)
+}
+
 func drawLoop(w *windowImpl) {
 	runtime.LockOSThread()
 
diff --git a/shiny/driver/gldriver/window.go b/shiny/driver/gldriver/window.go
index 82baf2c2c..08b3f6507 100644
--- a/shiny/driver/gldriver/window.go
+++ b/shiny/driver/gldriver/window.go
@@ -387,3 +387,7 @@ func (w *windowImpl) Publish() screen.PublishResult {
 
 	return res
 }
+
+func (w *windowImpl) SetTitle(title string) {
+	setTitle(w.id, title)
+}
diff --git a/shiny/driver/gldriver/x11.c b/shiny/driver/gldriver/x11.c
index dff6d2d64..9909ba30d 100644
--- a/shiny/driver/gldriver/x11.c
+++ b/shiny/driver/gldriver/x11.c
@@ -231,6 +231,12 @@ doCloseWindow(uintptr_t id) {
 	XDestroyWindow(x_dpy, win);
 }
 
+void
+doSetTitle(uintptr_t id, char* title, int title_len) {
+	Window win = (Window)(id);
+	XChangeProperty(x_dpy, win, net_wm_name, utf8_string, 8, PropModeReplace, title, title_len);
+}
+
 uintptr_t
 doNewWindow(int width, int height, char* title, int title_len) {
 	XSetWindowAttributes attr;
diff --git a/shiny/driver/gldriver/x11.go b/shiny/driver/gldriver/x11.go
index 4847e85b2..74f922803 100644
--- a/shiny/driver/gldriver/x11.go
+++ b/shiny/driver/gldriver/x11.go
@@ -23,6 +23,7 @@ void processEvents();
 void makeCurrent(uintptr_t ctx);
 void swapBuffers(uintptr_t ctx);
 void doCloseWindow(uintptr_t id);
+void doSetTitle(uintptr_t id, char* title, int title_len);
 uintptr_t doNewWindow(int width, int height, char* title, int title_len);
 uintptr_t doShowWindow(uintptr_t id);
 uintptr_t surfaceCreate();
@@ -98,6 +99,21 @@ func closeWindow(id uintptr) {
 	}
 }
 
+func setTitle(id uintptr, title string) {
+	ctitle := C.CString(title)
+	defer C.free(unsafe.Pointer(ctitle))
+
+	retc := make(chan uintptr)
+	uic <- uiClosure{
+		f: func() uintptr {
+			C.doSetTitle(C.uintptr_t(id), ctitle, C.int(len(title)))
+			return 0
+		},
+		retc: retc,
+	}
+	<-retc
+}
+
 func drawLoop(w *windowImpl) {
 	glcontextc <- w.ctx.(uintptr)
 	go func() {
diff --git a/shiny/driver/internal/win32/syscall_windows.go b/shiny/driver/internal/win32/syscall_windows.go
index d71536d6b..82e3e88d7 100644
--- a/shiny/driver/internal/win32/syscall_windows.go
+++ b/shiny/driver/internal/win32/syscall_windows.go
@@ -169,17 +169,18 @@ func _HIWORD(l uintptr) uint16 {
 //sys	_DispatchMessage(msg *_MSG) (ret int32) = user32.DispatchMessageW
 //sys	_GetClientRect(hwnd syscall.Handle, rect *_RECT) (err error) = user32.GetClientRect
 //sys	_GetWindowRect(hwnd syscall.Handle, rect *_RECT) (err error) = user32.GetWindowRect
-//sys   _GetKeyboardLayout(threadID uint32) (locale syscall.Handle) = user32.GetKeyboardLayout
-//sys   _GetKeyboardState(lpKeyState *byte) (err error) = user32.GetKeyboardState
+//sys	_GetKeyboardLayout(threadID uint32) (locale syscall.Handle) = user32.GetKeyboardLayout
+//sys	_GetKeyboardState(lpKeyState *byte) (err error) = user32.GetKeyboardState
 //sys	_GetKeyState(virtkey int32) (keystatus int16) = user32.GetKeyState
 //sys	_GetMessage(msg *_MSG, hwnd syscall.Handle, msgfiltermin uint32, msgfiltermax uint32) (ret int32, err error) [failretval==-1] = user32.GetMessageW
 //sys	_LoadCursor(hInstance syscall.Handle, cursorName uintptr) (cursor syscall.Handle, err error) = user32.LoadCursorW
 //sys	_LoadIcon(hInstance syscall.Handle, iconName uintptr) (icon syscall.Handle, err error) = user32.LoadIconW
 //sys	_MoveWindow(hwnd syscall.Handle, x int32, y int32, w int32, h int32, repaint bool) (err error) = user32.MoveWindow
 //sys	_PostMessage(hwnd syscall.Handle, uMsg uint32, wParam uintptr, lParam uintptr) (lResult bool) = user32.PostMessageW
-//sys   _PostQuitMessage(exitCode int32) = user32.PostQuitMessage
+//sys	_PostQuitMessage(exitCode int32) = user32.PostQuitMessage
 //sys	_RegisterClass(wc *_WNDCLASS) (atom uint16, err error) = user32.RegisterClassW
 //sys	_ShowWindow(hwnd syscall.Handle, cmdshow int32) (wasvisible bool) = user32.ShowWindow
+//sys	_SetWindowTextW(hwnd syscall.Handle, lpString *uint16) (err error) = user32.SetWindowTextW
 //sys	_ScreenToClient(hwnd syscall.Handle, lpPoint *_POINT) (ok bool) = user32.ScreenToClient
 //sys   _ToUnicodeEx(wVirtKey uint32, wScanCode uint32, lpKeyState *byte, pwszBuff *uint16, cchBuff int32, wFlags uint32, dwhkl syscall.Handle) (ret int32) = user32.ToUnicodeEx
 //sys	_TranslateMessage(msg *_MSG) (done bool) = user32.TranslateMessage
diff --git a/shiny/driver/internal/win32/win32.go b/shiny/driver/internal/win32/win32.go
index 22a601395..359235ec5 100644
--- a/shiny/driver/internal/win32/win32.go
+++ b/shiny/driver/internal/win32/win32.go
@@ -175,6 +175,15 @@ func sendClose(hwnd syscall.Handle, uMsg uint32, wParam, lParam uintptr) (lResul
 	return _DefWindowProc(hwnd, uMsg, wParam, lParam)
 }
 
+func SetWindowTitle(hwnd syscall.Handle, title string) error {
+	ctitle, err := syscall.UTF16PtrFromString(title)
+	if err != nil {
+		return err
+	}
+
+	return _SetWindowTextW(hwnd, ctitle)
+}
+
 func sendMouseEvent(hwnd syscall.Handle, uMsg uint32, wParam, lParam uintptr) (lResult uintptr) {
 	e := mouse.Event{
 		X:         float32(_GET_X_LPARAM(lParam)),
diff --git a/shiny/driver/internal/win32/zsyscall_windows.go b/shiny/driver/internal/win32/zsyscall_windows.go
index 26999f652..424259910 100644
--- a/shiny/driver/internal/win32/zsyscall_windows.go
+++ b/shiny/driver/internal/win32/zsyscall_windows.go
@@ -1,4 +1,4 @@
-// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+// Code generated by 'go generate'; DO NOT EDIT.
 
 package win32
 
@@ -19,6 +19,7 @@ const (
 
 var (
 	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+	errERROR_EINVAL     error = syscall.EINVAL
 )
 
 // errnoErr returns common boxed Errno values, to prevent
@@ -26,7 +27,7 @@ var (
 func errnoErr(e syscall.Errno) error {
 	switch e {
 	case 0:
-		return nil
+		return errERROR_EINVAL
 	case errnoERROR_IO_PENDING:
 		return errERROR_IO_PENDING
 	}
@@ -39,72 +40,38 @@ func errnoErr(e syscall.Errno) error {
 var (
 	moduser32 = windows.NewLazySystemDLL("user32.dll")
 
-	procGetDC             = moduser32.NewProc("GetDC")
-	procReleaseDC         = moduser32.NewProc("ReleaseDC")
-	procSendMessageW      = moduser32.NewProc("SendMessageW")
 	procCreateWindowExW   = moduser32.NewProc("CreateWindowExW")
 	procDefWindowProcW    = moduser32.NewProc("DefWindowProcW")
 	procDestroyWindow     = moduser32.NewProc("DestroyWindow")
 	procDispatchMessageW  = moduser32.NewProc("DispatchMessageW")
 	procGetClientRect     = moduser32.NewProc("GetClientRect")
-	procGetWindowRect     = moduser32.NewProc("GetWindowRect")
+	procGetDC             = moduser32.NewProc("GetDC")
+	procGetKeyState       = moduser32.NewProc("GetKeyState")
 	procGetKeyboardLayout = moduser32.NewProc("GetKeyboardLayout")
 	procGetKeyboardState  = moduser32.NewProc("GetKeyboardState")
-	procGetKeyState       = moduser32.NewProc("GetKeyState")
 	procGetMessageW       = moduser32.NewProc("GetMessageW")
+	procGetWindowRect     = moduser32.NewProc("GetWindowRect")
 	procLoadCursorW       = moduser32.NewProc("LoadCursorW")
 	procLoadIconW         = moduser32.NewProc("LoadIconW")
 	procMoveWindow        = moduser32.NewProc("MoveWindow")
 	procPostMessageW      = moduser32.NewProc("PostMessageW")
 	procPostQuitMessage   = moduser32.NewProc("PostQuitMessage")
 	procRegisterClassW    = moduser32.NewProc("RegisterClassW")
-	procShowWindow        = moduser32.NewProc("ShowWindow")
+	procReleaseDC         = moduser32.NewProc("ReleaseDC")
 	procScreenToClient    = moduser32.NewProc("ScreenToClient")
+	procSendMessageW      = moduser32.NewProc("SendMessageW")
+	procSetWindowTextW    = moduser32.NewProc("SetWindowTextW")
+	procShowWindow        = moduser32.NewProc("ShowWindow")
 	procToUnicodeEx       = moduser32.NewProc("ToUnicodeEx")
 	procTranslateMessage  = moduser32.NewProc("TranslateMessage")
 	procUnregisterClassW  = moduser32.NewProc("UnregisterClassW")
 )
 
-func GetDC(hwnd syscall.Handle) (dc syscall.Handle, err error) {
-	r0, _, e1 := syscall.Syscall(procGetDC.Addr(), 1, uintptr(hwnd), 0, 0)
-	dc = syscall.Handle(r0)
-	if dc == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
-	}
-	return
-}
-
-func ReleaseDC(hwnd syscall.Handle, dc syscall.Handle) (err error) {
-	r1, _, e1 := syscall.Syscall(procReleaseDC.Addr(), 2, uintptr(hwnd), uintptr(dc), 0)
-	if r1 == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
-	}
-	return
-}
-
-func sendMessage(hwnd syscall.Handle, uMsg uint32, wParam uintptr, lParam uintptr) (lResult uintptr) {
-	r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(hwnd), uintptr(uMsg), uintptr(wParam), uintptr(lParam), 0, 0)
-	lResult = uintptr(r0)
-	return
-}
-
 func _CreateWindowEx(exstyle uint32, className *uint16, windowText *uint16, style uint32, x int32, y int32, width int32, height int32, parent syscall.Handle, menu syscall.Handle, hInstance syscall.Handle, lpParam uintptr) (hwnd syscall.Handle, err error) {
 	r0, _, e1 := syscall.Syscall12(procCreateWindowExW.Addr(), 12, uintptr(exstyle), uintptr(unsafe.Pointer(className)), uintptr(unsafe.Pointer(windowText)), uintptr(style), uintptr(x), uintptr(y), uintptr(width), uintptr(height), uintptr(parent), uintptr(menu), uintptr(hInstance), uintptr(lpParam))
 	hwnd = syscall.Handle(r0)
 	if hwnd == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -118,11 +85,7 @@ func _DefWindowProc(hwnd syscall.Handle, uMsg uint32, wParam uintptr, lParam uin
 func _DestroyWindow(hwnd syscall.Handle) (err error) {
 	r1, _, e1 := syscall.Syscall(procDestroyWindow.Addr(), 1, uintptr(hwnd), 0, 0)
 	if r1 == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -136,27 +99,26 @@ func _DispatchMessage(msg *_MSG) (ret int32) {
 func _GetClientRect(hwnd syscall.Handle, rect *_RECT) (err error) {
 	r1, _, e1 := syscall.Syscall(procGetClientRect.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(rect)), 0)
 	if r1 == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
 
-func _GetWindowRect(hwnd syscall.Handle, rect *_RECT) (err error) {
-	r1, _, e1 := syscall.Syscall(procGetWindowRect.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(rect)), 0)
-	if r1 == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+func GetDC(hwnd syscall.Handle) (dc syscall.Handle, err error) {
+	r0, _, e1 := syscall.Syscall(procGetDC.Addr(), 1, uintptr(hwnd), 0, 0)
+	dc = syscall.Handle(r0)
+	if dc == 0 {
+		err = errnoErr(e1)
 	}
 	return
 }
 
+func _GetKeyState(virtkey int32) (keystatus int16) {
+	r0, _, _ := syscall.Syscall(procGetKeyState.Addr(), 1, uintptr(virtkey), 0, 0)
+	keystatus = int16(r0)
+	return
+}
+
 func _GetKeyboardLayout(threadID uint32) (locale syscall.Handle) {
 	r0, _, _ := syscall.Syscall(procGetKeyboardLayout.Addr(), 1, uintptr(threadID), 0, 0)
 	locale = syscall.Handle(r0)
@@ -166,30 +128,24 @@ func _GetKeyboardLayout(threadID uint32) (locale syscall.Handle) {
 func _GetKeyboardState(lpKeyState *byte) (err error) {
 	r1, _, e1 := syscall.Syscall(procGetKeyboardState.Addr(), 1, uintptr(unsafe.Pointer(lpKeyState)), 0, 0)
 	if r1 == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
 
-func _GetKeyState(virtkey int32) (keystatus int16) {
-	r0, _, _ := syscall.Syscall(procGetKeyState.Addr(), 1, uintptr(virtkey), 0, 0)
-	keystatus = int16(r0)
-	return
-}
-
 func _GetMessage(msg *_MSG, hwnd syscall.Handle, msgfiltermin uint32, msgfiltermax uint32) (ret int32, err error) {
 	r0, _, e1 := syscall.Syscall6(procGetMessageW.Addr(), 4, uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(msgfiltermin), uintptr(msgfiltermax), 0, 0)
 	ret = int32(r0)
 	if ret == -1 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func _GetWindowRect(hwnd syscall.Handle, rect *_RECT) (err error) {
+	r1, _, e1 := syscall.Syscall(procGetWindowRect.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(rect)), 0)
+	if r1 == 0 {
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -198,11 +154,7 @@ func _LoadCursor(hInstance syscall.Handle, cursorName uintptr) (cursor syscall.H
 	r0, _, e1 := syscall.Syscall(procLoadCursorW.Addr(), 2, uintptr(hInstance), uintptr(cursorName), 0)
 	cursor = syscall.Handle(r0)
 	if cursor == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -211,11 +163,7 @@ func _LoadIcon(hInstance syscall.Handle, iconName uintptr) (icon syscall.Handle,
 	r0, _, e1 := syscall.Syscall(procLoadIconW.Addr(), 2, uintptr(hInstance), uintptr(iconName), 0)
 	icon = syscall.Handle(r0)
 	if icon == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -224,16 +172,10 @@ func _MoveWindow(hwnd syscall.Handle, x int32, y int32, w int32, h int32, repain
 	var _p0 uint32
 	if repaint {
 		_p0 = 1
-	} else {
-		_p0 = 0
 	}
 	r1, _, e1 := syscall.Syscall6(procMoveWindow.Addr(), 6, uintptr(hwnd), uintptr(x), uintptr(y), uintptr(w), uintptr(h), uintptr(_p0))
 	if r1 == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -253,18 +195,16 @@ func _RegisterClass(wc *_WNDCLASS) (atom uint16, err error) {
 	r0, _, e1 := syscall.Syscall(procRegisterClassW.Addr(), 1, uintptr(unsafe.Pointer(wc)), 0, 0)
 	atom = uint16(r0)
 	if atom == 0 {
-		if e1 != 0 {
-			err = errnoErr(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
 
-func _ShowWindow(hwnd syscall.Handle, cmdshow int32) (wasvisible bool) {
-	r0, _, _ := syscall.Syscall(procShowWindow.Addr(), 2, uintptr(hwnd), uintptr(cmdshow), 0)
-	wasvisible = r0 != 0
+func ReleaseDC(hwnd syscall.Handle, dc syscall.Handle) (err error) {
+	r1, _, e1 := syscall.Syscall(procReleaseDC.Addr(), 2, uintptr(hwnd), uintptr(dc), 0)
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
 	return
 }
 
@@ -274,6 +214,26 @@ func _ScreenToClient(hwnd syscall.Handle, lpPoint *_POINT) (ok bool) {
 	return
 }
 
+func sendMessage(hwnd syscall.Handle, uMsg uint32, wParam uintptr, lParam uintptr) (lResult uintptr) {
+	r0, _, _ := syscall.Syscall6(procSendMessageW.Addr(), 4, uintptr(hwnd), uintptr(uMsg), uintptr(wParam), uintptr(lParam), 0, 0)
+	lResult = uintptr(r0)
+	return
+}
+
+func _SetWindowTextW(hwnd syscall.Handle, lpString *uint16) (err error) {
+	r1, _, e1 := syscall.Syscall(procSetWindowTextW.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(lpString)), 0)
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func _ShowWindow(hwnd syscall.Handle, cmdshow int32) (wasvisible bool) {
+	r0, _, _ := syscall.Syscall(procShowWindow.Addr(), 2, uintptr(hwnd), uintptr(cmdshow), 0)
+	wasvisible = r0 != 0
+	return
+}
+
 func _ToUnicodeEx(wVirtKey uint32, wScanCode uint32, lpKeyState *byte, pwszBuff *uint16, cchBuff int32, wFlags uint32, dwhkl syscall.Handle) (ret int32) {
 	r0, _, _ := syscall.Syscall9(procToUnicodeEx.Addr(), 7, uintptr(wVirtKey), uintptr(wScanCode), uintptr(unsafe.Pointer(lpKeyState)), uintptr(unsafe.Pointer(pwszBuff)), uintptr(cchBuff), uintptr(wFlags), uintptr(dwhkl), 0, 0)
 	ret = int32(r0)
diff --git a/shiny/driver/mtldriver/window.go b/shiny/driver/mtldriver/window.go
index 7bbb837ca..99b34052a 100644
--- a/shiny/driver/mtldriver/window.go
+++ b/shiny/driver/mtldriver/window.go
@@ -95,6 +95,10 @@ func (w *windowImpl) Publish() screen.PublishResult {
 	return screen.PublishResult{}
 }
 
+func (w *windowImpl) SetTitle(title string) {
+	w.window.SetTitle(title)
+}
+
 func (w *windowImpl) Upload(dp image.Point, src screen.Buffer, sr image.Rectangle) {
 	draw.Draw(w.rgba, sr.Sub(sr.Min).Add(dp), src.RGBA(), sr.Min, draw.Src)
 }
diff --git a/shiny/driver/windriver/syscall.go b/shiny/driver/windriver/syscall.go
index e4790328d..265c67695 100644
--- a/shiny/driver/windriver/syscall.go
+++ b/shiny/driver/windriver/syscall.go
@@ -2,6 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
+//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go syscall_windows.go
 
 package windriver
diff --git a/shiny/driver/windriver/window.go b/shiny/driver/windriver/window.go
index 9577f2c69..f987704a0 100644
--- a/shiny/driver/windriver/window.go
+++ b/shiny/driver/windriver/window.go
@@ -171,6 +171,10 @@ func (w *windowImpl) Publish() screen.PublishResult {
 	return screen.PublishResult{}
 }
 
+func (w *windowImpl) SetTitle(title string) {
+	_ = win32.SetWindowTitle(w.hwnd, title)
+}
+
 func init() {
 	send := func(hwnd syscall.Handle, e interface{}) {
 		theScreen.mu.Lock()
diff --git a/shiny/driver/windriver/zsyscall_windows.go b/shiny/driver/windriver/zsyscall_windows.go
index 18047b1cd..f78270146 100644
--- a/shiny/driver/windriver/zsyscall_windows.go
+++ b/shiny/driver/windriver/zsyscall_windows.go
@@ -1,4 +1,4 @@
-// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+// Code generated by 'go generate'; DO NOT EDIT.
 
 package windriver
 
@@ -11,12 +11,37 @@ import (
 
 var _ unsafe.Pointer
 
+// Do the interface allocations only once for common
+// Errno values.
+const (
+	errnoERROR_IO_PENDING = 997
+)
+
+var (
+	errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
+	errERROR_EINVAL     error = syscall.EINVAL
+)
+
+// errnoErr returns common boxed Errno values, to prevent
+// allocations at runtime.
+func errnoErr(e syscall.Errno) error {
+	switch e {
+	case 0:
+		return errERROR_EINVAL
+	case errnoERROR_IO_PENDING:
+		return errERROR_IO_PENDING
+	}
+	// TODO: add more here, after collecting data on the common
+	// error values see on Windows. (perhaps when running
+	// all.bat?)
+	return e
+}
+
 var (
-	modmsimg32 = windows.NewLazySystemDLL("msimg32.dll")
 	modgdi32   = windows.NewLazySystemDLL("gdi32.dll")
+	modmsimg32 = windows.NewLazySystemDLL("msimg32.dll")
 	moduser32  = windows.NewLazySystemDLL("user32.dll")
 
-	procAlphaBlend             = modmsimg32.NewProc("AlphaBlend")
 	procBitBlt                 = modgdi32.NewProc("BitBlt")
 	procCreateCompatibleBitmap = modgdi32.NewProc("CreateCompatibleBitmap")
 	procCreateCompatibleDC     = modgdi32.NewProc("CreateCompatibleDC")
@@ -24,35 +49,20 @@ var (
 	procCreateSolidBrush       = modgdi32.NewProc("CreateSolidBrush")
 	procDeleteDC               = modgdi32.NewProc("DeleteDC")
 	procDeleteObject           = modgdi32.NewProc("DeleteObject")
-	procFillRect               = moduser32.NewProc("FillRect")
+	procGetDeviceCaps          = modgdi32.NewProc("GetDeviceCaps")
 	procModifyWorldTransform   = modgdi32.NewProc("ModifyWorldTransform")
 	procSelectObject           = modgdi32.NewProc("SelectObject")
 	procSetGraphicsMode        = modgdi32.NewProc("SetGraphicsMode")
 	procSetWorldTransform      = modgdi32.NewProc("SetWorldTransform")
 	procStretchBlt             = modgdi32.NewProc("StretchBlt")
-	procGetDeviceCaps          = modgdi32.NewProc("GetDeviceCaps")
+	procAlphaBlend             = modmsimg32.NewProc("AlphaBlend")
+	procFillRect               = moduser32.NewProc("FillRect")
 )
 
-func _AlphaBlend(dcdest syscall.Handle, xoriginDest int32, yoriginDest int32, wDest int32, hDest int32, dcsrc syscall.Handle, xoriginSrc int32, yoriginSrc int32, wsrc int32, hsrc int32, ftn uintptr) (err error) {
-	r1, _, e1 := syscall.Syscall12(procAlphaBlend.Addr(), 11, uintptr(dcdest), uintptr(xoriginDest), uintptr(yoriginDest), uintptr(wDest), uintptr(hDest), uintptr(dcsrc), uintptr(xoriginSrc), uintptr(yoriginSrc), uintptr(wsrc), uintptr(hsrc), uintptr(ftn), 0)
-	if r1 == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
-	}
-	return
-}
-
 func _BitBlt(dcdest syscall.Handle, xdest int32, ydest int32, width int32, height int32, dcsrc syscall.Handle, xsrc int32, ysrc int32, rop uint32) (err error) {
 	r1, _, e1 := syscall.Syscall9(procBitBlt.Addr(), 9, uintptr(dcdest), uintptr(xdest), uintptr(ydest), uintptr(width), uintptr(height), uintptr(dcsrc), uintptr(xsrc), uintptr(ysrc), uintptr(rop))
 	if r1 == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -61,11 +71,7 @@ func _CreateCompatibleBitmap(dc syscall.Handle, width int32, height int32) (bitm
 	r0, _, e1 := syscall.Syscall(procCreateCompatibleBitmap.Addr(), 3, uintptr(dc), uintptr(width), uintptr(height))
 	bitmap = syscall.Handle(r0)
 	if bitmap == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -74,11 +80,7 @@ func _CreateCompatibleDC(dc syscall.Handle) (newdc syscall.Handle, err error) {
 	r0, _, e1 := syscall.Syscall(procCreateCompatibleDC.Addr(), 1, uintptr(dc), 0, 0)
 	newdc = syscall.Handle(r0)
 	if newdc == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -87,11 +89,7 @@ func _CreateDIBSection(dc syscall.Handle, bmi *_BITMAPINFO, usage uint32, bits *
 	r0, _, e1 := syscall.Syscall6(procCreateDIBSection.Addr(), 6, uintptr(dc), uintptr(unsafe.Pointer(bmi)), uintptr(usage), uintptr(unsafe.Pointer(bits)), uintptr(section), uintptr(offset))
 	bitmap = syscall.Handle(r0)
 	if bitmap == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -100,11 +98,7 @@ func _CreateSolidBrush(color _COLORREF) (brush syscall.Handle, err error) {
 	r0, _, e1 := syscall.Syscall(procCreateSolidBrush.Addr(), 1, uintptr(color), 0, 0)
 	brush = syscall.Handle(r0)
 	if brush == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -112,11 +106,7 @@ func _CreateSolidBrush(color _COLORREF) (brush syscall.Handle, err error) {
 func _DeleteDC(dc syscall.Handle) (err error) {
 	r1, _, e1 := syscall.Syscall(procDeleteDC.Addr(), 1, uintptr(dc), 0, 0)
 	if r1 == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,35 +114,21 @@ func _DeleteDC(dc syscall.Handle) (err error) {
 func _DeleteObject(object syscall.Handle) (err error) {
 	r1, _, e1 := syscall.Syscall(procDeleteObject.Addr(), 1, uintptr(object), 0, 0)
 	if r1 == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
 
-func _FillRect(dc syscall.Handle, rc *_RECT, brush syscall.Handle) (err error) {
-	r1, _, e1 := syscall.Syscall(procFillRect.Addr(), 3, uintptr(dc), uintptr(unsafe.Pointer(rc)), uintptr(brush))
-	if r1 == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
-	}
+func _GetDeviceCaps(dc syscall.Handle, index int32) (ret int32) {
+	r0, _, _ := syscall.Syscall(procGetDeviceCaps.Addr(), 2, uintptr(dc), uintptr(index), 0)
+	ret = int32(r0)
 	return
 }
 
 func _ModifyWorldTransform(dc syscall.Handle, x *_XFORM, mode uint32) (err error) {
 	r1, _, e1 := syscall.Syscall(procModifyWorldTransform.Addr(), 3, uintptr(dc), uintptr(unsafe.Pointer(x)), uintptr(mode))
 	if r1 == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -161,11 +137,7 @@ func _SelectObject(dc syscall.Handle, gdiobj syscall.Handle) (newobj syscall.Han
 	r0, _, e1 := syscall.Syscall(procSelectObject.Addr(), 2, uintptr(dc), uintptr(gdiobj), 0)
 	newobj = syscall.Handle(r0)
 	if newobj == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -174,11 +146,7 @@ func _SetGraphicsMode(dc syscall.Handle, mode int32) (oldmode int32, err error)
 	r0, _, e1 := syscall.Syscall(procSetGraphicsMode.Addr(), 2, uintptr(dc), uintptr(mode), 0)
 	oldmode = int32(r0)
 	if oldmode == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -186,11 +154,7 @@ func _SetGraphicsMode(dc syscall.Handle, mode int32) (oldmode int32, err error)
 func _SetWorldTransform(dc syscall.Handle, x *_XFORM) (err error) {
 	r1, _, e1 := syscall.Syscall(procSetWorldTransform.Addr(), 2, uintptr(dc), uintptr(unsafe.Pointer(x)), 0)
 	if r1 == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -198,17 +162,23 @@ func _SetWorldTransform(dc syscall.Handle, x *_XFORM) (err error) {
 func _StretchBlt(dcdest syscall.Handle, xdest int32, ydest int32, wdest int32, hdest int32, dcsrc syscall.Handle, xsrc int32, ysrc int32, wsrc int32, hsrc int32, rop uint32) (err error) {
 	r1, _, e1 := syscall.Syscall12(procStretchBlt.Addr(), 11, uintptr(dcdest), uintptr(xdest), uintptr(ydest), uintptr(wdest), uintptr(hdest), uintptr(dcsrc), uintptr(xsrc), uintptr(ysrc), uintptr(wsrc), uintptr(hsrc), uintptr(rop), 0)
 	if r1 == 0 {
-		if e1 != 0 {
-			err = error(e1)
-		} else {
-			err = syscall.EINVAL
-		}
+		err = errnoErr(e1)
 	}
 	return
 }
 
-func _GetDeviceCaps(dc syscall.Handle, index int32) (ret int32) {
-	r0, _, _ := syscall.Syscall(procGetDeviceCaps.Addr(), 2, uintptr(dc), uintptr(index), 0)
-	ret = int32(r0)
+func _AlphaBlend(dcdest syscall.Handle, xoriginDest int32, yoriginDest int32, wDest int32, hDest int32, dcsrc syscall.Handle, xoriginSrc int32, yoriginSrc int32, wsrc int32, hsrc int32, ftn uintptr) (err error) {
+	r1, _, e1 := syscall.Syscall12(procAlphaBlend.Addr(), 11, uintptr(dcdest), uintptr(xoriginDest), uintptr(yoriginDest), uintptr(wDest), uintptr(hDest), uintptr(dcsrc), uintptr(xoriginSrc), uintptr(yoriginSrc), uintptr(wsrc), uintptr(hsrc), uintptr(ftn), 0)
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func _FillRect(dc syscall.Handle, rc *_RECT, brush syscall.Handle) (err error) {
+	r1, _, e1 := syscall.Syscall(procFillRect.Addr(), 3, uintptr(dc), uintptr(unsafe.Pointer(rc)), uintptr(brush))
+	if r1 == 0 {
+		err = errnoErr(e1)
+	}
 	return
 }
diff --git a/shiny/driver/x11driver/window.go b/shiny/driver/x11driver/window.go
index f77b876e5..0e05d82b9 100644
--- a/shiny/driver/x11driver/window.go
+++ b/shiny/driver/x11driver/window.go
@@ -106,6 +106,10 @@ func (w *windowImpl) Publish() screen.PublishResult {
 	return screen.PublishResult{}
 }
 
+func (w *windowImpl) SetTitle(title string) {
+	xproto.ChangeProperty(w.s.xc, xproto.PropModeReplace, w.xw, w.s.atomNETWMName, w.s.atomUTF8String, 8, uint32(len(title)), []byte(title))
+}
+
 func (w *windowImpl) handleConfigureNotify(ev xproto.ConfigureNotifyEvent) {
 	// TODO: does the order of these lifecycle and size events matter? Should
 	// they really be a single, atomic event?
diff --git a/shiny/screen/screen.go b/shiny/screen/screen.go
index 5d89fe8c2..1dbcd9041 100644
--- a/shiny/screen/screen.go
+++ b/shiny/screen/screen.go
@@ -217,6 +217,9 @@ type Window interface {
 	// Publish flushes any pending Upload and Draw calls to the window, and
 	// swaps the back buffer to the front.
 	Publish() PublishResult
+
+	// SetTitle changes the window's title.
+	SetTitle(title string)
 }
 
 // PublishResult is the result of an Window.Publish call.