mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-03 00:16:15 +00:00
app: support changing Window options at runtime
A Window can now be requested to change its options after it has been started via its Option method. All options are supported on macOS, Windows and X11. On Wayland, only the Size and Title options can be changed at runtime. Signed-off-by: pierre <pierre.curto@gmail.com>
This commit is contained in:
@@ -172,11 +172,10 @@ func (w *window) Option(opts *Options) {
|
||||
func (w *window) SetWindowMode(mode WindowMode) {
|
||||
switch mode {
|
||||
case w.mode:
|
||||
return
|
||||
case Fullscreen:
|
||||
case Windowed, Fullscreen:
|
||||
C.gio_toggleFullScreen(w.window)
|
||||
w.mode = mode
|
||||
}
|
||||
w.mode = mode
|
||||
}
|
||||
|
||||
func (w *window) SetCursor(name pointer.CursorName) {
|
||||
|
||||
@@ -181,6 +181,7 @@ type window struct {
|
||||
|
||||
mu sync.Mutex
|
||||
animating bool
|
||||
opts *Options
|
||||
needAck bool
|
||||
// The most recent configure serial waiting to be ack'ed.
|
||||
serial C.uint32_t
|
||||
@@ -357,7 +358,7 @@ func (d *wlDisplay) createNativeWindow(opts *Options) (*window, error) {
|
||||
C.xdg_surface_add_listener(w.wmSurf, &C.gio_xdg_surface_listener, unsafe.Pointer(w.surf))
|
||||
C.xdg_toplevel_add_listener(w.topLvl, &C.gio_xdg_toplevel_listener, unsafe.Pointer(w.surf))
|
||||
|
||||
w.Option(opts)
|
||||
w.setOptions(opts)
|
||||
|
||||
if d.decor != nil {
|
||||
// Request server side decorations.
|
||||
@@ -910,6 +911,13 @@ func (w *window) WriteClipboard(s string) {
|
||||
}
|
||||
|
||||
func (w *window) Option(opts *Options) {
|
||||
w.mu.Lock()
|
||||
w.opts = opts
|
||||
w.mu.Unlock()
|
||||
w.disp.wakeup()
|
||||
}
|
||||
|
||||
func (w *window) setOptions(opts *Options) {
|
||||
_, _, cfg := w.config()
|
||||
if o := opts.Size; o != nil {
|
||||
w.width = cfg.Px(o.Width)
|
||||
@@ -1143,8 +1151,10 @@ func (w *window) process() {
|
||||
w.mu.Lock()
|
||||
readClipboard := w.readClipboard
|
||||
writeClipboard := w.writeClipboard
|
||||
opts := w.opts
|
||||
w.readClipboard = false
|
||||
w.writeClipboard = nil
|
||||
w.opts = nil
|
||||
w.mu.Unlock()
|
||||
if readClipboard {
|
||||
r, err := w.disp.readClipboard()
|
||||
@@ -1163,6 +1173,9 @@ func (w *window) process() {
|
||||
if writeClipboard != nil {
|
||||
w.disp.writeClipboard([]byte(*writeClipboard))
|
||||
}
|
||||
if opts != nil {
|
||||
w.setOptions(opts)
|
||||
}
|
||||
// pass false to skip unnecessary drawing.
|
||||
w.draw(false)
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ type window struct {
|
||||
const (
|
||||
_WM_REDRAW = windows.WM_USER + iota
|
||||
_WM_CURSOR
|
||||
_WM_OPTION
|
||||
)
|
||||
|
||||
type gpuAPI struct {
|
||||
@@ -317,6 +318,8 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
||||
windows.SetCursor(w.cursor)
|
||||
return windows.TRUE
|
||||
}
|
||||
case _WM_OPTION:
|
||||
w.setOptions()
|
||||
}
|
||||
|
||||
return windows.DefWindowProc(hwnd, msg, wParam, lParam)
|
||||
@@ -520,6 +523,18 @@ func (w *window) readClipboard() error {
|
||||
}
|
||||
|
||||
func (w *window) Option(opts *Options) {
|
||||
w.mu.Lock()
|
||||
w.opts = opts
|
||||
w.mu.Unlock()
|
||||
if err := windows.PostMessage(w.hwnd, _WM_OPTION, 0, 0); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) setOptions() {
|
||||
w.mu.Lock()
|
||||
opts := w.opts
|
||||
w.mu.Unlock()
|
||||
if o := opts.Size; o != nil {
|
||||
dpi := windows.GetSystemDPI()
|
||||
cfg := configForDPI(dpi)
|
||||
|
||||
+53
-10
@@ -89,6 +89,7 @@ type x11Window struct {
|
||||
|
||||
mu sync.Mutex
|
||||
animating bool
|
||||
opts *Options
|
||||
|
||||
pointerBtns pointer.Buttons
|
||||
|
||||
@@ -98,6 +99,7 @@ type x11Window struct {
|
||||
content []byte
|
||||
}
|
||||
cursor pointer.CursorName
|
||||
mode WindowMode
|
||||
}
|
||||
|
||||
func (w *x11Window) SetAnimating(anim bool) {
|
||||
@@ -124,22 +126,33 @@ func (w *x11Window) WriteClipboard(s string) {
|
||||
}
|
||||
|
||||
func (w *x11Window) Option(opts *Options) {
|
||||
dpy := w.x
|
||||
win := w.xw
|
||||
cfg := w.cfg
|
||||
w.mu.Lock()
|
||||
w.opts = opts
|
||||
w.mu.Unlock()
|
||||
w.wakeup()
|
||||
}
|
||||
|
||||
func (w *x11Window) setOptions() {
|
||||
w.mu.Lock()
|
||||
opts := w.opts
|
||||
w.opts = nil
|
||||
w.mu.Unlock()
|
||||
if opts == nil {
|
||||
return
|
||||
}
|
||||
var shints C.XSizeHints
|
||||
if o := opts.MinSize; o != nil {
|
||||
shints.min_width = C.int(cfg.Px(o.Width))
|
||||
shints.min_height = C.int(cfg.Px(o.Height))
|
||||
shints.min_width = C.int(w.cfg.Px(o.Width))
|
||||
shints.min_height = C.int(w.cfg.Px(o.Height))
|
||||
shints.flags = C.PMinSize
|
||||
}
|
||||
if o := opts.MaxSize; o != nil {
|
||||
shints.max_width = C.int(cfg.Px(o.Width))
|
||||
shints.max_height = C.int(cfg.Px(o.Height))
|
||||
shints.max_width = C.int(w.cfg.Px(o.Width))
|
||||
shints.max_height = C.int(w.cfg.Px(o.Height))
|
||||
shints.flags = shints.flags | C.PMaxSize
|
||||
}
|
||||
if shints.flags != 0 {
|
||||
C.XSetWMNormalHints(dpy, win, &shints)
|
||||
C.XSetWMNormalHints(w.x, w.xw, &shints)
|
||||
}
|
||||
|
||||
var title string
|
||||
@@ -148,9 +161,9 @@ func (w *x11Window) Option(opts *Options) {
|
||||
}
|
||||
ctitle := C.CString(title)
|
||||
defer C.free(unsafe.Pointer(ctitle))
|
||||
C.XStoreName(dpy, win, ctitle)
|
||||
C.XStoreName(w.x, w.xw, ctitle)
|
||||
// set _NET_WM_NAME as well for UTF-8 support in window title.
|
||||
C.XSetTextProperty(dpy, win,
|
||||
C.XSetTextProperty(w.x, w.xw,
|
||||
&C.XTextProperty{
|
||||
value: (*C.uchar)(unsafe.Pointer(ctitle)),
|
||||
encoding: w.atoms.utf8string,
|
||||
@@ -190,6 +203,8 @@ func (w *x11Window) SetCursor(name pointer.CursorName) {
|
||||
|
||||
func (w *x11Window) SetWindowMode(mode WindowMode) {
|
||||
switch mode {
|
||||
case w.mode:
|
||||
return
|
||||
case Windowed:
|
||||
C.XDeleteProperty(w.x, w.xw, w.atoms.wmStateFullscreen)
|
||||
case Fullscreen:
|
||||
@@ -197,7 +212,34 @@ func (w *x11Window) SetWindowMode(mode WindowMode) {
|
||||
32, C.PropModeReplace,
|
||||
(*C.uchar)(unsafe.Pointer(&w.atoms.wmStateFullscreen)), 1,
|
||||
)
|
||||
default:
|
||||
return
|
||||
}
|
||||
w.mode = mode
|
||||
// "A Client wishing to change the state of a window MUST send
|
||||
// a _NET_WM_STATE client message to the root window (see below)."
|
||||
var xev C.XEvent
|
||||
ev := (*C.XClientMessageEvent)(unsafe.Pointer(&xev))
|
||||
*ev = C.XClientMessageEvent{
|
||||
_type: C.ClientMessage,
|
||||
display: w.x,
|
||||
window: w.xw,
|
||||
message_type: w.atoms.wmState,
|
||||
format: 32,
|
||||
}
|
||||
arr := (*[5]C.long)(unsafe.Pointer(&ev.data))
|
||||
arr[0] = 2 // _NET_WM_STATE_TOGGLE
|
||||
arr[1] = C.long(w.atoms.wmStateFullscreen)
|
||||
arr[2] = 0
|
||||
arr[3] = 1 // application
|
||||
arr[4] = 0
|
||||
C.XSendEvent(
|
||||
w.x,
|
||||
C.XDefaultRootWindow(w.x), // MUST be the root window
|
||||
C.False,
|
||||
C.SubstructureNotifyMask|C.SubstructureRedirectMask,
|
||||
&xev,
|
||||
)
|
||||
}
|
||||
|
||||
func (w *x11Window) ShowTextInput(show bool) {}
|
||||
@@ -287,6 +329,7 @@ loop:
|
||||
}
|
||||
}
|
||||
}
|
||||
w.setOptions()
|
||||
// Clear notifications.
|
||||
for {
|
||||
_, err := syscall.Read(w.notify.read, buf)
|
||||
|
||||
@@ -211,6 +211,17 @@ func (w *Window) Invalidate() {
|
||||
}
|
||||
}
|
||||
|
||||
// Option applies the options to the window.
|
||||
func (w *Window) Option(opts ...Option) {
|
||||
go w.driverDo(func() {
|
||||
o := new(wm.Options)
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
w.driver.Option(o)
|
||||
})
|
||||
}
|
||||
|
||||
// ReadClipboard initiates a read of the clipboard in the form
|
||||
// of a clipboard.Event. Multiple reads may be coalesced
|
||||
// to a single event.
|
||||
|
||||
Reference in New Issue
Block a user