From efa67cb01c5d489d7f2346f86cc54de3a4c38014 Mon Sep 17 00:00:00 2001 From: Travis McLane Date: Thu, 28 Sep 2023 14:50:38 -0500 Subject: [PATCH] [v3 linux] systray implementation Linux requires a `gtk_menu_bar` for a gtk_window to display a menu. For the `systray` a `gtk_menu` is needed instead. This change creates the correct type of `impl` for the `Menu` depending on how it is being used. --- v3/pkg/application/application_linux.go | 1 + v3/pkg/application/linux_cgo.go | 35 ++++++++++++---------- v3/pkg/application/menu_linux.go | 8 +++++ v3/pkg/application/menuitem_linux.go | 1 + v3/pkg/application/systemtray_linux.go | 18 +++++------ v3/pkg/application/webview_window_linux.go | 5 ++-- 6 files changed, 39 insertions(+), 29 deletions(-) diff --git a/v3/pkg/application/application_linux.go b/v3/pkg/application/application_linux.go index 17dc6a7cd..27c04a89f 100644 --- a/v3/pkg/application/application_linux.go +++ b/v3/pkg/application/application_linux.go @@ -82,6 +82,7 @@ func (m *linuxApp) getApplicationMenu() pointer { menu := globalApplication.ApplicationMenu if menu != nil { + menu.impl = newMenuBarImpl(menu) InvokeSync(func() { menu.Update() }) diff --git a/v3/pkg/application/linux_cgo.go b/v3/pkg/application/linux_cgo.go index 7413afff8..d5b905917 100644 --- a/v3/pkg/application/linux_cgo.go +++ b/v3/pkg/application/linux_cgo.go @@ -280,10 +280,11 @@ func menuAddSeparator(menu *Menu) { C.gtk_separator_menu_item_new()) } -func menuAppend(parent *Menu, menu *MenuItem) { +func menuAppend(parent *Menu, item *MenuItem) { + C.gtk_menu_shell_append( (*C.GtkMenuShell)((parent.impl).(*linuxMenu).native), - (*C.GtkWidget)((menu.impl).(*linuxMenuItem).native), + (*C.GtkWidget)((item.impl).(*linuxMenuItem).native), ) /* gtk4 C.gtk_menu_item_set_submenu( @@ -361,13 +362,17 @@ func menuItemChecked(widget pointer) bool { func menuItemNew(label string) pointer { cLabel := C.CString(label) defer C.free(unsafe.Pointer(cLabel)) - return pointer(C.gtk_menu_item_new_with_label(cLabel)) + item := C.gtk_menu_item_new_with_label(cLabel) + C.gtk_widget_show((*C.GtkWidget)(item)) + return pointer(item) } func menuCheckItemNew(label string) pointer { cLabel := C.CString(label) defer C.free(unsafe.Pointer(cLabel)) - return pointer(C.gtk_check_menu_item_new_with_label(cLabel)) + item := C.gtk_check_menu_item_new_with_label(cLabel) + C.gtk_widget_show((*C.GtkWidget)(item)) + return pointer(item) } func menuItemSetChecked(widget pointer, checked bool) { @@ -607,7 +612,7 @@ func windowMinimize(window pointer) { C.gtk_window_iconify((*C.GtkWindow)(window)) } -func windowNew(application pointer, menu pointer, windowId uint, gpuPolicy int) (window, webview, vbox pointer) { +func windowNew(application pointer, menuBar pointer, windowId uint, gpuPolicy int) (window, webview, vbox pointer) { window = pointer(C.gtk_application_window_new((*C.GtkApplication)(application))) C.g_object_ref_sink(C.gpointer(window)) webview = windowNewWebview(windowId, gpuPolicy) @@ -615,10 +620,9 @@ func windowNew(application pointer, menu pointer, windowId uint, gpuPolicy int) name := C.CString("webview-box") defer C.free(unsafe.Pointer(name)) C.gtk_widget_set_name((*C.GtkWidget)(vbox), name) - C.gtk_container_add((*C.GtkContainer)(window), (*C.GtkWidget)(vbox)) - if menu != nil { - C.gtk_box_pack_start((*C.GtkBox)(vbox), (*C.GtkWidget)(menu), 0, 0, 0) + if menuBar != nil { + C.gtk_box_pack_start((*C.GtkBox)(vbox), (*C.GtkWidget)(menuBar), 0, 0, 0) } C.gtk_box_pack_start((*C.GtkBox)(unsafe.Pointer(vbox)), (*C.GtkWidget)(webview), 1, 1, 0) return @@ -1149,19 +1153,18 @@ func runSaveFileDialog(dialog *SaveFileDialogStruct) (string, error) { } // systray +func systrayDestroy(tray pointer) { + // FIXME: this is not the correct way to remove our systray + // C.g_object_unref(C.gpointer(tray)) +} + func systrayNew(label string) pointer { labelStr := C.CString(label) defer C.free(unsafe.Pointer(labelStr)) emptyStr := C.CString("") defer C.free(unsafe.Pointer(emptyStr)) indicator := C.app_indicator_new(labelStr, labelStr, C.APP_INDICATOR_CATEGORY_APPLICATION_STATUS) - - trayMenu := C.gtk_menu_new() - item := C.gtk_menu_item_new_with_label(labelStr) - C.gtk_menu_shell_append((*C.GtkMenuShell)(unsafe.Pointer(trayMenu)), item) - C.gtk_widget_show(item) C.app_indicator_set_status(indicator, C.APP_INDICATOR_STATUS_ACTIVE) - C.app_indicator_set_menu(indicator, (*C.GtkMenu)(unsafe.Pointer(trayMenu))) iconStr := C.CString("wails-systray-icon") defer C.free(unsafe.Pointer(iconStr)) C.app_indicator_set_icon_full(indicator, iconStr, emptyStr) @@ -1184,7 +1187,9 @@ func systraySetLabel(tray pointer, label string) { } func systrayMenuSet(tray pointer, menu pointer) { - // C.app_indicator_set_menu((*C.AppIndicator)(tray), (*C.GtkMenu)(unsafe.Pointer(menu))) + C.app_indicator_set_menu( + (*C.AppIndicator)(tray), + (*C.GtkMenu)(unsafe.Pointer(menu))) } func systraySetTemplateIcon(tray pointer, icon []byte) { diff --git a/v3/pkg/application/menu_linux.go b/v3/pkg/application/menu_linux.go index 8a5592bdd..19e3bfa12 100644 --- a/v3/pkg/application/menu_linux.go +++ b/v3/pkg/application/menu_linux.go @@ -8,6 +8,14 @@ type linuxMenu struct { } func newMenuImpl(menu *Menu) *linuxMenu { + result := &linuxMenu{ + menu: menu, + native: menuNew(), + } + return result +} + +func newMenuBarImpl(menu *Menu) *linuxMenu { result := &linuxMenu{ menu: menu, native: menuBarNew(), diff --git a/v3/pkg/application/menuitem_linux.go b/v3/pkg/application/menuitem_linux.go index cce9414bb..943104f7c 100644 --- a/v3/pkg/application/menuitem_linux.go +++ b/v3/pkg/application/menuitem_linux.go @@ -103,6 +103,7 @@ func newMenuItemImpl(item *MenuItem) *linuxMenuItem { default: panic(fmt.Sprintf("Unknown menu type: %v", item.itemType)) } + result.setDisabled(result.menuItem.disabled) return result } diff --git a/v3/pkg/application/systemtray_linux.go b/v3/pkg/application/systemtray_linux.go index 1a97b6504..4e76f8986 100644 --- a/v3/pkg/application/systemtray_linux.go +++ b/v3/pkg/application/systemtray_linux.go @@ -2,8 +2,6 @@ package application -import "fmt" - type linuxSystemTray struct { id uint label string @@ -13,6 +11,7 @@ type linuxSystemTray struct { iconPosition int isTemplateIcon bool tray pointer + nativeMenu pointer } func (s *linuxSystemTray) setIconPosition(position int) { @@ -20,8 +19,10 @@ func (s *linuxSystemTray) setIconPosition(position int) { } func (s *linuxSystemTray) setMenu(menu *Menu) { - fmt.Println("linuxSystemTray.SetMenu") s.menu = menu + s.menu.impl = newMenuImpl(menu) + menu.Update() + systrayMenuSet(s.tray, (menu.impl).(*linuxMenu).native) } func (s *linuxSystemTray) positionWindow(window *WebviewWindow, offset int) error { @@ -55,9 +56,8 @@ func (s *linuxSystemTray) run() { s.setIcon(s.icon) } if s.menu != nil { - s.menu.Update() - menu := (s.menu.impl).(*linuxMenu).menu - systrayMenuSet(s.tray, (menu.impl).(*linuxMenu).native) + // s.menu.Update() + s.setMenu(s.menu) } }) } @@ -101,15 +101,11 @@ func (s *linuxSystemTray) openMenu() { } } -func (s *linuxSystemTray) openMenu() { -} - func (s *linuxSystemTray) setLabel(label string) { s.label = label systraySetLabel(s.tray, label) } func (s *linuxSystemTray) destroy() { - // Remove the status item from the status bar and its associated menu - // C.systemTrayDestroy(s.nsStatusItem) + systrayDestroy(s.tray) } diff --git a/v3/pkg/application/webview_window_linux.go b/v3/pkg/application/webview_window_linux.go index ca3dad5ad..891c66840 100644 --- a/v3/pkg/application/webview_window_linux.go +++ b/v3/pkg/application/webview_window_linux.go @@ -353,9 +353,8 @@ func (w *linuxWebviewWindow) run() { } app := getNativeApplication() - - menu := app.getApplicationMenu() - w.window, w.webview, w.vbox = windowNew(app.application, menu, w.parent.id, 1) + nativeMenu := app.getApplicationMenu() + w.window, w.webview, w.vbox = windowNew(app.application, nativeMenu, w.parent.id, 1) app.registerWindow(w.window, w.parent.id) // record our mapping w.connectSignals() if w.parent.options.EnableDragAndDrop {