github.com/secoba/wails/v2@v2.6.4/internal/frontend/desktop/linux/gtk.go (about) 1 //go:build linux 2 // +build linux 3 4 package linux 5 6 /* 7 #cgo linux pkg-config: gtk+-3.0 webkit2gtk-4.0 8 9 #include "gtk/gtk.h" 10 11 static GtkCheckMenuItem *toGtkCheckMenuItem(void *pointer) { return (GTK_CHECK_MENU_ITEM(pointer)); } 12 13 extern void blockClick(GtkWidget* menuItem, gulong handler_id); 14 extern void unblockClick(GtkWidget* menuItem, gulong handler_id); 15 */ 16 import "C" 17 import ( 18 "unsafe" 19 20 "github.com/secoba/wails/v2/pkg/menu" 21 ) 22 23 func GtkMenuItemWithLabel(label string) *C.GtkWidget { 24 cLabel := C.CString(label) 25 result := C.gtk_menu_item_new_with_label(cLabel) 26 C.free(unsafe.Pointer(cLabel)) 27 return result 28 } 29 30 func GtkCheckMenuItemWithLabel(label string) *C.GtkWidget { 31 cLabel := C.CString(label) 32 result := C.gtk_check_menu_item_new_with_label(cLabel) 33 C.free(unsafe.Pointer(cLabel)) 34 return result 35 } 36 37 func GtkRadioMenuItemWithLabel(label string, group *C.GSList) *C.GtkWidget { 38 cLabel := C.CString(label) 39 result := C.gtk_radio_menu_item_new_with_label(group, cLabel) 40 C.free(unsafe.Pointer(cLabel)) 41 return result 42 } 43 44 //export handleMenuItemClick 45 func handleMenuItemClick(gtkWidget unsafe.Pointer) { 46 // Make sure to execute the final callback on a new goroutine otherwise if the callback e.g. tries to open a dialog, the 47 // main thread will get blocked and so the message loop blocks. As a result the app will block and shows a 48 // "not responding" dialog. 49 50 item := gtkSignalToMenuItem[(*C.GtkWidget)(gtkWidget)] 51 switch item.Type { 52 case menu.CheckboxType: 53 item.Checked = !item.Checked 54 checked := C.int(0) 55 if item.Checked { 56 checked = C.int(1) 57 } 58 for _, gtkCheckbox := range gtkCheckboxCache[item] { 59 handler := gtkSignalHandlers[gtkCheckbox] 60 C.blockClick(gtkCheckbox, handler) 61 C.gtk_check_menu_item_set_active(C.toGtkCheckMenuItem(unsafe.Pointer(gtkCheckbox)), checked) 62 C.unblockClick(gtkCheckbox, handler) 63 } 64 go item.Click(&menu.CallbackData{MenuItem: item}) 65 case menu.RadioType: 66 gtkRadioItems := gtkRadioMenuCache[item] 67 active := C.gtk_check_menu_item_get_active(C.toGtkCheckMenuItem(gtkWidget)) 68 if int(active) == 1 { 69 for _, gtkRadioItem := range gtkRadioItems { 70 handler := gtkSignalHandlers[gtkRadioItem] 71 C.blockClick(gtkRadioItem, handler) 72 C.gtk_check_menu_item_set_active(C.toGtkCheckMenuItem(unsafe.Pointer(gtkRadioItem)), 1) 73 C.unblockClick(gtkRadioItem, handler) 74 } 75 item.Checked = true 76 go item.Click(&menu.CallbackData{MenuItem: item}) 77 } else { 78 item.Checked = false 79 } 80 default: 81 go item.Click(&menu.CallbackData{MenuItem: item}) 82 } 83 }