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  }