mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-15 23:25:49 +01:00
* feat(v3): add server mode for headless HTTP deployment Server mode allows Wails applications to run as pure HTTP servers without native GUI dependencies. Enable with `-tags server` build tag. Features: - HTTP server with configurable host/port via ServerOptions - WAILS_SERVER_HOST and WAILS_SERVER_PORT env var overrides - WebSocket event broadcasting to connected browsers - Browser clients represented as BrowserWindow (Window interface) - Health check endpoint at /health - Graceful shutdown with configurable timeout - Docker support with Dockerfile.server template and tasks Build and run: wails3 task build:server wails3 task run:server wails3 task build:docker wails3 task run:docker Documentation at docs/guides/server-build.mdx Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(v3): add server mode for headless HTTP deployment Server mode allows Wails applications to run as pure HTTP servers without native GUI dependencies. Enable with `-tags server` build tag. Features: - HTTP server with configurable host/port via ServerOptions - WAILS_SERVER_HOST and WAILS_SERVER_PORT env var overrides - WebSocket event broadcasting to connected browsers - Browser clients represented as BrowserWindow (Window interface) - Health check endpoint at /health - Graceful shutdown with configurable timeout - Docker support with Dockerfile.server template and tasks Build and run: wails3 task build:server wails3 task run:server wails3 task build:docker wails3 task run:docker Documentation at docs/guides/server-build.mdx Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address CodeRabbit review comments - Fix corrupted test file with embedded terminal output - Fix module name mismatch in gin-routing (was gin-example) - Fix replace directive version mismatch in gin-service - Fix placeholder module name in ios example (was changeme) - Fix Dockerfile COPY path to work from both build contexts - Fix bare URL in README (MD034 compliance) - Fix comment accuracy in getScreens (returns error, not empty slice) - Remove deprecated docker-compose version field - Add port documentation in Taskfile template Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: address CodeRabbit review comments - Add note about healthcheck wget not being available in distroless images - Add !server build constraint to menu_windows.go and menu_darwin.go - Downgrade window-visibility-test go.mod from 1.25 to 1.24 to match CI Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
135 lines
3 KiB
Go
135 lines
3 KiB
Go
//go:build darwin && !ios && !server
|
|
|
|
package application
|
|
|
|
/*
|
|
#cgo CFLAGS: -mmacosx-version-min=10.10 -x objective-c
|
|
#cgo LDFLAGS: -framework Cocoa
|
|
|
|
#include "menuitem_darwin.h"
|
|
|
|
extern void setMenuItemChecked(void*, unsigned int, bool);
|
|
extern void setMenuItemBitmap(void*, unsigned char*, int);
|
|
|
|
// Clear and release all menu items in the menu
|
|
void clearMenu(void* nsMenu) {
|
|
NSMenu *menu = (NSMenu *)nsMenu;
|
|
[menu removeAllItems];
|
|
}
|
|
|
|
|
|
// Create a new NSMenu
|
|
void* createNSMenu(char* label) {
|
|
NSMenu *menu = [[NSMenu alloc] init];
|
|
if( label != NULL && strlen(label) > 0 ) {
|
|
menu.title = [NSString stringWithUTF8String:label];
|
|
free(label);
|
|
}
|
|
[menu setAutoenablesItems:NO];
|
|
return (void*)menu;
|
|
}
|
|
|
|
void addMenuItem(void* nsMenu, void* nsMenuItem) {
|
|
NSMenu *menu = (NSMenu *)nsMenu;
|
|
[menu addItem:nsMenuItem];
|
|
}
|
|
|
|
// add seperator to menu
|
|
void addMenuSeparator(void* nsMenu) {
|
|
NSMenu *menu = (NSMenu *)nsMenu;
|
|
[menu addItem:[NSMenuItem separatorItem]];
|
|
}
|
|
|
|
// Set the submenu of a menu item
|
|
void setMenuItemSubmenu(void* nsMenuItem, void* nsMenu) {
|
|
NSMenuItem *menuItem = (NSMenuItem *)nsMenuItem;
|
|
NSMenu *menu = (NSMenu *)nsMenu;
|
|
[menuItem setSubmenu:menu];
|
|
}
|
|
|
|
// Add services menu
|
|
static void addServicesMenu(void* menu) {
|
|
NSMenu *nsMenu = (__bridge NSMenu *)menu;
|
|
[NSApp setServicesMenu:nsMenu];
|
|
}
|
|
|
|
// Add windows menu
|
|
void addWindowsMenu(void* menu) {
|
|
NSMenu *nsMenu = (__bridge NSMenu *)menu;
|
|
[NSApp setWindowsMenu:nsMenu];
|
|
}
|
|
|
|
|
|
*/
|
|
import "C"
|
|
import "unsafe"
|
|
|
|
type macosMenu struct {
|
|
menu *Menu
|
|
|
|
nsMenu unsafe.Pointer
|
|
}
|
|
|
|
func newMenuImpl(menu *Menu) *macosMenu {
|
|
result := &macosMenu{
|
|
menu: menu,
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (m *macosMenu) update() {
|
|
InvokeSync(func() {
|
|
if m.nsMenu == nil {
|
|
m.nsMenu = C.createNSMenu(C.CString(m.menu.label))
|
|
} else {
|
|
C.clearMenu(m.nsMenu)
|
|
}
|
|
m.processMenu(m.nsMenu, m.menu)
|
|
})
|
|
}
|
|
|
|
func (m *macosMenu) processMenu(parent unsafe.Pointer, menu *Menu) {
|
|
for _, item := range menu.items {
|
|
switch item.itemType {
|
|
case submenu:
|
|
submenu := item.submenu
|
|
nsSubmenu := C.createNSMenu(C.CString(item.label))
|
|
m.processMenu(nsSubmenu, submenu)
|
|
menuItem := newMenuItemImpl(item)
|
|
item.impl = menuItem
|
|
C.addMenuItem(parent, menuItem.nsMenuItem)
|
|
C.setMenuItemSubmenu(menuItem.nsMenuItem, nsSubmenu)
|
|
if item.role == ServicesMenu {
|
|
C.addServicesMenu(nsSubmenu)
|
|
}
|
|
if item.role == WindowMenu {
|
|
C.addWindowsMenu(nsSubmenu)
|
|
}
|
|
case text, checkbox, radio:
|
|
menuItem := newMenuItemImpl(item)
|
|
item.impl = menuItem
|
|
if item.hidden {
|
|
menuItem.setHidden(true)
|
|
}
|
|
C.addMenuItem(parent, menuItem.nsMenuItem)
|
|
case separator:
|
|
C.addMenuSeparator(parent)
|
|
}
|
|
if item.bitmap != nil {
|
|
macMenuItem := item.impl.(*macosMenuItem)
|
|
C.setMenuItemBitmap(macMenuItem.nsMenuItem, (*C.uchar)(&item.bitmap[0]), C.int(len(item.bitmap)))
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
func DefaultApplicationMenu() *Menu {
|
|
menu := NewMenu()
|
|
menu.AddRole(AppMenu)
|
|
menu.AddRole(FileMenu)
|
|
menu.AddRole(EditMenu)
|
|
menu.AddRole(ViewMenu)
|
|
menu.AddRole(WindowMenu)
|
|
menu.AddRole(HelpMenu)
|
|
return menu
|
|
}
|