shiny: add window title support
Titles are UTF-8 compatible on all platforms; drivers
default to an empty string.
Change-Id: I4cf1a16ceb4e9641b2e1fc78dcff0501aac7dedb
Reviewed-on: https://go-review.googlesource.com/37200
Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/shiny/driver/gldriver/cocoa.go b/shiny/driver/gldriver/cocoa.go
index b089c64..c41ec3c 100644
--- a/shiny/driver/gldriver/cocoa.go
+++ b/shiny/driver/gldriver/cocoa.go
@@ -16,12 +16,13 @@
#import <Cocoa/Cocoa.h>
#include <pthread.h>
#include <stdint.h>
+#include <stdlib.h>
void startDriver();
void stopDriver();
void makeCurrentContext(uintptr_t ctx);
void flushContext(uintptr_t ctx);
-uintptr_t doNewWindow(int width, int height);
+uintptr_t doNewWindow(int width, int height, char* title);
void doShowWindow(uintptr_t id);
void doCloseWindow(uintptr_t id);
uint64_t threadID();
@@ -33,6 +34,7 @@
"fmt"
"log"
"runtime"
+ "unsafe"
"golang.org/x/exp/shiny/driver/internal/lifecycler"
"golang.org/x/exp/shiny/screen"
@@ -62,7 +64,15 @@
func newWindow(opts *screen.NewWindowOptions) (uintptr, error) {
width, height := optsSize(opts)
- return uintptr(C.doNewWindow(C.int(width), C.int(height))), nil
+
+ var title string
+ if opts != nil {
+ title = opts.Title
+ }
+ titlePtr := C.CString(title)
+ defer C.free(unsafe.Pointer(titlePtr))
+
+ return uintptr(C.doNewWindow(C.int(width), C.int(height), titlePtr)), nil
}
func initWindow(w *windowImpl) {
diff --git a/shiny/driver/gldriver/cocoa.m b/shiny/driver/gldriver/cocoa.m
index 8da18f1..e8e863e 100644
--- a/shiny/driver/gldriver/cocoa.m
+++ b/shiny/driver/gldriver/cocoa.m
@@ -241,7 +241,7 @@
}
@end
-uintptr_t doNewWindow(int width, int height) {
+uintptr_t doNewWindow(int width, int height, char* title) {
NSScreen *screen = [NSScreen mainScreen];
double w = (double)width / [screen backingScaleFactor];
double h = (double)height / [screen backingScaleFactor];
@@ -254,7 +254,7 @@
[NSApp setMainMenu:menuBar];
id menu = [NSMenu new];
- NSString* name = [[NSProcessInfo processInfo] processName];
+ NSString* name = [[NSString alloc] initWithUTF8String:title];
id hideMenuItem = [[NSMenuItem alloc] initWithTitle:@"Hide"
action:@selector(hide:) keyEquivalent:@"h"];
diff --git a/shiny/driver/gldriver/x11.c b/shiny/driver/gldriver/x11.c
index 58ca910..11d7084 100644
--- a/shiny/driver/gldriver/x11.c
+++ b/shiny/driver/gldriver/x11.c
@@ -8,10 +8,14 @@
#include <EGL/egl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+Atom utf8_string;
Atom wm_delete_window;
+Atom wm_name;
Atom wm_protocols;
Atom wm_take_focus;
+
EGLConfig e_config;
EGLContext e_ctx;
EGLDisplay e_dpy;
@@ -127,9 +131,11 @@
exit(1);
}
+ utf8_string = XInternAtom(x_dpy, "UTF8_STRING", False);
wm_delete_window = XInternAtom(x_dpy, "WM_DELETE_WINDOW", False);
+ wm_name = XInternAtom(x_dpy, "WM_NAME", False);
wm_protocols = XInternAtom(x_dpy, "WM_PROTOCOLS", False);
- wm_take_focus= XInternAtom(x_dpy, "WM_TAKE_FOCUS", False);
+ wm_take_focus = XInternAtom(x_dpy, "WM_TAKE_FOCUS", False);
const int key_lo = 8;
const int key_hi = 255;
@@ -225,7 +231,7 @@
}
uintptr_t
-doNewWindow(int width, int height) {
+doNewWindow(int width, int height, char* title) {
XSetWindowAttributes attr;
attr.colormap = x_colormap;
attr.event_mask =
@@ -253,7 +259,9 @@
atoms[1] = wm_take_focus;
XSetWMProtocols(x_dpy, win, atoms, 2);
- XSetStandardProperties(x_dpy, win, "App", "App", None, (char **)NULL, 0, &sizehints);
+ XSetStandardProperties(x_dpy, win, "", "App", None, (char **)NULL, 0, &sizehints);
+ XChangeProperty(x_dpy, win, wm_name, utf8_string, 8, PropModeReplace, title, strlen(title));
+
return win;
}
diff --git a/shiny/driver/gldriver/x11.go b/shiny/driver/gldriver/x11.go
index 03f68e6..0985dd7 100644
--- a/shiny/driver/gldriver/x11.go
+++ b/shiny/driver/gldriver/x11.go
@@ -11,6 +11,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include <stdlib.h>
char *eglGetErrorStr();
void startDriver();
@@ -18,7 +19,7 @@
void makeCurrent(uintptr_t ctx);
void swapBuffers(uintptr_t ctx);
void doCloseWindow(uintptr_t id);
-uintptr_t doNewWindow(int width, int height);
+uintptr_t doNewWindow(int width, int height, char* title);
uintptr_t doShowWindow(uintptr_t id);
uintptr_t surfaceCreate();
*/
@@ -27,6 +28,7 @@
"errors"
"runtime"
"time"
+ "unsafe"
"golang.org/x/exp/shiny/driver/internal/x11key"
"golang.org/x/exp/shiny/screen"
@@ -50,10 +52,18 @@
func newWindow(opts *screen.NewWindowOptions) (uintptr, error) {
width, height := optsSize(opts)
+
+ var title string
+ if opts != nil {
+ title = opts.Title
+ }
+ titlePtr := C.CString(title)
+ defer C.free(unsafe.Pointer(titlePtr))
+
retc := make(chan uintptr)
uic <- uiClosure{
f: func() uintptr {
- return uintptr(C.doNewWindow(C.int(width), C.int(height)))
+ return uintptr(C.doNewWindow(C.int(width), C.int(height), titlePtr))
},
retc: retc,
}
diff --git a/shiny/driver/internal/win32/win32.go b/shiny/driver/internal/win32/win32.go
index 78895bd..151d198 100644
--- a/shiny/driver/internal/win32/win32.go
+++ b/shiny/driver/internal/win32/win32.go
@@ -66,7 +66,11 @@
if err != nil {
return 0, err
}
- title, err := syscall.UTF16PtrFromString("Shiny Window")
+ var title string
+ if opts != nil {
+ title = opts.Title
+ }
+ windowTitle, err := syscall.UTF16PtrFromString(title)
if err != nil {
return 0, err
}
@@ -80,7 +84,7 @@
}
}
hwnd, err := _CreateWindowEx(0,
- wcname, title,
+ wcname, windowTitle,
_WS_OVERLAPPEDWINDOW,
_CW_USEDEFAULT, _CW_USEDEFAULT,
int32(w), int32(h),
diff --git a/shiny/driver/x11driver/screen.go b/shiny/driver/x11driver/screen.go
index a9208c5..2f9cc71 100644
--- a/shiny/driver/x11driver/screen.go
+++ b/shiny/driver/x11driver/screen.go
@@ -33,6 +33,7 @@
xsi *xproto.ScreenInfo
keysyms x11key.KeysymTable
+ atomUTF8String xproto.Atom
atomWMDeleteWindow xproto.Atom
atomWMProtocols xproto.Atom
atomWMTakeFocus xproto.Atom
@@ -421,6 +422,13 @@
},
)
s.setProperty(xw, s.atomWMProtocols, s.atomWMDeleteWindow, s.atomWMTakeFocus)
+
+ var title []byte
+ if opts != nil {
+ title = []byte(opts.Title)
+ }
+ xproto.ChangeProperty(s.xc, xproto.PropModeReplace, xw, xproto.AtomWmName, s.atomUTF8String, 8, uint32(len(title)), title)
+
xproto.CreateGC(s.xc, xg, xproto.Drawable(xw), 0, nil)
render.CreatePicture(s.xc, xp, xproto.Drawable(xw), pictformat, 0, nil)
xproto.MapWindow(s.xc, xw)
@@ -429,6 +437,10 @@
}
func (s *screenImpl) initAtoms() (err error) {
+ s.atomUTF8String, err = s.internAtom("UTF8_STRING")
+ if err != nil {
+ return err
+ }
s.atomWMDeleteWindow, err = s.internAtom("WM_DELETE_WINDOW")
if err != nil {
return err
diff --git a/shiny/screen/screen.go b/shiny/screen/screen.go
index c4b326b..d3c7d7b 100644
--- a/shiny/screen/screen.go
+++ b/shiny/screen/screen.go
@@ -232,7 +232,10 @@
// zero value dimension.
Width, Height int
- // TODO: fullscreen, title, icon, cursorHidden?
+ // Title specifies the window title.
+ Title string
+
+ // TODO: fullscreen, icon, cursorHidden?
}
// Uploader is something you can upload a Buffer to.