#include NSColor* nscolor(gg__Color c) { float red = (float)c.r / 255.0f; float green = (float)c.g / 255.0f; float blue = (float)c.b / 255.0f; return [NSColor colorWithDeviceRed:red green:green blue:blue alpha:1.0f]; } NSString* nsstring(string s) { return [[NSString alloc] initWithBytesNoCopy:s.str length:s.len encoding:NSUTF8StringEncoding freeWhenDone:false]; } gg__Size gg_get_screen_size() { NSScreen *currentScreen = nil; NSWindow *mainWindow = [NSApp mainWindow]; // 1. Try screen containing the main window if (mainWindow) { currentScreen = [mainWindow screen]; } // 2. If no main window, try the key window (might be different, e.g., a panel) if (!currentScreen) { NSWindow *keyWindow = [NSApp keyWindow]; if (keyWindow) { currentScreen = [keyWindow screen]; } } // 3. If no relevant window, find the screen containing the mouse cursor if (!currentScreen) { // Get mouse location in global screen coordinates (bottom-left origin) NSPoint mouseLocation = [NSEvent mouseLocation]; NSArray *screens = [NSScreen screens]; for (NSScreen *screen in screens) { // Check if the mouse location is within the screen's frame // Note: Both mouseLocation and screen.frame use bottom-left origin coordinates if (NSMouseInRect(mouseLocation, [screen frame], NO)) { currentScreen = screen; break; // Found the screen with the mouse } } } // 4. As a last resort, fall back to the main screen if (!currentScreen) { NSLog(@"Warning: Could not determine current screen based on window or mouse. Falling back to mainScreen."); currentScreen = [NSScreen mainScreen]; } // Now get the size of the determined screen NSDictionary *description = [currentScreen deviceDescription]; // Use NSDeviceSize to get pixel dimensions NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue]; // Create the V gg.Size object gg__Size res; res.width = displayPixelSize.width; res.height = displayPixelSize.height; return res; } void gg_macos_resize_window(void *window_ptr, int width, int height) { if (window_ptr == nil || width <= 0 || height <= 0) { return; } NSWindow *window = (__bridge NSWindow *)window_ptr; [window setContentSize:NSMakeSize((CGFloat)width, (CGFloat)height)]; } void gg_macos_set_window_resizable(void *window_ptr, bool resizable) { if (window_ptr == nil) { return; } NSWindow *window = (__bridge NSWindow *)window_ptr; NSWindowStyleMask style = [window styleMask]; if (resizable) { style |= NSWindowStyleMaskResizable; } else { style &= ~NSWindowStyleMaskResizable; } [window setStyleMask:style]; } void darwin_draw_string(int x, int y, string s, gg__TextCfg cfg) { NSFont* font = [NSFont userFontOfSize:cfg.size]; // # NSFont* font = [NSFont fontWithName:@"Roboto Mono" size:cfg.size]; if (cfg.mono) { // # font = [NSFont fontWithName:@"Roboto Mono" size:cfg.size]; font = [NSFont fontWithName:@"Menlo" size:cfg.size - 5]; } if (cfg.bold) { font = [[NSFontManager sharedFontManager] convertFont:font toHaveTrait:NSBoldFontMask]; } NSDictionary* attr = @{ NSForegroundColorAttributeName : nscolor(cfg.color), // NSParagraphStyleAttributeName: paragraphStyle, NSFontAttributeName : font, }; [nsstring(s) drawAtPoint:NSMakePoint(x, y - 15) withAttributes:attr]; } int darwin_text_width(string s) { // println('text_width "${s}" len=${s.len}') NSString* n = @""; if (s.len == 1) { // println('len=1') n = [NSString stringWithFormat:@"%c", s.str[0]]; } else { n = nsstring(s); } /* # if (!defaultFont){ # defaultFont = [NSFont userFontOfSize: ui__DEFAULT_FONT_SIZE]; # } # NSDictionary *attrs = @{ # NSFontAttributeName: defaultFont, # }; */ NSSize size = [n sizeWithAttributes:nil]; // # printf("!!!%f\n", ceil(size.width)); return (int)(ceil(size.width)); } void darwin_draw_rect(float x, float y, float width, float height, gg__Color c) { NSColor* color = nscolor(c); NSRect rect = NSMakeRect(x, y, width, height); [color setFill]; NSRectFill(rect); } static void mark_view_tree_needs_display(NSView *view) { if (view == nil) { return; } [view setNeedsDisplay:YES]; for (NSView *subview in [view subviews]) { mark_view_tree_needs_display(subview); } } void darwin_window_refresh() { dispatch_async(dispatch_get_main_queue(), ^{ NSWindow *window = [NSApp mainWindow]; if (window == nil) { window = [NSApp keyWindow]; } if (window == nil) { return; } NSView *contentView = [window contentView]; if (contentView == nil) { return; } mark_view_tree_needs_display(contentView); [window displayIfNeeded]; }); // puts("refresh"); //[[NSApp mainWindow].contentView drawRect:NSMakeRect(0,0,2000,2000)]; //[[NSGraphicsContext currentContext] flushGraphics]; } gg__Image darwin_create_image(string path_) { // file = file.trim_space() NSString* path = nsstring(path_); NSImage* img = [[NSImage alloc] initWithContentsOfFile:path]; if (img == 0) { } NSSize size = [img size]; gg__Image res; res.width = size.width; res.height = size.height; res.path = path_; res.ok = true; // printf("inited img width=%d\n", res.width) ; // need __bridge_retained so that the pointer is not freed by ARC res.data = (__bridge_retained voidptr)(img); return res; } void darwin_draw_image(float x, float y, float w, float h, gg__Image* img) { NSImage* i = (__bridge NSImage*)(img->data); [i drawInRect:NSMakeRect(x, y, w, h)]; } void darwin_draw_circle(float x, float y, float d, gg__Color color) { NSColor* c = nscolor(color); NSRect rect = NSMakeRect(x, y, d * 2, d * 2); NSBezierPath* circlePath = [NSBezierPath bezierPath]; [circlePath appendBezierPathWithOvalInRect:rect]; [c setFill]; // [circlePath stroke]; [circlePath fill]; // NSRectFill(rect); } void darwin_draw_circle_empty(float x, float y, float d, gg__Color color) { NSColor* outlineColor = nscolor(color); CGFloat outlineWidth = 1.0; //2.0; NSRect rect = NSMakeRect(x, y, d * 2, d * 2); NSBezierPath* circlePath = [NSBezierPath bezierPath]; [circlePath appendBezierPathWithOvalInRect:rect]; [outlineColor setStroke]; [circlePath setLineWidth:outlineWidth]; [circlePath stroke]; }