diff --git a/v2/internal/ffenestri/ffenestri_darwin.c b/v2/internal/ffenestri/ffenestri_darwin.c index e59fba4b..9edc7c07 100644 --- a/v2/internal/ffenestri/ffenestri_darwin.c +++ b/v2/internal/ffenestri/ffenestri_darwin.c @@ -150,6 +150,12 @@ void Fatal(struct Application *app, const char *message, ... ) { va_end(args); } +// Requires NSString input EG lookupStringConstant(str("NSFontAttributeName")) +void* lookupStringConstant(id constantName) { + void ** dataPtr = CFBundleGetDataPointerForName(CFBundleGetBundleWithIdentifier(str("com.apple.AppKit")), (CFStringRef) constantName); + return (dataPtr ? *dataPtr : nil); +} + bool isRetina(struct Application *app) { CGFloat scale = GET_BACKINGSCALEFACTOR(app->mainWindow); if( (int)scale == 1 ) { diff --git a/v2/internal/ffenestri/ffenestri_darwin.go b/v2/internal/ffenestri/ffenestri_darwin.go index fafb391b..e33fcc06 100644 --- a/v2/internal/ffenestri/ffenestri_darwin.go +++ b/v2/internal/ffenestri/ffenestri_darwin.go @@ -2,7 +2,7 @@ package ffenestri /* #cgo darwin CFLAGS: -DFFENESTRI_DARWIN=1 -#cgo darwin LDFLAGS: -framework WebKit -lobjc +#cgo darwin LDFLAGS: -framework WebKit -framework CoreFoundation -lobjc #include "ffenestri.h" #include "ffenestri_darwin.h" diff --git a/v2/internal/ffenestri/ffenestri_darwin.h b/v2/internal/ffenestri/ffenestri_darwin.h index ddb94f8a..b930d66b 100644 --- a/v2/internal/ffenestri/ffenestri_darwin.h +++ b/v2/internal/ffenestri/ffenestri_darwin.h @@ -6,6 +6,7 @@ #define OBJC_OLD_DISPATCH_PROTOTYPES 1 #include #include +#include #include "json.h" #include "hashmap.h" #include "stdlib.h" @@ -20,7 +21,6 @@ #define strunicode(input) msg(c("NSString"), s("stringWithFormat:"), str("%C"), (unsigned short)input) #define cstr(input) (const char *)msg(input, s("UTF8String")) #define url(input) msg(c("NSURL"), s("fileURLWithPath:"), str(input)) - #define ALLOC(classname) msg(c(classname), s("alloc")) #define ALLOC_INIT(classname) msg(msg(c(classname), s("alloc")), s("init")) #define GET_FRAME(receiver) ((CGRect(*)(id, SEL))objc_msgSend_stret)(receiver, s("frame")) @@ -110,4 +110,6 @@ void SetTray(struct Application* app, const char *, const char *, const char *); //void SetContextMenus(struct Application* app, const char *); void AddTrayMenu(struct Application* app, const char *); +void* lookupStringConstant(id constantName); + #endif \ No newline at end of file diff --git a/v2/internal/ffenestri/menu_darwin.c b/v2/internal/ffenestri/menu_darwin.c index 562e4e69..677391f0 100644 --- a/v2/internal/ffenestri/menu_darwin.c +++ b/v2/internal/ffenestri/menu_darwin.c @@ -5,6 +5,7 @@ #include "ffenestri_darwin.h" #include "menu_darwin.h" #include "contextmenus_darwin.h" +#include "common.h" // NewMenu creates a new Menu struct, saving the given menu structure as JSON Menu* NewMenu(JsonNode *menuData) { @@ -574,7 +575,7 @@ id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const c return item; } -id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image) { +id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA) { id item = ALLOC("NSMenuItem"); // Create a MenuItemCallbackData @@ -591,6 +592,7 @@ id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char msg(item, s("setToolTip:"), str(tooltip)); } + // Process image if( image != NULL && strlen(image) > 0) { id data = ALLOC("NSData"); id imageData = msg(data, s("initWithBase64EncodedString:options:"), str(image), 0); @@ -599,6 +601,60 @@ id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char msg(item, s("setImage:"), nsimage); } + // Process Menu Item attributes + id dictionary = ALLOC_INIT("NSMutableDictionary"); + + // Process font + id font; + CGFloat fontSizeFloat = (CGFloat)fontSize; + + // Check if valid + id fontNameAsNSString = str(fontName); + id fontsOnSystem = msg(msg(c("NSFontManager"), s("sharedFontManager")), s("availableFonts")); + bool valid = msg(fontsOnSystem, s("containsObject:"), fontNameAsNSString); + if( valid ) { + font = msg(c("NSFont"), s("fontWithName:size:"), fontNameAsNSString, fontSizeFloat); + } else { + bool supportsMonospacedDigitSystemFont = (bool) msg(c("NSFont"), s("respondsToSelector:"), s("monospacedDigitSystemFontOfSize:weight:")); + if( supportsMonospacedDigitSystemFont ) { + font = msg(c("NSFont"), s("monospacedDigitSystemFontOfSize:weight:"), fontSizeFloat, NSFontWeightRegular); + } else { + font = msg(c("NSFont"), s("menuFontOfSize:"), fontSizeFloat); + } + } + + // Add font to dictionary + msg(dictionary, s("setObject:forKey:"), font, lookupStringConstant(str("NSFontAttributeName"))); + + // Add offset to dictionary + id offset = msg(c("NSNumber"), s("numberWithFloat:"), 0.0); + msg(dictionary, s("setObject:forKey:"), offset, lookupStringConstant(str("NSBaselineOffsetAttributeName"))); + + // RGBA + if( RGBA != NULL && strlen(RGBA) > 0) { + unsigned short r, g, b, a; + + // white by default + r = g = b = a = 255; + int count = sscanf(RGBA, "#%02hx%02hx%02hx%02hx", &r, &g, &b, &a); + if (count > 0) { + id colour = msg(c("NSColor"), s("colorWithCalibratedRed:green:blue:alpha:"), + (float)r / 255.0, + (float)g / 255.0, + (float)b / 255.0, + (float)a / 255.0); + msg(dictionary, s("setObject:forKey:"), colour, lookupStringConstant(str("NSForegroundColorAttributeName"))); + msg(colour, s("release")); + } + } + + id attributedString = ALLOC("NSMutableAttributedString"); + msg(attributedString, s("initWithString:attributes:"), str(title), dictionary); + msg(dictionary, s("release")); + + msg(item, s("setAttributedTitle:"), attributedString); + msg(attributedString, s("autorelease")); + msg(item, s("setEnabled:"), !disabled); msg(item, s("autorelease")); @@ -682,6 +738,10 @@ void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) { const char *tooltip = getJSONString(item, "Tooltip"); const char *image = getJSONString(item, "Image"); + const char *fontName = getJSONString(item, "FontName"); + const char *RGBA = getJSONString(item, "RGBA"); + int fontSize = 0; + getJSONInt(item, "FontSize", &fontSize); // If we have an accelerator if( accelerator != NULL ) { @@ -715,7 +775,7 @@ void processMenuItem(Menu *menu, id parentMenu, JsonNode *item) { if( type != NULL ) { if( STREQ(type->string_, "Text")) { - processTextMenuItem(menu, parentMenu, label, menuid, disabled, acceleratorkey, modifiers, tooltip, image); + processTextMenuItem(menu, parentMenu, label, menuid, disabled, acceleratorkey, modifiers, tooltip, image, fontName, fontSize, RGBA); } else if ( STREQ(type->string_, "Separator")) { addSeparator(parentMenu); diff --git a/v2/internal/ffenestri/menu_darwin.h b/v2/internal/ffenestri/menu_darwin.h index 0fd9deb7..05ef13b4 100644 --- a/v2/internal/ffenestri/menu_darwin.h +++ b/v2/internal/ffenestri/menu_darwin.h @@ -14,6 +14,21 @@ static const char *MenuTypeAsString[] = { "ApplicationMenu", "ContextMenu", "TrayMenu", }; +typedef struct _NSRange { + unsigned long location; + unsigned long length; +} NSRange; + +#define NSFontWeightUltraLight -0.8 +#define NSFontWeightThin -0.6 +#define NSFontWeightLight -0.4 +#define NSFontWeightRegular 0 +#define NSFontWeightMedium 0.23 +#define NSFontWeightSemibold 0.3 +#define NSFontWeightBold 0.4 +#define NSFontWeightHeavy 0.56 +#define NSFontWeightBlack 0.62 + extern void messageFromWindowCallback(const char *); typedef struct { @@ -90,8 +105,7 @@ id processRadioMenuItem(Menu *menu, id parentmenu, const char *title, const char id processCheckboxMenuItem(Menu *menu, id parentmenu, const char *title, const char *menuid, bool disabled, bool checked, const char *key); -id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image); - +id processTextMenuItem(Menu *menu, id parentMenu, const char *title, const char *menuid, bool disabled, const char *acceleratorkey, const char **modifiers, const char* tooltip, const char* image, const char* fontName, int fontSize, const char* RGBA); void processMenuItem(Menu *menu, id parentMenu, JsonNode *item); void processMenuData(Menu *menu, JsonNode *menuData); diff --git a/v2/internal/ffenestri/traymenustore_darwin.c b/v2/internal/ffenestri/traymenustore_darwin.c index 6c451a47..bc52d038 100644 --- a/v2/internal/ffenestri/traymenustore_darwin.c +++ b/v2/internal/ffenestri/traymenustore_darwin.c @@ -97,14 +97,13 @@ void UpdateTrayMenuLabelInStore(TrayMenuStore* store, const char* JSON) { void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) { TrayMenu* newMenu = NewTrayMenu(menuJSON); - DumpTrayMenu(newMenu); +// DumpTrayMenu(newMenu); // Get the current menu TrayMenu *currentMenu = GetTrayMenuFromStore(store, newMenu->ID); // If we don't have a menu, we create one if ( currentMenu == NULL ) { - printf(" currentMenu = NULL\n"); // Store the new menu hashmap_put(&store->trayMenuMap, newMenu->ID, strlen(newMenu->ID), newMenu); @@ -112,7 +111,7 @@ void UpdateTrayMenuInStore(TrayMenuStore* store, const char* menuJSON) { ShowTrayMenu(newMenu); return; } - DumpTrayMenu(currentMenu); +// DumpTrayMenu(currentMenu); // Save the status bar reference newMenu->statusbaritem = currentMenu->statusbaritem;