Skip to content

Commit a3c0024

Browse files
authored
Merge pull request #4312 from atterpac/v3/mac-menu-fixes
V3/mac menu fixes
2 parents 6be5913 + ae4a217 commit a3c0024

8 files changed

Lines changed: 972 additions & 481 deletions

File tree

v3/examples/menu/main.go

Lines changed: 63 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
_ "embed"
5+
"fmt"
56
"log"
67
"runtime"
78

@@ -468,24 +469,30 @@ func main() {
468469

469470
// Add a button to update the submenu label in the Demo menu
470471
labelOperations.Add("Update Demo Submenu Label").OnClick(func(*application.Context) {
471-
// Find the submenu item in the Demo menu
472-
submenuItem := myMenu.FindByLabel("Submenu")
473-
if submenuItem != nil {
474-
// Change the label
475-
submenuItem.SetLabel("Updated Submenu Label")
476-
// Update the menu to reflect the changes
477-
menu.Update()
478-
println("Submenu label changed to: Updated Submenu Label")
472+
// Use the direct reference 'myDemoMenuItemForSubmenu' captured when the menu was created.
473+
if submenu != nil {
474+
oldLabel := submenu.Label()
475+
targetNewLabel := "Updated Submenu Label"
476+
477+
if oldLabel == targetNewLabel {
478+
fmt.Printf("Demo submenu ('%s') label in myMenu is already: %s\n", oldLabel, targetNewLabel)
479+
return
480+
}
479481

480-
// Verify the change
481-
updatedItem := myMenu.FindByLabel("Updated Submenu Label")
482-
if updatedItem != nil {
483-
println("Verification: Found submenu with updated label:", updatedItem.Label())
482+
submenu.SetLabel(targetNewLabel)
483+
menu.Update() // Global update
484+
485+
fmt.Printf("Submenu label in myMenu changed from '%s' to: '%s'\n", oldLabel, submenu.Label())
486+
487+
// Verification (using the direct reference)
488+
if submenu.Label() == targetNewLabel {
489+
fmt.Printf("Verification: Submenu MenuItem in myMenu now has label: %s\n", submenu.Label())
484490
} else {
485-
println("Verification failed: Could not find submenu with updated label")
491+
fmt.Printf("Verification FAILED: Submenu MenuItem in myMenu has label: %s, but expected %s\n", submenu.Label(), targetNewLabel)
486492
}
487493
} else {
488-
println("Submenu not found!")
494+
// This means myDemoMenuItemForSubmenu was nil when captured (myMenu.GetItemByLabel("Submenu") failed during setup).
495+
fmt.Println("Error: The 'myDemoMenuItemForSubmenu' variable is nil (was not found during menu setup).")
489496
}
490497
})
491498

@@ -519,47 +526,61 @@ func main() {
519526

520527
// Add a button to the nested submenu to change its own label
521528
nestedSubmenu.Add("Change My Own Label").OnClick(func(*application.Context) {
522-
// Find the nested submenu item
523-
submenuItem := labelOperations.FindByLabel("Nested Submenu")
524-
if submenuItem != nil {
525-
// Change the label
526-
submenuItem.SetLabel("Self-Updated Submenu")
527-
// Update the menu to reflect the changes
528-
menu.Update()
529-
println("Nested submenu changed its own label to: Self-Updated Submenu")
529+
// 'nestedSubmenu' is the Go variable pointing to the menu whose label we want to change.
530+
// It's captured by this closure.
531+
if nestedSubmenu != nil {
532+
oldLabel := nestedSubmenu.Label()
533+
targetNewLabel := "Self-Updated Submenu"
534+
535+
// Avoid re-setting if already set, to prevent redundant updates/logs if clicked multiple times
536+
if oldLabel == targetNewLabel {
537+
fmt.Printf("Nested submenu (self) label is already: %s\n", targetNewLabel)
538+
return
539+
}
530540

531-
// Verify the change
532-
updatedItem := labelOperations.FindByLabel("Self-Updated Submenu")
533-
if updatedItem != nil {
534-
println("Verification: Found nested submenu with self-updated label:", updatedItem.Label())
541+
nestedSubmenu.SetLabel(targetNewLabel)
542+
menu.Update() // Or app.Update()
543+
544+
fmt.Printf("Nested submenu (self) changed label from '%s' to: %s\n", oldLabel, nestedSubmenu.Label())
545+
546+
// Verification
547+
if nestedSubmenu.Label() == targetNewLabel {
548+
fmt.Printf("Verification: Nested submenu (self) object now has label: %s\n", nestedSubmenu.Label())
535549
} else {
536-
println("Verification failed: Could not find nested submenu with self-updated label")
550+
fmt.Printf("Verification FAILED: Nested submenu (self) object has label: %s, but expected %s\n", nestedSubmenu.Label(), targetNewLabel)
537551
}
538552
} else {
539-
println("Nested submenu not found!")
553+
println("Error: The 'nestedSubmenu' variable is nil in the 'Change My Own Label' click handler scope.")
540554
}
541555
})
542556

543557
// Add a button to update the nested submenu's label
544558
labelOperations.Add("Update Nested Submenu Label").OnClick(func(*application.Context) {
545-
// Find the nested submenu item
546-
submenuItem := labelOperations.FindByLabel("Nested Submenu")
547-
if submenuItem != nil {
548-
// Change the label
549-
submenuItem.SetLabel("Updated Nested Submenu")
550-
// Update the menu to reflect the changes
551-
menu.Update()
552-
println("Nested submenu label changed to: Updated Nested Submenu")
559+
// 'nestedSubmenu' is the Go variable pointing to the target menu.
560+
// It's captured by this closure.
561+
if nestedSubmenu != nil {
562+
oldLabel := nestedSubmenu.Label()
563+
targetNewLabel := "Updated Nested Submenu"
564+
565+
// Avoid re-setting if already set
566+
if oldLabel == targetNewLabel {
567+
fmt.Printf("Nested submenu label is already: %s\n", targetNewLabel)
568+
return
569+
}
553570

554-
// Verify the change
555-
updatedItem := labelOperations.FindByLabel("Updated Nested Submenu")
556-
if updatedItem != nil {
557-
println("Verification: Found nested submenu with updated label:", updatedItem.Label())
571+
nestedSubmenu.SetLabel(targetNewLabel)
572+
menu.Update() // Or app.Update()
573+
574+
fmt.Printf("Nested submenu label changed from '%s' to: %s\n", oldLabel, nestedSubmenu.Label())
575+
576+
// Verification
577+
if nestedSubmenu.Label() == targetNewLabel {
578+
fmt.Printf("Verification: Nested submenu object now has label: %s\n", nestedSubmenu.Label())
558579
} else {
559-
println("Verification failed: Could not find nested submenu with updated label")
580+
fmt.Printf("Verification FAILED: Nested submenu object has label: %s, but expected %s\n", nestedSubmenu.Label(), targetNewLabel)
560581
}
561582
} else {
562-
println("Nested submenu not found!")
583+
println("Error: The 'nestedSubmenu' variable is nil in the 'Update Nested Submenu Label' click handler scope.")
563584
}
564585
})
565586

v3/pkg/application/application_darwin.go

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ static void startSingleInstanceListener(const char *uniqueID) {
169169
import "C"
170170
import (
171171
"encoding/json"
172+
"fmt"
172173
"unsafe"
173174

174175
"github.com/wailsapp/wails/v3/internal/operatingsystem"
@@ -218,14 +219,48 @@ func (m *macosApp) getCurrentWindowID() uint {
218219

219220
func (m *macosApp) setApplicationMenu(menu *Menu) {
220221
if menu == nil {
221-
// Create a default menu for mac
222-
menu = DefaultApplicationMenu()
222+
// Create a default menu for mac.
223+
defaultM := DefaultApplicationMenu()
224+
// DefaultApplicationMenu creates a new Menu. It needs to be fully processed.
225+
defaultM.Update() // This processes defaultM, creates its impl, and updates its nsMenu.
226+
// Since defaultM is a new instance, this Update() won't loop back here for itself.
227+
if defaultM.impl != nil { // Ensure impl was created
228+
nsMenu := (defaultM.impl).(*macosMenu).nsMenu
229+
InvokeSync(func() { // Ensure C call is on main thread
230+
m.applicationMenu = nsMenu
231+
C.setApplicationMenu(nsMenu)
232+
})
233+
} else {
234+
fmt.Println("Error: DefaultApplicationMenu().impl is nil. Cannot set default menu.")
235+
}
236+
return
237+
}
238+
239+
// If menu is not nil:
240+
if menu.impl == nil {
241+
// This menu hasn't been processed by Menu.Update() to create its platform impl.
242+
fmt.Println("Info: Initializing menu.impl in setApplicationMenu as it was nil.")
243+
menu.processRadioGroups()
244+
menu.impl = newMenuImpl(menu) // Creates *macosMenu
245+
// Directly call the platform-specific update on the new impl
246+
if macosM, ok := menu.impl.(*macosMenu); ok {
247+
macosM.update() // Builds/updates nsMenu within macosM. This uses InvokeSync internally for its C calls.
248+
} else {
249+
fmt.Println("Critical Error: menu.impl is not *macosMenu after newMenuImpl on macOS for a non-nil menu.")
250+
return // Cannot proceed to set native menu
251+
}
223252
}
224-
menu.Update()
225253

226-
// Convert impl to macosMenu object
227-
m.applicationMenu = (menu.impl).(*macosMenu).nsMenu
228-
C.setApplicationMenu(m.applicationMenu)
254+
// At this point, menu.impl should be non-nil and its nsMenu should be built.
255+
if menu.impl != nil {
256+
nsMenu := (menu.impl).(*macosMenu).nsMenu
257+
InvokeSync(func() { // Ensure C call is on main thread
258+
m.applicationMenu = nsMenu
259+
C.setApplicationMenu(nsMenu)
260+
})
261+
} else {
262+
fmt.Println("Error: menu.impl is still nil after attempted initialization in setApplicationMenu. Native menu not set.")
263+
}
229264
}
230265

231266
func (m *macosApp) run() error {

0 commit comments

Comments
 (0)