| 1 | /* |
|---|
| 2 | * libcaca Colour ASCII-Art library |
|---|
| 3 | * Copyright (c) 2006 Colin Delacroix <colin@zoy.org> |
|---|
| 4 | * All Rights Reserved |
|---|
| 5 | * |
|---|
| 6 | * $Id$ |
|---|
| 7 | * |
|---|
| 8 | * This library is free software. It comes without any warranty, to |
|---|
| 9 | * the extent permitted by applicable law. You can redistribute it |
|---|
| 10 | * and/or modify it under the terms of the Do What The Fuck You Want |
|---|
| 11 | * To Public License, Version 2, as published by Sam Hocevar. See |
|---|
| 12 | * http://sam.zoy.org/wtfpl/COPYING for more details. |
|---|
| 13 | */ |
|---|
| 14 | |
|---|
| 15 | /* |
|---|
| 16 | * This file contains the libcaca Cocoa input and output driver |
|---|
| 17 | */ |
|---|
| 18 | |
|---|
| 19 | #include "config.h" |
|---|
| 20 | |
|---|
| 21 | #if defined USE_COCOA |
|---|
| 22 | |
|---|
| 23 | #import <Cocoa/Cocoa.h> |
|---|
| 24 | |
|---|
| 25 | #include "caca.h" |
|---|
| 26 | #include "caca.h" |
|---|
| 27 | #include "caca_internals.h" |
|---|
| 28 | |
|---|
| 29 | //#define COCOA_DEBUG |
|---|
| 30 | |
|---|
| 31 | // many ways to draw the chars : |
|---|
| 32 | // - NSString and drawInRect:withAttributes: or drawWithRect:options:attributes: |
|---|
| 33 | // - NSAttributedString and drawInRect: or drawWithRect:options: |
|---|
| 34 | // - NSTextLayout and co. |
|---|
| 35 | // - Quartz 2D |
|---|
| 36 | // - ATSUI (more accessible from carbon) |
|---|
| 37 | // 2 firsts are high level cocoa, 3rd is low-level cocoa, other are untested |
|---|
| 38 | // also see http://www.cocoabuilder.com/archive/message/cocoa/2004/11/18/121928 |
|---|
| 39 | // update: actually high-level is faster, so keep it like that |
|---|
| 40 | //#define USE_LOWLEVEL_COCOA 1 |
|---|
| 41 | |
|---|
| 42 | // build a complete color table cache for the view |
|---|
| 43 | #define PRECACHE_WHOLE_COLOR_TABLE 1 |
|---|
| 44 | |
|---|
| 45 | //#define USE_RGB12_FGBG 1 |
|---|
| 46 | |
|---|
| 47 | //#define USE_GLOBAL_AUTORELEASE_POOL 1 |
|---|
| 48 | |
|---|
| 49 | #ifdef COCOA_DEBUG |
|---|
| 50 | #define debug_log NSLog |
|---|
| 51 | #else |
|---|
| 52 | #define debug_log(...) |
|---|
| 53 | #endif |
|---|
| 54 | |
|---|
| 55 | #define NCOLORS 0x1000 |
|---|
| 56 | |
|---|
| 57 | static BOOL s_quit = NO; |
|---|
| 58 | static BOOL s_quitting = NO; |
|---|
| 59 | |
|---|
| 60 | @interface CacaView : NSView |
|---|
| 61 | { |
|---|
| 62 | //NSFont* _font; |
|---|
| 63 | NSRect _font_rect; |
|---|
| 64 | int _h, _w; |
|---|
| 65 | uint32_t* _attrs; |
|---|
| 66 | uint32_t* _chars; |
|---|
| 67 | NSRect* _bkg_rects; |
|---|
| 68 | NSColor** _bkg_colors; |
|---|
| 69 | #ifdef PRECACHE_WHOLE_COLOR_TABLE |
|---|
| 70 | NSColor* _colorCache[NCOLORS]; |
|---|
| 71 | #else |
|---|
| 72 | NSMutableDictionary* _colorCache; |
|---|
| 73 | #endif |
|---|
| 74 | NSMutableDictionary* _attrDict; |
|---|
| 75 | NSMutableDictionary* _attrDictUnderline; // lame optim |
|---|
| 76 | #ifdef USE_LOWLEVEL_COCOA |
|---|
| 77 | NSTextStorage* _textStorage; |
|---|
| 78 | NSLayoutManager* _layoutManager; |
|---|
| 79 | NSTextContainer* _textContainer; |
|---|
| 80 | #endif |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | - (void)setFont:(NSFont *)aFont; |
|---|
| 84 | - (void)updateBuffersFromCaca:(caca_display_t *)dp; |
|---|
| 85 | @end |
|---|
| 86 | |
|---|
| 87 | @interface NSColor(Caca) |
|---|
| 88 | + (NSColor *)colorFromRgb12:(uint16_t) ui_rgb12; |
|---|
| 89 | @end |
|---|
| 90 | |
|---|
| 91 | @implementation CacaView |
|---|
| 92 | - (id)initWithFrame:(NSRect)frameRect |
|---|
| 93 | { |
|---|
| 94 | self = [super initWithFrame:frameRect]; |
|---|
| 95 | if(!self) |
|---|
| 96 | return nil; |
|---|
| 97 | |
|---|
| 98 | [[self window] makeFirstResponder:self]; |
|---|
| 99 | |
|---|
| 100 | #ifdef PRECACHE_WHOLE_COLOR_TABLE |
|---|
| 101 | int i; |
|---|
| 102 | for(i = 0; i < NCOLORS; i++) |
|---|
| 103 | _colorCache[i] = [[NSColor colorFromRgb12:i] retain]; |
|---|
| 104 | #else |
|---|
| 105 | _colorCache = [[NSMutableDictionary alloc] initWithCapacity:NCOLORS]; |
|---|
| 106 | #endif |
|---|
| 107 | _attrDict = [[NSMutableDictionary alloc] initWithCapacity:3]; |
|---|
| 108 | _attrDictUnderline = [[NSMutableDictionary alloc] initWithCapacity:3]; |
|---|
| 109 | [_attrDictUnderline setObject:[NSNumber numberWithInt:NSUnderlineStyleSingle] |
|---|
| 110 | forKey:NSUnderlineStyleAttributeName]; |
|---|
| 111 | #ifdef USE_LOWLEVEL_COCOA |
|---|
| 112 | _textStorage = [[NSTextStorage alloc] init]; |
|---|
| 113 | _layoutManager = [[NSLayoutManager alloc] init]; |
|---|
| 114 | _textContainer = [[NSTextContainer alloc] init]; |
|---|
| 115 | [_textContainer setLineFragmentPadding:0.0]; |
|---|
| 116 | [_layoutManager addTextContainer:_textContainer]; |
|---|
| 117 | [_textStorage addLayoutManager:_layoutManager]; |
|---|
| 118 | #endif |
|---|
| 119 | |
|---|
| 120 | return self; |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | - (void)dealloc |
|---|
| 124 | { |
|---|
| 125 | //[_font release]; |
|---|
| 126 | #ifdef PRECACHE_WHOLE_COLOR_TABLE |
|---|
| 127 | short i; |
|---|
| 128 | for(i = 0; i < NCOLORS; i++) |
|---|
| 129 | [_colorCache[i] release]; |
|---|
| 130 | #else |
|---|
| 131 | [_colorCache release]; |
|---|
| 132 | #endif |
|---|
| 133 | [_attrDict release]; |
|---|
| 134 | [_attrDictUnderline release]; |
|---|
| 135 | #ifdef USE_LOWLEVEL_COCOA |
|---|
| 136 | [_textStorage release]; |
|---|
| 137 | [_layoutManager release]; |
|---|
| 138 | [_textContainer release]; |
|---|
| 139 | #endif |
|---|
| 140 | if(_attrs) |
|---|
| 141 | free(_attrs); |
|---|
| 142 | if(_bkg_rects) |
|---|
| 143 | free(_bkg_rects); |
|---|
| 144 | if(_bkg_colors) |
|---|
| 145 | free(_bkg_colors); |
|---|
| 146 | |
|---|
| 147 | [super dealloc]; |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | // to accelerate the window drawing speed |
|---|
| 151 | - (BOOL)isOpaque |
|---|
| 152 | { |
|---|
| 153 | return YES; |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | - (BOOL)isFlipped |
|---|
| 157 | { |
|---|
| 158 | return YES; |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | - (void)setupNewSize |
|---|
| 162 | { |
|---|
| 163 | float fw = _font_rect.size.width; |
|---|
| 164 | float fh = _font_rect.size.height; |
|---|
| 165 | _w = ceilf([self bounds].size.width / fw); |
|---|
| 166 | _h = ceilf([self bounds].size.height / fh); |
|---|
| 167 | debug_log(@"fw=%f selfw=%f %u %f", fw, [self bounds].size.width, |
|---|
| 168 | _w, [self bounds].size.width-(_w*fw)); |
|---|
| 169 | debug_log(@"fh=%f selfh=%f %u %f", fh, [self bounds].size.height, |
|---|
| 170 | _h, [self bounds].size.height-(_h*fh)); |
|---|
| 171 | } |
|---|
| 172 | |
|---|
| 173 | - (void)keyDown:(NSEvent *)theEvent |
|---|
| 174 | { |
|---|
| 175 | NSLog(@"key %@", theEvent); |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | - (void)mouseMoved:(NSEvent *)theEvent |
|---|
| 179 | { |
|---|
| 180 | NSLog(@"mouse %@", theEvent); |
|---|
| 181 | } |
|---|
| 182 | |
|---|
| 183 | - (void)setFont:(NSFont *)aFont |
|---|
| 184 | { |
|---|
| 185 | //[_font release]; |
|---|
| 186 | //_font = [aFont retain]; |
|---|
| 187 | _font_rect = [aFont boundingRectForFont]; |
|---|
| 188 | _font_rect = NSMakeRect(0, 0, ceilf(_font_rect.size.width), ceilf(_font_rect.size.height)); |
|---|
| 189 | [self setupNewSize]; |
|---|
| 190 | [_attrDict setObject:aFont forKey:NSFontAttributeName]; |
|---|
| 191 | [_attrDictUnderline setObject:aFont forKey:NSFontAttributeName]; |
|---|
| 192 | [aFont set]; |
|---|
| 193 | } |
|---|
| 194 | |
|---|
| 195 | - (void)resizeIfNeeded:(caca_display_t *)dp |
|---|
| 196 | { |
|---|
| 197 | if(_w != caca_get_canvas_width(dp->cv) |
|---|
| 198 | || _h != caca_get_canvas_height(dp->cv) |
|---|
| 199 | || !_attrs || !_bkg_rects || !_bkg_colors) |
|---|
| 200 | { |
|---|
| 201 | debug_log(@"%s resize to %ux%u", _cmd, _w, _h); |
|---|
| 202 | |
|---|
| 203 | _w = caca_get_canvas_width(dp->cv); |
|---|
| 204 | _h = caca_get_canvas_height(dp->cv); |
|---|
| 205 | |
|---|
| 206 | if(_attrs) |
|---|
| 207 | free(_attrs); |
|---|
| 208 | _attrs = malloc(_w * _h * sizeof(uint32_t) * 2); |
|---|
| 209 | |
|---|
| 210 | if(_bkg_rects) |
|---|
| 211 | free(_bkg_rects); |
|---|
| 212 | _bkg_rects = malloc(_w * _h * sizeof(NSRect)); |
|---|
| 213 | |
|---|
| 214 | if(_bkg_colors) |
|---|
| 215 | free(_bkg_colors); |
|---|
| 216 | _bkg_colors = malloc(_w * _h * sizeof(NSColor*)); |
|---|
| 217 | |
|---|
| 218 | [[self window] setContentSize: NSMakeSize(caca_get_canvas_width(dp->cv) * _font_rect.size.width, |
|---|
| 219 | caca_get_canvas_height(dp->cv) * _font_rect.size.height)]; |
|---|
| 220 | } |
|---|
| 221 | } |
|---|
| 222 | |
|---|
| 223 | - (void)updateBuffersFromCaca:(caca_display_t *)dp |
|---|
| 224 | { |
|---|
| 225 | [self resizeIfNeeded:dp]; |
|---|
| 226 | |
|---|
| 227 | if(_attrs) |
|---|
| 228 | { |
|---|
| 229 | _chars = _attrs + _w * _h; |
|---|
| 230 | memcpy(_attrs, caca_get_canvas_attrs(dp->cv), |
|---|
| 231 | _w * _h * sizeof(uint32_t)); |
|---|
| 232 | memcpy(_chars, caca_get_canvas_chars(dp->cv), |
|---|
| 233 | _w * _h * sizeof(uint32_t)); |
|---|
| 234 | |
|---|
| 235 | [self setNeedsDisplay:TRUE]; |
|---|
| 236 | } |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | - (void)drawRect:(NSRect)rect |
|---|
| 240 | { |
|---|
| 241 | //if([self inLiveResize]) [self setupNewSize]; |
|---|
| 242 | |
|---|
| 243 | if(!_attrs || !_chars) |
|---|
| 244 | { |
|---|
| 245 | [[NSColor blueColor] set]; |
|---|
| 246 | NSRectFill(rect); |
|---|
| 247 | return; |
|---|
| 248 | } |
|---|
| 249 | |
|---|
| 250 | int x, y; |
|---|
| 251 | float fw = _font_rect.size.width; |
|---|
| 252 | float fh = _font_rect.size.height; |
|---|
| 253 | uint32_t* attrs; |
|---|
| 254 | uint32_t* chars = _chars; |
|---|
| 255 | |
|---|
| 256 | /* first take care of the background */ |
|---|
| 257 | [[NSColor blackColor] set]; |
|---|
| 258 | NSRectFill(rect); |
|---|
| 259 | |
|---|
| 260 | int arrayLength = 0; |
|---|
| 261 | for(y = 0; y < _h; y++) |
|---|
| 262 | { |
|---|
| 263 | int yoff = y * fh; |
|---|
| 264 | for(x = 0; x < _w; x++) |
|---|
| 265 | { |
|---|
| 266 | NSRect r = NSMakeRect(x * fw, yoff, fw, fh); |
|---|
| 267 | if(NSIntersectsRect(r, rect)) |
|---|
| 268 | { |
|---|
| 269 | attrs = _attrs + x + y * _w; |
|---|
| 270 | NSColor* color = nil; |
|---|
| 271 | #if USE_RGB12_FGBG |
|---|
| 272 | uint16_t bg = caca_attr_to_rgb12_bg(*attrs); |
|---|
| 273 | if(bg) |
|---|
| 274 | { |
|---|
| 275 | # ifdef PRECACHE_WHOLE_COLOR_TABLE |
|---|
| 276 | color = _colorCache[bg]; |
|---|
| 277 | # else |
|---|
| 278 | NSNumber* numberBg = [NSNumber numberWithInt:bg]; |
|---|
| 279 | color = [_colorCache objectForKey:numberBg]; |
|---|
| 280 | if(!color) |
|---|
| 281 | { |
|---|
| 282 | color = [NSColor colorFromRgb12:bg]; |
|---|
| 283 | if(color) |
|---|
| 284 | [_colorCache setObject:color forKey:numberBg]; |
|---|
| 285 | } |
|---|
| 286 | # endif |
|---|
| 287 | } |
|---|
| 288 | #else |
|---|
| 289 | uint8_t argb[8]; |
|---|
| 290 | caca_attr_to_argb64(*attrs, argb); |
|---|
| 291 | color = [NSColor colorWithCalibratedRed:((float)argb[1]) / 15.0 |
|---|
| 292 | green:((float)argb[2]) / 15.0 |
|---|
| 293 | blue:((float)argb[3]) / 15.0 |
|---|
| 294 | alpha:1.0]; |
|---|
| 295 | #endif |
|---|
| 296 | if(color) |
|---|
| 297 | { |
|---|
| 298 | _bkg_colors[arrayLength] = color; |
|---|
| 299 | _bkg_rects[arrayLength++] = r; |
|---|
| 300 | } |
|---|
| 301 | } |
|---|
| 302 | } |
|---|
| 303 | } |
|---|
| 304 | NSRectFillListWithColors(_bkg_rects, _bkg_colors, arrayLength); |
|---|
| 305 | |
|---|
| 306 | /* Then print the foreground characters */ |
|---|
| 307 | for(y = 0; y < _h; y++) |
|---|
| 308 | { |
|---|
| 309 | int yoff = y * fh; |
|---|
| 310 | for(x = 0; x < _w; x++, chars++) |
|---|
| 311 | { |
|---|
| 312 | attrs = _attrs + x + y * _w; |
|---|
| 313 | |
|---|
| 314 | /* Skip spaces */ |
|---|
| 315 | if(*chars <= 0x00000020) |
|---|
| 316 | continue; |
|---|
| 317 | |
|---|
| 318 | if(*chars == CACA_MAGIC_FULLWIDTH) |
|---|
| 319 | continue; |
|---|
| 320 | |
|---|
| 321 | /* Plain ASCII, no problem. */ |
|---|
| 322 | // TODO: test me with wide chars |
|---|
| 323 | //if(*chars > 0x00000020 && *chars < 0x00000080) |
|---|
| 324 | { |
|---|
| 325 | NSRect r = NSMakeRect(x * fw + 1, yoff, fw - 1, fh); |
|---|
| 326 | if(NSIntersectsRect(r, rect)) |
|---|
| 327 | { |
|---|
| 328 | NSColor* color = nil; |
|---|
| 329 | #if USE_RGB12_FGBG |
|---|
| 330 | uint16_t fg = caca_attr_to_rgb12_fg(*attrs); |
|---|
| 331 | # ifdef PRECACHE_WHOLE_COLOR_TABLE |
|---|
| 332 | color = _colorCache[fg]; |
|---|
| 333 | # else // PRECACHE_WHOLE_COLOR_TABLE |
|---|
| 334 | NSNumber* numberFg = [NSNumber numberWithInt:fg]; |
|---|
| 335 | color = [_colorCache objectForKey:numberFg]; |
|---|
| 336 | if(!color) |
|---|
| 337 | { |
|---|
| 338 | color = [NSColor colorFromRgb12:fg]; |
|---|
| 339 | if(color) |
|---|
| 340 | [_colorCache setObject:color forKey:numberFg]; |
|---|
| 341 | } |
|---|
| 342 | # endif // PRECACHE_WHOLE_COLOR_TABLE |
|---|
| 343 | #else // USE_RGB12_FGBG |
|---|
| 344 | uint8_t argb[8]; |
|---|
| 345 | caca_attr_to_argb64(*attrs, argb); |
|---|
| 346 | debug_log(@"x,y=[%d,%d] r,g,b back=[%u %u %u] front=[%u %u %u]", |
|---|
| 347 | x, y, argb[1], argb[2], argb[3], argb[5], argb[6], argb[7]); |
|---|
| 348 | color = [NSColor colorWithCalibratedRed:((float)argb[5]) / 15.0 |
|---|
| 349 | green:((float)argb[6]) / 15.0 |
|---|
| 350 | blue:((float)argb[7]) / 15.0 |
|---|
| 351 | alpha:1.0]; |
|---|
| 352 | #endif // USE_RGB12_FGBG |
|---|
| 353 | |
|---|
| 354 | if(color) |
|---|
| 355 | { |
|---|
| 356 | NSMutableDictionary* attrDict = (*attrs & CACA_UNDERLINE) ? |
|---|
| 357 | _attrDictUnderline : _attrDict; |
|---|
| 358 | [attrDict setObject:color forKey:NSForegroundColorAttributeName]; |
|---|
| 359 | |
|---|
| 360 | unichar ch = *chars; |
|---|
| 361 | NSString* str = [[NSString alloc] initWithCharacters:&ch length:1]; |
|---|
| 362 | |
|---|
| 363 | #ifdef USE_LOWLEVEL_COCOA |
|---|
| 364 | [[_textStorage mutableString] setString:str]; |
|---|
| 365 | [_textStorage setAttributes:attrDict range:NSMakeRange(0, 1)]; |
|---|
| 366 | [_layoutManager drawGlyphsForGlyphRange:NSMakeRange(0, 1) atPoint:r.origin]; |
|---|
| 367 | #else |
|---|
| 368 | [str drawInRect:r withAttributes:attrDict]; |
|---|
| 369 | #endif |
|---|
| 370 | [str release]; |
|---|
| 371 | } |
|---|
| 372 | } |
|---|
| 373 | continue; |
|---|
| 374 | } |
|---|
| 375 | } |
|---|
| 376 | } |
|---|
| 377 | } |
|---|
| 378 | |
|---|
| 379 | @end |
|---|
| 380 | |
|---|
| 381 | struct driver_private |
|---|
| 382 | { |
|---|
| 383 | NSWindow* window; |
|---|
| 384 | CacaView* view; |
|---|
| 385 | #ifdef USE_GLOBAL_AUTORELEASE_POOL |
|---|
| 386 | NSAutoreleasePool* pool; |
|---|
| 387 | #endif |
|---|
| 388 | }; |
|---|
| 389 | |
|---|
| 390 | //============================================================================ |
|---|
| 391 | // NSApplication(Caca) |
|---|
| 392 | //============================================================================ |
|---|
| 393 | |
|---|
| 394 | @implementation NSApplication(Caca) |
|---|
| 395 | - (void)setRunning |
|---|
| 396 | { |
|---|
| 397 | _running = 1; |
|---|
| 398 | } |
|---|
| 399 | @end |
|---|
| 400 | |
|---|
| 401 | //============================================================================ |
|---|
| 402 | // NSColor(Caca) |
|---|
| 403 | //============================================================================ |
|---|
| 404 | |
|---|
| 405 | @implementation NSColor(Caca) |
|---|
| 406 | + (NSColor *)colorFromRgb12:(uint16_t)ui_rgb12 |
|---|
| 407 | { |
|---|
| 408 | float red = ((float)((ui_rgb12 & 0x0f00) >> 3)) / 15.0, |
|---|
| 409 | green = ((float)((ui_rgb12 & 0x00f0) >> 2)) / 15.0, |
|---|
| 410 | blue = ((float)( ui_rgb12 & 0x000f) ) / 15.0; |
|---|
| 411 | return [NSColor colorWithDeviceRed:red green:green |
|---|
| 412 | blue:blue alpha:1.0]; |
|---|
| 413 | } |
|---|
| 414 | @end |
|---|
| 415 | |
|---|
| 416 | //============================================================================ |
|---|
| 417 | // CacaWindowDelegate |
|---|
| 418 | //============================================================================ |
|---|
| 419 | |
|---|
| 420 | @interface CacaWindowDelegate : NSObject |
|---|
| 421 | @end |
|---|
| 422 | |
|---|
| 423 | @implementation CacaWindowDelegate |
|---|
| 424 | - (BOOL)windowShouldClose:(id)sender |
|---|
| 425 | { |
|---|
| 426 | debug_log(@"%s", _cmd); |
|---|
| 427 | [NSApp terminate:self]; |
|---|
| 428 | return NO; |
|---|
| 429 | } |
|---|
| 430 | @end |
|---|
| 431 | |
|---|
| 432 | //============================================================================ |
|---|
| 433 | // CacaAppDelegate |
|---|
| 434 | //============================================================================ |
|---|
| 435 | |
|---|
| 436 | @interface CacaAppDelegate : NSObject |
|---|
| 437 | @end |
|---|
| 438 | |
|---|
| 439 | @implementation CacaAppDelegate : NSObject |
|---|
| 440 | - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender |
|---|
| 441 | { |
|---|
| 442 | s_quit = YES; |
|---|
| 443 | return NSTerminateCancel; |
|---|
| 444 | } |
|---|
| 445 | @end |
|---|
| 446 | |
|---|
| 447 | /* setAppleMenu disappeared from the headers in 10.4 */ |
|---|
| 448 | #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 |
|---|
| 449 | @interface NSApplication(NSAppleMenu) |
|---|
| 450 | - (void)setAppleMenu:(NSMenu *)menu; |
|---|
| 451 | @end |
|---|
| 452 | #endif |
|---|
| 453 | |
|---|
| 454 | //============================================================================ |
|---|
| 455 | // utility methods |
|---|
| 456 | //============================================================================ |
|---|
| 457 | |
|---|
| 458 | static NSString* get_application_name() |
|---|
| 459 | { |
|---|
| 460 | NSString* appName = [[NSBundle mainBundle] objectForInfoDictionaryKey: |
|---|
| 461 | @"CFBundleName"]; |
|---|
| 462 | if(![appName length]) |
|---|
| 463 | appName = [[NSProcessInfo processInfo] processName]; |
|---|
| 464 | |
|---|
| 465 | return appName; |
|---|
| 466 | } |
|---|
| 467 | |
|---|
| 468 | static void create_application_menus() |
|---|
| 469 | { |
|---|
| 470 | /* Create the main menu bar */ |
|---|
| 471 | [NSApp setMainMenu:[[NSMenu alloc] init]]; |
|---|
| 472 | |
|---|
| 473 | /* Create the application menu */ |
|---|
| 474 | NSString* appName = get_application_name(); |
|---|
| 475 | NSMenu* appleMenu = [[NSMenu alloc] initWithTitle:@""]; |
|---|
| 476 | |
|---|
| 477 | /* Add menu items */ |
|---|
| 478 | NSString* title = [@"About " stringByAppendingString:appName]; |
|---|
| 479 | [appleMenu addItemWithTitle:title |
|---|
| 480 | action:@selector(orderFrontStandardAboutPanel:) |
|---|
| 481 | keyEquivalent:@""]; |
|---|
| 482 | [appleMenu addItem:[NSMenuItem separatorItem]]; |
|---|
| 483 | |
|---|
| 484 | title = [@"Hide " stringByAppendingString:appName]; |
|---|
| 485 | [appleMenu addItemWithTitle:title action:@selector(hide:) |
|---|
| 486 | keyEquivalent:@"h"]; |
|---|
| 487 | |
|---|
| 488 | id<NSMenuItem> menuItem = [appleMenu addItemWithTitle:@"Hide Others" |
|---|
| 489 | action:@selector(hideOtherApplications:) |
|---|
| 490 | keyEquivalent:@"h"]; |
|---|
| 491 | [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; |
|---|
| 492 | |
|---|
| 493 | [appleMenu addItemWithTitle:@"Show All" |
|---|
| 494 | action:@selector(unhideAllApplications:) |
|---|
| 495 | keyEquivalent:@""]; |
|---|
| 496 | [appleMenu addItem:[NSMenuItem separatorItem]]; |
|---|
| 497 | |
|---|
| 498 | title = [@"Quit " stringByAppendingString:appName]; |
|---|
| 499 | [appleMenu addItemWithTitle:title action:@selector(terminate:) |
|---|
| 500 | keyEquivalent:@"q"]; |
|---|
| 501 | |
|---|
| 502 | /* Put menu into the menubar */ |
|---|
| 503 | menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; |
|---|
| 504 | [menuItem setSubmenu:appleMenu]; |
|---|
| 505 | [[NSApp mainMenu] addItem:menuItem]; |
|---|
| 506 | [menuItem release]; |
|---|
| 507 | |
|---|
| 508 | /* Tell the application object that this is now the application menu */ |
|---|
| 509 | [NSApp setAppleMenu:appleMenu]; |
|---|
| 510 | [appleMenu release]; |
|---|
| 511 | |
|---|
| 512 | /* Create the window menu */ |
|---|
| 513 | NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; |
|---|
| 514 | |
|---|
| 515 | /* "Minimize" item */ |
|---|
| 516 | menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" |
|---|
| 517 | action:@selector(performMiniaturize:) |
|---|
| 518 | keyEquivalent:@"m"]; |
|---|
| 519 | [windowMenu addItem:menuItem]; |
|---|
| 520 | [menuItem release]; |
|---|
| 521 | |
|---|
| 522 | /* Put menu into the menubar */ |
|---|
| 523 | menuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; |
|---|
| 524 | [menuItem setSubmenu:windowMenu]; |
|---|
| 525 | [[NSApp mainMenu] addItem:menuItem]; |
|---|
| 526 | [menuItem release]; |
|---|
| 527 | |
|---|
| 528 | /* Tell the application object that this is now the window menu */ |
|---|
| 529 | [NSApp setWindowsMenu:windowMenu]; |
|---|
| 530 | [windowMenu release]; |
|---|
| 531 | } |
|---|
| 532 | |
|---|
| 533 | static void register_cocoa_app(caca_display_t *dp) |
|---|
| 534 | { |
|---|
| 535 | ProcessSerialNumber psn; |
|---|
| 536 | if(!GetCurrentProcess(&psn)) |
|---|
| 537 | { |
|---|
| 538 | TransformProcessType(&psn, kProcessTransformToForegroundApplication); |
|---|
| 539 | SetFrontProcess(&psn); |
|---|
| 540 | } |
|---|
| 541 | |
|---|
| 542 | if(NSApp == nil) |
|---|
| 543 | { |
|---|
| 544 | [NSApplication sharedApplication]; |
|---|
| 545 | |
|---|
| 546 | if(![NSApp mainMenu]) |
|---|
| 547 | create_application_menus(); |
|---|
| 548 | |
|---|
| 549 | [NSApp finishLaunching]; |
|---|
| 550 | } |
|---|
| 551 | |
|---|
| 552 | if ([NSApp delegate] == nil) |
|---|
| 553 | [NSApp setDelegate:[[CacaAppDelegate alloc] init]]; |
|---|
| 554 | |
|---|
| 555 | [NSApp setRunning]; |
|---|
| 556 | } |
|---|
| 557 | |
|---|
| 558 | static __inline__ void convert_NSRect(NSRect *r) |
|---|
| 559 | { |
|---|
| 560 | float mb_height = 38.0; // [[NSApp mainMenu] menuBarHeight] is 0 - wtf ? |
|---|
| 561 | /*debug_log(@"%@ %f %f %d %d %d", [NSApp mainMenu], |
|---|
| 562 | [[NSApp mainMenu] menuBarHeight], mb_height, |
|---|
| 563 | (int)CGDisplayPixelsHigh(kCGDirectMainDisplay), |
|---|
| 564 | (int)r->origin.y, (int)r->size.height);*/ |
|---|
| 565 | r->origin.y = CGDisplayPixelsHigh(kCGDirectMainDisplay) - mb_height |
|---|
| 566 | - r->origin.y - r->size.height; |
|---|
| 567 | } |
|---|
| 568 | |
|---|
| 569 | static void create_first_window(caca_display_t *dp) |
|---|
| 570 | { |
|---|
| 571 | NSFont* font = [NSFont fontWithName:@"Monaco" size:10]; |
|---|
| 572 | NSRect fontRect = [font boundingRectForFont]; |
|---|
| 573 | fontRect = NSMakeRect(0, 0, ceilf(fontRect.size.width), ceilf(fontRect.size.height)); |
|---|
| 574 | NSRect windowRect = NSMakeRect(20, 20, caca_get_canvas_width(dp->cv) * fontRect.size.width, |
|---|
| 575 | caca_get_canvas_height(dp->cv) * fontRect.size.height); |
|---|
| 576 | convert_NSRect(&windowRect); |
|---|
| 577 | |
|---|
| 578 | CacaView* view = [[CacaView alloc] initWithFrame:windowRect]; |
|---|
| 579 | NSWindow* win = [[NSWindow alloc] initWithContentRect:windowRect |
|---|
| 580 | styleMask: NSTitledWindowMask |
|---|
| 581 | //| NSResizableWindowMask |
|---|
| 582 | | NSClosableWindowMask |
|---|
| 583 | | NSWindowMiniaturizeButton |
|---|
| 584 | backing:NSBackingStoreBuffered |
|---|
| 585 | defer:NO]; |
|---|
| 586 | |
|---|
| 587 | NSString* appName = get_application_name(); |
|---|
| 588 | if(appName) |
|---|
| 589 | [win setTitle: appName]; |
|---|
| 590 | [win setDelegate:[CacaWindowDelegate new]]; |
|---|
| 591 | [win setContentView:view]; |
|---|
| 592 | [view setFont:font]; |
|---|
| 593 | [win makeKeyAndOrderFront:nil]; |
|---|
| 594 | |
|---|
| 595 | dp->drv.p->window = win; |
|---|
| 596 | dp->drv.p->view = view; |
|---|
| 597 | } |
|---|
| 598 | |
|---|
| 599 | static int get_caca_keycode(NSEvent* event) |
|---|
| 600 | { |
|---|
| 601 | int caca_keycode = 0; |
|---|
| 602 | /* |
|---|
| 603 | unsigned short mac_keycode = [event keyCode]; |
|---|
| 604 | debug_log(@"keycode %u (%x)", mac_keycode, mac_keycode); |
|---|
| 605 | switch(mac_keycode) |
|---|
| 606 | { |
|---|
| 607 | } |
|---|
| 608 | */ |
|---|
| 609 | if(/*!caca_keycode &&*/ ([event modifierFlags] & NSControlKeyMask)) |
|---|
| 610 | { |
|---|
| 611 | NSString *chars = [event charactersIgnoringModifiers]; |
|---|
| 612 | unichar ch = [chars characterAtIndex: 0]; |
|---|
| 613 | // CACA_KEY_CTRL_A -> CACA_KEY_CTRL_Z |
|---|
| 614 | if(ch >= 'a' && ch <= 'z') |
|---|
| 615 | caca_keycode = CACA_KEY_CTRL_A + ch - 'a'; |
|---|
| 616 | } |
|---|
| 617 | |
|---|
| 618 | if(!caca_keycode) |
|---|
| 619 | { |
|---|
| 620 | NSString *chars = [event characters]; |
|---|
| 621 | unichar ch = 0; |
|---|
| 622 | if([chars length]) |
|---|
| 623 | ch = [chars characterAtIndex: 0]; |
|---|
| 624 | switch(ch) |
|---|
| 625 | { |
|---|
| 626 | case NSUpArrowFunctionKey: |
|---|
| 627 | caca_keycode = CACA_KEY_UP; |
|---|
| 628 | break; |
|---|
| 629 | case NSDownArrowFunctionKey: |
|---|
| 630 | caca_keycode = CACA_KEY_DOWN; |
|---|
| 631 | break; |
|---|
| 632 | case NSLeftArrowFunctionKey: |
|---|
| 633 | caca_keycode = CACA_KEY_LEFT; |
|---|
| 634 | break; |
|---|
| 635 | case NSRightArrowFunctionKey: |
|---|
| 636 | caca_keycode = CACA_KEY_RIGHT; |
|---|
| 637 | break; |
|---|
| 638 | case 27: |
|---|
| 639 | caca_keycode = CACA_KEY_ESCAPE; |
|---|
| 640 | break; |
|---|
| 641 | case NSDeleteCharacter: |
|---|
| 642 | caca_keycode = CACA_KEY_DELETE; |
|---|
| 643 | break; |
|---|
| 644 | case NSBackspaceCharacter: |
|---|
| 645 | caca_keycode = CACA_KEY_BACKSPACE; |
|---|
| 646 | break; |
|---|
| 647 | case NSTabCharacter: |
|---|
| 648 | caca_keycode = CACA_KEY_TAB; |
|---|
| 649 | break; |
|---|
| 650 | case NSNewlineCharacter: |
|---|
| 651 | case NSCarriageReturnCharacter: |
|---|
| 652 | caca_keycode = CACA_KEY_RETURN; |
|---|
| 653 | break; |
|---|
| 654 | case NSPageUpFunctionKey: |
|---|
| 655 | caca_keycode = CACA_KEY_PAGEUP; |
|---|
| 656 | break; |
|---|
| 657 | case NSPageDownFunctionKey: |
|---|
| 658 | caca_keycode = CACA_KEY_PAGEDOWN; |
|---|
| 659 | break; |
|---|
| 660 | case NSF1FunctionKey: |
|---|
| 661 | caca_keycode = CACA_KEY_F1; |
|---|
| 662 | break; |
|---|
| 663 | case NSF2FunctionKey: |
|---|
| 664 | caca_keycode = CACA_KEY_F2; |
|---|
| 665 | break; |
|---|
| 666 | case NSF3FunctionKey: |
|---|
| 667 | caca_keycode = CACA_KEY_F3; |
|---|
| 668 | break; |
|---|
| 669 | case NSF4FunctionKey: |
|---|
| 670 | caca_keycode = CACA_KEY_F4; |
|---|
| 671 | break; |
|---|
| 672 | case NSF5FunctionKey: |
|---|
| 673 | caca_keycode = CACA_KEY_F5; |
|---|
| 674 | break; |
|---|
| 675 | case NSF6FunctionKey: |
|---|
| 676 | caca_keycode = CACA_KEY_F6; |
|---|
| 677 | break; |
|---|
| 678 | case NSF7FunctionKey: |
|---|
| 679 | caca_keycode = CACA_KEY_F7; |
|---|
| 680 | break; |
|---|
| 681 | case NSF8FunctionKey: |
|---|
| 682 | caca_keycode = CACA_KEY_F8; |
|---|
| 683 | break; |
|---|
| 684 | case NSF9FunctionKey: |
|---|
| 685 | caca_keycode = CACA_KEY_F9; |
|---|
| 686 | break; |
|---|
| 687 | case NSF10FunctionKey: |
|---|
| 688 | caca_keycode = CACA_KEY_F10; |
|---|
| 689 | break; |
|---|
| 690 | case NSF11FunctionKey: |
|---|
| 691 | caca_keycode = CACA_KEY_F11; |
|---|
| 692 | break; |
|---|
| 693 | case NSF12FunctionKey: |
|---|
| 694 | caca_keycode = CACA_KEY_F12; |
|---|
| 695 | break; |
|---|
| 696 | case NSF13FunctionKey: |
|---|
| 697 | caca_keycode = CACA_KEY_F13; |
|---|
| 698 | break; |
|---|
| 699 | case NSF14FunctionKey: |
|---|
| 700 | caca_keycode = CACA_KEY_F14; |
|---|
| 701 | break; |
|---|
| 702 | case NSF15FunctionKey: |
|---|
| 703 | caca_keycode = CACA_KEY_F15; |
|---|
| 704 | break; |
|---|
| 705 | case NSPauseFunctionKey: |
|---|
| 706 | caca_keycode = CACA_KEY_PAUSE; |
|---|
| 707 | break; |
|---|
| 708 | case NSInsertFunctionKey: |
|---|
| 709 | debug_log(@"insert key"); |
|---|
| 710 | caca_keycode = CACA_KEY_INSERT; |
|---|
| 711 | break; |
|---|
| 712 | case NSHomeFunctionKey: |
|---|
| 713 | caca_keycode = CACA_KEY_HOME; |
|---|
| 714 | break; |
|---|
| 715 | case NSEndFunctionKey: |
|---|
| 716 | caca_keycode = CACA_KEY_END; |
|---|
| 717 | break; |
|---|
| 718 | } |
|---|
| 719 | } |
|---|
| 720 | |
|---|
| 721 | return caca_keycode; |
|---|
| 722 | } |
|---|
| 723 | |
|---|
| 724 | static BOOL handle_key_event(caca_privevent_t *ev, NSEvent* event) |
|---|
| 725 | { |
|---|
| 726 | if(!ev || !event) |
|---|
| 727 | return NO; |
|---|
| 728 | |
|---|
| 729 | BOOL eventHandled = NO; |
|---|
| 730 | |
|---|
| 731 | if([event modifierFlags] & NSCommandKeyMask) |
|---|
| 732 | { |
|---|
| 733 | // let the system handle the Apple-commands for now |
|---|
| 734 | return NO; |
|---|
| 735 | } |
|---|
| 736 | |
|---|
| 737 | switch ([event type]) { |
|---|
| 738 | case NSKeyDown: |
|---|
| 739 | /* test [event isARepeat] ? */ |
|---|
| 740 | ev->type = CACA_EVENT_KEY_PRESS; |
|---|
| 741 | break; |
|---|
| 742 | case NSKeyUp: |
|---|
| 743 | ev->type = CACA_EVENT_KEY_RELEASE; |
|---|
| 744 | break; |
|---|
| 745 | default: |
|---|
| 746 | ; |
|---|
| 747 | } |
|---|
| 748 | |
|---|
| 749 | int caca_keycode = get_caca_keycode(event); |
|---|
| 750 | if(caca_keycode) |
|---|
| 751 | { |
|---|
| 752 | ev->data.key.ch = caca_keycode; |
|---|
| 753 | eventHandled = YES; |
|---|
| 754 | } |
|---|
| 755 | else |
|---|
| 756 | { |
|---|
| 757 | NSString *chars = [event characters]; |
|---|
| 758 | unichar mac_keycode = 0; |
|---|
| 759 | if([chars length]) |
|---|
| 760 | mac_keycode = [chars characterAtIndex: 0]; |
|---|
| 761 | if(mac_keycode) |
|---|
| 762 | { |
|---|
| 763 | ev->data.key.ch = mac_keycode; |
|---|
| 764 | ev->data.key.utf32 = (uint32_t)mac_keycode; |
|---|
| 765 | ev->data.key.utf8[0] = mac_keycode & 0x00ff; // FIXME: endianness |
|---|
| 766 | ev->data.key.utf8[1] = mac_keycode & 0xff00; |
|---|
| 767 | |
|---|
| 768 | eventHandled = YES; |
|---|
| 769 | } |
|---|
| 770 | } |
|---|
| 771 | |
|---|
| 772 | return eventHandled; |
|---|
| 773 | } |
|---|
| 774 | |
|---|
| 775 | // TODO: handle CACA_EVENT_RESIZE |
|---|
| 776 | static BOOL handle_mouse_event(caca_display_t *dp, caca_privevent_t *ev, |
|---|
| 777 | NSEvent* event) |
|---|
| 778 | { |
|---|
| 779 | if(!ev || !event) |
|---|
| 780 | return NO; |
|---|
| 781 | |
|---|
| 782 | switch ([event type]) { |
|---|
| 783 | case NSLeftMouseDown: |
|---|
| 784 | ev->type = CACA_EVENT_MOUSE_PRESS; |
|---|
| 785 | ev->data.mouse.button = 1; |
|---|
| 786 | break; |
|---|
| 787 | case NSLeftMouseUp: |
|---|
| 788 | ev->type = CACA_EVENT_MOUSE_RELEASE; |
|---|
| 789 | ev->data.mouse.button = 1; |
|---|
| 790 | break; |
|---|
| 791 | case NSRightMouseDown: |
|---|
| 792 | ev->type = CACA_EVENT_MOUSE_PRESS; |
|---|
| 793 | ev->data.mouse.button = 2; |
|---|
| 794 | break; |
|---|
| 795 | case NSRightMouseUp: |
|---|
| 796 | ev->type = CACA_EVENT_MOUSE_RELEASE; |
|---|
| 797 | ev->data.mouse.button = 2; |
|---|
| 798 | break; |
|---|
| 799 | case NSMouseMoved: |
|---|
| 800 | { |
|---|
| 801 | NSPoint mouseLoc = [NSEvent mouseLocation]; |
|---|
| 802 | int mouse_x = round(mouseLoc.x); |
|---|
| 803 | int mouse_y = round(mouseLoc.y); |
|---|
| 804 | if(dp->mouse.x == mouse_x && dp->mouse.y == mouse_y) |
|---|
| 805 | break; |
|---|
| 806 | |
|---|
| 807 | dp->mouse.x = mouse_x; |
|---|
| 808 | dp->mouse.y = mouse_y; |
|---|
| 809 | |
|---|
| 810 | ev->type = CACA_EVENT_MOUSE_MOTION; |
|---|
| 811 | ev->data.mouse.x = dp->mouse.x; |
|---|
| 812 | ev->data.mouse.y = dp->mouse.y; |
|---|
| 813 | break; |
|---|
| 814 | } |
|---|
| 815 | default: |
|---|
| 816 | ; |
|---|
| 817 | } |
|---|
| 818 | |
|---|
| 819 | return YES; |
|---|
| 820 | } |
|---|
| 821 | |
|---|
| 822 | //============================================================================ |
|---|
| 823 | // caca driver methods |
|---|
| 824 | //============================================================================ |
|---|
| 825 | |
|---|
| 826 | static int cocoa_init_graphics(caca_display_t *dp) |
|---|
| 827 | { |
|---|
| 828 | int width = caca_get_canvas_width(dp->cv); |
|---|
| 829 | int height = caca_get_canvas_height(dp->cv); |
|---|
| 830 | |
|---|
| 831 | debug_log(@"%s dp->cv: %ux%u", __PRETTY_FUNCTION__, width, height); |
|---|
| 832 | |
|---|
| 833 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
|---|
| 834 | |
|---|
| 835 | dp->drv.p = malloc(sizeof(struct driver_private)); |
|---|
| 836 | if(dp->drv.p == NULL) |
|---|
| 837 | return -1; |
|---|
| 838 | |
|---|
| 839 | dp->resize.allow = 1; |
|---|
| 840 | caca_set_canvas_size(dp->cv, width ? width : 80, height ? height : 32); |
|---|
| 841 | dp->resize.allow = 0; |
|---|
| 842 | |
|---|
| 843 | // first create a full cocoa app if the host has no bundle |
|---|
| 844 | if(![[NSBundle mainBundle] bundleIdentifier]) |
|---|
| 845 | register_cocoa_app(dp); |
|---|
| 846 | create_first_window(dp); |
|---|
| 847 | |
|---|
| 848 | #ifdef USE_GLOBAL_AUTORELEASE_POOL |
|---|
| 849 | dp->drv.p->pool = pool; |
|---|
| 850 | #else |
|---|
| 851 | [pool release]; |
|---|
| 852 | #endif |
|---|
| 853 | |
|---|
| 854 | return 0; |
|---|
| 855 | } |
|---|
| 856 | |
|---|
| 857 | static int cocoa_end_graphics(caca_display_t *dp) |
|---|
| 858 | { |
|---|
| 859 | debug_log(@"%s dp->cv: %ux%u", __PRETTY_FUNCTION__, |
|---|
| 860 | caca_get_canvas_width(dp->cv), caca_get_canvas_height(dp->cv)); |
|---|
| 861 | |
|---|
| 862 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
|---|
| 863 | [dp->drv.p->window close]; |
|---|
| 864 | CacaWindowDelegate* delegate = [dp->drv.p->window delegate]; |
|---|
| 865 | [dp->drv.p->window setDelegate:nil]; |
|---|
| 866 | [delegate release]; |
|---|
| 867 | // don't release the window yourself |
|---|
| 868 | //[dp->drv.p->window release]; |
|---|
| 869 | #ifdef USE_GLOBAL_AUTORELEASE_POOL |
|---|
| 870 | [dp->drv.p->pool release]; |
|---|
| 871 | #endif |
|---|
| 872 | free(dp->drv.p); |
|---|
| 873 | debug_log(@"%s end", __PRETTY_FUNCTION__); |
|---|
| 874 | [pool release]; |
|---|
| 875 | |
|---|
| 876 | return 0; |
|---|
| 877 | } |
|---|
| 878 | |
|---|
| 879 | static void cocoa_display(caca_display_t *dp) |
|---|
| 880 | { |
|---|
| 881 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
|---|
| 882 | [dp->drv.p->view updateBuffersFromCaca:dp]; |
|---|
| 883 | [pool release]; |
|---|
| 884 | } |
|---|
| 885 | |
|---|
| 886 | static int cocoa_get_event(caca_display_t *dp, caca_privevent_t *ev) |
|---|
| 887 | { |
|---|
| 888 | if(s_quit) |
|---|
| 889 | { |
|---|
| 890 | if(s_quitting) |
|---|
| 891 | { |
|---|
| 892 | // host app isn't handling the quit event properly, aborting |
|---|
| 893 | debug_log(@"duplicate quit event, aborting."); |
|---|
| 894 | abort(); |
|---|
| 895 | } |
|---|
| 896 | debug_log(@"posting quit event."); |
|---|
| 897 | ev->type = CACA_EVENT_QUIT; |
|---|
| 898 | s_quitting = YES; |
|---|
| 899 | return 1; |
|---|
| 900 | } |
|---|
| 901 | |
|---|
| 902 | BOOL eventHandled = NO, forceRedispatch = NO; |
|---|
| 903 | ev->type = CACA_EVENT_NONE; |
|---|
| 904 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
|---|
| 905 | |
|---|
| 906 | if([NSApp isRunning]) |
|---|
| 907 | { |
|---|
| 908 | NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask |
|---|
| 909 | untilDate:[NSDate distantPast] |
|---|
| 910 | inMode:NSDefaultRunLoopMode |
|---|
| 911 | dequeue:YES]; |
|---|
| 912 | if(event) |
|---|
| 913 | { |
|---|
| 914 | switch([event type]) |
|---|
| 915 | { |
|---|
| 916 | case NSKeyDown: |
|---|
| 917 | case NSKeyUp: |
|---|
| 918 | eventHandled = handle_key_event(ev, event); |
|---|
| 919 | break; |
|---|
| 920 | |
|---|
| 921 | case NSFlagsChanged: |
|---|
| 922 | break; |
|---|
| 923 | |
|---|
| 924 | case NSLeftMouseDown: |
|---|
| 925 | case NSLeftMouseUp: |
|---|
| 926 | case NSRightMouseDown: |
|---|
| 927 | case NSRightMouseUp: |
|---|
| 928 | case NSMouseMoved: |
|---|
| 929 | if([NSApp isActive]) |
|---|
| 930 | { |
|---|
| 931 | eventHandled = handle_mouse_event(dp, ev, event); |
|---|
| 932 | forceRedispatch = YES; |
|---|
| 933 | } |
|---|
| 934 | else |
|---|
| 935 | { |
|---|
| 936 | [NSApp sendEvent:event]; |
|---|
| 937 | eventHandled = YES; |
|---|
| 938 | } |
|---|
| 939 | break; |
|---|
| 940 | |
|---|
| 941 | default: |
|---|
| 942 | ; |
|---|
| 943 | } |
|---|
| 944 | |
|---|
| 945 | if(!eventHandled || forceRedispatch) |
|---|
| 946 | [NSApp sendEvent:event]; |
|---|
| 947 | } |
|---|
| 948 | } |
|---|
| 949 | [pool release]; |
|---|
| 950 | |
|---|
| 951 | if(eventHandled) |
|---|
| 952 | return 1; |
|---|
| 953 | |
|---|
| 954 | return 0; |
|---|
| 955 | } |
|---|
| 956 | |
|---|
| 957 | static void cocoa_handle_resize(caca_display_t *dp) |
|---|
| 958 | { |
|---|
| 959 | debug_log(@"%s", __PRETTY_FUNCTION__); |
|---|
| 960 | dp->resize.w = caca_get_canvas_width(dp->cv); |
|---|
| 961 | dp->resize.h = caca_get_canvas_height(dp->cv); |
|---|
| 962 | } |
|---|
| 963 | |
|---|
| 964 | static int cocoa_set_display_title(caca_display_t *dp, char const *title) |
|---|
| 965 | { |
|---|
| 966 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
|---|
| 967 | [dp->drv.p->window setTitle:[NSString stringWithUTF8String:title]]; |
|---|
| 968 | [pool release]; |
|---|
| 969 | return 0; |
|---|
| 970 | } |
|---|
| 971 | |
|---|
| 972 | static int cocoa_get_display_width(caca_display_t const *dp) |
|---|
| 973 | { |
|---|
| 974 | return [dp->drv.p->window frame].size.width; |
|---|
| 975 | } |
|---|
| 976 | |
|---|
| 977 | static int cocoa_get_display_height(caca_display_t const *dp) |
|---|
| 978 | { |
|---|
| 979 | return [dp->drv.p->window frame].size.height; |
|---|
| 980 | } |
|---|
| 981 | |
|---|
| 982 | static void cocoa_set_mouse(caca_display_t *dp, int flag) |
|---|
| 983 | { |
|---|
| 984 | NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; |
|---|
| 985 | if(flag) |
|---|
| 986 | [[NSCursor arrowCursor] set]; |
|---|
| 987 | else { |
|---|
| 988 | [[NSCursor disappearingItemCursor] set]; |
|---|
| 989 | } |
|---|
| 990 | [pool release]; |
|---|
| 991 | } |
|---|
| 992 | |
|---|
| 993 | /* |
|---|
| 994 | * Driver initialisation |
|---|
| 995 | */ |
|---|
| 996 | |
|---|
| 997 | int cocoa_install(caca_display_t *dp) |
|---|
| 998 | { |
|---|
| 999 | dp->drv.id = CACA_DRIVER_COCOA; |
|---|
| 1000 | dp->drv.driver = "cocoa"; |
|---|
| 1001 | |
|---|
| 1002 | dp->drv.init_graphics = cocoa_init_graphics; |
|---|
| 1003 | dp->drv.end_graphics = cocoa_end_graphics; |
|---|
| 1004 | dp->drv.set_display_title = cocoa_set_display_title; |
|---|
| 1005 | dp->drv.get_display_width = cocoa_get_display_width; |
|---|
| 1006 | dp->drv.get_display_height = cocoa_get_display_height; |
|---|
| 1007 | dp->drv.display = cocoa_display; |
|---|
| 1008 | dp->drv.handle_resize = cocoa_handle_resize; |
|---|
| 1009 | dp->drv.get_event = cocoa_get_event; |
|---|
| 1010 | dp->drv.set_mouse = cocoa_set_mouse; |
|---|
| 1011 | |
|---|
| 1012 | return 0; |
|---|
| 1013 | } |
|---|
| 1014 | |
|---|
| 1015 | #endif /* USE_COCOA */ |
|---|