mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-04 03:29:03 +08:00
Updated tray icon
This commit is contained in:
parent
a1f9d9ca06
commit
34ac62e4ac
@ -65,6 +65,14 @@
|
|||||||
// then right buttons are reported as left buttons
|
// then right buttons are reported as left buttons
|
||||||
#define NSEventMaskLeftMouseDown 1 << 1
|
#define NSEventMaskLeftMouseDown 1 << 1
|
||||||
#define NSEventMaskLeftMouseUp 1 << 2
|
#define NSEventMaskLeftMouseUp 1 << 2
|
||||||
|
#define NSEventMaskRightMouseDown 1 << 3
|
||||||
|
#define NSEventMaskRightMouseUp 1 << 4
|
||||||
|
|
||||||
|
#define NSEventTypeLeftMouseDown 1
|
||||||
|
#define NSEventTypeLeftMouseUp 2
|
||||||
|
#define NSEventTypeRightMouseDown 3
|
||||||
|
#define NSEventTypeRightMouseUp 4
|
||||||
|
|
||||||
|
|
||||||
// References to assets
|
// References to assets
|
||||||
extern const unsigned char *assets[];
|
extern const unsigned char *assets[];
|
||||||
@ -90,6 +98,15 @@ struct hashmap_s menuItemMapForTrayMenu;
|
|||||||
// RadioGroup map for the tray menu. Maps a menuitem id with its associated radio group items
|
// RadioGroup map for the tray menu. Maps a menuitem id with its associated radio group items
|
||||||
struct hashmap_s radioGroupMapForTrayMenu;
|
struct hashmap_s radioGroupMapForTrayMenu;
|
||||||
|
|
||||||
|
// contextMenuMap is a hashmap of context menus keyed on a string ID
|
||||||
|
struct hashmap_s contextMenuMap;
|
||||||
|
|
||||||
|
// MenuItem map for the context menus
|
||||||
|
struct hashmap_s menuItemMapForContextMenus;
|
||||||
|
|
||||||
|
// RadioGroup map for the context menus. Maps a menuitem id with its associated radio group items
|
||||||
|
struct hashmap_s radioGroupMapForContextMenus;
|
||||||
|
|
||||||
// Dispatch Method
|
// Dispatch Method
|
||||||
typedef void (^dispatchMethod)(void);
|
typedef void (^dispatchMethod)(void);
|
||||||
|
|
||||||
@ -205,6 +222,10 @@ struct Application {
|
|||||||
JsonNode *processedTrayMenu;
|
JsonNode *processedTrayMenu;
|
||||||
id statusItem;
|
id statusItem;
|
||||||
|
|
||||||
|
// Context Menus
|
||||||
|
const char *contextMenusAsJSON;
|
||||||
|
JsonNode *processedContextMenus;
|
||||||
|
|
||||||
// User Data
|
// User Data
|
||||||
char *HTML;
|
char *HTML;
|
||||||
|
|
||||||
@ -294,6 +315,31 @@ void applyWindowColour(struct Application *app) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showContextMenu(struct Application *app, const char *contextMenuID) {
|
||||||
|
|
||||||
|
// If no context menu ID was given
|
||||||
|
if( contextMenuID == NULL ) {
|
||||||
|
// Show default context menu if we have one
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ON_MAIN_THREAD (
|
||||||
|
|
||||||
|
// Look for the context menu for this ID
|
||||||
|
id contextMenu = (id)hashmap_get(&contextMenuMap, (char*)contextMenuID, strlen(contextMenuID));
|
||||||
|
|
||||||
|
// Grab the content view and show the menu
|
||||||
|
id contentView = msg(app->mainWindow, s("contentView"));
|
||||||
|
|
||||||
|
// Get the triggering event
|
||||||
|
id menuEvent = msg(app->mainWindow, s("currentEvent"));
|
||||||
|
|
||||||
|
// Show popup
|
||||||
|
msg(c("NSMenu"), s("popUpContextMenu:withEvent:forView:"), contextMenu, menuEvent, contentView);
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void SetColour(struct Application *app, int red, int green, int blue, int alpha) {
|
void SetColour(struct Application *app, int red, int green, int blue, int alpha) {
|
||||||
app->red = red;
|
app->red = red;
|
||||||
app->green = green;
|
app->green = green;
|
||||||
@ -342,6 +388,62 @@ void messageHandler(id self, SEL cmd, id contentController, id message) {
|
|||||||
msg(app->mainWindow, s("performWindowDragWithEvent:"), app->mouseEvent);
|
msg(app->mainWindow, s("performWindowDragWithEvent:"), app->mouseEvent);
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else if( strcmp(name, "contextMenu") == 0 ) {
|
||||||
|
|
||||||
|
// Did we get a context menu selector?
|
||||||
|
if( message == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *contextMenuMessage = cstr(msg(message, s("body")));
|
||||||
|
|
||||||
|
// Parse the message
|
||||||
|
JsonNode *contextMenuMessageJSON = json_decode(contextMenuMessage);
|
||||||
|
if( contextMenuMessageJSON == NULL ) {
|
||||||
|
Debug(app, "Error decoding context menu message: %s", contextMenuMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get menu ID
|
||||||
|
JsonNode *contextMenuIDNode = json_find_member(contextMenuMessageJSON, "id");
|
||||||
|
if( contextMenuIDNode == NULL ) {
|
||||||
|
Debug(app, "Error decoding context menu ID: %s", contextMenuMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if( contextMenuIDNode->tag != JSON_STRING ) {
|
||||||
|
Debug(app, "Error decoding context menu ID (Not a string): %s", contextMenuMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: Use the X & Y coordinates of the menu to programmatically open
|
||||||
|
// the context menu at that point rather than relying on the current NSEvent.
|
||||||
|
// I got it mostly working (IE not crashing) but the menu was invisible...
|
||||||
|
// Revisit later
|
||||||
|
|
||||||
|
// // Get menu X
|
||||||
|
// JsonNode *contextMenuXNode = json_find_member(contextMenuMessageJSON, "x");
|
||||||
|
// if( contextMenuXNode == NULL ) {
|
||||||
|
// Debug(app, "Error decoding context menu X: %s", contextMenuMessage);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if( contextMenuXNode->tag != JSON_NUMBER ) {
|
||||||
|
// Debug(app, "Error decoding context menu X (Not a number): %s", contextMenuMessage);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// // Get menu Y
|
||||||
|
// JsonNode *contextMenuYNode = json_find_member(contextMenuMessageJSON, "y");
|
||||||
|
// if( contextMenuYNode == NULL ) {
|
||||||
|
// Debug(app, "Error decoding context menu Y: %s", contextMenuMessage);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if( contextMenuYNode->tag != JSON_NUMBER ) {
|
||||||
|
// Debug(app, "Error decoding context menu Y (Not a number): %s", contextMenuMessage);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
ON_MAIN_THREAD(
|
||||||
|
showContextMenu(app, contextMenuIDNode->string_);
|
||||||
|
);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// const char *m = (const char *)msg(msg(message, s("body")), s("UTF8String"));
|
// const char *m = (const char *)msg(msg(message, s("body")), s("UTF8String"));
|
||||||
const char *m = cstr(msg(message, s("body")));
|
const char *m = cstr(msg(message, s("body")));
|
||||||
@ -367,6 +469,16 @@ void menuItemPressedForTrayMenu(id self, SEL cmd, id sender) {
|
|||||||
free((void*)message);
|
free((void*)message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Callback for context menu items
|
||||||
|
void menuItemPressedForContextMenus(id self, SEL cmd, id sender) {
|
||||||
|
const char *menuID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||||
|
// Notify the backend
|
||||||
|
const char *message = concat("XC", menuID);
|
||||||
|
messageFromWindowCallback(message);
|
||||||
|
free((void*)message);
|
||||||
|
}
|
||||||
|
|
||||||
// Callback for menu items
|
// Callback for menu items
|
||||||
void checkboxMenuItemPressedForApplicationMenu(id self, SEL cmd, id sender, struct hashmap_s *menuItemMap) {
|
void checkboxMenuItemPressedForApplicationMenu(id self, SEL cmd, id sender, struct hashmap_s *menuItemMap) {
|
||||||
const char *menuID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
const char *menuID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||||
@ -405,6 +517,25 @@ void checkboxMenuItemPressedForTrayMenu(id self, SEL cmd, id sender, struct hash
|
|||||||
free((void*)message);
|
free((void*)message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Callback for context menu items
|
||||||
|
void checkboxMenuItemPressedForContextMenus(id self, SEL cmd, id sender, struct hashmap_s *menuItemMap) {
|
||||||
|
const char *menuID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||||
|
|
||||||
|
// Get the menu item from the menu item map
|
||||||
|
id menuItem = (id)hashmap_get(&menuItemMapForContextMenus, (char*)menuID, strlen(menuID));
|
||||||
|
|
||||||
|
// Get the current state
|
||||||
|
bool state = msg(menuItem, s("state"));
|
||||||
|
|
||||||
|
// Toggle the state
|
||||||
|
msg(menuItem, s("setState:"), (state? NSControlStateValueOff : NSControlStateValueOn));
|
||||||
|
|
||||||
|
// Notify the backend
|
||||||
|
const char *message = concat("XC", menuID);
|
||||||
|
messageFromWindowCallback(message);
|
||||||
|
free((void*)message);
|
||||||
|
}
|
||||||
|
|
||||||
// radioMenuItemPressedForApplicationMenu
|
// radioMenuItemPressedForApplicationMenu
|
||||||
void radioMenuItemPressedForApplicationMenu(id self, SEL cmd, id sender) {
|
void radioMenuItemPressedForApplicationMenu(id self, SEL cmd, id sender) {
|
||||||
const char *menuID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
const char *menuID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||||
@ -478,6 +609,42 @@ void radioMenuItemPressedForTrayMenu(id self, SEL cmd, id sender) {
|
|||||||
free((void*)message);
|
free((void*)message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// radioMenuItemPressedForContextMenus
|
||||||
|
void radioMenuItemPressedForContextMenus(id self, SEL cmd, id sender) {
|
||||||
|
const char *menuID = (const char *)msg(msg(sender, s("representedObject")), s("pointerValue"));
|
||||||
|
|
||||||
|
// Get the menu item from the menu item map
|
||||||
|
id menuItem = (id)hashmap_get(&menuItemMapForContextMenus, (char*)menuID, strlen(menuID));
|
||||||
|
|
||||||
|
// Check the menu items' current state
|
||||||
|
bool selected = msg(menuItem, s("state"));
|
||||||
|
|
||||||
|
// If it's already selected, exit early
|
||||||
|
if (selected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get this item's radio group members and turn them off
|
||||||
|
id *members = (id*)hashmap_get(&radioGroupMapForContextMenus, (char*)menuID, strlen(menuID));
|
||||||
|
|
||||||
|
// Uncheck all members of the group
|
||||||
|
id thisMember = members[0];
|
||||||
|
int count = 0;
|
||||||
|
while(thisMember != NULL) {
|
||||||
|
msg(thisMember, s("setState:"), NSControlStateValueOff);
|
||||||
|
count = count + 1;
|
||||||
|
thisMember = members[count];
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the selected menu item
|
||||||
|
msg(menuItem, s("setState:"), NSControlStateValueOn);
|
||||||
|
|
||||||
|
// Notify the backend
|
||||||
|
const char *message = concat("XC", menuID);
|
||||||
|
messageFromWindowCallback(message);
|
||||||
|
free((void*)message);
|
||||||
|
}
|
||||||
|
|
||||||
// closeWindow is called when the close button is pressed
|
// closeWindow is called when the close button is pressed
|
||||||
void closeWindow(id self, SEL cmd, id sender) {
|
void closeWindow(id self, SEL cmd, id sender) {
|
||||||
struct Application *app = (struct Application *) objc_getAssociatedObject(self, "application");
|
struct Application *app = (struct Application *) objc_getAssociatedObject(self, "application");
|
||||||
@ -547,6 +714,28 @@ void allocateTrayHashMaps(struct Application *app) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void allocateContextMenuHashMaps(struct Application *app) {
|
||||||
|
|
||||||
|
// Allocate new context menu map
|
||||||
|
if( 0 != hashmap_create((const unsigned)4, &contextMenuMap)) {
|
||||||
|
// Couldn't allocate map
|
||||||
|
Fatal(app, "Not enough memory to allocate contextMenuMap!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate new menuItem map
|
||||||
|
if( 0 != hashmap_create((const unsigned)16, &menuItemMapForContextMenus)) {
|
||||||
|
// Couldn't allocate map
|
||||||
|
Fatal(app, "Not enough memory to allocate menuItemMapForContextMenus!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate the Radio Group Cache
|
||||||
|
if( 0 != hashmap_create((const unsigned)4, &radioGroupMapForContextMenus)) {
|
||||||
|
// Couldn't allocate map
|
||||||
|
Fatal(app, "Not enough memory to allocate radioGroupMapForContextMenus!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel) {
|
void* NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel) {
|
||||||
// Setup main application struct
|
// Setup main application struct
|
||||||
struct Application *result = malloc(sizeof(struct Application));
|
struct Application *result = malloc(sizeof(struct Application));
|
||||||
@ -594,6 +783,9 @@ void* NewApplication(const char *title, int width, int height, int resizable, in
|
|||||||
result->processedTrayMenu = NULL;
|
result->processedTrayMenu = NULL;
|
||||||
result->statusItem = NULL;
|
result->statusItem = NULL;
|
||||||
|
|
||||||
|
// Context Menus
|
||||||
|
result->contextMenusAsJSON = NULL;
|
||||||
|
|
||||||
// Window Appearance
|
// Window Appearance
|
||||||
result->vibrancyLayer = NULL;
|
result->vibrancyLayer = NULL;
|
||||||
result->titlebarAppearsTransparent = 0;
|
result->titlebarAppearsTransparent = 0;
|
||||||
@ -637,6 +829,34 @@ void destroyMenu(struct Application *app) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void destroyContextMenus(struct Application *app) {
|
||||||
|
|
||||||
|
// If we don't have a context menu, return
|
||||||
|
if( app->contextMenusAsJSON == NULL ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free menu item hashmap
|
||||||
|
hashmap_destroy(&menuItemMapForContextMenus);
|
||||||
|
|
||||||
|
// Free radio group members
|
||||||
|
if( hashmap_num_entries(&radioGroupMapForContextMenus) > 0 ) {
|
||||||
|
if (0!=hashmap_iterate_pairs(&radioGroupMapForContextMenus, freeHashmapItem, NULL)) {
|
||||||
|
Fatal(app, "failed to deallocate hashmap entries!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Free radio groups hashmap
|
||||||
|
hashmap_destroy(&radioGroupMapForContextMenus);
|
||||||
|
|
||||||
|
//Free context menu map
|
||||||
|
hashmap_destroy(&contextMenuMap);
|
||||||
|
|
||||||
|
// Destroy context menu JSON
|
||||||
|
free((void*)app->contextMenusAsJSON);
|
||||||
|
app->contextMenusAsJSON = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void destroyTray(struct Application *app) {
|
void destroyTray(struct Application *app) {
|
||||||
|
|
||||||
@ -658,11 +878,13 @@ void destroyTray(struct Application *app) {
|
|||||||
//Free radio groups hashmap
|
//Free radio groups hashmap
|
||||||
hashmap_destroy(&radioGroupMapForTrayMenu);
|
hashmap_destroy(&radioGroupMapForTrayMenu);
|
||||||
|
|
||||||
// Release the menu json if we have it
|
// Free up the context menu map
|
||||||
if ( app->trayMenuAsJSON != NULL ) {
|
hashmap_destroy(&contextMenuMap);
|
||||||
|
|
||||||
|
// Release the menu json
|
||||||
free((void*)app->trayMenuAsJSON);
|
free((void*)app->trayMenuAsJSON);
|
||||||
app->trayMenuAsJSON = NULL;
|
app->trayMenuAsJSON = NULL;
|
||||||
}
|
|
||||||
|
|
||||||
// Release processed tray
|
// Release processed tray
|
||||||
if( app->processedTrayMenu != NULL) {
|
if( app->processedTrayMenu != NULL) {
|
||||||
@ -699,7 +921,11 @@ void DestroyApplication(struct Application *app) {
|
|||||||
// Destroy the tray
|
// Destroy the tray
|
||||||
destroyTray(app);
|
destroyTray(app);
|
||||||
|
|
||||||
|
// Destroy the context menus
|
||||||
|
destroyContextMenus(app);
|
||||||
|
|
||||||
// Remove script handlers
|
// Remove script handlers
|
||||||
|
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("contextMenu"));
|
||||||
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("windowDrag"));
|
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("windowDrag"));
|
||||||
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("external"));
|
msg(app->manager, s("removeScriptMessageHandlerForName:"), str("external"));
|
||||||
|
|
||||||
@ -1055,6 +1281,11 @@ void SetTray(struct Application *app, const char *trayMenuAsJSON) {
|
|||||||
app->trayMenuAsJSON = trayMenuAsJSON;
|
app->trayMenuAsJSON = trayMenuAsJSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetContextMenus sets the context menu map for this application
|
||||||
|
void SetContextMenus(struct Application *app, const char *contextMenusAsJSON) {
|
||||||
|
app->contextMenusAsJSON = contextMenusAsJSON;
|
||||||
|
}
|
||||||
|
|
||||||
void SetBindings(struct Application *app, const char *bindings) {
|
void SetBindings(struct Application *app, const char *bindings) {
|
||||||
const char* temp = concat("window.wailsbindings = \"", bindings);
|
const char* temp = concat("window.wailsbindings = \"", bindings);
|
||||||
const char* jscall = concat(temp, "\";");
|
const char* jscall = concat(temp, "\";");
|
||||||
@ -1149,7 +1380,9 @@ void createDelegate(struct Application *app) {
|
|||||||
class_addMethod(delegateClass, s("menuCallbackForTrayMenu:"), (IMP)menuItemPressedForTrayMenu, "v@:@");
|
class_addMethod(delegateClass, s("menuCallbackForTrayMenu:"), (IMP)menuItemPressedForTrayMenu, "v@:@");
|
||||||
class_addMethod(delegateClass, s("checkboxMenuCallbackForTrayMenu:"), (IMP) checkboxMenuItemPressedForTrayMenu, "v@:@");
|
class_addMethod(delegateClass, s("checkboxMenuCallbackForTrayMenu:"), (IMP) checkboxMenuItemPressedForTrayMenu, "v@:@");
|
||||||
class_addMethod(delegateClass, s("radioMenuCallbackForTrayMenu:"), (IMP) radioMenuItemPressedForTrayMenu, "v@:@");
|
class_addMethod(delegateClass, s("radioMenuCallbackForTrayMenu:"), (IMP) radioMenuItemPressedForTrayMenu, "v@:@");
|
||||||
|
class_addMethod(delegateClass, s("menuCallbackForContextMenus:"), (IMP)menuItemPressedForContextMenus, "v@:@");
|
||||||
|
class_addMethod(delegateClass, s("checkboxMenuCallbackForContextMenus:"), (IMP) checkboxMenuItemPressedForContextMenus, "v@:@");
|
||||||
|
class_addMethod(delegateClass, s("radioMenuCallbackForContextMenus:"), (IMP) radioMenuItemPressedForContextMenus, "v@:@");
|
||||||
|
|
||||||
// Script handler
|
// Script handler
|
||||||
class_addMethod(delegateClass, s("userContentController:didReceiveScriptMessage:"), (IMP) messageHandler, "v@:@@");
|
class_addMethod(delegateClass, s("userContentController:didReceiveScriptMessage:"), (IMP) messageHandler, "v@:@@");
|
||||||
@ -1575,15 +1808,15 @@ id processAcceleratorKey(const char *key) {
|
|||||||
if( STREQ(key, "F35") ) {
|
if( STREQ(key, "F35") ) {
|
||||||
return strunicode(0xf726);
|
return strunicode(0xf726);
|
||||||
}
|
}
|
||||||
if( STREQ(key, "Insert") ) {
|
// if( STREQ(key, "Insert") ) {
|
||||||
return strunicode(0xf727);
|
// return strunicode(0xf727);
|
||||||
}
|
// }
|
||||||
if( STREQ(key, "PrintScreen") ) {
|
// if( STREQ(key, "PrintScreen") ) {
|
||||||
return strunicode(0xf72e);
|
// return strunicode(0xf72e);
|
||||||
}
|
// }
|
||||||
if( STREQ(key, "ScrollLock") ) {
|
// if( STREQ(key, "ScrollLock") ) {
|
||||||
return strunicode(0xf72f);
|
// return strunicode(0xf72f);
|
||||||
}
|
// }
|
||||||
if( STREQ(key, "NumLock") ) {
|
if( STREQ(key, "NumLock") ) {
|
||||||
return strunicode(0xf739);
|
return strunicode(0xf739);
|
||||||
}
|
}
|
||||||
@ -1917,6 +2150,36 @@ void UpdateMenu(struct Application *app, const char *menuAsJSON) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void parseContextMenus(struct Application *app) {
|
||||||
|
|
||||||
|
// Allocation the hashmaps we need
|
||||||
|
allocateContextMenuHashMaps(app);
|
||||||
|
|
||||||
|
// Parse the context menu json
|
||||||
|
app->processedContextMenus = json_decode(app->contextMenusAsJSON);
|
||||||
|
|
||||||
|
if( app->processedContextMenus == NULL ) {
|
||||||
|
// Parse error!
|
||||||
|
Fatal(app, "Unable to parse Context Menus JSON: %s", app->contextMenusAsJSON);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate context menus
|
||||||
|
JsonNode *contextMenu;
|
||||||
|
json_foreach(contextMenu, app->processedContextMenus) {
|
||||||
|
// Create a new menu
|
||||||
|
id menu = createMenu(str(""));
|
||||||
|
|
||||||
|
// parse the menu
|
||||||
|
parseMenu(app, menu, contextMenu, &menuItemMapForContextMenus,
|
||||||
|
"checkboxMenuCallbackForContextMenus:", "radioMenuCallbackForContextMenus:", "menuCallbackForContextMenus:");
|
||||||
|
|
||||||
|
// Store the item in the context menu map
|
||||||
|
hashmap_put(&contextMenuMap, (char*)contextMenu->key, strlen(contextMenu->key), menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void parseTrayData(struct Application *app) {
|
void parseTrayData(struct Application *app) {
|
||||||
|
|
||||||
// Allocate the hashmaps we need
|
// Allocate the hashmaps we need
|
||||||
@ -1944,8 +2207,6 @@ void parseTrayData(struct Application *app) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Debug(app, ">>>>>>>>>>> TRAY MENU: %s", app->trayMenuAsJSON);
|
|
||||||
|
|
||||||
// Parse the processed menu json
|
// Parse the processed menu json
|
||||||
app->processedTrayMenu = json_decode(app->trayMenuAsJSON);
|
app->processedTrayMenu = json_decode(app->trayMenuAsJSON);
|
||||||
|
|
||||||
@ -1995,9 +2256,7 @@ void parseTrayData(struct Application *app) {
|
|||||||
|
|
||||||
// UpdateTray replaces the current tray menu with the given one
|
// UpdateTray replaces the current tray menu with the given one
|
||||||
void UpdateTray(struct Application *app, const char *trayMenuAsJSON) {
|
void UpdateTray(struct Application *app, const char *trayMenuAsJSON) {
|
||||||
Debug(app, "tray is now: %s", trayMenuAsJSON);
|
|
||||||
ON_MAIN_THREAD (
|
ON_MAIN_THREAD (
|
||||||
|
|
||||||
// Free up memory
|
// Free up memory
|
||||||
destroyTray(app);
|
destroyTray(app);
|
||||||
|
|
||||||
@ -2010,16 +2269,18 @@ void UpdateTray(struct Application *app, const char *trayMenuAsJSON) {
|
|||||||
|
|
||||||
void Run(struct Application *app, int argc, char **argv) {
|
void Run(struct Application *app, int argc, char **argv) {
|
||||||
|
|
||||||
|
// Process window decorations
|
||||||
processDecorations(app);
|
processDecorations(app);
|
||||||
|
|
||||||
|
// Create the application
|
||||||
createApplication(app);
|
createApplication(app);
|
||||||
|
|
||||||
// Define delegate
|
// Define delegate
|
||||||
createDelegate(app);
|
createDelegate(app);
|
||||||
|
|
||||||
|
// Create the main window
|
||||||
createMainWindow(app);
|
createMainWindow(app);
|
||||||
|
|
||||||
|
|
||||||
// Create Content View
|
// Create Content View
|
||||||
id contentView = msg( ALLOC("NSView"), s("init") );
|
id contentView = msg( ALLOC("NSView"), s("init") );
|
||||||
msg(app->mainWindow, s("setContentView:"), contentView);
|
msg(app->mainWindow, s("setContentView:"), contentView);
|
||||||
@ -2033,6 +2294,7 @@ void Run(struct Application *app, int argc, char **argv) {
|
|||||||
// Set Colour
|
// Set Colour
|
||||||
applyWindowColour(app);
|
applyWindowColour(app);
|
||||||
|
|
||||||
|
// Process translucency
|
||||||
if (app->windowBackgroundIsTranslucent) {
|
if (app->windowBackgroundIsTranslucent) {
|
||||||
makeWindowBackgroundTranslucent(app);
|
makeWindowBackgroundTranslucent(app);
|
||||||
}
|
}
|
||||||
@ -2083,6 +2345,9 @@ void Run(struct Application *app, int argc, char **argv) {
|
|||||||
return incomingEvent;
|
return incomingEvent;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Setup context menu message handler
|
||||||
|
msg(manager, s("addScriptMessageHandler:name:"), app->delegate, str("contextMenu"));
|
||||||
|
|
||||||
// Toolbar
|
// Toolbar
|
||||||
if( app->useToolBar ) {
|
if( app->useToolBar ) {
|
||||||
Debug(app, "Setting Toolbar");
|
Debug(app, "Setting Toolbar");
|
||||||
@ -2139,7 +2404,7 @@ void Run(struct Application *app, int argc, char **argv) {
|
|||||||
|
|
||||||
// Disable context menu if not in debug mode
|
// Disable context menu if not in debug mode
|
||||||
if( debug != 1 ) {
|
if( debug != 1 ) {
|
||||||
temp = concat(internalCode, "wails._.DisableContextMenu();");
|
temp = concat(internalCode, "wails._.DisableDefaultContextMenu();");
|
||||||
free((void*)internalCode);
|
free((void*)internalCode);
|
||||||
internalCode = temp;
|
internalCode = temp;
|
||||||
}
|
}
|
||||||
@ -2179,6 +2444,11 @@ void Run(struct Application *app, int argc, char **argv) {
|
|||||||
parseTrayData(app);
|
parseTrayData(app);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have context menus, process them
|
||||||
|
if( app->contextMenusAsJSON != NULL ) {
|
||||||
|
parseContextMenus(app);
|
||||||
|
}
|
||||||
|
|
||||||
// Finally call run
|
// Finally call run
|
||||||
Debug(app, "Run called");
|
Debug(app, "Run called");
|
||||||
msg(app->application, s("run"));
|
msg(app->application, s("run"));
|
||||||
|
@ -16,6 +16,7 @@ extern void WebviewIsTransparent(void *);
|
|||||||
extern void SetWindowBackgroundIsTranslucent(void *);
|
extern void SetWindowBackgroundIsTranslucent(void *);
|
||||||
extern void SetMenu(void *, const char *);
|
extern void SetMenu(void *, const char *);
|
||||||
extern void SetTray(void *, const char *);
|
extern void SetTray(void *, const char *);
|
||||||
|
extern void SetContextMenus(void *, const char *);
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
import (
|
import (
|
||||||
@ -111,5 +112,15 @@ func (a *Application) processPlatformSettings() error {
|
|||||||
C.SetTray(a.app, a.string2CString(string(trayMenuJSON)))
|
C.SetTray(a.app, a.string2CString(string(trayMenuJSON)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process context menus
|
||||||
|
contextMenus := options.GetContextMenus(a.config)
|
||||||
|
if contextMenus != nil {
|
||||||
|
contextMenusJSON, err := json.Marshal(contextMenus)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
C.SetContextMenus(a.app, a.string2CString(string(contextMenusJSON)))
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ func (d *DesktopBuilder) processTrayIcons(assetDir string, options *Options) err
|
|||||||
// Setup target
|
// Setup target
|
||||||
targetFilename := "trayicon"
|
targetFilename := "trayicon"
|
||||||
targetFile := filepath.Join(assetDir, targetFilename+".c")
|
targetFile := filepath.Join(assetDir, targetFilename+".c")
|
||||||
//d.addFileToDelete(targetFile)
|
d.addFileToDelete(targetFile)
|
||||||
|
|
||||||
var dataBytes []byte
|
var dataBytes []byte
|
||||||
|
|
||||||
|
@ -10,4 +10,5 @@ type Options struct {
|
|||||||
WindowBackgroundIsTranslucent bool
|
WindowBackgroundIsTranslucent bool
|
||||||
Menu *menu.Menu
|
Menu *menu.Menu
|
||||||
Tray *menu.Menu
|
Tray *menu.Menu
|
||||||
|
ContextMenus map[string]*menu.Menu
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ type App struct {
|
|||||||
StartHidden bool
|
StartHidden bool
|
||||||
DevTools bool
|
DevTools bool
|
||||||
RGBA int
|
RGBA int
|
||||||
|
ContextMenus map[string]*menu.Menu
|
||||||
Tray *menu.Menu
|
Tray *menu.Menu
|
||||||
Menu *menu.Menu
|
Menu *menu.Menu
|
||||||
Mac *mac.Options
|
Mac *mac.Options
|
||||||
@ -95,3 +96,31 @@ func GetApplicationMenu(appoptions *App) *menu.Menu {
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetContextMenus(appoptions *App) map[string]*menu.Menu {
|
||||||
|
var result map[string]*menu.Menu
|
||||||
|
|
||||||
|
result = appoptions.ContextMenus
|
||||||
|
var contextMenuOverrides map[string]*menu.Menu
|
||||||
|
switch runtime.GOOS {
|
||||||
|
case "darwin":
|
||||||
|
if appoptions.Mac != nil {
|
||||||
|
contextMenuOverrides = appoptions.Mac.ContextMenus
|
||||||
|
}
|
||||||
|
//case "linux":
|
||||||
|
// if appoptions.Linux != nil {
|
||||||
|
// result = appoptions.Linux.Tray
|
||||||
|
// }
|
||||||
|
//case "windows":
|
||||||
|
// if appoptions.Windows != nil {
|
||||||
|
// result = appoptions.Windows.Tray
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite defaults with OS Specific context menus
|
||||||
|
for id, contextMenu := range contextMenuOverrides {
|
||||||
|
result[id] = contextMenu
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
<!-- Sticky alerts (toasts), empty container -->
|
<!-- Sticky alerts (toasts), empty container -->
|
||||||
<div class="sticky-alerts"></div>
|
<div class="sticky-alerts"></div>
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<div class="sidebar noselect">
|
<div class="sidebar noselect" data-wails-context-menu-id="test">
|
||||||
<div data-wails-no-drag class="sidebar-menu">
|
<div data-wails-no-drag class="sidebar-menu">
|
||||||
<!-- Sidebar brand -->
|
<!-- Sidebar brand -->
|
||||||
<div on:click="{ homepageClicked }" class="sidebar-brand">
|
<div on:click="{ homepageClicked }" class="sidebar-brand">
|
||||||
@ -53,7 +53,7 @@
|
|||||||
<h5 class="sidebar-title">Runtime</h5>
|
<h5 class="sidebar-title">Runtime</h5>
|
||||||
<div class="sidebar-divider"></div>
|
<div class="sidebar-divider"></div>
|
||||||
{#each runtimePages as link}
|
{#each runtimePages as link}
|
||||||
<span on:click="{linkClicked}" class="sidebar-link" class:active="{$selectedPage == link}">{link}</span>
|
<span on:click="{linkClicked}" class="sidebar-link" class:active="{$selectedPage === link}">{link}</span>
|
||||||
{/each}
|
{/each}
|
||||||
<br />
|
<br />
|
||||||
<h5 class="sidebar-title">Links</h5>
|
<h5 class="sidebar-title">Links</h5>
|
||||||
@ -65,7 +65,7 @@
|
|||||||
<!-- Content wrapper -->
|
<!-- Content wrapper -->
|
||||||
<div class="content-wrapper noselect" class:dark-content-wrapper="{$darkMode}">
|
<div class="content-wrapper noselect" class:dark-content-wrapper="{$darkMode}">
|
||||||
<div class="inner-content">
|
<div class="inner-content">
|
||||||
<MainPage></MainPage>
|
<MainPage/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/wailsapp/wails/v2"
|
"github.com/wailsapp/wails/v2"
|
||||||
"github.com/wailsapp/wails/v2/pkg/logger"
|
"github.com/wailsapp/wails/v2/pkg/logger"
|
||||||
|
"github.com/wailsapp/wails/v2/pkg/menu"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
"github.com/wailsapp/wails/v2/pkg/options/mac"
|
||||||
"log"
|
"log"
|
||||||
@ -19,6 +20,9 @@ func main() {
|
|||||||
MinHeight: 600,
|
MinHeight: 600,
|
||||||
//Tray: menu.NewMenuFromItems(menu.AppMenu()),
|
//Tray: menu.NewMenuFromItems(menu.AppMenu()),
|
||||||
//Menu: menu.NewMenuFromItems(menu.AppMenu()),
|
//Menu: menu.NewMenuFromItems(menu.AppMenu()),
|
||||||
|
ContextMenus: map[string]*menu.Menu{
|
||||||
|
"test": menu.NewMenuFromItems(menu.Text("Test Menu", "Test Context Menu")),
|
||||||
|
},
|
||||||
Mac: &mac.Options{
|
Mac: &mac.Options{
|
||||||
WebviewIsTransparent: true,
|
WebviewIsTransparent: true,
|
||||||
WindowBackgroundIsTranslucent: true,
|
WindowBackgroundIsTranslucent: true,
|
||||||
|
BIN
v2/test/kitchensink/tray.png
Normal file
BIN
v2/test/kitchensink/tray.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
Loading…
Reference in New Issue
Block a user