From f5df9ef609c410eddc16af7681008f4ea58fe49c Mon Sep 17 00:00:00 2001 From: kali Date: Thu, 8 Nov 2018 20:36:30 +0100 Subject: keep a slice with the visible items to fix positioning bug in windows, Hide() destroys a menuItem. this has problems when later we try to Show() it and end up using the original menuID, for instance if we did hide several elements in a row: if we insert the element in the original position, it will end up inserted past some other elements that were intended to be placed after the items that were hidden. by keeping a slice where we insert and delete the id of the elements that are shown, we can sort this slice and take the index of a given element as the correct index in which we want to insert the menuItem when calling Show() again. - Resolves: #72 --- systray_windows.go | 58 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 41 insertions(+), 17 deletions(-) (limited to 'systray_windows.go') diff --git a/systray_windows.go b/systray_windows.go index 26a0f80..9d560b7 100644 --- a/systray_windows.go +++ b/systray_windows.go @@ -8,6 +8,7 @@ import ( "io/ioutil" "os" "path/filepath" + "sort" "syscall" "unsafe" @@ -172,6 +173,8 @@ type winTray struct { wmSystrayMessage, wmTaskbarCreated uint32 + + visibleItems []uint32 } // Loads an image from file and shows it in tray. @@ -462,29 +465,25 @@ func (t *winTray) addOrUpdateMenuItem(menuId int32, title string, disabled, chec } mi.Size = uint32(unsafe.Sizeof(mi)) - // The return value is the identifier of the specified menu item. - // If the menu item identifier is NULL or if the specified item opens a submenu, the return value is -1. - // If the given menu identifier is not found (becase we deleted the menu item when hiding it), - // the call will return the next integer that is available as an existing menu item. - res, _, err := pGetMenuItemID.Call(uintptr(t.menu), uintptr(menuId)) - if int32(res) == -1 || int32(res) != menuId { + // We set the menu item info based on the menuID + res, _, err := pSetMenuItemInfo.Call( + uintptr(t.menu), + uintptr(menuId), + 0, + uintptr(unsafe.Pointer(&mi)), + ) + + if res == 0 { + t.addToVisibleItems(menuId) + position := t.getVisibleItemIndex(menuId) res, _, err = pInsertMenuItem.Call( uintptr(t.menu), - uintptr(menuId), + uintptr(position), 1, uintptr(unsafe.Pointer(&mi)), ) if res == 0 { - return err - } - } else { - res, _, err = pSetMenuItemInfo.Call( - uintptr(t.menu), - uintptr(menuId), - 0, - uintptr(unsafe.Pointer(&mi)), - ) - if res == 0 { + t.delFromVisibleItems(menuId) return err } } @@ -535,6 +534,7 @@ func (t *winTray) hideMenuItem(menuId int32) error { if res == 0 && err.(syscall.Errno) != ERROR_SUCCESS { return err } + t.delFromVisibleItems(menuId) return nil } @@ -567,6 +567,30 @@ func (t *winTray) showMenu() error { return nil } +func (t *winTray) delFromVisibleItems(val int32) { + for i, itemval := range t.visibleItems { + if uint32(val) == itemval { + t.visibleItems = append(t.visibleItems[:i], t.visibleItems[i+1:]...) + break + } + } +} + +func (t *winTray) addToVisibleItems(val int32) { + newvisible := append(t.visibleItems, uint32(val)) + sort.Slice(newvisible, func(i, j int) bool { return newvisible[i] < newvisible[j] }) + t.visibleItems = newvisible +} + +func (t *winTray) getVisibleItemIndex(val int32) int { + for i, itemval := range t.visibleItems { + if uint32(val) == itemval { + return i + } + } + return -1 +} + func nativeLoop() { if err := wt.initInstance(); err != nil { log.Errorf("Unable to init instance: %v", err) -- cgit v1.2.3