mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 04:59:38 +08:00
165 lines
5.0 KiB
Go
165 lines
5.0 KiB
Go
//go:build linux
|
|
// +build linux
|
|
|
|
package linux
|
|
|
|
/*
|
|
#cgo linux pkg-config: gtk+-3.0
|
|
#cgo !webkit2_41 pkg-config: webkit2gtk-4.0
|
|
#cgo webkit2_41 pkg-config: webkit2gtk-4.1
|
|
|
|
#include "gtk/gtk.h"
|
|
|
|
static GtkMenuItem *toGtkMenuItem(void *pointer) { return (GTK_MENU_ITEM(pointer)); }
|
|
static GtkMenuShell *toGtkMenuShell(void *pointer) { return (GTK_MENU_SHELL(pointer)); }
|
|
static GtkCheckMenuItem *toGtkCheckMenuItem(void *pointer) { return (GTK_CHECK_MENU_ITEM(pointer)); }
|
|
static GtkRadioMenuItem *toGtkRadioMenuItem(void *pointer) { return (GTK_RADIO_MENU_ITEM(pointer)); }
|
|
|
|
extern void handleMenuItemClick(void*);
|
|
|
|
void blockClick(GtkWidget* menuItem, gulong handler_id) {
|
|
g_signal_handler_block (menuItem, handler_id);
|
|
}
|
|
|
|
void unblockClick(GtkWidget* menuItem, gulong handler_id) {
|
|
g_signal_handler_unblock (menuItem, handler_id);
|
|
}
|
|
|
|
gulong connectClick(GtkWidget* menuItem) {
|
|
return g_signal_connect(menuItem, "activate", G_CALLBACK(handleMenuItemClick), (void*)menuItem);
|
|
}
|
|
|
|
void addAccelerator(GtkWidget* menuItem, GtkAccelGroup* group, guint key, GdkModifierType mods) {
|
|
gtk_widget_add_accelerator(menuItem, "activate", group, key, mods, GTK_ACCEL_VISIBLE);
|
|
}
|
|
*/
|
|
import "C"
|
|
import "github.com/wailsapp/wails/v2/pkg/menu"
|
|
import "unsafe"
|
|
|
|
var menuIdCounter int
|
|
var menuItemToId map[*menu.MenuItem]int
|
|
var menuIdToItem map[int]*menu.MenuItem
|
|
var gtkCheckboxCache map[*menu.MenuItem][]*C.GtkWidget
|
|
var gtkMenuCache map[*menu.MenuItem]*C.GtkWidget
|
|
var gtkRadioMenuCache map[*menu.MenuItem][]*C.GtkWidget
|
|
var gtkSignalHandlers map[*C.GtkWidget]C.gulong
|
|
var gtkSignalToMenuItem map[*C.GtkWidget]*menu.MenuItem
|
|
|
|
func (f *Frontend) MenuSetApplicationMenu(menu *menu.Menu) {
|
|
f.mainWindow.SetApplicationMenu(menu)
|
|
}
|
|
|
|
func (f *Frontend) MenuUpdateApplicationMenu() {
|
|
f.mainWindow.SetApplicationMenu(f.mainWindow.applicationMenu)
|
|
}
|
|
|
|
func (w *Window) SetApplicationMenu(inmenu *menu.Menu) {
|
|
if inmenu == nil {
|
|
return
|
|
}
|
|
|
|
// Setup accelerator group
|
|
w.accels = C.gtk_accel_group_new()
|
|
C.gtk_window_add_accel_group(w.asGTKWindow(), w.accels)
|
|
|
|
menuItemToId = make(map[*menu.MenuItem]int)
|
|
menuIdToItem = make(map[int]*menu.MenuItem)
|
|
gtkCheckboxCache = make(map[*menu.MenuItem][]*C.GtkWidget)
|
|
gtkMenuCache = make(map[*menu.MenuItem]*C.GtkWidget)
|
|
gtkRadioMenuCache = make(map[*menu.MenuItem][]*C.GtkWidget)
|
|
gtkSignalHandlers = make(map[*C.GtkWidget]C.gulong)
|
|
gtkSignalToMenuItem = make(map[*C.GtkWidget]*menu.MenuItem)
|
|
|
|
// Increase ref count?
|
|
w.menubar = C.gtk_menu_bar_new()
|
|
|
|
processMenu(w, inmenu)
|
|
|
|
C.gtk_widget_show(w.menubar)
|
|
}
|
|
|
|
func processMenu(window *Window, menu *menu.Menu) {
|
|
for _, menuItem := range menu.Items {
|
|
submenu := processSubmenu(menuItem, window.accels)
|
|
C.gtk_menu_shell_append(C.toGtkMenuShell(unsafe.Pointer(window.menubar)), submenu)
|
|
}
|
|
}
|
|
|
|
func processSubmenu(menuItem *menu.MenuItem, group *C.GtkAccelGroup) *C.GtkWidget {
|
|
existingMenu := gtkMenuCache[menuItem]
|
|
if existingMenu != nil {
|
|
return existingMenu
|
|
}
|
|
gtkMenu := C.gtk_menu_new()
|
|
submenu := GtkMenuItemWithLabel(menuItem.Label)
|
|
for _, menuItem := range menuItem.SubMenu.Items {
|
|
menuID := menuIdCounter
|
|
menuIdToItem[menuID] = menuItem
|
|
menuItemToId[menuItem] = menuID
|
|
menuIdCounter++
|
|
processMenuItem(gtkMenu, menuItem, group)
|
|
}
|
|
C.gtk_menu_item_set_submenu(C.toGtkMenuItem(unsafe.Pointer(submenu)), gtkMenu)
|
|
gtkMenuCache[menuItem] = existingMenu
|
|
return submenu
|
|
}
|
|
|
|
var currentRadioGroup *C.GSList
|
|
|
|
func processMenuItem(parent *C.GtkWidget, menuItem *menu.MenuItem, group *C.GtkAccelGroup) {
|
|
if menuItem.Hidden {
|
|
return
|
|
}
|
|
|
|
if menuItem.Type != menu.RadioType {
|
|
currentRadioGroup = nil
|
|
}
|
|
|
|
if menuItem.Type == menu.SeparatorType {
|
|
result := C.gtk_separator_menu_item_new()
|
|
C.gtk_menu_shell_append(C.toGtkMenuShell(unsafe.Pointer(parent)), result)
|
|
return
|
|
}
|
|
|
|
var result *C.GtkWidget
|
|
|
|
switch menuItem.Type {
|
|
case menu.TextType:
|
|
result = GtkMenuItemWithLabel(menuItem.Label)
|
|
case menu.CheckboxType:
|
|
result = GtkCheckMenuItemWithLabel(menuItem.Label)
|
|
if menuItem.Checked {
|
|
C.gtk_check_menu_item_set_active(C.toGtkCheckMenuItem(unsafe.Pointer(result)), 1)
|
|
}
|
|
gtkCheckboxCache[menuItem] = append(gtkCheckboxCache[menuItem], result)
|
|
|
|
case menu.RadioType:
|
|
result = GtkRadioMenuItemWithLabel(menuItem.Label, currentRadioGroup)
|
|
currentRadioGroup = C.gtk_radio_menu_item_get_group(C.toGtkRadioMenuItem(unsafe.Pointer(result)))
|
|
if menuItem.Checked {
|
|
C.gtk_check_menu_item_set_active(C.toGtkCheckMenuItem(unsafe.Pointer(result)), 1)
|
|
}
|
|
gtkRadioMenuCache[menuItem] = append(gtkRadioMenuCache[menuItem], result)
|
|
case menu.SubmenuType:
|
|
result = processSubmenu(menuItem, group)
|
|
}
|
|
C.gtk_menu_shell_append(C.toGtkMenuShell(unsafe.Pointer(parent)), result)
|
|
C.gtk_widget_show(result)
|
|
|
|
if menuItem.Click != nil {
|
|
handler := C.connectClick(result)
|
|
gtkSignalHandlers[result] = handler
|
|
gtkSignalToMenuItem[result] = menuItem
|
|
}
|
|
|
|
if menuItem.Disabled {
|
|
C.gtk_widget_set_sensitive(result, 0)
|
|
}
|
|
|
|
if menuItem.Accelerator != nil {
|
|
key, mods := acceleratorToGTK(menuItem.Accelerator)
|
|
C.addAccelerator(result, group, key, mods)
|
|
}
|
|
}
|