From da47026d1c72f8d2a95a7ae9d0dce16c7a9a7849 Mon Sep 17 00:00:00 2001 From: Sasha Koshka Date: Mon, 10 Apr 2023 16:22:47 -0400 Subject: [PATCH] Added untested support for OverrideRedirect windows --- backends/x/window.go | 46 +++++++++++++++++++++++++++++++++++++------- window.go | 16 +++++++++++++++ 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/backends/x/window.go b/backends/x/window.go index 7fb2e93..ccd99d8 100644 --- a/backends/x/window.go +++ b/backends/x/window.go @@ -16,6 +16,7 @@ import "git.tebibyte.media/sashakoshka/tomo/canvas" // import "runtime/debug" type mainWindow struct { *window } +type menuWindow struct { *window } type window struct { backend *Backend xWindow *xwindow.Window @@ -48,13 +49,14 @@ func (backend *Backend) NewWindow ( err error, ) { if backend == nil { panic("nil backend") } - window, err := backend.newWindow(bounds) + window, err := backend.newWindow(bounds, false) output = mainWindow { window } return output, err } func (backend *Backend) newWindow ( - bounds image.Rectangle, + bounds image.Rectangle, + override bool, ) ( output *window, err error, @@ -66,10 +68,19 @@ func (backend *Backend) newWindow ( window.xWindow, err = xwindow.Generate(backend.connection) if err != nil { return } - err = window.xWindow.CreateChecked ( - backend.connection.RootWin(), - bounds.Min.X, bounds.Min.Y, bounds.Dx(), bounds.Dy(), 0) + + if override { + err = window.xWindow.CreateChecked ( + backend.connection.RootWin(), + bounds.Min.X, bounds.Min.Y, bounds.Dx(), bounds.Dy(), + xproto.CwOverrideRedirect, 1) + } else { + err = window.xWindow.CreateChecked ( + backend.connection.RootWin(), + bounds.Min.X, bounds.Min.Y, bounds.Dx(), bounds.Dy(), 0) + } if err != nil { return } + err = window.xWindow.Listen ( xproto.EventMaskExposure, xproto.EventMaskStructureNotify, @@ -252,7 +263,8 @@ func (window *window) SetIcon (sizes []image.Image) { } func (window *window) NewModal (bounds image.Rectangle) (tomo.Window, error) { - modal, err := window.backend.newWindow(bounds.Add(window.metrics.bounds.Min)) + modal, err := window.backend.newWindow ( + bounds.Add(window.metrics.bounds.Min), false) icccm.WmTransientForSet ( window.backend.connection, modal.xWindow.Id, @@ -267,8 +279,24 @@ func (window *window) NewModal (bounds image.Rectangle) (tomo.Window, error) { return modal, err } +func (window *window) NewMenu (bounds image.Rectangle) (tomo.MenuWindow, error) { + menu, err := window.backend.newWindow ( + bounds.Add(window.metrics.bounds.Min), true) + icccm.WmTransientForSet ( + window.backend.connection, + menu.xWindow.Id, + window.xWindow.Id) + ewmh.WmStateSet ( + window.backend.connection, + menu.xWindow.Id, + []string { "_NET_WM_STATE_SKIP_TASKBAR" }) + menu.inheritProperties(window) + return menuWindow { window: menu }, err +} + func (window mainWindow) NewPanel (bounds image.Rectangle) (tomo.Window, error) { - panel, err := window.backend.newWindow(bounds.Add(window.metrics.bounds.Min)) + panel, err := window.backend.newWindow ( + bounds.Add(window.metrics.bounds.Min), false) if err != nil { return nil, err } panel.setClientLeader(window.window) window.setClientLeader(window.window) @@ -281,6 +309,10 @@ func (window mainWindow) NewPanel (bounds image.Rectangle) (tomo.Window, error) return panel, err } +func (window menuWindow) Pin () { + // TODO +} + func (window *window) inheritProperties (parent *window) { window.SetApplicationName(parent.application) } diff --git a/window.go b/window.go index 012fe74..1813a81 100644 --- a/window.go +++ b/window.go @@ -38,6 +38,13 @@ type Window interface { // window, but this position may be overridden by the backend or // operating system. NewModal (bounds image.Rectangle) (Window, error) + + // NewMenu creates a new temporary window for things like dropdown or + // context menus. It automatically closes when the user presses escape + // or clicks outside of it. Like NewModal, the pulldown window will + // inherit this window's application name and icon, and will be + // positioned relative to it. + NewMenu (bounds image.Rectangle) (MenuWindow, error) // Copy puts data into the clipboard. Copy (data.Data) @@ -73,3 +80,12 @@ type MainWindow interface { // be manually overridden. NewPanel (bounds image.Rectangle) (Window, error) } + +// MenuWindow is a temporary window that automatically closes when the user +// presses escape or clicks outside of it. +type MenuWindow interface { + Window + + // Pin converts this window into a panel, pinning it to the screen. + Pin () +}