forked from joejulian/gio
app: update Window for macOS, X11 and Wayland
Commit #c4f98d3c1eab201419be255fafb139f7e10ad273 added the Minimized and Maximized options for the Windows platform. This change adds those for the remaining desktop platforms. Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
+76
-38
@@ -129,6 +129,16 @@ static void setScreenFrame(CFTypeRef windowRef, CGFloat x, CGFloat y, CGFloat w,
|
||||
[window setFrame:r display:YES];
|
||||
}
|
||||
|
||||
static void hideWindow(CFTypeRef windowRef) {
|
||||
NSWindow* window = (__bridge NSWindow *)windowRef;
|
||||
[window miniaturize:window];
|
||||
}
|
||||
|
||||
static void unhideWindow(CFTypeRef windowRef) {
|
||||
NSWindow* window = (__bridge NSWindow *)windowRef;
|
||||
[window deminiaturize:window];
|
||||
}
|
||||
|
||||
static NSRect getScreenFrame(CFTypeRef windowRef) {
|
||||
NSWindow* window = (__bridge NSWindow *)windowRef;
|
||||
return [[window screen] frame];
|
||||
@@ -252,35 +262,81 @@ func (w *window) Configure(options []Option) {
|
||||
cnf.MinSize = cnf.MinSize.Div(int(screenScale))
|
||||
cnf.MaxSize = cnf.MaxSize.Div(int(screenScale))
|
||||
|
||||
if cnf.Mode != Fullscreen && prev.Size != cnf.Size {
|
||||
w.config.Size = cnf.Size
|
||||
C.setSize(w.window, C.CGFloat(cnf.Size.X), C.CGFloat(cnf.Size.Y))
|
||||
switch cnf.Mode {
|
||||
case Fullscreen:
|
||||
switch prev.Mode {
|
||||
case Fullscreen:
|
||||
case Minimized:
|
||||
C.unhideWindow(w.window)
|
||||
fallthrough
|
||||
default:
|
||||
w.config.Mode = Fullscreen
|
||||
C.toggleFullScreen(w.window)
|
||||
}
|
||||
case Minimized:
|
||||
switch prev.Mode {
|
||||
case Minimized, Fullscreen:
|
||||
default:
|
||||
w.config.Mode = Minimized
|
||||
C.hideWindow(w.window)
|
||||
}
|
||||
case Maximized:
|
||||
switch prev.Mode {
|
||||
case Fullscreen:
|
||||
case Minimized:
|
||||
C.unhideWindow(w.window)
|
||||
fallthrough
|
||||
default:
|
||||
w.config.Mode = Maximized
|
||||
r := C.getScreenFrame(w.window) // the screen size of the window
|
||||
C.setScreenFrame(w.window, C.CGFloat(0), C.CGFloat(0), r.size.width, r.size.height)
|
||||
w.config.Size = image.Pt(int(r.size.width), int(r.size.height))
|
||||
w.setTitle(prev, cnf)
|
||||
}
|
||||
case Windowed:
|
||||
switch prev.Mode {
|
||||
case Fullscreen:
|
||||
w.config.Mode = Windowed
|
||||
C.toggleFullScreen(w.window)
|
||||
case Minimized:
|
||||
w.config.Mode = Windowed
|
||||
C.unhideWindow(w.window)
|
||||
case Maximized:
|
||||
w.config.Mode = Windowed
|
||||
}
|
||||
w.setTitle(prev, cnf)
|
||||
if prev.Size != cnf.Size {
|
||||
w.config.Size = cnf.Size
|
||||
C.setSize(w.window, C.CGFloat(cnf.Size.X), C.CGFloat(cnf.Size.Y))
|
||||
}
|
||||
if prev.MinSize != cnf.MinSize {
|
||||
w.config.MinSize = cnf.MinSize
|
||||
C.setMinSize(w.window, C.CGFloat(cnf.MinSize.X), C.CGFloat(cnf.MinSize.Y))
|
||||
}
|
||||
if prev.MaxSize != cnf.MaxSize {
|
||||
w.config.MaxSize = cnf.MaxSize
|
||||
C.setMaxSize(w.window, C.CGFloat(cnf.MaxSize.X), C.CGFloat(cnf.MaxSize.Y))
|
||||
}
|
||||
if cnf.center {
|
||||
r := C.getScreenFrame(w.window) // the screen size of the window
|
||||
sz := w.config.Size
|
||||
x := (int(r.size.width) - sz.X) / 2
|
||||
y := (int(r.size.height) - sz.Y) / 2
|
||||
C.setScreenFrame(w.window, C.CGFloat(x), C.CGFloat(y), C.CGFloat(sz.X), C.CGFloat(sz.Y))
|
||||
}
|
||||
}
|
||||
if prev.MinSize != cnf.MinSize {
|
||||
w.config.MinSize = cnf.MinSize
|
||||
C.setMinSize(w.window, C.CGFloat(cnf.MinSize.X), C.CGFloat(cnf.MinSize.Y))
|
||||
}
|
||||
if prev.MaxSize != cnf.MaxSize {
|
||||
w.config.MaxSize = cnf.MaxSize
|
||||
C.setMaxSize(w.window, C.CGFloat(cnf.MaxSize.X), C.CGFloat(cnf.MaxSize.Y))
|
||||
if w.config != prev {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) setTitle(prev, cnf Config) {
|
||||
if prev.Title != cnf.Title {
|
||||
w.config.Title = cnf.Title
|
||||
title := C.CString(cnf.Title)
|
||||
defer C.free(unsafe.Pointer(title))
|
||||
C.setTitle(w.window, title)
|
||||
}
|
||||
if prev.Mode != cnf.Mode {
|
||||
switch cnf.Mode {
|
||||
case Windowed, Fullscreen:
|
||||
w.config.Mode = cnf.Mode
|
||||
C.toggleFullScreen(w.window)
|
||||
}
|
||||
}
|
||||
if w.config != prev {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) SetCursor(name pointer.CursorName) {
|
||||
@@ -317,24 +373,6 @@ func (w *window) Close() {
|
||||
C.closeWindow(w.window)
|
||||
}
|
||||
|
||||
// Maximize the window.
|
||||
func (w *window) Maximize() {
|
||||
r := C.getScreenFrame(w.window) // the screen size of the window
|
||||
C.setScreenFrame(w.window, C.CGFloat(0), C.CGFloat(0), r.size.width, r.size.height)
|
||||
}
|
||||
|
||||
// Center the window.
|
||||
func (w *window) Center() {
|
||||
r := C.getScreenFrame(w.window) // the screen size of the window
|
||||
|
||||
screenScale := float32(C.getScreenBackingScale())
|
||||
sz := w.config.Size.Div(int(screenScale))
|
||||
x := (int(r.size.width) - sz.X) / 2
|
||||
y := (int(r.size.height) - sz.Y) / 2
|
||||
|
||||
C.setScreenFrame(w.window, C.CGFloat(x), C.CGFloat(y), C.CGFloat(sz.X), C.CGFloat(sz.Y))
|
||||
}
|
||||
|
||||
func (w *window) setStage(stage system.Stage) {
|
||||
if stage == w.stage {
|
||||
return
|
||||
|
||||
+66
-10
@@ -190,6 +190,7 @@ type window struct {
|
||||
// size is the unscaled window size (unlike config.Size which is scaled).
|
||||
size image.Point
|
||||
config Config
|
||||
wsize image.Point // window config size before going fullscreen
|
||||
|
||||
wakeups chan struct{}
|
||||
}
|
||||
@@ -919,22 +920,77 @@ func (w *window) Configure(options []Option) {
|
||||
prev := w.config
|
||||
cnf := w.config
|
||||
cnf.apply(cfg, options)
|
||||
if prev.Size != cnf.Size {
|
||||
w.size = image.Pt(cnf.Size.X/w.scale, cnf.Size.Y/w.scale)
|
||||
w.config.Size = cnf.Size
|
||||
}
|
||||
if prev.Title != cnf.Title {
|
||||
w.config.Title = cnf.Title
|
||||
title := C.CString(cnf.Title)
|
||||
C.xdg_toplevel_set_title(w.topLvl, title)
|
||||
C.free(unsafe.Pointer(title))
|
||||
|
||||
switch cnf.Mode {
|
||||
case Fullscreen:
|
||||
switch prev.Mode {
|
||||
case Minimized, Fullscreen:
|
||||
default:
|
||||
w.config.Mode = Fullscreen
|
||||
w.wsize = w.config.Size
|
||||
C.xdg_toplevel_set_fullscreen(w.topLvl, nil)
|
||||
}
|
||||
case Minimized:
|
||||
switch prev.Mode {
|
||||
case Minimized, Fullscreen:
|
||||
default:
|
||||
w.config.Mode = Minimized
|
||||
C.xdg_toplevel_set_minimized(w.topLvl)
|
||||
}
|
||||
case Maximized:
|
||||
switch prev.Mode {
|
||||
case Minimized, Fullscreen:
|
||||
default:
|
||||
w.config.Mode = Maximized
|
||||
w.wsize = w.config.Size
|
||||
C.xdg_toplevel_set_maximized(w.topLvl)
|
||||
}
|
||||
case Windowed:
|
||||
switch prev.Mode {
|
||||
case Fullscreen:
|
||||
w.config.Mode = Windowed
|
||||
w.size = w.wsize.Div(w.scale)
|
||||
C.xdg_toplevel_unset_fullscreen(w.topLvl)
|
||||
case Minimized:
|
||||
w.config.Mode = Windowed
|
||||
w.config.Size = w.wsize
|
||||
case Maximized:
|
||||
w.config.Mode = Windowed
|
||||
w.size = w.wsize.Div(w.scale)
|
||||
C.xdg_toplevel_unset_maximized(w.topLvl)
|
||||
}
|
||||
w.setTitle(prev, cnf)
|
||||
if prev.Size != cnf.Size {
|
||||
w.config.Size = cnf.Size
|
||||
w.size = cnf.Size.Div(w.scale)
|
||||
}
|
||||
if prev.MinSize != cnf.MinSize {
|
||||
w.config.MinSize = cnf.MinSize
|
||||
C.xdg_toplevel_set_min_size(w.topLvl, C.int32_t(cnf.MinSize.X), C.int32_t(cnf.MinSize.Y))
|
||||
}
|
||||
if prev.MaxSize != cnf.MaxSize {
|
||||
w.config.MaxSize = cnf.MaxSize
|
||||
C.xdg_toplevel_set_max_size(w.topLvl, C.int32_t(cnf.MaxSize.X), C.int32_t(cnf.MaxSize.Y))
|
||||
}
|
||||
}
|
||||
if w.config != prev {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) Raise() {}
|
||||
func (w *window) setTitle(prev, cnf Config) {
|
||||
if prev.Title != cnf.Title {
|
||||
w.config.Title = cnf.Title
|
||||
title := C.CString(cnf.Title)
|
||||
C.xdg_toplevel_set_title(w.topLvl, title)
|
||||
C.free(unsafe.Pointer(title))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) Raise() {
|
||||
// NB. there is no way for a minimized window to be unminimized.
|
||||
// https://wayland.app/protocols/xdg-shell#xdg_toplevel:request:set_minimized
|
||||
}
|
||||
|
||||
func (w *window) SetCursor(name pointer.CursorName) {
|
||||
ptr := w.disp.seat.pointer
|
||||
|
||||
+1
-1
@@ -571,7 +571,7 @@ func (w *window) Configure(options []Option) {
|
||||
}
|
||||
|
||||
// A config event is sent to the main event loop whenever the configuration is changed
|
||||
if oldConfig.Mode != w.config.Mode || oldConfig.Size != w.config.Size {
|
||||
if oldConfig != w.config {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
+85
-65
@@ -160,27 +160,93 @@ func (w *x11Window) Configure(options []Option) {
|
||||
prev := w.config
|
||||
cnf := w.config
|
||||
cnf.apply(w.metric, options)
|
||||
if prev.MinSize != cnf.MinSize {
|
||||
w.config.MinSize = cnf.MinSize
|
||||
shints.min_width = C.int(cnf.MinSize.X)
|
||||
shints.min_height = C.int(cnf.MinSize.Y)
|
||||
shints.flags = C.PMinSize
|
||||
}
|
||||
if prev.MaxSize != cnf.MaxSize {
|
||||
w.config.MaxSize = cnf.MaxSize
|
||||
shints.max_width = C.int(cnf.MaxSize.X)
|
||||
shints.max_height = C.int(cnf.MaxSize.Y)
|
||||
shints.flags = shints.flags | C.PMaxSize
|
||||
}
|
||||
if shints.flags != 0 {
|
||||
C.XSetWMNormalHints(w.x, w.xw, &shints)
|
||||
}
|
||||
|
||||
if cnf.Mode != Fullscreen && prev.Size != cnf.Size {
|
||||
w.config.Size = cnf.Size
|
||||
C.XResizeWindow(w.x, w.xw, C.uint(cnf.Size.X), C.uint(cnf.Size.Y))
|
||||
}
|
||||
switch cnf.Mode {
|
||||
case Fullscreen:
|
||||
switch prev.Mode {
|
||||
case Fullscreen:
|
||||
case Minimized:
|
||||
w.Raise()
|
||||
fallthrough
|
||||
default:
|
||||
w.config.Mode = Fullscreen
|
||||
w.sendWMStateEvent(_NET_WM_STATE_ADD, w.atoms.wmStateFullscreen, 0)
|
||||
}
|
||||
case Minimized:
|
||||
switch prev.Mode {
|
||||
case Minimized, Fullscreen:
|
||||
default:
|
||||
w.config.Mode = Minimized
|
||||
screen := C.XDefaultScreen(w.x)
|
||||
C.XIconifyWindow(w.x, w.xw, screen)
|
||||
}
|
||||
case Maximized:
|
||||
switch prev.Mode {
|
||||
case Fullscreen:
|
||||
case Minimized:
|
||||
w.Raise()
|
||||
fallthrough
|
||||
default:
|
||||
w.config.Mode = Maximized
|
||||
w.sendWMStateEvent(_NET_WM_STATE_ADD, w.atoms.wmStateMaximizedHorz, w.atoms.wmStateMaximizedVert)
|
||||
w.setTitle(prev, cnf)
|
||||
}
|
||||
case Windowed:
|
||||
switch prev.Mode {
|
||||
case Fullscreen:
|
||||
w.config.Mode = Windowed
|
||||
w.sendWMStateEvent(_NET_WM_STATE_REMOVE, w.atoms.wmStateFullscreen, 0)
|
||||
C.XResizeWindow(w.x, w.xw, C.uint(cnf.Size.X), C.uint(cnf.Size.Y))
|
||||
case Minimized:
|
||||
w.config.Mode = Windowed
|
||||
w.Raise()
|
||||
case Maximized:
|
||||
w.config.Mode = Windowed
|
||||
w.sendWMStateEvent(_NET_WM_STATE_REMOVE, w.atoms.wmStateMaximizedHorz, w.atoms.wmStateMaximizedVert)
|
||||
}
|
||||
w.setTitle(prev, cnf)
|
||||
if prev.Size != cnf.Size {
|
||||
w.config.Size = cnf.Size
|
||||
C.XResizeWindow(w.x, w.xw, C.uint(cnf.Size.X), C.uint(cnf.Size.Y))
|
||||
}
|
||||
if prev.MinSize != cnf.MinSize {
|
||||
w.config.MinSize = cnf.MinSize
|
||||
shints.min_width = C.int(cnf.MinSize.X)
|
||||
shints.min_height = C.int(cnf.MinSize.Y)
|
||||
shints.flags = C.PMinSize
|
||||
}
|
||||
if prev.MaxSize != cnf.MaxSize {
|
||||
w.config.MaxSize = cnf.MaxSize
|
||||
shints.max_width = C.int(cnf.MaxSize.X)
|
||||
shints.max_height = C.int(cnf.MaxSize.Y)
|
||||
shints.flags = shints.flags | C.PMaxSize
|
||||
}
|
||||
if shints.flags != 0 {
|
||||
C.XSetWMNormalHints(w.x, w.xw, &shints)
|
||||
}
|
||||
if cnf.center {
|
||||
screen := C.XDefaultScreen(w.x)
|
||||
width := C.XDisplayWidth(w.x, screen)
|
||||
height := C.XDisplayHeight(w.x, screen)
|
||||
|
||||
var attrs C.XWindowAttributes
|
||||
C.XGetWindowAttributes(w.x, w.xw, &attrs)
|
||||
width -= attrs.border_width
|
||||
height -= attrs.border_width
|
||||
|
||||
sz := w.config.Size
|
||||
x := (int(width) - sz.X) / 2
|
||||
y := (int(height) - sz.Y) / 2
|
||||
|
||||
C.XMoveResizeWindow(w.x, w.xw, C.int(x), C.int(y), C.uint(sz.X), C.uint(sz.Y))
|
||||
}
|
||||
}
|
||||
if w.config != prev {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *x11Window) setTitle(prev, cnf Config) {
|
||||
if prev.Title != cnf.Title {
|
||||
title := cnf.Title
|
||||
ctitle := C.CString(title)
|
||||
@@ -196,13 +262,6 @@ func (w *x11Window) Configure(options []Option) {
|
||||
},
|
||||
w.atoms.wmName)
|
||||
}
|
||||
|
||||
if prev.Mode != cnf.Mode {
|
||||
w.SetWindowMode(cnf.Mode)
|
||||
}
|
||||
if w.config != prev {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *x11Window) Raise() {
|
||||
@@ -249,22 +308,6 @@ func (w *x11Window) SetCursor(name pointer.CursorName) {
|
||||
C.XDefineCursor(w.x, w.xw, c)
|
||||
}
|
||||
|
||||
func (w *x11Window) SetWindowMode(mode WindowMode) {
|
||||
var action C.long
|
||||
switch mode {
|
||||
case Windowed:
|
||||
action = _NET_WM_STATE_REMOVE
|
||||
case Fullscreen:
|
||||
action = _NET_WM_STATE_ADD
|
||||
default:
|
||||
return
|
||||
}
|
||||
w.config.Mode = mode
|
||||
// "A Client wishing to change the state of a window MUST send
|
||||
// a _NET_WM_STATE client message to the root window."
|
||||
w.sendWMStateEvent(action, w.atoms.wmStateFullscreen, 0)
|
||||
}
|
||||
|
||||
func (w *x11Window) ShowTextInput(show bool) {}
|
||||
|
||||
func (w *x11Window) SetInputHint(_ key.InputHint) {}
|
||||
@@ -286,29 +329,6 @@ func (w *x11Window) Close() {
|
||||
C.XSendEvent(w.x, w.xw, C.False, C.NoEventMask, &xev)
|
||||
}
|
||||
|
||||
// Maximize the window.
|
||||
func (w *x11Window) Maximize() {
|
||||
w.sendWMStateEvent(_NET_WM_STATE_ADD, w.atoms.wmStateMaximizedHorz, w.atoms.wmStateMaximizedVert)
|
||||
}
|
||||
|
||||
// Center the window.
|
||||
func (w *x11Window) Center() {
|
||||
screen := C.XDefaultScreen(w.x)
|
||||
width := C.XDisplayWidth(w.x, screen)
|
||||
height := C.XDisplayHeight(w.x, screen)
|
||||
|
||||
var attrs C.XWindowAttributes
|
||||
C.XGetWindowAttributes(w.x, w.xw, &attrs)
|
||||
width -= attrs.border_width
|
||||
height -= attrs.border_width
|
||||
|
||||
sz := w.config.Size
|
||||
x := (int(width) - sz.X) / 2
|
||||
y := (int(height) - sz.Y) / 2
|
||||
|
||||
C.XMoveResizeWindow(w.x, w.xw, C.int(x), C.int(y), C.uint(sz.X), C.uint(sz.Y))
|
||||
}
|
||||
|
||||
// action is one of _NET_WM_STATE_REMOVE, _NET_WM_STATE_ADD.
|
||||
func (w *x11Window) sendWMStateEvent(action C.long, atom1, atom2 C.ulong) {
|
||||
var xev C.XEvent
|
||||
|
||||
+2
-2
@@ -704,8 +704,8 @@ func Size(w, h unit.Value) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Center is an option to center the window on the screen.
|
||||
// The option is ignored in Fullscreen mode.
|
||||
// Centered is an option to center the window on the screen.
|
||||
// The option is ignored in Fullscreen mode and on Wayland.
|
||||
func Centered() Option {
|
||||
return func(m unit.Metric, cnf *Config) {
|
||||
// Set the flag so the driver can later do the actual centering.
|
||||
|
||||
Reference in New Issue
Block a user