Initial support for multiple traymenus

This commit is contained in:
Lea Anthony
2021-01-13 10:28:32 +11:00
parent 1921862b53
commit 5c9402323a
11 changed files with 177 additions and 14 deletions

View File

@@ -45,6 +45,29 @@ const char* getJSONString(JsonNode *item, const char* key) {
return result;
}
void ABORT_JSON(JsonNode *node, const char* key) {
ABORT("Unable to read required key '%s' from JSON: %s\n", key, json_encode(node));
}
const char* mustJSONString(JsonNode *node, const char* key) {
const char* result = getJSONString(node, key);
if ( result == NULL ) {
ABORT_JSON(node, key);
}
return result;
}
JsonNode* mustJSONObject(JsonNode *node, const char* key) {
struct JsonNode* result = getJSONObject(node, key);
if ( result == NULL ) {
ABORT_JSON(node, key);
}
return result;
}
JsonNode* getJSONObject(JsonNode* node, const char* key) {
return json_find_member(node, key);
}
bool getJSONBool(JsonNode *item, const char* key, bool *result) {
JsonNode *node = json_find_member(item, key);
if ( node != NULL && node->tag == JSON_BOOL) {

View File

@@ -17,6 +17,7 @@
#include "json.h"
#define STREQ(a,b) strcmp(a, b) == 0
#define STREMPTY(string) strlen(string) == 0
#define STRCOPY(a) concat(a, "")
#define STR_HAS_CHARS(input) input != NULL && strlen(input) > 0
#define MEMFREE(input) free((void*)input); input = NULL;
@@ -27,6 +28,10 @@ char* concat(const char *string1, const char *string2);
void ABORT(const char *message, ...);
int freeHashmapItem(void *const context, struct hashmap_element_s *const e);
const char* getJSONString(JsonNode *item, const char* key);
const char* mustJSONString(JsonNode *node, const char* key);
JsonNode* getJSONObject(JsonNode* node, const char* key);
JsonNode* mustJSONObject(JsonNode *node, const char* key);
bool getJSONBool(JsonNode *item, const char* key, bool *result);
bool getJSONInt(JsonNode *item, const char* key, int *result);

View File

@@ -1999,6 +1999,9 @@ void Run(struct Application *app, int argc, char **argv) {
msg(msg(c("NSApplication"), s("sharedApplication")), s("setMainMenu:"), menu);
}
// Setup initial trays
ShowTrayMenusInStore(app->trayMenuStore);
// If we have a tray menu, process it
if( app->trayMenuAsJSON != NULL ) {
parseTrayData(app);

View File

@@ -149,12 +149,12 @@ void menuItemCallback(id self, SEL cmd, id sender) {
ContextMenu* contextMenu = (ContextMenu*) callbackData->menu->parentData;
data = contextMenu->contextMenuData;
parentID = contextMenu->ID;
} else if ( menuType == TrayMenuType ) {
parentID = (const char*) callbackData->menu->parentData;
}
message = createMenuClickedMessage(menuID, data, menuType, parentID);
// TODO: Add other menu types here!
// Notify the backend
messageFromWindowCallback(message);
MEMFREE(message);

View File

@@ -5,17 +5,96 @@
#include "common.h"
#include "traymenu_darwin.h"
extern struct hashmap_s trayIconCache;
TrayMenu* NewTrayMenu(const char* menuJSON) {
TrayMenu* result = malloc(sizeof(TrayMenu));
/*
{"ID":"0","Label":"Test Tray Label","Icon":"","ProcessedMenu":{"Menu":{"Items":[{"ID":"0","Label":"Show Window","Type":"Text","Disabled":false,"Hidden":false,"Checked":false,"Foreground":0,"Background":0},{"ID":"1","Label":"Hide Window","Type":"Text","Disabled":false,"Hidden":false,"Checked":false,"Foreground":0,"Background":0},{"ID":"2","Label":"Minimise Window","Type":"Text","Disabled":false,"Hidden":false,"Checked":false,"Foreground":0,"Background":0},{"ID":"3","Label":"Unminimise Window","Type":"Text","Disabled":false,"Hidden":false,"Checked":false,"Foreground":0,"Background":0}]},"RadioGroups":null}}
*/
JsonNode* processedJSON = json_decode(menuJSON);
if( processedJSON == NULL ) {
ABORT("[NewTrayMenu] Unable to parse TrayMenu JSON: %s", menuJSON);
}
// TODO: Make this configurable
result->trayIconPosition = NSImageLeft;
result->ID = mustJSONString(processedJSON, "ID");
result->label = mustJSONString(processedJSON, "Label");
result->icon = mustJSONString(processedJSON, "Icon");
JsonNode* processedMenu = mustJSONObject(processedJSON, "ProcessedMenu");
// Create the menu
result->menu = NewMenu(processedMenu);
// Set the menu type and store the tray ID in the parent data
result->menu->menuType = TrayMenuType;
result->menu->parentData = (void*) result->ID;
return result;
}
void DumpTrayMenu(TrayMenu* trayMenu) {
printf(" ['%s':%p] = { label: '%s', icon: '%s', menu: %p }\n", trayMenu->ID, trayMenu, trayMenu->label, trayMenu->icon, trayMenu->menu );
}
void ShowTrayMenu(TrayMenu* trayMenu) {
// Create a status bar item if we don't have one
if( trayMenu->statusbaritem == NULL ) {
id statusBar = msg( c("NSStatusBar"), s("systemStatusBar") );
trayMenu->statusbaritem = msg(statusBar, s("statusItemWithLength:"), NSVariableStatusItemLength);
msg(trayMenu->statusbaritem, s("retain"));
id statusBarButton = msg(trayMenu->statusbaritem, s("button"));
msg(statusBarButton, s("setImagePosition:"), trayMenu->trayIconPosition);
// Update the icon if needed
UpdateTrayMenuIcon(trayMenu);
// Update the label if needed
UpdateTrayMenuLabel(trayMenu);
}
id menu = GetMenu(trayMenu->menu);
msg(trayMenu->statusbaritem, s("setMenu:"), menu);
}
void UpdateTrayMenuLabel(TrayMenu *trayMenu) {
// Exit early if NULL
if( trayMenu->label == NULL ) {
return;
}
// We don't check for a
id statusBarButton = msg(trayMenu->statusbaritem, s("button"));
msg(statusBarButton, s("setTitle:"), str(trayMenu->label));
}
void UpdateTrayMenuIcon(TrayMenu *trayMenu) {
// Exit early if NULL or emptystring
if( trayMenu->icon == NULL || STREMPTY(trayMenu->icon ) ) {
return;
}
id trayImage = hashmap_get(&trayIconCache, trayMenu->icon, strlen(trayMenu->icon));
id statusBarButton = msg(trayMenu->statusbaritem, s("button"));
msg(statusBarButton, s("setImagePosition:"), trayMenu->trayIconPosition);
msg(statusBarButton, s("setImage:"), trayImage);
}
void DeleteTrayMenu(TrayMenu* trayMenu) {
// printf("Freeing TrayMenu:\n");
// DumpTrayMenu(trayMenu);
// Delete the menu
DeleteMenu(trayMenu->menu);
// Free JSON
json_delete(trayMenu->processedJSON);
// Free the tray menu memory
MEMFREE(trayMenu);
}

View File

@@ -5,19 +5,30 @@
#ifndef TRAYMENU_DARWIN_H
#define TRAYMENU_DARWIN_H
#include "common.h"
#include "menu_darwin.h"
typedef struct {
const char *label;
const char *icon;
const char *trayID;
const char *ID;
Menu* menu;
id statusbaritem;
int trayIconPosition;
JsonNode* processedJSON;
} TrayMenu;
TrayMenu* NewTrayMenu(const char *trayJSON);
void DumpTrayMenu(TrayMenu* trayMenu);
void ShowTrayMenu(TrayMenu* trayMenu);
void UpdateTrayMenuIcon(TrayMenu *trayMenu);
void UpdateTrayMenuLabel(TrayMenu *trayMenu);
void DeleteTrayMenu(TrayMenu* trayMenu);
#endif //TRAYMENU_DARWIN_H

View File

@@ -21,12 +21,22 @@ TrayMenuStore* NewTrayMenuStore() {
void AddTrayMenuToStore(TrayMenuStore* store, const char* menuJSON) {
TrayMenu* newMenu = NewTrayMenu(menuJSON);
const char *ID = "TEST";
hashmap_put(&store->trayMenuMap, ID, strlen(ID), newMenu);
hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu);
}
int showTrayMenu(void *const context, struct hashmap_element_s *const e) {
ShowTrayMenu(e->data);
return -1;
}
void ShowTrayMenusInStore(TrayMenuStore* store) {
if( hashmap_num_entries(&store->trayMenuMap) > 0 ) {
hashmap_iterate_pairs(&store->trayMenuMap, showTrayMenu, NULL);
}
}
int freeTrayMenu(void *const context, struct hashmap_element_s *const e) {
DeleteTrayMenu(e->data);
return -1;

View File

@@ -19,6 +19,7 @@ typedef struct {
TrayMenuStore* NewTrayMenuStore();
void AddTrayMenuToStore(TrayMenuStore* store, const char* menuJSON);
void ShowTrayMenusInStore(TrayMenuStore* store);
void DeleteTrayMenuStore(TrayMenuStore* store);
#endif //TRAYMENUSTORE_DARWIN_H

View File

@@ -41,14 +41,17 @@ func (m *Manager) ProcessClick(menuID string, data string, menuType string, pare
case "ApplicationMenu":
menuItemMap = m.applicationMenuItemMap
case "ContextMenu":
// TBD
contextMenu := m.contextMenus[parentID]
if contextMenu == nil {
return fmt.Errorf("unknown context menu: %s", parentID)
}
menuItemMap = contextMenu.menuItemMap
//case "TrayMenu":
// // TBD
case "TrayMenu":
trayMenu := m.trayMenus[parentID]
if trayMenu == nil {
return fmt.Errorf("unknown tray menu: %s", parentID)
}
menuItemMap = trayMenu.menuItemMap
default:
return fmt.Errorf("unknown menutype: %s", menuType)
}

View File

@@ -46,6 +46,7 @@ func main() {
app.Bind(&Dialog{})
app.Bind(&Window{})
app.Bind(Menu)
app.Bind(Tray)
app.Bind(&ContextMenu{})
err = app.Run()

View File

@@ -14,7 +14,8 @@ type Tray struct {
//dynamicMenuItems map[string]*menu.MenuItem
//anotherDynamicMenuCounter int
trayMenu *menu.TrayMenu
trayMenu *menu.TrayMenu
secondTrayMenu *menu.TrayMenu
done bool
}
@@ -53,6 +54,22 @@ func (t *Tray) WailsInit(runtime *wails.Runtime) error {
return nil
}
func (t *Tray) showWindow(_ *menu.CallbackData) {
t.runtime.Window.Show()
}
func (t *Tray) hideWindow(_ *menu.CallbackData) {
t.runtime.Window.Hide()
}
func (t *Tray) unminimiseWindow(_ *menu.CallbackData) {
t.runtime.Window.Unminimise()
}
func (t *Tray) minimiseWindow(_ *menu.CallbackData) {
t.runtime.Window.Minimise()
}
func (t *Tray) WailsShutdown() {
t.done = true
}
@@ -137,14 +154,24 @@ func (t *Tray) createTrayMenus() []*menu.TrayMenu {
trayMenu := &menu.TrayMenu{}
trayMenu.Label = "Test Tray Label"
trayMenu.Menu = menu.NewMenuFromItems(
menu.Text("Show Window", "Show Window", nil, nil),
menu.Text("Hide Window", "Hide Window", nil, nil),
menu.Text("Minimise Window", "Minimise Window", nil, nil),
menu.Text("Unminimise Window", "Unminimise Window", nil, nil),
menu.Text("Show Window", "Show Window", nil, t.showWindow),
menu.Text("Hide Window", "Hide Window", nil, t.hideWindow),
menu.Text("Minimise Window", "Minimise Window", nil, t.minimiseWindow),
menu.Text("Unminimise Window", "Unminimise Window", nil, t.unminimiseWindow),
)
t.trayMenu = trayMenu
secondTrayMenu := &menu.TrayMenu{}
secondTrayMenu.Label = "Another tray label"
secondTrayMenu.Menu = menu.NewMenuFromItems(
menu.Text("Show Window", "Show Window", nil, t.showWindow),
menu.Text("Hide Window", "Hide Window", nil, t.hideWindow),
menu.Text("Minimise Window", "Minimise Window", nil, t.minimiseWindow),
menu.Text("Unminimise Window", "Unminimise Window", nil, t.unminimiseWindow),
)
t.secondTrayMenu = secondTrayMenu
return []*menu.TrayMenu{
trayMenu,
secondTrayMenu,
}
}