wails/v3/pkg/application/menuitem_linux.go
Lea Anthony 3087ba0bdc
Refactor Manager API to use singular naming convention (#4367)
* Refactor Manager API to use singular naming convention

This is a RENAME-ONLY exercise that converts the Wails v3 Manager API from plural to singular naming for better consistency and clarity.

## Changes Applied

### API Transformations:
- `app.Windows.*` → `app.Window.*`
- `app.Events.*` → `app.Event.*`
- `app.ContextMenus.*` → `app.ContextMenu.*`
- `app.KeyBindings.*` → `app.KeyBinding.*`
- `app.Dialogs.*` → `app.Dialog.*`
- `app.Menus.*` → `app.Menu.*`
- `app.Screens.*` → `app.Screen.*`

### Files Updated:
- **Core Application**: 22 files in `v3/pkg/application/`
- **Examples**: 43+ files in `v3/examples/`
- **Documentation**: 13 files in `docs/src/content/docs/`
- **CLI Tests**: 1 file in `v3/internal/commands/`

### Critical Constraints Preserved:
-  Event string constants unchanged (e.g., "windows:WindowShow")
-  Platform event names preserved (events.Windows, events.Mac, etc.)
-  TypeScript API remains compatible
-  All functionality intact

### Verification:
-  All examples build successfully (`task test:examples` passes)
-  Application package compiles without errors
-  Documentation reflects new API patterns

## Benefits

- **Improved Clarity**: Singular names are more intuitive (`app.Window` vs `app.Windows`)
- **Better Consistency**: Aligns with Go naming conventions
- **Enhanced Developer Experience**: Clearer autocomplete and API discovery

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix generator testcases and add cross-platform test cleanup

- Update 28 generator testcase files to use singular API (app.Window.New() vs app.Windows.New())
- Add cross-platform cleanup system with Go script to remove test artifacts
- Add test:all task with comprehensive testing and automatic cleanup
- Fix cleanup to target files vs directories correctly (preserves source directories)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* Fix remaining Windows CI failures by updating all plural API usage to singular

Fixed the last remaining instances of old plural Manager API usage:
- tests/window-visibility-test/main.go: Updated all app.Windows -> app.Window and app.Menus -> app.Menu
- internal/templates/_common/main.go.tmpl: Updated app.Windows -> app.Window and app.Events -> app.Event
- pkg/services/badge/badge_windows.go: Updated app.Windows -> app.Window (Windows-specific fix)

These fixes address the Windows CI failures where platform-specific files still used the old API.
The tests didn't catch this locally because Windows-specific files only compile on Windows.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-06-22 12:19:14 +10:00

436 lines
9.1 KiB
Go

//go:build linux
package application
import (
"fmt"
"runtime"
)
type linuxMenuItem struct {
menuItem *MenuItem
native pointer
handlerId uint
}
func (l linuxMenuItem) setTooltip(tooltip string) {
InvokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
menuItemSetToolTip(l.native, tooltip)
})
}
func (l linuxMenuItem) destroy() {
InvokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
menuItemDestroy(l.native)
})
}
func (l linuxMenuItem) blockSignal() {
if l.handlerId != 0 {
menuItemSignalBlock(l.native, l.handlerId, true)
}
}
func (l linuxMenuItem) setBitmap(data []byte) {
InvokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
menuItemSetBitmap(l.native, data)
})
}
func (l linuxMenuItem) unBlockSignal() {
if l.handlerId != 0 {
menuItemSignalBlock(l.native, l.handlerId, false)
}
}
func (l linuxMenuItem) setLabel(s string) {
InvokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
menuItemSetLabel(l.native, s)
})
}
func (l linuxMenuItem) isChecked() bool {
return menuItemChecked(l.native)
}
func (l linuxMenuItem) setDisabled(disabled bool) {
InvokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
menuItemSetDisabled(l.native, disabled)
})
}
func (l linuxMenuItem) setChecked(checked bool) {
InvokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
menuItemSetChecked(l.native, checked)
})
}
func (l linuxMenuItem) setHidden(hidden bool) {
InvokeSync(func() {
l.blockSignal()
defer l.unBlockSignal()
widgetSetVisible(l.native, hidden)
})
}
func (l linuxMenuItem) setAccelerator(accelerator *accelerator) {
fmt.Println("setAccelerator", accelerator)
// Set the keyboard shortcut of the menu item
// var modifier C.int
// var key *C.char
if accelerator != nil {
// modifier = C.int(toMacModifier(accelerator.Modifiers))
// key = C.CString(accelerator.Key)
}
// Convert the key to a string
// C.setMenuItemKeyEquivalent(m.nsMenuItem, key, modifier)
}
func newMenuItemImpl(item *MenuItem) *linuxMenuItem {
result := &linuxMenuItem{
menuItem: item,
}
switch item.itemType {
case text:
result.native = menuItemNew(item.label, item.bitmap)
case checkbox:
result.native = menuCheckItemNew(item.label, item.bitmap)
result.setChecked(item.checked)
if item.accelerator != nil {
result.setAccelerator(item.accelerator)
}
case submenu:
result.native = menuItemNew(item.label, item.bitmap)
default:
panic(fmt.Sprintf("Unknown menu type: %v", item.itemType))
}
result.setDisabled(result.menuItem.disabled)
return result
}
func newRadioItemImpl(item *MenuItem, group GSListPointer) *linuxMenuItem {
result := &linuxMenuItem{
menuItem: item,
native: menuRadioItemNew(group, item.label),
}
result.setChecked(item.checked)
result.setDisabled(result.menuItem.disabled)
return result
}
func newSpeechMenu() *MenuItem {
speechMenu := NewMenu()
speechMenu.Add("Start Speaking").
SetAccelerator("CmdOrCtrl+OptionOrAlt+Shift+.").
OnClick(func(ctx *Context) {
// C.startSpeaking()
})
speechMenu.Add("Stop Speaking").
SetAccelerator("CmdOrCtrl+OptionOrAlt+Shift+,").
OnClick(func(ctx *Context) {
// C.stopSpeaking()
})
subMenu := NewSubMenuItem("Speech")
subMenu.submenu = speechMenu
return subMenu
}
func newFrontMenuItem() *MenuItem {
panic("implement me")
}
func newHideMenuItem() *MenuItem {
return NewMenuItem("Hide " + globalApplication.options.Name).
SetAccelerator("CmdOrCtrl+h").
OnClick(func(ctx *Context) {
// C.hideApplication()
})
}
func newHideOthersMenuItem() *MenuItem {
return NewMenuItem("Hide Others").
SetAccelerator("CmdOrCtrl+OptionOrAlt+h").
OnClick(func(ctx *Context) {
// C.hideOthers()
})
}
func newUnhideMenuItem() *MenuItem {
return NewMenuItem("Show All").
OnClick(func(ctx *Context) {
// C.showAll()
})
}
func newUndoMenuItem() *MenuItem {
return NewMenuItem("Undo").
SetAccelerator("CmdOrCtrl+z").
OnClick(func(ctx *Context) {
// C.undo()
})
}
// newRedoMenuItem creates a new menu item for redoing the last action
func newRedoMenuItem() *MenuItem {
return NewMenuItem("Redo").
SetAccelerator("CmdOrCtrl+Shift+z").
OnClick(func(ctx *Context) {
// C.redo()
})
}
func newCutMenuItem() *MenuItem {
return NewMenuItem("Cut").
SetAccelerator("CmdOrCtrl+x").
OnClick(func(ctx *Context) {
// C.cut()
})
}
func newCopyMenuItem() *MenuItem {
return NewMenuItem("Copy").
SetAccelerator("CmdOrCtrl+c").
OnClick(func(ctx *Context) {
// C.copy()
})
}
func newPasteMenuItem() *MenuItem {
return NewMenuItem("Paste").
SetAccelerator("CmdOrCtrl+v").
OnClick(func(ctx *Context) {
// C.paste()
})
}
func newPasteAndMatchStyleMenuItem() *MenuItem {
return NewMenuItem("Paste and Match Style").
SetAccelerator("CmdOrCtrl+OptionOrAlt+Shift+v").
OnClick(func(ctx *Context) {
// C.pasteAndMatchStyle()
})
}
func newDeleteMenuItem() *MenuItem {
return NewMenuItem("Delete").
SetAccelerator("backspace").
OnClick(func(ctx *Context) {
// C.delete()
})
}
func newQuitMenuItem() *MenuItem {
return NewMenuItem("Quit " + globalApplication.options.Name).
SetAccelerator("CmdOrCtrl+q").
OnClick(func(ctx *Context) {
globalApplication.Quit()
})
}
func newSelectAllMenuItem() *MenuItem {
return NewMenuItem("Select All").
SetAccelerator("CmdOrCtrl+a").
OnClick(func(ctx *Context) {
// C.selectAll()
})
}
func newAboutMenuItem() *MenuItem {
return NewMenuItem("About " + globalApplication.options.Name).
OnClick(func(ctx *Context) {
globalApplication.Menu.ShowAbout()
})
}
func newCloseMenuItem() *MenuItem {
return NewMenuItem("Close").
SetAccelerator("CmdOrCtrl+w").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.Window.Current()
if currentWindow != nil {
currentWindow.Close()
}
})
}
func newReloadMenuItem() *MenuItem {
return NewMenuItem("Reload").
SetAccelerator("CmdOrCtrl+r").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.Window.Current()
if currentWindow != nil {
currentWindow.Reload()
}
})
}
func newForceReloadMenuItem() *MenuItem {
return NewMenuItem("Force Reload").
SetAccelerator("CmdOrCtrl+Shift+r").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.Window.Current()
if currentWindow != nil {
currentWindow.ForceReload()
}
})
}
func newToggleFullscreenMenuItem() *MenuItem {
result := NewMenuItem("Toggle Full Screen").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.Window.Current()
if currentWindow != nil {
currentWindow.ToggleFullscreen()
}
})
if runtime.GOOS == "darwin" {
result.SetAccelerator("Ctrl+Command+F")
} else {
result.SetAccelerator("F11")
}
return result
}
func newZoomResetMenuItem() *MenuItem {
// reset zoom menu item
return NewMenuItem("Actual Size").
SetAccelerator("CmdOrCtrl+0").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.Window.Current()
if currentWindow != nil {
currentWindow.ZoomReset()
}
})
}
func newZoomInMenuItem() *MenuItem {
return NewMenuItem("Zoom In").
SetAccelerator("CmdOrCtrl+plus").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.Window.Current()
if currentWindow != nil {
currentWindow.ZoomIn()
}
})
}
func newZoomOutMenuItem() *MenuItem {
return NewMenuItem("Zoom Out").
SetAccelerator("CmdOrCtrl+-").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.Window.Current()
if currentWindow != nil {
currentWindow.ZoomOut()
}
})
}
func newMinimizeMenuItem() *MenuItem {
return NewMenuItem("Minimize").
SetAccelerator("CmdOrCtrl+M").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.Window.Current()
if currentWindow != nil {
currentWindow.Minimise()
}
})
}
func newZoomMenuItem() *MenuItem {
return NewMenuItem("Zoom").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.Window.Current()
if currentWindow != nil {
currentWindow.Zoom()
}
})
}
func newFullScreenMenuItem() *MenuItem {
return NewMenuItem("Fullscreen").
OnClick(func(ctx *Context) {
currentWindow := globalApplication.Window.Current()
if currentWindow != nil {
currentWindow.Fullscreen()
}
})
}
func newPrintMenuItem() *MenuItem {
panic("Implement me")
}
func newPageLayoutMenuItem() *MenuItem {
panic("Implement me")
}
func newShowAllMenuItem() *MenuItem {
panic("Implement me")
}
func newBringAllToFrontMenuItem() *MenuItem {
panic("Implement me")
}
func newNewFileMenuItem() *MenuItem {
panic("Implement me")
}
func newOpenMenuItem() *MenuItem {
panic("Implement me")
}
func newSaveMenuItem() *MenuItem {
panic("Implement me")
}
func newSaveAsMenuItem() *MenuItem {
panic("Implement me")
}
func newStartSpeakingMenuItem() *MenuItem {
panic("Implement me")
}
func newStopSpeakingMenuItem() *MenuItem {
panic("Implement me")
}
func newRevertMenuItem() *MenuItem {
panic("Implement me")
}
func newFindMenuItem() *MenuItem {
panic("Implement me")
}
func newFindAndReplaceMenuItem() *MenuItem {
panic("Implement me")
}
func newFindNextMenuItem() *MenuItem {
panic("Implement me")
}
func newFindPreviousMenuItem() *MenuItem {
panic("Implement me")
}
func newHelpMenuItem() *MenuItem {
panic("Implement me")
}