mirror of
https://github.com/taigrr/wails.git
synced 2026-04-02 05:08:54 -07:00
[windows] Fixes for radiobox sync
This commit is contained in:
@@ -33,6 +33,7 @@ require (
|
||||
github.com/tidwall/sjson v1.1.7
|
||||
github.com/wzshiming/ctc v1.2.3
|
||||
github.com/xyproto/xpm v1.2.1
|
||||
github.com/ztrue/tracerr v0.3.0
|
||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
|
||||
golang.org/x/mod v0.4.1 // indirect
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897
|
||||
|
||||
@@ -107,6 +107,8 @@ github.com/leaanthony/winicon v0.0.0-20200606125418-4419cea822a0 h1:FPGYnfxuuxqC
|
||||
github.com/leaanthony/winicon v0.0.0-20200606125418-4419cea822a0/go.mod h1:en5xhijl92aphrJdmRPlh4NI1L6wq3gEm0LpXAPghjU=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e h1:9MlwzLdW7QSDrhDjFlsEYmxpFyIoXmYRon3dt0io31k=
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
|
||||
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
@@ -166,6 +168,8 @@ github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6e
|
||||
github.com/xyproto/xpm v1.2.1 h1:trdvGjjWBsOOKzBBUPT6JvaIQM3acJEEYfbxN7M96wg=
|
||||
github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/ztrue/tracerr v0.3.0 h1:lDi6EgEYhPYPnKcjsYzmWw4EkFEoA/gfe+I9Y5f+h6Y=
|
||||
github.com/ztrue/tracerr v0.3.0/go.mod h1:qEalzze4VN9O8tnhBXScfCrmoJo10o8TN5ciKjm6Mww=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
|
||||
@@ -14,7 +14,7 @@ extern void DisableWindowIcon(struct Application* app);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||
)
|
||||
@@ -105,7 +105,9 @@ been sent.
|
||||
|
||||
func checkFatal(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
globalRadioGroupCache.Dump()
|
||||
globalRadioGroupMap.Dump()
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,7 +152,7 @@ func menuClicked(id uint32) {
|
||||
// Determine if the menu is set or not
|
||||
res, _, err := win32GetMenuState.Call(uintptr(menuItemDetails.parent), uintptr(id), uintptr(MF_BYCOMMAND))
|
||||
if int(res) == -1 {
|
||||
log.Fatal(err)
|
||||
checkFatal(err)
|
||||
}
|
||||
|
||||
flag := MF_CHECKED
|
||||
@@ -163,11 +165,12 @@ func menuClicked(id uint32) {
|
||||
menuItemDetails := getMenuCacheEntry(menuid)
|
||||
res, _, err = win32CheckMenuItem.Call(uintptr(menuItemDetails.parent), uintptr(menuid), uintptr(flag))
|
||||
if int(res) == -1 {
|
||||
log.Fatal(err)
|
||||
checkFatal(err)
|
||||
}
|
||||
}
|
||||
case menu.RadioType:
|
||||
selectRadioItemFromWailsMenuID(wailsMenuID, win32MenuID)
|
||||
err := selectRadioItemFromWailsMenuID(wailsMenuID, win32MenuID)
|
||||
checkFatal(err)
|
||||
}
|
||||
|
||||
// Print the click error - it's not fatal
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
package ffenestri
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
"os"
|
||||
"sync"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
/* ---------------------------------------------------------------------------------
|
||||
@@ -28,6 +32,26 @@ func NewCheckboxCache() *CheckboxCache {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CheckboxCache) Dump() {
|
||||
// Start a new tabwriter
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
|
||||
println("---------------- Checkbox", c, "Dump ----------------")
|
||||
for _, processedMenu := range c.cache {
|
||||
println("Menu", processedMenu)
|
||||
for wailsMenuItemID, win32menus := range processedMenu {
|
||||
println(" WailsMenu: ", wailsMenuItemID)
|
||||
menus := slicer.String()
|
||||
for _, win32menu := range win32menus {
|
||||
menus.Add(fmt.Sprintf("%v", win32menu))
|
||||
}
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\n", wailsMenuItemID, menus.Join(", "))
|
||||
_ = w.Flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CheckboxCache) addToCheckboxCache(menu *menumanager.ProcessedMenu, item wailsMenuItemID, menuID win32MenuItemID) {
|
||||
|
||||
// Get map for menu
|
||||
|
||||
28
v2/internal/ffenestri/windows_errorhandler_debug.go
Normal file
28
v2/internal/ffenestri/windows_errorhandler_debug.go
Normal file
@@ -0,0 +1,28 @@
|
||||
//+build windows,debug
|
||||
|
||||
package ffenestri
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/ztrue/tracerr"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func wall(err error, inputs ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
pc, _, _, _ := runtime.Caller(1)
|
||||
funcName := runtime.FuncForPC(pc).Name()
|
||||
splitName := strings.Split(funcName, ".")
|
||||
message := "[" + splitName[len(splitName)-1] + "]"
|
||||
if len(inputs) > 0 {
|
||||
params := []string{}
|
||||
for _, param := range inputs {
|
||||
params = append(params, fmt.Sprintf("%v", param))
|
||||
}
|
||||
message += "(" + strings.Join(params, " ") + ")"
|
||||
}
|
||||
return tracerr.Errorf(message)
|
||||
}
|
||||
47
v2/internal/ffenestri/windows_errorhandler_production.go
Normal file
47
v2/internal/ffenestri/windows_errorhandler_production.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// +build windows,!debug
|
||||
|
||||
package ffenestri
|
||||
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"golang.org/x/sys/windows"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func wall(err error, inputs ...interface{}) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
pc, _, _, _ := runtime.Caller(1)
|
||||
funcName := runtime.FuncForPC(pc).Name()
|
||||
splitName := strings.Split(funcName, ".")
|
||||
message := "[" + splitName[len(splitName)-1] + "]"
|
||||
if len(inputs) > 0 {
|
||||
params := []string{}
|
||||
for _, param := range inputs {
|
||||
params = append(params, fmt.Sprintf("%v", param))
|
||||
}
|
||||
message += "(" + strings.Join(params, " ") + ")"
|
||||
}
|
||||
|
||||
title, err := syscall.UTF16PtrFromString("Fatal Error")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
text, err := syscall.UTF16PtrFromString("There has been a fatal error. Details:\n" + message)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
var flags uint32 = windows.MB_ICONERROR | windows.MB_OK
|
||||
|
||||
_, err = windows.MessageBox(0, text, title, flags|windows.MB_SYSTEMMODAL)
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
@@ -142,7 +142,10 @@ func (m *Menu) processRadioGroups() error {
|
||||
for _, win32MenuID := range m.initiallySelectedRadioItems {
|
||||
menuItemDetails := getMenuCacheEntry(win32MenuID)
|
||||
wailsMenuID := wailsMenuItemID(menuItemDetails.item.ID)
|
||||
selectRadioItemFromWailsMenuID(wailsMenuID, win32MenuID)
|
||||
err := selectRadioItemFromWailsMenuID(wailsMenuID, win32MenuID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -156,6 +159,8 @@ func (m *Menu) Destroy() error {
|
||||
// Unload this menu's radio groups from the cache
|
||||
globalRadioGroupCache.removeMenuFromRadioBoxCache(m.wailsMenu.Menu)
|
||||
|
||||
globalRadioGroupMap.removeMenuFromRadioGroupMapping(m.wailsMenu.Menu)
|
||||
|
||||
// Delete menu
|
||||
return destroyWin32Menu(m.menu)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
package ffenestri
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/leaanthony/slicer"
|
||||
"os"
|
||||
"sync"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
)
|
||||
@@ -36,6 +40,26 @@ func NewRadioGroupCache() *RadioGroupCache {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RadioGroupCache) Dump() {
|
||||
// Start a new tabwriter
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
|
||||
println("---------------- RadioGroupCache", c, "Dump ----------------")
|
||||
for menu, processedMenu := range c.cache {
|
||||
println("Menu", menu)
|
||||
_, _ = fmt.Fprintf(w, "Wails ID \tWindows ID Pairs\n")
|
||||
for wailsMenuItemID, radioGroupStartEnd := range processedMenu {
|
||||
menus := slicer.String()
|
||||
for _, se := range radioGroupStartEnd {
|
||||
menus.Add(fmt.Sprintf("[%d -> %d]", se.startID, se.endID))
|
||||
}
|
||||
_, _ = fmt.Fprintf(w, "%s\t%s\n", wailsMenuItemID, menus.Join(", "))
|
||||
_ = w.Flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RadioGroupCache) addToRadioGroupCache(menu *menumanager.ProcessedMenu, item wailsMenuItemID, radioGroupMaps []*radioGroupStartEnd) {
|
||||
|
||||
c.mutex.Lock()
|
||||
@@ -87,6 +111,25 @@ func NewRadioGroupMap() *RadioGroupMap {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *RadioGroupMap) Dump() {
|
||||
// Start a new tabwriter
|
||||
w := new(tabwriter.Writer)
|
||||
w.Init(os.Stdout, 8, 8, 0, '\t', 0)
|
||||
|
||||
println("---------------- RadioGroupMap", c, "Dump ----------------")
|
||||
for _, processedMenu := range c.cache {
|
||||
_, _ = fmt.Fprintf(w, "Menu\tWails ID \tWindows IDs\n")
|
||||
for wailsMenuItemID, win32menus := range processedMenu {
|
||||
menus := slicer.String()
|
||||
for _, win32menu := range win32menus {
|
||||
menus.Add(fmt.Sprintf("%v", win32menu))
|
||||
}
|
||||
_, _ = fmt.Fprintf(w, "%p\t%s\t%s\n", processedMenu, wailsMenuItemID, menus.Join(", "))
|
||||
_ = w.Flush()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *RadioGroupMap) addRadioGroupMapping(menu *menumanager.ProcessedMenu, item wailsMenuItemID, win32ID win32MenuItemID) {
|
||||
m.mutex.Lock()
|
||||
|
||||
@@ -106,6 +149,12 @@ func (m *RadioGroupMap) addRadioGroupMapping(menu *menumanager.ProcessedMenu, it
|
||||
m.mutex.Unlock()
|
||||
}
|
||||
|
||||
func (m *RadioGroupMap) removeMenuFromRadioGroupMapping(menu *menumanager.ProcessedMenu) {
|
||||
m.mutex.Lock()
|
||||
delete(m.cache, menu)
|
||||
m.mutex.Unlock()
|
||||
}
|
||||
|
||||
func (m *RadioGroupMap) getRadioGroupMapping(wailsMenuID wailsMenuItemID) []win32MenuItemID {
|
||||
m.mutex.Lock()
|
||||
result := []win32MenuItemID{}
|
||||
@@ -119,7 +168,7 @@ func (m *RadioGroupMap) getRadioGroupMapping(wailsMenuID wailsMenuItemID) []win3
|
||||
return result
|
||||
}
|
||||
|
||||
func selectRadioItemFromWailsMenuID(wailsMenuID wailsMenuItemID, win32MenuID win32MenuItemID) {
|
||||
func selectRadioItemFromWailsMenuID(wailsMenuID wailsMenuItemID, win32MenuID win32MenuItemID) error {
|
||||
radioItemGroups := globalRadioGroupCache.getRadioGroupMappings(wailsMenuID)
|
||||
// Figure out offset into group
|
||||
var offset win32MenuItemID = 0
|
||||
@@ -132,6 +181,14 @@ func selectRadioItemFromWailsMenuID(wailsMenuID wailsMenuItemID, win32MenuID win
|
||||
for _, radioItemGroup := range radioItemGroups {
|
||||
selectedMenuID := radioItemGroup.startID + offset
|
||||
menuItemDetails := getMenuCacheEntry(selectedMenuID)
|
||||
selectRadioItem(selectedMenuID, radioItemGroup.startID, radioItemGroup.endID, menuItemDetails.parent)
|
||||
if menuItemDetails != nil {
|
||||
if menuItemDetails.parent != 0 {
|
||||
err := selectRadioItem(selectedMenuID, radioItemGroup.startID, radioItemGroup.endID, menuItemDetails.parent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
package ffenestri
|
||||
|
||||
import (
|
||||
"log"
|
||||
"unsafe"
|
||||
|
||||
"github.com/wailsapp/wails/v2/internal/menumanager"
|
||||
@@ -45,15 +44,15 @@ const MF_BYPOSITION uint32 = 0x00000400
|
||||
func createWin32Menu() (win32Menu, error) {
|
||||
res, _, err := win32CreateMenu.Call()
|
||||
if res == 0 {
|
||||
return 0, err
|
||||
return 0, wall(err)
|
||||
}
|
||||
return win32Menu(res), nil
|
||||
}
|
||||
|
||||
func destroyWin32Menu(menu win32Menu) error {
|
||||
res, _, err := win32CreateMenu.Call(uintptr(menu))
|
||||
res, _, err := win32DestroyMenu.Call(uintptr(menu))
|
||||
if res == 0 {
|
||||
return err
|
||||
return wall(err, "Menu:", menu)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -61,7 +60,7 @@ func destroyWin32Menu(menu win32Menu) error {
|
||||
func createWin32PopupMenu() (win32Menu, error) {
|
||||
res, _, err := win32CreatePopupMenu.Call()
|
||||
if res == 0 {
|
||||
return 0, err
|
||||
return 0, wall(err)
|
||||
}
|
||||
return win32Menu(res), nil
|
||||
}
|
||||
@@ -78,7 +77,7 @@ func appendWin32MenuItem(menu win32Menu, flags uintptr, submenuOrID uintptr, lab
|
||||
uintptr(unsafe.Pointer(menuText)),
|
||||
)
|
||||
if res == 0 {
|
||||
return err
|
||||
return wall(err, "Menu", menu, "Flags", flags, "submenuOrID", submenuOrID, "label", label)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -86,14 +85,15 @@ func appendWin32MenuItem(menu win32Menu, flags uintptr, submenuOrID uintptr, lab
|
||||
func setWindowMenu(window win32Window, menu win32Menu) error {
|
||||
res, _, err := win32SetMenu.Call(uintptr(window), uintptr(menu))
|
||||
if res == 0 {
|
||||
return err
|
||||
return wall(err, "window", window, "menu", menu)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func selectRadioItem(selectedMenuID, startMenuItemID, endMenuItemID win32MenuItemID, parent win32Menu) {
|
||||
func selectRadioItem(selectedMenuID, startMenuItemID, endMenuItemID win32MenuItemID, parent win32Menu) error {
|
||||
res, _, err := win32CheckMenuRadioItem.Call(uintptr(parent), uintptr(startMenuItemID), uintptr(endMenuItemID), uintptr(selectedMenuID), uintptr(MF_BYCOMMAND))
|
||||
if int(res) == 0 {
|
||||
log.Fatal(err)
|
||||
return wall(err, selectedMenuID, startMenuItemID, endMenuItemID, parent)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ func (m *Manager) processApplicationMenu() error {
|
||||
|
||||
// Process the menu
|
||||
m.processedApplicationMenu = NewWailsMenu(m.applicationMenuItemMap, m.applicationMenu)
|
||||
m.processRadioGroups(m.processedApplicationMenu, m.applicationMenuItemMap)
|
||||
applicationMenuJSON, err := m.processedApplicationMenu.AsJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -22,6 +22,9 @@ type Manager struct {
|
||||
// Tray menu stores
|
||||
trayMenus map[string]*TrayMenu
|
||||
trayMenuPointers map[*menu.TrayMenu]string
|
||||
|
||||
// Radio groups
|
||||
radioGroups map[*menu.MenuItem][]*menu.MenuItem
|
||||
}
|
||||
|
||||
func NewManager() *Manager {
|
||||
@@ -31,6 +34,7 @@ func NewManager() *Manager {
|
||||
contextMenuPointers: make(map[*menu.ContextMenu]string),
|
||||
trayMenus: make(map[string]*TrayMenu),
|
||||
trayMenuPointers: make(map[*menu.TrayMenu]string),
|
||||
radioGroups: make(map[*menu.MenuItem][]*menu.MenuItem),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +77,14 @@ func (m *Manager) ProcessClick(menuID string, data string, menuType string, pare
|
||||
menuItem.Checked = !menuItem.Checked
|
||||
}
|
||||
|
||||
if menuItem.Type == menu.RadioType {
|
||||
println("Toggle radio")
|
||||
// Get my radio group
|
||||
for _, radioMenuItem := range m.radioGroups[menuItem] {
|
||||
radioMenuItem.Checked = (radioMenuItem == menuItem)
|
||||
}
|
||||
}
|
||||
|
||||
if menuItem.Click == nil {
|
||||
// No callback
|
||||
return fmt.Errorf("No callback for menu '%s'", menuItem.Label)
|
||||
@@ -89,3 +101,16 @@ func (m *Manager) ProcessClick(menuID string, data string, menuType string, pare
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) processRadioGroups(processedMenu *WailsMenu, itemMap *MenuItemMap) {
|
||||
for _, group := range processedMenu.RadioGroups {
|
||||
radioGroupMenuItems := []*menu.MenuItem{}
|
||||
for _, member := range group.Members {
|
||||
item := m.getMenuItemByID(itemMap, member)
|
||||
radioGroupMenuItems = append(radioGroupMenuItems, item)
|
||||
}
|
||||
for _, radioGroupMenuItem := range radioGroupMenuItems {
|
||||
m.radioGroups[radioGroupMenuItem] = radioGroupMenuItems
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user