Skip to content

Feature Request: Add Support for Custom Menu Items in Main App Menu (macOS) #1725

@camdarley

Description

@camdarley

Feature Request: Add Support for Custom Menu Items in Main App Menu (macOS)

Description

Currently, pywebview allows creating custom menus through the menu parameter, but these menus are always added as separate top-level menus in the menu bar. There is no way to add custom menu items to the main application menu (the first menu that shows the app name on macOS).

The main app menu currently only contains the standard system items:

  • About
  • Services
  • Hide/Show
  • Quit

This limitation prevents developers from adding app-specific items like:

  • Preferences/Settings
  • Check for Updates
  • License Information
  • Custom app-specific actions

Use Case

Many macOS applications have custom items in their main app menu. For example:

  • Preferences (⌘,) - Standard location for app settings
  • Check for Updates - Common for apps with auto-update functionality
  • Registration/License - For commercial applications
  • Custom Actions - App-specific global actions

Proposed Solutions

I'd like to propose several approaches and get feedback on which would be most appropriate:

Option 1: Special Flag in Menu Class (Minimal API Change)

Add an is_app_menu parameter to the Menu class:

import webview
from webview import Menu, MenuAction

def open_preferences():
    print("Opening preferences...")

def check_updates():
    print("Checking for updates...")

# Special menu with is_app_menu flag
app_menu_items = Menu('', [
    MenuAction('Preferences...', open_preferences),
    MenuSeparator(),
    MenuAction('Check for Updates', check_updates)
], is_app_menu=True)

# Regular menus
file_menu = Menu('File', [
    MenuAction('New', new_file),
    MenuAction('Open', open_file)
])

window = webview.create_window('App', menu=[app_menu_items, file_menu])

Pros:

  • Minimal API change
  • Backward compatible
  • Clear intent with the flag

Cons:

  • The title parameter is ignored when is_app_menu=True
  • Might be confusing to have a Menu object that doesn't create a menu

Option 2: Separate Parameter for App Menu Items

Add a new app_menu_items parameter to create_window:

import webview
from webview import MenuAction, MenuSeparator

def open_preferences():
    print("Opening preferences...")

app_items = [
    MenuAction('Preferences...', open_preferences),
    MenuSeparator(),
    MenuAction('Check for Updates', check_updates)
]

regular_menus = [
    Menu('File', [MenuAction('New', new_file)])
]

window = webview.create_window(
    'App',
    menu=regular_menus,
    app_menu_items=app_items  # New parameter
)

Pros:

  • Clear separation of concerns
  • No ambiguity about menu titles
  • More explicit API

Cons:

  • Adds another parameter to create_window
  • Breaks existing API pattern

Option 3: Special Menu Title Convention

Use a special title (like __app__ or empty string) to indicate app menu items:

import webview
from webview import Menu, MenuAction

# Empty title or special string means app menu
app_menu = Menu('', [  # or Menu('__app__', [...])
    MenuAction('Preferences...', open_preferences),
    MenuAction('Check for Updates', check_updates)
])

file_menu = Menu('File', [
    MenuAction('New', new_file)
])

window = webview.create_window('App', menu=[app_menu, file_menu])

Pros:

  • No API changes needed
  • Works with existing code structure

Cons:

  • Implicit behavior based on magic strings
  • Less discoverable

Option 4: Platform-Specific Menu Configuration

Create a more comprehensive menu system that handles platform differences:

import webview
from webview import MenuConfig, MenuAction

menu_config = MenuConfig()
menu_config.add_to_app_menu([  # macOS only, ignored on other platforms
    MenuAction('Preferences...', open_preferences),
    MenuAction('Check for Updates', check_updates)
])
menu_config.add_menu('File', [
    MenuAction('New', new_file)
])

window = webview.create_window('App', menu_config=menu_config)

Pros:

  • Can handle platform-specific differences elegantly
  • More extensible for future menu features
  • Could support shortcuts, accelerators, etc.

Cons:

  • Larger API change
  • More complex implementation

Implementation Considerations

Platform Compatibility

  • macOS: Full support - has a distinct app menu
  • Windows/Linux: These platforms don't have a separate app menu. Options:
    • Ignore app menu items on these platforms
    • Add them to a "File" or first menu
    • Create a synthetic app menu

Menu Item Positioning

Where should custom items be placed in the app menu?

  1. After "About" but before system items
  2. Before "Quit" at the bottom
  3. Configurable position

Separator Handling

Should we automatically add separators between custom items and system items, or leave it to the developer?

Questions for Maintainers

  1. Which approach aligns best with pywebview's design philosophy?
  2. Are there any concerns about platform compatibility?
  3. Should this be macOS-only or have fallback behavior for other platforms?
  4. Any preferences for the implementation approach?

Willing to Contribute

I'm happy to implement this feature once we agree on the approach. I've already explored the codebase and understand how the current menu system works in the Cocoa implementation.

Related Issues

  • This could potentially relate to keyboard shortcuts/accelerators support
  • May benefit from a more comprehensive menu system redesign

Environment:

  • pywebview version: [latest master]
  • Platform: macOS
  • Python version: 3.x

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions