From 39ca977b18f1b51b0815c9ca636fb93dceba6852 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Sat, 27 Nov 2021 20:36:25 +1100 Subject: [PATCH] [linux] basic windowing pt2 --- v2/go.mod | 2 - v2/go.sum | 2 - .../frontend/desktop/linux/frontend.go | 159 +++---- v2/internal/frontend/desktop/linux/window.go | 392 ++++++++++-------- v2/pkg/commands/build/base.go | 4 + v2/pkg/options/linux/linux.go | 4 +- 6 files changed, 311 insertions(+), 252 deletions(-) diff --git a/v2/go.mod b/v2/go.mod index 477e5a2cd..1a6af9d4a 100644 --- a/v2/go.mod +++ b/v2/go.mod @@ -49,8 +49,6 @@ require ( nhooyr.io/websocket v1.8.6 ) -require github.com/gotk3/gotk3 v0.6.1 - require ( github.com/Microsoft/go-winio v0.4.16 // indirect github.com/andybalholm/brotli v1.0.2 // indirect diff --git a/v2/go.sum b/v2/go.sum index dd5e50bc3..f75e6d19e 100644 --- a/v2/go.sum +++ b/v2/go.sum @@ -82,8 +82,6 @@ github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/gotk3/gotk3 v0.6.1 h1:GJ400a0ecEEWrzjBvzBzH+pB/esEMIGdB9zPSmBdoeo= -github.com/gotk3/gotk3 v0.6.1/go.mod h1:/hqFpkNa9T3JgNAE2fLvCdov7c5bw//FHNZrZ3Uv9/Q= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/jackmordaunt/icns v1.0.0 h1:RYSxplerf/l/DUd09AHtITwckkv/mqjVv4DjYdPmAMQ= diff --git a/v2/internal/frontend/desktop/linux/frontend.go b/v2/internal/frontend/desktop/linux/frontend.go index 4f8100fd3..0c08537fa 100644 --- a/v2/internal/frontend/desktop/linux/frontend.go +++ b/v2/internal/frontend/desktop/linux/frontend.go @@ -3,20 +3,28 @@ package linux +/* +#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 + +#include "gtk/gtk.h" + +*/ +import "C" import ( + "bytes" "context" "encoding/json" - "log" - "strconv" - "text/template" - "github.com/wailsapp/wails/v2/internal/binding" "github.com/wailsapp/wails/v2/internal/frontend" "github.com/wailsapp/wails/v2/internal/frontend/assetserver" "github.com/wailsapp/wails/v2/internal/logger" "github.com/wailsapp/wails/v2/pkg/options" - - "github.com/gotk3/gotk3/gtk" + "github.com/xyproto/xpm" + "image/png" + "log" + "os" + "strconv" + "text/template" ) type Frontend struct { @@ -33,25 +41,46 @@ type Frontend struct { startURL string // main window handle - mainWindow *Window - minWidth, minHeight, maxWidth, maxHeight int - bindings *binding.Bindings - dispatcher frontend.Dispatcher - servingFromDisk bool + mainWindow *Window + //minWidth, minHeight, maxWidth, maxHeight int + bindings *binding.Bindings + dispatcher frontend.Dispatcher + servingFromDisk bool +} + +func png2XPM(pngData []byte) string { + + // Create a new XPM encoder + enc := xpm.NewEncoder("icon") + + // Open the PNG file + m, err := png.Decode(bytes.NewReader(pngData)) + if err != nil { + log.Fatal(err) + } + + var buf bytes.Buffer + + // Generate and output the XPM data + err = enc.Encode(&buf, m) + if err != nil { + log.Fatal(err) + } + return buf.String() + } func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger.Logger, appBindings *binding.Bindings, dispatcher frontend.Dispatcher) *Frontend { + // Set GDK_BACKEND=x11 + os.Setenv("GDK_BACKEND", "x11") + result := &Frontend{ frontendOptions: appoptions, logger: myLogger, bindings: appBindings, dispatcher: dispatcher, ctx: ctx, - minHeight: appoptions.MinHeight, - minWidth: appoptions.MinWidth, - maxHeight: appoptions.MaxHeight, - maxWidth: appoptions.MaxWidth, startURL: "file://wails/", } @@ -72,7 +101,7 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. // Check if we have been given a directory to serve assets from. // If so, this means we are in dev mode and are serving assets off disk. // We indicate this through the `servingFromDisk` flag to ensure requests - // aren't cached by WebView2 in dev mode + // aren't cached by webkit. _assetdir := ctx.Value("assetdir") if _assetdir != nil { @@ -85,8 +114,13 @@ func NewFrontend(ctx context.Context, appoptions *options.App, myLogger *logger. } result.assets = assets - // Initialise GTK - gtk.Init(nil) + C.gtk_init(nil, nil) + + var _debug = ctx.Value("debug") + if _debug != nil { + result.debug = _debug.(bool) + } + result.mainWindow = NewWindow(appoptions, result.debug) return result } @@ -99,108 +133,83 @@ func (f *Frontend) Run(ctx context.Context) error { f.ctx = context.WithValue(ctx, "frontend", f) - mainWindow := NewWindow(f.frontendOptions) - f.mainWindow = mainWindow - - var _debug = ctx.Value("debug") - if _debug != nil { - f.debug = _debug.(bool) - } - - //f.WindowCenter() - //f.setupChromium() - // - //gtkWindow.OnSize().Bind(func(arg *winc.Event) { - // f.chromium.Resize() - //}) - // - //gtkWindow.OnClose().Bind(func(arg *winc.Event) { - // if f.frontendOptions.HideWindowOnClose { - // f.WindowHide() - // } else { - // f.Quit() - // } - //}) - go func() { if f.frontendOptions.OnStartup != nil { f.frontendOptions.OnStartup(f.ctx) } }() - if f.frontendOptions.Fullscreen { - mainWindow.Fullscreen() - } + f.mainWindow.Run() - mainWindow.Run() - mainWindow.Close() return nil } func (f *Frontend) WindowCenter() { - f.mainWindow.Center() + ////dCenter() } func (f *Frontend) WindowSetPos(x, y int) { - f.mainWindow.SetPos(x, y) + ////dSetPos(x, y) } func (f *Frontend) WindowGetPos() (int, int) { - return f.mainWindow.Pos() + ////return dPos() + return 0, 0 } func (f *Frontend) WindowSetSize(width, height int) { - f.mainWindow.SetSize(width, height) + ////dSetSize(width, height) } func (f *Frontend) WindowGetSize() (int, int) { - return f.mainWindow.Size() + ////return dSize() + return 0, 0 } func (f *Frontend) WindowSetTitle(title string) { - f.mainWindow.SetText(title) + ////dSetText(title) } func (f *Frontend) WindowFullscreen() { - f.mainWindow.SetMaxSize(0, 0) - f.mainWindow.SetMinSize(0, 0) - f.mainWindow.Fullscreen() + ////dSetMaxSize(0, 0) + ////dSetMinSize(0, 0) + ////dFullscreen() } func (f *Frontend) WindowUnFullscreen() { - f.mainWindow.UnFullscreen() - f.mainWindow.SetMaxSize(f.maxWidth, f.maxHeight) - f.mainWindow.SetMinSize(f.minWidth, f.minHeight) + ////dUnFullscreen() + ////dSetMaxSize(f.maxWidth, f.maxHeight) + ////dSetMinSize(f.minWidth, f.minHeight) } func (f *Frontend) WindowShow() { - f.mainWindow.Show() + ////dShow() } func (f *Frontend) WindowHide() { - f.mainWindow.Hide() + ////dHide() } func (f *Frontend) WindowMaximise() { - f.mainWindow.Maximise() + ////dMaximise() } func (f *Frontend) WindowUnmaximise() { - f.mainWindow.UnMaximise() + ////dUnMaximise() } func (f *Frontend) WindowMinimise() { - f.mainWindow.Minimise() + //dMinimise() } func (f *Frontend) WindowUnminimise() { - f.mainWindow.UnMinimise() + //dUnMinimise() } func (f *Frontend) WindowSetMinSize(width int, height int) { - f.minWidth = width - f.minHeight = height - f.mainWindow.SetMinSize(width, height) + //f.minWidth = width + ////f.minHeight = height + //dSetMinSize(width, height) } func (f *Frontend) WindowSetMaxSize(width int, height int) { - f.maxWidth = width - f.maxHeight = height - f.mainWindow.SetMaxSize(width, height) + //f.maxWidth = width + ////f.maxHeight = height + //dSetMaxSize(width, height) } func (f *Frontend) WindowSetRGBA(col *options.RGBA) { @@ -341,12 +350,12 @@ func (f *Frontend) Notify(name string, data ...interface{}) { func (f *Frontend) processMessage(message string) { if message == "drag" { - if !f.mainWindow.IsFullScreen() { - err := f.startDrag() - if err != nil { - f.logger.Error(err.Error()) - } + //if !f.mainWindow.IsFullScreen() { + err := f.startDrag() + if err != nil { + f.logger.Error(err.Error()) } + //} return } result, err := f.dispatcher.ProcessMessage(message, f) diff --git a/v2/internal/frontend/desktop/linux/window.go b/v2/internal/frontend/desktop/linux/window.go index 3376080b2..40d553750 100644 --- a/v2/internal/frontend/desktop/linux/window.go +++ b/v2/internal/frontend/desktop/linux/window.go @@ -3,245 +3,295 @@ package linux -import ( - "github.com/gotk3/gotk3/gdk" - "github.com/gotk3/gotk3/glib" - "github.com/gotk3/gotk3/gtk" - "github.com/wailsapp/wails/v2/pkg/menu" - "github.com/wailsapp/wails/v2/pkg/options" - "github.com/wailsapp/wails/v2/pkg/options/linux" - "log" - "math" - "sync" -) +/* +#cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 -type Window struct { - frontendOptions *options.App - applicationMenu *menu.Menu - m sync.Mutex - application *gtk.Application - gtkWindow *gtk.ApplicationWindow - //dispatchq []func() +#include "gtk/gtk.h" +#include +#include + +static GtkWidget* GTKWIDGET(void *pointer) { + return GTK_WIDGET(pointer); } -func NewWindow(options *options.App) *Window { - result := new(Window) - result.frontendOptions = options +static GtkWindow* GTKWINDOW(void *pointer) { + return GTK_WINDOW(pointer); +} - var linuxOptions linux.Options - if options.Linux != nil { - linuxOptions = *options.Linux +static void SetMinSize(GtkWindow* window, int width, int height) { + GdkGeometry size; + size.min_height = height; + size.min_width = width; + gtk_window_set_geometry_hints(window, NULL, &size, GDK_HINT_MIN_SIZE); +} + +static void SetMaxSize(GtkWindow* window, int width, int height) { + GdkGeometry size; + if( width == 0 ) { + width = INT_MAX; } - appID := linuxOptions.AppID - if appID == "" { - appID = "io.wails" + if( height == 0 ) { + height = INT_MAX; } - println("AppID =", appID) + size.max_height = height; + size.max_width = width; + gtk_window_set_geometry_hints(window, NULL, &size, GDK_HINT_MAX_SIZE); +} - application, err := gtk.ApplicationNew(appID, glib.APPLICATION_FLAGS_NONE) - if err != nil { - log.Fatal("Could not create application:", err) +GdkRectangle getCurrentMonitorGeometry(GtkWindow *window) { + // Get the monitor that the window is currently on + GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(window)); + GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window)); + GdkMonitor *monitor = gdk_display_get_monitor_at_window (display, gdk_window); + + // Get the geometry of the monitor + GdkRectangle result; + gdk_monitor_get_geometry (monitor,&result); + return result; +} + +void SetPosition(GtkWindow *window, int x, int y) { + GdkRectangle monitorDimensions = getCurrentMonitorGeometry(window); + gtk_window_move(window, monitorDimensions.x + x, monitorDimensions.y + y); +} + +void Center(GtkWindow *window) +{ + // Get the geometry of the monitor + GdkRectangle m = getCurrentMonitorGeometry(window); + + // Get the window width/height + int windowWidth, windowHeight; + gtk_window_get_size(window, &windowWidth, &windowHeight); + + int newX = ((m.width - windowWidth) / 2) + m.x; + int newY = ((m.height - windowHeight) / 2) + m.y; + + // Place the window at the center of the monitor + gtk_window_move(window, newX, newY); +} + +int IsFullscreen(GtkWidget *widget) { + GdkWindow *gdkwindow = gtk_widget_get_window(widget); + GdkWindowState state = gdk_window_get_state(GDK_WINDOW(gdkwindow)); + return state & GDK_WINDOW_STATE_FULLSCREEN == GDK_WINDOW_STATE_FULLSCREEN; +} + +*/ +import "C" +import ( + "github.com/wailsapp/wails/v2/pkg/options" + "unsafe" +) + +func gtkBool(input bool) C.gboolean { + if input { + return C.gboolean(1) + } + return C.gboolean(0) +} + +type Window struct { + appoptions *options.App + debug bool + gtkWindow unsafe.Pointer +} + +func NewWindow(appoptions *options.App, debug bool) *Window { + + result := &Window{ + appoptions: appoptions, + debug: debug, } - result.application = application + gtkWindow := C.gtk_window_new(C.GTK_WINDOW_TOPLEVEL) + C.g_object_ref_sink(C.gpointer(gtkWindow)) - application.Connect("activate", func() { + result.gtkWindow = unsafe.Pointer(gtkWindow) + result.SetKeepAbove(appoptions.AlwaysOnTop) + result.SetResizable(!appoptions.DisableResize) + result.SetSize(appoptions.Width, appoptions.Height) + result.Center() + result.SetDecorated(!appoptions.Frameless) + result.SetTitle(appoptions.Title) + result.SetMinSize(appoptions.MinWidth, appoptions.MinHeight) + result.SetMaxSize(appoptions.MaxWidth, appoptions.MaxHeight) - window, err := gtk.ApplicationWindowNew(application) - if err != nil { - log.Fatal("Could not create application window:", err) - } - window.Connect("delete-event", func() { - if options.HideWindowOnClose { - result.gtkWindow.Hide() - return - } - result.gtkWindow.Close() - }) - result.gtkWindow = window - window.SetTitle(options.Title) - window.SetDecorated(!options.Frameless) - window.SetDefaultSize(600, 300) - window.SetResizable(!options.DisableResize) - window.SetKeepAbove(options.AlwaysOnTop) - window.SetPosition(gtk.WIN_POS_CENTER) - if !options.StartHidden { - window.ShowAll() - } - }) + //if appoptions.Linux != nil && appoptions.Linux.Icon != nil { + // xpmData := png2XPM(appoptions.Linux.Icon) + // xpm := C.CString(xpmData) + // defer C.free(unsafe.Pointer(xpm)) + // appIcon := C.gdk_pixbuf_new_from_xpm_data( + // C.gtk_window_set_icon(result.asGTKWindow(), appIcon) + //} - //result.SetIsForm(true) - // - //var exStyle int - //if options.Windows != nil { - // exStyle = w32.WS_EX_CONTROLPARENT | w32.WS_EX_APPWINDOW - // if options.Windows.WindowIsTranslucent { - // exStyle |= w32.WS_EX_NOREDIRECTIONBITMAP - // } + //windowStartState := C.int(int(a.appoptions.WindowStartState)) + + //if a.appoptions.RGBA != nil { + // result.SetRGBA(a.appoptions.RGBA.R, a.appoptions.RGBA.G, a.appoptions.RGBA.B, a.appoptions.RGBA.A) //} - //if options.AlwaysOnTop { - // exStyle |= w32.WS_EX_TOPMOST - //} - // - //var dwStyle = w32.WS_OVERLAPPEDWINDOW - //if options.Frameless { - // dwStyle = w32.WS_POPUP - //} - // - //winc.RegClassOnlyOnce("wailsWindow") - //result.SetHandle(winc.CreateWindow("wailsWindow", parent, uint(exStyle), uint(dwStyle))) - //result.SetParent(parent) - // - //loadIcon := true - //if options.Windows != nil && options.Windows.DisableWindowIcon == true { - // loadIcon = false - //} - //if loadIcon { - // if ico, err := winc.NewIconFromResource(winc.GetAppInstance(), uint16(winc.AppIconID)); err == nil { - // result.SetIcon(0, ico) - // } - //} - // - //result.SetSize(options.Width, options.Height) - //result.SetText(options.Title) - //if options.Frameless == false && !options.Fullscreen { - // result.EnableMaxButton(!options.DisableResize) - // result.EnableSizable(!options.DisableResize) - // result.SetMinSize(options.MinWidth, options.MinHeight) - // result.SetMaxSize(options.MaxWidth, options.MaxHeight) - //} - // - //if options.Windows != nil { - // if options.Windows.WindowIsTranslucent { - // result.SetTranslucentBackground() - // } - // - // if options.Windows.DisableWindowIcon { - // result.DisableIcon() - // } - //} - // - //// Dlg forces display of focus rectangles, as soon as the user starts to type. - //w32.SendMessage(result.Handle(), w32.WM_CHANGEUISTATE, w32.UIS_INITIALIZE, 0) - //winc.RegMsgHandler(result) - // - //result.SetFont(winc.DefaultFont) - // - //if options.Menu != nil { - // result.SetApplicationMenu(options.Menu) + + //if a.appoptions.Menu != nil { + // result.SetApplicationMenu(a.appoptions.Menu) //} return result } -func (w *Window) Run() { - w.application.Run(nil) +func (w *Window) asGTKWidget() *C.GtkWidget { + return C.GTKWIDGET(w.gtkWindow) } -func (w *Window) Dispatch(f func()) { - glib.IdleAdd(f) +func (w *Window) asGTKWindow() *C.GtkWindow { + return C.GTKWINDOW(w.gtkWindow) } +//func (w *Window) Dispatch(f func()) { +// glib.IdleAdd(f) +//} +// + func (w *Window) Fullscreen() { - w.gtkWindow.Fullscreen() + C.gtk_window_fullscreen(w.asGTKWindow()) } func (w *Window) UnFullscreen() { - w.gtkWindow.Unfullscreen() + C.gtk_window_unfullscreen(w.asGTKWindow()) +} + +func (w *Window) Destroy() { + /* + for (gulong connection: { + impl_->deleteEventConnection, + impl_->focusInEventConnection, + impl_->focusOutEventConnection, + impl_->configureEventConnection + }) { + g_signal_handler_disconnect(impl_->gtkWindow, connection); + } + gtk_widget_destroy(GTK_WIDGET(impl_->gtkWindow)); + */ + + //TODO: Proper shutdown + C.g_object_unref(C.gpointer(w.gtkWindow)) + C.gtk_widget_destroy(w.asGTKWidget()) } func (w *Window) Close() { - w.application.Quit() + C.gtk_window_close(w.asGTKWindow()) } func (w *Window) Center() { - w.gtkWindow.SetPosition(gtk.WIN_POS_CENTER) + C.Center(w.asGTKWindow()) } func (w *Window) SetPos(x int, y int) { - display, err := w.gtkWindow.GetDisplay() - if err != nil { - w.gtkWindow.Move(x, y) - return - } - window, err := w.gtkWindow.GetWindow() - if err != nil { - w.gtkWindow.Move(x, y) - return - } - - monitor, err := display.GetMonitorAtWindow(window) - if err != nil { - w.gtkWindow.Move(x, y) - return - } - - geom := monitor.GetGeometry() - w.gtkWindow.Move(geom.GetX()+x, geom.GetY()+y) -} - -func (w *Window) Pos() (int, int) { - return w.gtkWindow.GetPosition() -} - -func (w *Window) SetSize(width int, height int) { - w.gtkWindow.SetDefaultSize(width, height) + cX := C.int(x) + cY := C.int(y) + C.gtk_window_move(w.asGTKWindow(), cX, cY) } func (w *Window) Size() (int, int) { - return w.gtkWindow.GetSize() + var width, height C.int + C.gtk_window_get_size(w.asGTKWindow(), &width, &height) + return int(width), int(height) } -func (w *Window) SetText(title string) { - w.gtkWindow.SetTitle(title) +func (w *Window) Pos() (int, int) { + var width, height C.int + C.gtk_window_get_position(w.asGTKWindow(), &width, &height) + return int(width), int(height) } func (w *Window) SetMaxSize(maxWidth int, maxHeight int) { - var geom gdk.Geometry - if maxWidth == 0 { - maxWidth = math.MaxInt - } - if maxHeight == 0 { - maxHeight = math.MaxInt - } - geom.SetMaxWidth(maxWidth) - geom.SetMaxHeight(maxHeight) - w.gtkWindow.SetGeometryHints(w.gtkWindow, geom, gdk.HINT_MAX_SIZE) + C.SetMaxSize(w.asGTKWindow(), C.int(maxWidth), C.int(maxHeight)) } func (w *Window) SetMinSize(minWidth int, minHeight int) { - var geom gdk.Geometry - geom.SetMinWidth(minWidth) - geom.SetMinHeight(minHeight) - w.gtkWindow.SetGeometryHints(w.gtkWindow, geom, gdk.HINT_MIN_SIZE) + C.SetMinSize(w.asGTKWindow(), C.int(minWidth), C.int(minHeight)) } func (w *Window) Show() { - w.gtkWindow.ShowAll() + C.gtk_widget_show(w.asGTKWidget()) } func (w *Window) Hide() { - w.gtkWindow.Hide() + C.gtk_widget_hide(w.asGTKWidget()) } func (w *Window) Maximise() { - w.gtkWindow.Maximize() + C.gtk_window_maximize(w.asGTKWindow()) } func (w *Window) UnMaximise() { - w.gtkWindow.Unmaximize() + C.gtk_window_unmaximize(w.asGTKWindow()) } func (w *Window) Minimise() { - w.gtkWindow.Iconify() + C.gtk_window_iconify(w.asGTKWindow()) } func (w *Window) UnMinimise() { - w.gtkWindow.Present() + C.gtk_window_present(w.asGTKWindow()) } func (w *Window) IsFullScreen() bool { + result := C.IsFullscreen(w.asGTKWidget()) + if result == 1 { + return true + } return false } + +func (w *Window) SetRGBA(r uint8, g uint8, b uint8, a uint8) { + //C.SetRGBA(w.context, C.int(r), C.int(g), C.int(b), C.int(a)) +} + +//func (w *Window) SetApplicationMenu(inMenu *menu.Menu) { +// //mainMenu := NewNSMenu(w.context, "") +// //processMenu(mainMenu, inMenu) +// //C.SetAsApplicationMenu(w.context, mainMenu.nsmenu) +//} + +func (w *Window) UpdateApplicationMenu() { + //C.UpdateApplicationMenu(w.context) +} + +func (w *Window) Run() { + C.gtk_widget_show_all(w.asGTKWidget()) + //switch w.appoptions.WindowStartState { + //case options.Fullscreen: + // w.Fullscreen() + //case options.Minimised: + // w.Minimise() + //case options.Maximised: + // w.Maximise() + //} + + //println("Fullscreen: ", w.IsFullScreen()) + C.gtk_main() +} + +func (w *Window) SetKeepAbove(top bool) { + C.gtk_window_set_keep_above(w.asGTKWindow(), gtkBool(top)) +} + +func (w *Window) SetResizable(resizable bool) { + C.gtk_window_set_resizable(w.asGTKWindow(), gtkBool(resizable)) +} + +func (w *Window) SetSize(width int, height int) { + C.gtk_window_resize(w.asGTKWindow(), C.gint(width), C.gint(height)) +} + +func (w *Window) SetDecorated(frameless bool) { + C.gtk_window_set_decorated(w.asGTKWindow(), gtkBool(frameless)) +} + +func (w *Window) SetTitle(title string) { + cTitle := C.CString(title) + defer C.free(unsafe.Pointer(cTitle)) + C.gtk_window_set_title(w.asGTKWindow(), cTitle) +} diff --git a/v2/pkg/commands/build/base.go b/v2/pkg/commands/build/base.go index b93aa9b55..144aa1025 100644 --- a/v2/pkg/commands/build/base.go +++ b/v2/pkg/commands/build/base.go @@ -215,6 +215,10 @@ func (b *BaseBuilder) CompileProject(options *Options) error { commands.Add(`"all=-N -l"`) } + if options.ForceBuild { + commands.Add("-a") + } + var tags slicer.StringSlicer tags.Add(options.OutputType) tags.AddSlice(options.UserTags) diff --git a/v2/pkg/options/linux/linux.go b/v2/pkg/options/linux/linux.go index a3b044e22..1d5b669ef 100644 --- a/v2/pkg/options/linux/linux.go +++ b/v2/pkg/options/linux/linux.go @@ -2,6 +2,6 @@ package linux // Options specific to Linux builds type Options struct { - // AppID is the gtk application id string. Defaults to a random uuid. - AppID string + // Linux needs the icon embedded + Icon []byte }