1/* sqUnixQuartz.m -- display via native windows on Mac OS X -*- ObjC -*- 2 * 3 * Author: Ian Piumarta <ian.piumarta@squeakland.org> 4 * 5 * Copyright (C) 1996-2007 by Ian Piumarta and other authors/contributors 6 * listed elsewhere in this file. 7 * All rights reserved. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a copy 10 * of this software and associated documentation files (the "Software"), to deal 11 * in the Software without restriction, including without limitation the rights 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 * copies of the Software, and to permit persons to whom the Software is 14 * furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 * 27 * Last edited: 2009-08-19 04:38:45 by piumarta on emilia-2.local 28 */ 29 30 31//xxx ... 32// 33// check use of winRect and titleRect. reduce to (int)winHeight and 34// (int)titleHeight in setRects. 35// 36// investigate creating sq events in the UI thread and then sending 37// them down the notification pipe, instead of locking the event 38// queue. 39 40 41#import <Cocoa/Cocoa.h> 42 43#include "sqUnixMain.h" 44#include "sqUnixGlobals.h" 45#include "sqUnixCharConv.h" 46 47#include "sq.h" 48#include "sqaio.h" 49 50#include <unistd.h> 51#include <stdlib.h> 52#include <stdarg.h> 53#include <stdio.h> 54#include <string.h> 55#include <sys/param.h> 56#include <sys/types.h> 57#include <sys/stat.h> 58#include <sys/socket.h> 59#include <sys/ioctl.h> 60#include <fcntl.h> 61#include <pthread.h> 62#include <sched.h> 63 64#include "debug.h" 65 66#include "config.h" 67#undef HAVE_GL_GL_H 68#include "SqDisplay.h" 69 70 71/// 72/// Things you can tweak, if you're curious/bored enough to want to... 73/// 74 75// do we draw the current screen extent (width x height) in the title 76// bar during live resize? 77// 78#define RESIZE_IN_TITLE 1 79 80// how large a (square) area, in the lower right of the window, should 81// respond to mouse down by initiating window resize? (the resize 82// icon itself is, when we allow it to be shown, 13x13 pixels.) 83// 84#define RESIZE_EXTENT 8 85 86// do we fade the screen out and back in gently when changing to 87// fullscreen mode, or just switch with one big violent click? if 88// this is defined then it represents the incr/decrement per 89// millisecond of the gamma multiplier (1.0 to 0.0 and back); if 90// undefined then the switch is immediate. 91// 92#undef FULLSCREEN_FADE 0.02 93 94/// 95/// No more user-serviceable parts in this file. Stop Tweaking Now! 96/// 97 98#if defined (__ppc__) 99# define USE_SPINLOCK 1 100#else 101# define USE_SPINLOCK 0 102#endif 103#define USE_OWN_ICON 0 104 105static inline int min(int x, int y) { return x < y ? x : y; } 106static inline int max(int x, int y) { return x > y ? x : y; } 107 108 109// -*- ObjC -*- 110 111@interface Squeak : NSApplication 112- (void) applicationDidFinishLaunching: (NSNotification *)note; 113- (void) applicationDidChangeScreenParameters: (NSNotification *)note; 114- (void) unhideAllApplications: (id)sender; 115- (BOOL) windowShouldClose: (id)sender; 116- (void) maybeTerminate: (id)sender; 117- (void) terminate: (id)sender; 118- (void) performEnableKeys: (id)sender; 119- (void) performDisableKeys: (id)sender; 120@end 121 122 123@interface SqueakWindow : NSWindow 124{ 125 NSImage *icon; 126} 127- (BOOL) isOpaque; 128- (BOOL) canBecomeKeyWindow; 129- (void) setIcon; 130#if 0 131- (NSImage *) dockImage 132- (void) miniaturize: (id)sender; 133#endif 134- (void) performMiniaturize: (id)sender; 135@end 136 137 138// Why QDView? Well... 139// 140// 1) we can trivially obtain a raw pointer to its backing store, so 141// 2) no need to putz around with the lockFocus/DataProvider/ImageRep crap; plus 142// 3) its buffer's coordinate system is already the right way up for Squeak, so 143// 4) we avoid potential recopy (just to have CG recopy again); besides 144// 5) QDFlushBuffer is _blindingly_ fast (even compared to drawing directly on 145// the framebuffer [go measure it if you don't believe me]); but most importantly 146// 6) the QD API is completely free of ObjC and attendant inefficiencies. 147 148@interface SqueakView : NSQuickDrawView <NSTextInput> 149- (BOOL) acceptsFirstResponder; 150- (BOOL) becomeFirstResponder; 151- (BOOL) isOpaque; 152- (BOOL) isFlipped; 153- (id) initWithFrame: (NSRect)frame; 154- (void) setFrame: (NSRect)rect; 155- (void) drawRect: (NSRect)rect; 156- (void) viewWillStartLiveResize; 157- (void) viewDidEndLiveResize; 158- (int) draggingEntered: (id<NSDraggingInfo>)sender; 159- (int) draggingUpdated: (id<NSDraggingInfo>)sender; 160- (void) draggingExited: (id<NSDraggingInfo>)sender; 161- (BOOL) performDragOperation: (id<NSDraggingInfo>)sender; 162- (int) composeKeyDown: (NSEvent *)event; 163- (int) composeKeyUp: (NSEvent *)event; 164@end 165 166 167static SqueakView *view = 0; /* app view (occupies topRect) */ 168 169 170@interface TopView : NSView 171- (void) setFrame: (NSRect)rect; 172@end 173 174@implementation TopView 175- (void) setFrame: (NSRect)rect 176{ 177 [super setFrame: rect]; 178 if (view) [view setFrame: rect]; 179} 180@end 181 182 183static int styleMask = 0; /* window style mask */ 184static int dragCount = 0; /* number of items during drag/drop */ 185static int showExtent = 0; /* 1 if title bar shows view extent */ 186 int inModalLoop= 0; /* 1 when WS is in tracking loop */ 187static int active = 0; /* 1 when app window is active */ 188 189//static CFArrayRef dpyModes = 0; /* one of these days... */ 190 191static CGDirectDisplayID dpy = 0; 192static NSDictionary *dpyMode = 0; 193static int dpyWidth = 0; 194static int dpyHeight = 0; 195static int dpyDepth = 0; 196 char *dpyPixels = 0; 197 int dpyPitch = 0; 198 199static SqueakWindow *win = 0; /* main application window */ 200static NSRect topRect; /* main window frame (excl. decoration) */ 201static NSRect titleRect; /* decoration area (above topRect) */ 202static NSRect resizeRect; /* area sensitive to resize */ 203 204static TopView *topView = 0; /* top view (occupies topRect) */ 205 206static char *pixBase = 0; 207static int pixWidth = 0; /* pixmap width (pixels) */ 208static int pixHeight = 0; /* pixmap height */ 209static int pixDepth = 0; /* pixmap depth */ 210static int pixPitch = 0; 211static RgnHandle pixRegion = 0; 212 213static int cmdKeys = 0; /* 1 if app command keys enabled */ 214static int fromFinder = 0; /* 1 if app launched from finder */ 215static int noTitle = 0; /* 1 if app window is undecorated */ 216static int headless = 0; /* 1 if app has no window */ 217static int noDock = 0; /* 1 if app window is undocked */ 218static int fullscreen = 0; /* 1 if window fullscreen and on top */ 219 220static char *clipboard = 0; 221 222static int stXfd = -1; 223static int osXfd = -1; 224 225#if (USE_SPINLOCK) 226static int displayMx = 0; 227#else 228static pthread_mutex_t displayMx = PTHREAD_MUTEX_INITIALIZER; 229#endif 230 231static char resourcePath[MAXPATHLEN]; 232 233static int glActive= 0; 234static void reframeRenderers(void); 235static void updateRenderers(void); 236 237 238 239#if 0 //xxx REMOVE ME 240 241#define RED 0xff0000 242#define GREEN 0x00ff00 243#define BLUE 0x0000ff 244#define WHITE 0xffffff 245#define BLACK 0x000000 246 247void feedback(int offset, int pixel) 248{ 249 const int width= 4, height= 4; 250 long *base= CGDisplayBaseAddress(dpy); 251 int pitch= CGDisplayBytesPerRow(dpy); 252 int x, y; 253 254 base= base + width * offset; 255 256 for (y= 0; y < height; ++y) 257 { 258 for (x= 0; x < width; ++x) 259 base[x]= pixel; 260 base= (long *)((char *)base + pitch); 261 } 262} 263 264#endif 265 266 267#if (USE_SPINLOCK) 268 269extern inline int testAndSet(int *lock) 270{ 271 int valu; 272# if defined(__i386__) 273 asm volatile(" movl $1, %0 \n" 274 " xchg %0, %1 \n" 275 : "=&r"(valu) : "r"(lock)); 276# else 277 asm volatile(" lwarx %0, 0, %1 \n" 278 " cmpwi %0, 0 \n" 279 " bne- 1f \n" 280 " li %0, 1 \n" 281 " stwcx. %0, 0, %1 \n" 282 " bne- 1f \n" 283 " li %0, 0 \n" 284 "1: \n" 285 : "=&r"(valu) : "r"(lock) : "cr0","memory"); 286# endif 287 return valu; 288} 289 290extern inline int doLock(int *lock, const char *who) 291{ 292 while (testAndSet(lock)) 293 ; 294 return 1; 295} 296 297extern inline void doUnlock(int *lock) 298{ 299 *lock= 0; 300} 301 302#else 303 304//xxx FIXME SOON: check all uses of lock() and conditionalise the 305// sections where failure could cause SEGV (rather than just 306// inconsistent geometry or whatever) 307 308static int doLock(pthread_mutex_t *mx, char *who) 309{ 310 static char *owner= "<none>"; 311 int backoff, i= 0; 312 // wait about 1 second before giving up (10000 == timeslice quantum) 313 for (backoff= 10000; backoff < 1280000; ++i, backoff <<= 1) 314 if (0 == pthread_mutex_trylock(mx)) 315 { 316 owner= who; 317 return 1; 318 } 319 else 320 { 321# ifndef NDEBUG 322 fprintf(stderr, "lock %d: %s waiting for %-20s\n", i, who, owner); 323# endif 324 usleep(backoff); 325 } 326 perror("pthread_mutex_trylock"); 327 return 0; 328} 329 330static void doUnlock(pthread_mutex_t *mx) 331{ 332 if (pthread_mutex_unlock(mx)) 333 perror("pthread_mutex_unlock"); 334} 335 336#endif 337 338 339#define lock(MX) doLock(&MX##Mx, __FUNCTION__) 340#define unlock(MX) doUnlock(&MX##Mx) 341 342 343#include "sqUnixEvent.c" 344 345 346 347//xxx FIXME: this is currently monochrome 348 349static sqInt display_ioFormPrint(sqInt bitsAddr, sqInt width, sqInt height, sqInt depth, 350 double hScale, double vScale, sqInt landscapeFlag) 351{ 352 //xxx hScale and vScale are ppi. is there a way to use this 353 // meaningfully with PrintInfo or NSPrinter? 354 355 NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init]; 356 int opp= depth / 8; 357 int success= 1; 358 359 debugf(("ioFormPrint %f %f\n", hScale, vScale)); 360 { 361 unsigned char *planes[1]= { (unsigned char *)pointerForOop(bitsAddr) }; 362 NSBitmapImageRep *bitmap= 0; 363 NSImage *image= 0; 364 NSImageView *view= 0; 365 366 bitmap= [[NSBitmapImageRep alloc] 367 initWithBitmapDataPlanes: planes 368 pixelsWide: width 369 pixelsHigh: height 370 bitsPerSample: depth 371 samplesPerPixel: 1 372 hasAlpha: NO 373 isPlanar: NO 374 colorSpaceName: NSCalibratedBlackColorSpace 375 bytesPerRow: width * opp 376 bitsPerPixel: depth]; 377 if (!bitmap) { debugf(("bitmap fail\n")); success= 0; goto done; } 378 image= [NSImage alloc]; 379 //[image setSize: NSMakeSize(width, height)]; 380 [image addRepresentation: bitmap]; 381 if (!image) { debugf(("image fail\n")); success= 0; goto done; } 382 view= [[NSImageView alloc] initWithFrame: NSMakeRect(0, 0, width, height)]; 383 [view setImage: image]; 384 { 385 NSPrintOperation *op= [NSPrintOperation printOperationWithView: view]; 386 [op setShowPanels: YES]; 387 debugf(("launch print operation\n")); 388 [op runOperation]; 389 } 390 } 391 392 done: 393 debugf(("ioFormPrint done.\n")); 394 [pool release]; 395 return success; 396} 397 398 399static sqInt display_ioBeep(void) 400{ 401 NSBeep(); 402 return 0; 403} 404 405 406static sqInt display_ioRelinquishProcessorForMicroseconds(sqInt microSeconds) 407{ 408 aioSleep(microSeconds); 409 return 0; 410} 411 412 413 414/// 415/// events 416/// 417 418 419static unsigned int qz2sqModifiers(unsigned int qz) 420{ 421 return 422 ( ((qz & (NSShiftKeyMask | NSAlphaShiftKeyMask)) ? ShiftKeyBit : 0)) 423 | ((qz & NSControlKeyMask) ? CtrlKeyBit : 0) 424 | ((qz & NSAlternateKeyMask) ? OptionKeyBit : 0) 425 | ((qz & NSCommandKeyMask) ? CommandKeyBit : 0); 426} 427 428static unsigned int qz2sqButton(unsigned int button) 429{ 430 // the image has blue and yellow back-to-front. fix that here... 431 switch (button) 432 { 433 case 0: return RedButtonBit; 434 case 1: return (swapBtn ? YellowButtonBit : BlueButtonBit); 435 case 2: return (swapBtn ? BlueButtonBit : YellowButtonBit); 436 } 437 debugf(("unknown mouse button %d\n", button)); 438 return RedButtonBit; 439} 440 441 442static unsigned int qz2sqKey(NSEvent *event) 443{ 444 NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init]; 445 NSString *chars= [event characters]; 446 UInt32 enc= CFStringConvertEncodingToNSStringEncoding((CFStringEncoding)sqTextEncoding); 447 NSData *data= [chars dataUsingEncoding: enc allowLossyConversion: NO]; 448 int keyCode= -1; 449 450# define returnKey(N) keyCode= (N); goto done 451 452 if ([data length]) 453 { 454 keyCode= ((unsigned char *)[data bytes])[0]; 455 if (keyCode == 127) 456 keyCode= 8; 457 goto done; 458 } 459 460 if ([chars length]) 461 { 462 keyCode= [chars characterAtIndex: 0]; 463 switch (keyCode) 464 { 465 case NSDeleteFunctionKey: returnKey( 8); 466 case NSUpArrowFunctionKey: returnKey(30); 467 case NSDownArrowFunctionKey: returnKey(31); 468 case NSLeftArrowFunctionKey: returnKey(28); 469 case NSRightArrowFunctionKey: returnKey(29); 470 case NSHomeFunctionKey: returnKey( 1); 471 case NSEndFunctionKey: returnKey( 4); 472 case NSPageUpFunctionKey: returnKey(11); 473 case NSPageDownFunctionKey: returnKey(12); 474 /* -- these should probably be implemented -- */ 475# define unknown(KEY) printf(KEY"\n"); returnKey(-1) 476 case NSClearLineFunctionKey: unknown("Clear/Num Lock"); 477 case NSHelpFunctionKey: unknown("Help"); 478 /* -- the rest are missing on most mac keyboards -- */ 479 case NSBeginFunctionKey: unknown("Begin"); 480 case NSPrintScreenFunctionKey: unknown("Print Screen"); 481 case NSScrollLockFunctionKey: unknown("Scroll Lock"); 482 case NSPauseFunctionKey: unknown("Pause"); 483 case NSSysReqFunctionKey: unknown("System Request"); 484 case NSBreakFunctionKey: unknown("Break"); 485 case NSResetFunctionKey: unknown("Reset"); 486 case NSStopFunctionKey: unknown("Stop"); 487 case NSMenuFunctionKey: unknown("Menu"); 488 case NSUserFunctionKey: unknown("User"); 489 case NSSystemFunctionKey: unknown("System"); 490 case NSPrintFunctionKey: unknown("Print"); 491 case NSClearDisplayFunctionKey: unknown("Clear Display"); 492 case NSInsertLineFunctionKey: unknown("Insert Line"); 493 case NSDeleteLineFunctionKey: unknown("Delete Line"); 494 case NSInsertCharFunctionKey: unknown("Insert Character"); 495 case NSDeleteCharFunctionKey: unknown("Delete Character"); 496 case NSPrevFunctionKey: unknown("Previous"); 497 case NSNextFunctionKey: unknown("Next"); 498 case NSSelectFunctionKey: unknown("Select"); 499 case NSExecuteFunctionKey: unknown("Execute"); 500 case NSUndoFunctionKey: unknown("Undo"); 501 case NSRedoFunctionKey: unknown("Redo"); 502 case NSFindFunctionKey: unknown("Find"); 503 case NSModeSwitchFunctionKey: unknown("Mode Switch"); 504# undef unknown 505 } 506 if (keyCode & 0xff00) 507 keyCode= -1; 508 } 509 510 done: 511 [pool release]; 512 return keyCode; 513} 514 515 516 517static inline void noteMousePoint(NSPoint loc) 518{ 519 int x= (int)loc.x; 520 int y= (int)topRect.size.height - (int)loc.y; 521 // mouse motion/up is tracked outside of topRect when active, so 522 // clamp it explicitly 523 // (note: there's a race here, but it's benign) 524 mousePosition.x= max(0, min(x, pixWidth - 1)); 525 mousePosition.y= max(0, min(y, pixHeight - 1)); 526} 527 528 529static void evtHandler(int fd, void *data, int flags) 530{ 531 for (;;) 532 { 533 sqInputEvent evt; 534 int n= read(fd, (void *)&evt, sizeof(evt)); 535 if (n < 0) 536 { 537 if ((EINTR == errno) || (EAGAIN == errno)) 538 break; 539 perror("evtHandler: read"); 540 } 541 else if (n == 0) 542 break; 543 else if (n != sizeof(evt)) 544 fprintf(stderr, "evtHandler: read returned %d -- why?\n", n); 545 else 546 { 547 sqInputEvent *evp= allocateInputEvent(0); 548 *evp= evt; 549 signalInputEvent(); 550 } 551 } 552 aioHandle(fd, evtHandler, AIO_RX); 553} 554 555 556static void sendEvent(sqInputEvent *evt) 557{ 558 if (inModalLoop) //xxx there are other ways to escape from one of these 559 inModalLoop= 0; 560 if (sizeof(*evt) != write(osXfd, evt, sizeof(*evt))) 561 perror("sendEvent: write"); 562} 563 564 565static int makeButtonState(void) 566{ 567 int btn= buttonState; 568 int mod= modifierState; 569 if (btn == RedButtonBit) 570 switch (mod) 571 { 572 case OptionKeyBit: btn= YellowButtonBit; mod= 0; break; 573 case CommandKeyBit: btn= BlueButtonBit; mod= 0; break; 574 } 575 return (mod << 3) | btn; 576} 577 578 579static void noteMouseEvent(void) 580{ 581 int state= makeButtonState(); 582 sqMouseEvent evt; 583 evt.type= EventTypeMouse; 584 evt.timeStamp= ioMSecs(); 585 evt.x= mousePosition.x; 586 evt.y= mousePosition.y; 587 evt.buttons= (state & 0x7); 588 evt.modifiers= (state >> 3); 589 evt.reserved1= 0; 590 evt.windowIndex= 0; 591#ifdef DEBUG_EVENTS 592 printf("EVENT: mouse (%d,%d)", mousePosition.x, mousePosition.y); 593 printModifiers(state >> 3); 594 printButtons(state & 7); 595 printf("\n"); 596#endif 597 sendEvent((sqInputEvent *)&evt); 598} 599 600 601static void noteKeyboardEvent(int keyCode, int pressCode, int modifiers) 602{ 603 sqKeyboardEvent evt; 604 evt.type= EventTypeKeyboard; 605 evt.timeStamp= ioMSecs(); 606 evt.charCode= keyCode; 607 evt.pressCode= pressCode; 608 evt.modifiers= modifiers; 609 evt.utf32Code= 0; /* xxx TODO xxx */ 610 evt.reserved1= 0; 611 evt.windowIndex= 0; 612#ifdef DEBUG_EVENTS 613 printf("EVENT: keyboard"); 614 printModifiers(modifiers); 615 printKey(keyCode); 616 printf("\n"); 617#endif 618 sendEvent((sqInputEvent *)&evt); 619} 620 621 622static void noteDragEvent(int dragType, int numFiles) 623{ 624 int state= makeButtonState(); 625 sqDragDropFilesEvent evt; 626 evt.type= EventTypeDragDropFiles; 627 evt.timeStamp= ioMSecs(); 628 evt.dragType= dragType; 629 evt.x= mousePosition.x; 630 evt.y= mousePosition.y; 631 evt.modifiers= (state >> 3); 632 evt.numFiles= numFiles; 633 evt.windowIndex= 0; 634 sendEvent((sqInputEvent *)&evt); 635} 636 637 638static sqInt display_ioProcessEvents(void) 639{ 640 return aioPoll(0); 641} 642 643 644static sqInt display_ioScreenDepth(void) 645{ 646 return headless ? 1 : dpyDepth; 647} 648 649static int displayChanged= 0; 650 651static sqInt display_ioScreenSize(void) 652{ 653 int size; 654 if (headless) 655 return ((16 << 16) | 16); 656 if (displayChanged) 657 { 658 displayChanged= 0; 659 [win setFrame: [win frame] display: YES]; 660 return 0; 661 } 662 lock(display); 663 size= getSavedWindowSize(); 664 unlock(display); 665 return size; 666} 667 668 669static sqInt display_ioSetCursorWithMask(sqInt cursorBitsIndex, sqInt cursorMaskIndex, sqInt offsetX, sqInt offsetY) 670{ 671 if (headless) 672 return 0; 673 674 if ([view lockFocusIfCanDraw]) 675 { 676 NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init]; 677 NSBitmapImageRep *bitmap= 0; 678 NSImage *image= 0; 679 NSCursor *cursor= 0; 680 681 if (cursorMaskIndex == 0) 682 cursorMaskIndex= cursorBitsIndex; 683 684 bitmap= [[NSBitmapImageRep alloc] 685 initWithBitmapDataPlanes: 0 pixelsWide: 16 pixelsHigh: 16 686 bitsPerSample: 1 samplesPerPixel: 2 687 hasAlpha: YES isPlanar: YES 688 colorSpaceName: NSCalibratedBlackColorSpace 689 bytesPerRow: 2 690 bitsPerPixel: 0]; 691 { 692 unsigned char *planes[5]; 693 [bitmap getBitmapDataPlanes: planes]; 694 { 695 unsigned char *data= planes[0]; 696 unsigned char *mask= planes[1]; 697 int i; 698 699 for (i= 0; i < 16; ++i) 700 { 701 unsigned int word= ((unsigned int *)pointerForOop(cursorBitsIndex))[i]; 702 data[i*2 + 0]= (word >> 24) & 0xFF; 703 data[i*2 + 1]= (word >> 16) & 0xFF; 704 word= ((unsigned int *)pointerForOop(cursorMaskIndex))[i]; 705 mask[i*2 + 0]= (word >> 24) & 0xFF; 706 mask[i*2 + 1]= (word >> 16) & 0xFF; 707 } 708 } 709 } 710 image= [[NSImage alloc] init]; 711 [image addRepresentation: bitmap]; 712 { 713 NSPoint hotSpot= { -offsetX, -offsetY }; 714 cursor= [[NSCursor alloc] initWithImage: image hotSpot: hotSpot]; 715 } 716 [cursor set]; 717 [pool release]; 718 [view unlockFocus]; 719 } 720 return 1; 721} 722 723static sqInt display_ioSetCursorARGB(sqInt cursorBitsIndex, sqInt extentX, sqInt extentY, sqInt offsetX, sqInt offsetY) 724{ 725 if (headless) 726 return 0; 727 728 if ([view lockFocusIfCanDraw]) 729 { 730 NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init]; 731 NSBitmapImageRep *bitmap= 0; 732 NSImage *image= 0; 733 NSCursor *cursor= 0; 734 735 bitmap= [[NSBitmapImageRep alloc] 736 initWithBitmapDataPlanes: 0 pixelsWide: extentX pixelsHigh: extentY 737 bitsPerSample: 8 samplesPerPixel: 4 738 hasAlpha: YES isPlanar: NO 739 colorSpaceName: NSCalibratedRGBColorSpace 740 bytesPerRow: extentX * 4 741 bitsPerPixel: 0]; 742 { 743 unsigned *planes[5]; 744 [bitmap getBitmapDataPlanes: planes]; 745 unsigned* src= (unsigned*)cursorBitsIndex; 746 unsigned* dst= planes[0]; 747 int i; 748 for (i= 0; i < extentX * extentY; ++i, ++dst, ++src) 749 *dst= (*src & 0xFF00FF00) | ((*src & 0x000000FF) << 16) | ((*src & 0x00FF0000) >> 16); 750 } 751 image= [[NSImage alloc] init]; 752 [image addRepresentation: bitmap]; 753 { 754 NSPoint hotSpot= { -offsetX, -offsetY }; 755 cursor= [[NSCursor alloc] initWithImage: image hotSpot: hotSpot]; 756 } 757 [cursor set]; 758 [pool release]; 759 [view unlockFocus]; 760 } 761 return 1; 762} 763 764#if 0 765static sqInt display_ioSetCursor(sqInt cursorBitsIndex, sqInt offsetX, sqInt offsetY) 766{ 767 return ioSetCursorWithMask(cursorBitsIndex, cursorBitsIndex, offsetX, offsetY); 768} 769#endif 770 771 772static sqInt display_ioForceDisplayUpdate(void) 773{ 774 return 0; 775} 776 777 778#if 0 779 780static void setRects(int w, int h) 781{ 782 debugf(("setRects %d %d\n", w, h)); 783 topRect= NSMakeRect(0,0, w,h); 784 if (fullscreen) 785 { 786 titleRect= NSMakeRect(0, dpyHeight, dpyWidth, 0); 787 resizeRect= NSMakeRect(dpyWidth, 0, 0, 0); 788 } 789 else 790 { 791 void *port= [view qdPort]; 792 titleRect = [NSWindow frameRectForContentRect: topRect styleMask: styleMask]; 793 titleRect.origin.y += h; 794 titleRect.size.height -= h; 795 resizeRect= NSMakeRect(pixWidth - RESIZE_EXTENT, 0, RESIZE_EXTENT, RESIZE_EXTENT); 796 if (port) // no port while window is deferred 797 { 798 PixMapHandle pix; 799 LockPortBits(port); 800 { 801 pix = GetPortPixMap(port); 802 pixPitch = GetPixRowBytes(pix); 803 pixBase = ((char *)GetPixBaseAddr(pix) 804 + ((int)titleRect.size.height * pixPitch)); 805 } 806 UnlockPortBits(port); 807 } 808 } 809 setSavedWindowSize((w << 16) | h); // assume this is atomic 810} 811 812#endif 813 814 815static char *updatePix(void) 816{ 817 void *port= [view qdPort]; 818 assert(win); assert(topView); assert(view); 819 if (port) // no port while window is deferred 820 { 821 int w, h; 822 NSRect winRect= [win frame]; 823 winRect.origin= NSMakePoint(0, 0); // window coordinates 824 topRect= [NSWindow contentRectForFrameRect: winRect styleMask: styleMask]; 825 w= NSWidth(topRect); 826 h= NSHeight(topRect); 827 debugf(("updatePix w=%d h=%d\n", w, h)); 828 setSavedWindowSize((w << 16) | h); // assume this is atomic 829 if (fullscreen) 830 { 831 titleRect= NSMakeRect(0, dpyHeight, dpyWidth, 0); // empty & offscreen 832 resizeRect= NSMakeRect(dpyWidth, 0, 0, 0); // empty & offscreen 833 } 834 else 835 { 836 titleRect= winRect; 837 titleRect.origin.y += h; 838 titleRect.size.height -= h; 839 resizeRect= NSMakeRect(w - RESIZE_EXTENT, 0, RESIZE_EXTENT, RESIZE_EXTENT); 840 } 841 pixWidth= w; 842 pixHeight= h; 843 LockPortBits(port); 844 { 845 PixMapHandle pix= GetPortPixMap(port); 846 pixDepth= GetPixDepth(pix); 847 pixPitch= GetPixRowBytes(pix); 848 assert(pixPitch); 849 assert(pixPitch >= w * (pixDepth / 8)); 850 pixBase= ((char *)GetPixBaseAddr(pix) + ((int)NSHeight(titleRect) * pixPitch)); 851 assert(pixBase); 852 } 853 UnlockPortBits(port); 854 } 855 else 856 { 857 debugf(("updatePix: NO PORT!\n")); 858 pixBase= 0; 859 } 860 debugf(("pixBase %p, width %d, height %d, depth %d, pitch %d\n", pixBase, pixWidth, pixHeight, pixDepth, pixPitch)); 861 return pixBase; 862} 863 864 865 866#define bytesPerLine(width, depth) ((((width)*(depth) + 31) >> 5) << 2) 867 868static sqInt display_ioShowDisplay(sqInt dispBitsIndex, sqInt width, sqInt height, sqInt depth, 869 sqInt affectedL, sqInt affectedR, sqInt affectedT, sqInt affectedB) 870{ 871 int affectedW, affectedH; 872 873 if (headless 874 || (width != pixWidth) || (width < 1) || (height != pixHeight) || (height < 1) || (depth != pixDepth) 875 || ((!pixBase) && !updatePix()) 876 || (displayChanged) 877 || (![view lockFocusIfCanDraw])) 878 { 879 debugf(("ioShowDisplay squashed: dpy %dx%dx%d pix %dx%dx%d\n", 880 (int)width, (int)height, (int)depth, 881 (int)pixWidth, (int)pixHeight, (int)pixDepth)); 882 return 0; 883 } 884 885 debugf(("ioShowDisplay %p %ldx%ldx%ld %ld,%ld-%ld,%ld\n", 886 (void *)dispBitsIndex, width, height, depth, 887 affectedL, affectedR, affectedT, affectedB)); 888 889 lock(display); 890 affectedR= min(affectedR, min(width, pixWidth )); 891 affectedB= min(affectedB, min(height, pixHeight)); 892 affectedW= affectedR - affectedL; 893 affectedH= affectedB - affectedT; 894 if ((affectedW > 0) && (affectedH > 0)) 895 { 896 int opp= depth / 8; // octets per pixel 897 char *out= pixBase; 898 int outPitch= pixPitch; 899 void *port= [view qdPort]; 900 LockPortBits(port); 901 //xxx FIXME SOON: cope with dpy depth mismatch (share the code 902 // used by the other types of Unix display) 903 { 904 int pitch= bytesPerLine(width, depth); 905 char *in= pointerForOop(dispBitsIndex) + affectedL * opp + affectedT * pitch; 906 int lines= affectedH; 907 int bytes= affectedW * opp; 908 909 out += (affectedL * opp) + (affectedT * outPitch); 910 911 if ((bytes == pitch) && (bytes == outPitch)) 912 memcpy(out, in, bytes * lines); 913 else if (bytes < 9) // empirical 914 while (lines--) 915 { 916 register char *to= out; 917 register char *from= in; 918 register int count= bytes; 919 while (count--) 920 *to++= *from++; 921 in += pitch; 922 out += outPitch; 923 } 924 else 925 while (lines--) 926 { 927 memcpy((void *)out, (void *)in, bytes); 928 in += pitch; 929 out += outPitch; 930 } 931 } 932 SetRectRgn(pixRegion, affectedL, affectedT, affectedR, affectedB); 933 QDFlushPortBuffer([view qdPort], pixRegion); 934 UnlockPortBits(port); 935 } 936 unlock(display); 937 [view unlockFocus]; 938 939 return 0; 940} 941 942 943#if 0 944 945static void display_ioFlushDisplay(void) 946{ 947 void *port; 948 lock(display); 949 port= [view qdPort]; 950 LockPortBits(port); 951 SetRectRgn(pixRegion, 0, 0, pixWidth, pixHeight); 952 QDFlushPortBuffer([view qdPort], pixRegion); 953 UnlockPortBits(port); 954 unlock(display); 955} 956 957#endif 958 959static sqInt display_ioHasDisplayDepth(sqInt i) 960{ 961 return i == (headless ? 1 : dpyDepth); 962} 963 964static sqInt display_ioSetDisplayMode(sqInt width, sqInt height, sqInt depth, sqInt fullscreenFlag) 965{ 966 if (headless) 967 return 0; 968 969 printf("ioSetDisplayMode: IMPLEMENT ME\n"); 970 return ((width == dpyWidth) && (height == dpyHeight) && (depth == dpyDepth)); 971} 972 973 974static void *display_ioGetDisplay(void) 975{ 976 if (headless) 977 return 0; 978 979 debugf(("ioGetDisplay: WARNING: check the client to see it knows what it's doing\n")); 980 return dpy; 981} 982 983static void *display_ioGetWindow(void) 984{ 985 if (headless) 986 return 0; 987 988 printf("ioGetWindow: WARNING: check the client to see it knows what it's doing\n"); 989 return 0; 990} 991 992static sqInt display_clipboardWriteFromAt(sqInt count, sqInt byteArrayIndex, sqInt startIndex) 993{ 994 NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init]; 995 NSPasteboard *pboard= [NSPasteboard generalPasteboard]; 996 char *buf= malloc(count * 2); 997 int len= sq2uxText(pointerForOop(byteArrayIndex) + startIndex, count, buf, count * 2, 1); 998 NSString *string= [NSString stringWithCString: buf length: len]; 999 [pboard declareTypes: [NSArray arrayWithObject: NSStringPboardType] owner: nil]; 1000 [pboard setString: string forType: NSStringPboardType]; 1001 free(buf); 1002 [pool release]; 1003 return 0; 1004} 1005 1006 1007static sqInt display_clipboardSize(void) 1008{ 1009 NSAutoreleasePool *pool= [[NSAutoreleasePool alloc] init]; 1010 NSPasteboard *pboard= [NSPasteboard generalPasteboard]; 1011 NSString *type= [pboard availableTypeFromArray: 1012 [NSArray arrayWithObject: 1013 NSStringPboardType]]; 1014 int clipSize= 0; 1015 if (clipboard) 1016 free(clipboard); 1017 clipboard= 0; 1018 if (type != nil) 1019 { 1020 NSString *contents= [pboard stringForType: type]; 1021 if (contents != nil) 1022 { 1023 const char *cString= [contents cString]; 1024 int len= [contents length]; 1025 if (len) 1026 { 1027 clipboard= (char *)malloc(len * 2); 1028 if (!clipboard) 1029 fprintf(stderr, "could not allocate clipboard\n"); 1030 else 1031 clipSize= ux2sqText((char *)cString, len, clipboard, len * 2, 1); 1032 } 1033 } 1034 } 1035 [pool release]; 1036 return clipSize; 1037} 1038 1039static sqInt display_clipboardReadIntoAt(sqInt count, sqInt byteArrayIndex, sqInt startIndex) 1040{ 1041 if (clipboard) 1042 { 1043 memcpy(pointerForOop(byteArrayIndex) + startIndex, clipboard, count); 1044 return count; 1045 } 1046 return 0; 1047} 1048 1049static char **display_clipboardGetTypeNames(void) 1050{ 1051 return 0; 1052}; 1053 1054static sqInt display_clipboardSizeWithType(char *typeName, int ntypeName) 1055{ 1056 return 0; 1057} 1058 1059static void display_clipboardWriteWithType(char *data, size_t nData, char *typeName, size_t nTypeName, int isDnd, int isClaiming) 1060{ 1061 return; 1062} 1063 1064static sqInt display_dndOutStart(char *types, int ntypes) { return 0; } 1065static void display_dndOutSend(char *bytes, int nbytes) { return ; } 1066static sqInt display_dndOutAcceptedType(char * buf, int nbuf) { return 0; } 1067 1068static void display_winExit(void) 1069{ 1070 [win close]; 1071} 1072 1073 1074static void display_winSetName(char *title) 1075{ 1076 char *base= strrchr(title, '/'); 1077 if (base) title= base + 1; 1078#if (RESIZE_IN_TITLE) 1079 if (showExtent) 1080 { 1081 char buf[NAME_MAX]; 1082 NSRect frame= [view frame]; 1083 sprintf(buf, "%s (%dx%d)", title, (int)NSWidth(frame), (int)NSHeight(frame)); 1084 title= buf; 1085 } 1086#endif 1087 [win setTitle: [NSString stringWithCString: title]]; 1088} 1089 1090 1091static void display_parseEnvironment(void) {} 1092 1093static int display_parseArgument(int argc, char **argv) 1094{ 1095 if (!strncmp(*argv, "-psn_", 5)) return fromFinder= 1; 1096 else if (!strcmp(*argv, "-quartz")) return 1; 1097 else if (!strcmp(*argv, "-fullscreen")) return fullscreen= 1; 1098 else if (!strcmp(*argv, "-headless")) return headless= 1; 1099 else if (!strcmp(*argv, "-notitle")) return noTitle= 1; 1100 else if (!strcmp(*argv, "-nodock")) return noDock= 1; 1101 else if (!strcmp(*argv, "-swapbtn")) return swapBtn= 1; 1102 return 0; 1103} 1104 1105static void display_printUsage(void) 1106{ 1107 printf("\nQuartz/Aqua <option>s:\n"); 1108 printf(" -fullscreen occupy the entire screen\n"); 1109 printf(" -headless run in headless (no window) mode\n"); 1110 printf(" -nodock don't show Squeak in the dock\n"); 1111 printf(" -notitle disable the Squeak window title bar\n"); 1112 printf(" -swapbtn swap mouse buttons 2 (yellow) and 3 (blue)\n"); 1113} 1114 1115static void display_printUsageNotes(void) 1116{ 1117 printf(" -nodock is only useful with `-headless'.\n"); 1118} 1119 1120 1121/// 1122/// window initialization 1123/// 1124 1125 1126static void menuAddItem(NSMenu *menu, NSString *title, SEL action, 1127 NSString *key, int opt) 1128{ 1129 NSMenuItem *item= [[NSMenuItem alloc] 1130 initWithTitle: title 1131 action: action 1132 keyEquivalent: (cmdKeys ? key : @"")]; 1133 [menu addItem: item]; 1134 if (opt) 1135 [item setKeyEquivalentModifierMask: (NSCommandKeyMask | NSAlternateKeyMask)]; 1136 [item release]; 1137} 1138 1139static void installMenu(SEL install, NSMenu *menu) 1140{ 1141 NSMenuItem *item= [[NSMenuItem alloc] 1142 initWithTitle: @"" 1143 action: nil 1144 keyEquivalent: @""]; 1145 [item setSubmenu: menu]; 1146 [[NSApp mainMenu] addItem: item]; 1147 if (install != NULL) 1148 { 1149 extern id objc_msgSend(id theReceiver, SEL theSelector, ...); 1150 objc_msgSend(NSApp, install, menu); 1151 } 1152 [item release]; 1153 [menu release]; 1154} 1155 1156 1157// InterfaceBuilder? Just Say No! 1158 1159static void setUpMenus(void) 1160{ 1161 if (headless && noDock) 1162 return; 1163 1164 [NSApp setMainMenu: [[NSMenu alloc] init]]; 1165 { 1166 NSMenu *menu= [[NSMenu alloc] initWithTitle: @"Squeak"]; 1167 menuAddItem(menu, @"About Squeak", @selector(performAbout:), @"", 0); 1168 [menu addItem: [NSMenuItem separatorItem]]; 1169 menuAddItem(menu, @"Preferences...", @selector(performPreferences:), @"y", 0); 1170 [menu addItem: [NSMenuItem separatorItem]]; 1171 menuAddItem(menu, @"Hide Squeak", @selector(hide:), @"h", 0); 1172 menuAddItem(menu, @"Hide Others", @selector(hideOtherApplications:), @"h", 1); 1173 menuAddItem(menu, @"Show All", @selector(unhideAllApplications:), @"", 0); 1174 [menu addItem: [NSMenuItem separatorItem]]; 1175 menuAddItem(menu, @"Quit Squeak", @selector(terminate:), @"q", 0); 1176 installMenu(@selector(setAppleMenu:), menu); 1177 } 1178 { 1179 NSMenu *menu= [[NSMenu alloc] initWithTitle: @"File"]; 1180 menuAddItem(menu, @"Page Setup...", @selector(performPageSetup:), @"P", 0); 1181 menuAddItem(menu, @"Print", @selector(performPrint:), @"p", 0); 1182 installMenu(NULL, menu); 1183 } 1184 { 1185 NSMenu *menu= [[NSMenu alloc] initWithTitle: @"Window"]; 1186 menuAddItem(menu, @"Minimise", @selector(performMiniaturize:), @"m", 0); 1187 if (cmdKeys) 1188 menuAddItem(menu, @"Disable Command Keys", @selector(performDisableKeys:), @"k", 0); 1189 else 1190 menuAddItem(menu, @"Enable Command Keys", @selector(performEnableKeys:), @"", 0); 1191 installMenu(@selector(setWindowsMenu:), menu); 1192 } 1193 { 1194 NSMenu *menu= [[NSMenu alloc] initWithTitle: @"Help"]; 1195 menuAddItem(menu, @"Squeak Help", @selector(showHelp:), @"?", 0); 1196 installMenu(NULL, menu); 1197 } 1198} 1199 1200 1201#include "CPS.h" 1202 1203static char *str4(UInt32 chars) 1204{ 1205 static char str[5]; 1206 *(int *)&str= chars; 1207 str[4]= '\0'; 1208 return str; 1209} 1210 1211static void setUpDock(void) 1212{ 1213 // this was passed to us in argv, but we have to pick it up from CPS 1214 // anyway if the VM was started from a command line or script 1215 CPSProcessSerNum psn; 1216 OSErr err; 1217 1218 if (headless && noDock) 1219 return; 1220 1221# define try(FN, ARGS, CAVEAT) \ 1222 if ((err= FN ARGS)) fprintf(stderr, "%s: error %d%s\n", #FN, err, CAVEAT) 1223 1224 try(CPSGetCurrentProcess, (&psn), ""); 1225 else try(CPSSetProcessName, (&psn, "Squeak"), ""); 1226 else 1227 { 1228 CPSEnableForegroundOperation(&psn, 0x03, 0x3c, 0x2c, 0x1103); 1229 try(CPSSetFrontProcess, (&psn), ""); 1230 } 1231# undef try 1232# if defined(DEBUG_APP) 1233 { 1234 CPSProcessInfoRec info; 1235 char path[4096]; 1236 int len; 1237 char name[4096]; 1238 CPSGetProcessInfo(&psn, &info, path, sizeof(path), &len, name, sizeof(name)); 1239 printf("process:\n"); 1240 printf(" pid: %d\n", info.UnixPID); 1241 printf(" path: %s\n", path); 1242 printf(" name: %s\n", name); 1243 printf(" creator: %s\n", str4(info.ExecFileCreator)); 1244 printf(" type: %s\n", str4(info.ExecFileType)); 1245 printf(" flavour: "); 1246 switch(info.Flavour) 1247 { 1248 case kCPSBlueApp: printf("BlueApp\n"); break; 1249 case kCPSBlueBox: printf("BlueBox\n"); break; 1250 case kCPSCarbonApp: printf("Carbon\n"); break; 1251 case kCPSYellowApp: printf("YellowApp\n"); break; 1252 case kCPSUnknownApp: printf("unknown\n"); break; 1253 } 1254 printf(" attrs: %d", info.Attributes); 1255 if (info.Attributes & kCPSBGOnlyAttr) printf(" BGOnly"); 1256 if (info.Attributes & kCPSUIElementAttr) printf(" UIElement"); 1257 if (info.Attributes & kCPSHiddenAttr) printf(" Hidden"); 1258 if (info.Attributes & kCPSNoConnectAttr) printf(" NoConnect"); 1259 if (info.Attributes & kCPSFullScreenAttr) printf(" FullScreen"); 1260 if (info.Attributes & kCPSClassicReqAttr) printf(" ClassicReq"); 1261 if (info.Attributes & kCPSNativeReqAttr) printf(" NativeReq"); 1262 printf("\n"); 1263 } 1264#endif 1265} 1266 1267 1268static char *display_winSystemName(void) 1269{ 1270 return "Quartz"; 1271} 1272 1273 1274static void display_winInit(void) 1275{ 1276 [[NSAutoreleasePool alloc] init]; 1277 [Squeak sharedApplication]; 1278 [NSApp setDelegate: NSApp]; 1279 // from winOpen()... 1280 setUpMenus(); 1281 setUpDock(); 1282 [NSApp run]; 1283} 1284 1285 1286static void display_winOpen(void) {} 1287 1288 1289static void setUpDisplay(void) 1290{ 1291 if (headless) 1292 return; 1293 1294 if (!dpy) 1295 pixRegion= NewRgn(); 1296 1297 dpy = kCGDirectMainDisplay; 1298 dpyMode = (NSDictionary *)CGDisplayCurrentMode(dpy); 1299 dpyWidth = [[dpyMode objectForKey: (id)kCGDisplayWidth] intValue]; 1300 dpyHeight = [[dpyMode objectForKey: (id)kCGDisplayHeight] intValue]; 1301 dpyDepth = [[dpyMode objectForKey: (id)kCGDisplayBitsPerPixel] intValue]; 1302 dpyPixels = CGDisplayBaseAddress(dpy); 1303 dpyPitch = CGDisplayBytesPerRow(dpy); 1304 1305 debugf(("display is %dx%dx%d at %p pitch %d\n", dpyWidth, dpyHeight, dpyDepth, dpyPixels, dpyPitch)); 1306} 1307 1308 1309static void setUpWindow(int fs) 1310{ 1311 if (!headless) 1312 { 1313 int w, h; 1314 NSRect contentRect; 1315 if (fs) 1316 { 1317 setUpDisplay(); 1318 w= dpyWidth; 1319 h= dpyHeight; 1320 } 1321 else 1322 { 1323 int winSize= getSavedWindowSize(); 1324 if (winSize) 1325 { 1326 w= winSize >> 16; 1327 h= winSize & 0xffff; 1328 } 1329 else 1330 { 1331 w= 640; 1332 h= 480; 1333 } 1334 } 1335 debugf(("initial winSize %d %d\n", w, h)); 1336 styleMask= (fs 1337 ? (NSBorderlessWindowMask) 1338 : ( NSTitledWindowMask 1339 | NSMiniaturizableWindowMask 1340 | NSResizableWindowMask)); 1341 //xxx does quartz _really_ have _no_ mechanism to set window bit gravity?!? 1342 win= [[SqueakWindow alloc] 1343 initWithContentRect: NSMakeRect(0,0, w,h) 1344 styleMask: styleMask 1345 backing: NSBackingStoreBuffered 1346 defer: NO]; 1347 1348 contentRect= [[win contentView] frame]; 1349 w= NSWidth(contentRect); 1350 h= NSHeight(contentRect); 1351 debugf(("alloc winSize %d %d\n", w, h)); 1352 setSavedWindowSize((w << 16) | h); 1353 1354 view= [[SqueakView alloc] initWithFrame: contentRect]; 1355 [view setAutoresizingMask: (NSViewWidthSizable | NSViewHeightSizable)]; 1356 1357 [win setReleasedWhenClosed: YES]; 1358 [win setAcceptsMouseMovedEvents: YES]; 1359 [win setShowsResizeIndicator: NO]; 1360 1361 topView= [[TopView alloc] initWithFrame: contentRect]; 1362 1363 [win setInitialFirstResponder: view]; 1364 [win setDelegate: NSApp]; 1365 [win useOptimizedDrawing: YES]; 1366 1367 // [win setBackgroundColor: [NSColor clearColor]]; 1368 // [win setAlphaValue: 1.0]; 1369 // [win setOpaque: YES]; 1370 // [win setAutodisplay: YES]; 1371 //[win disableFlushWindow]; 1372 1373 if (fs) 1374 [win setLevel: CGShieldingWindowLevel()]; 1375 else 1376 { 1377 [win center]; 1378 if (!fromFinder) 1379 [win setIcon]; 1380 display_winSetName(shortImageName); 1381 } 1382 1383 [topView addSubview: view]; //[view release]; 1384 [win setContentView: topView]; //[topView release]; 1385 [win makeKeyAndOrderFront: nil]; // need platform window to get pixBase 1386 } 1387} 1388 1389 1390static int imageWidth; 1391static int imageHeight; 1392static char *imageData; 1393static CGDataProviderRef imageDataProvider; 1394static CGImageRef imageRef; 1395 1396static void cgdpRelease(void *info, const void *data, size_t size) {} 1397 1398static void captureImage(int inverted) 1399{ 1400 imageWidth= pixWidth; 1401 imageHeight= pixHeight; 1402 imageData= (char *)malloc(pixPitch * imageHeight); 1403 if (inverted) 1404 { 1405 char *in= pixBase, *out= imageData + ((imageHeight - 1) * pixPitch); 1406 int y; 1407 for (y= pixHeight; y--; (in += pixPitch), (out -= pixPitch)) 1408 memcpy(out, in, pixPitch); 1409 } 1410 else 1411 { 1412 memcpy(imageData, pixBase, imageHeight * pixPitch); 1413 } 1414 imageDataProvider= 1415 CGDataProviderCreateWithData(0, imageData, pixPitch*imageHeight, 1416 cgdpRelease); 1417 imageRef= 1418 CGImageCreate(imageWidth, imageHeight, 8, 32, pixPitch, 1419 CGColorSpaceCreateDeviceRGB(), 1420 kCGImageAlphaNoneSkipFirst, 1421 imageDataProvider, 0, 0, 1422 kCGRenderingIntentDefault); 1423} 1424 1425 1426static void drawImage(CGContextRef cgc, int offset) 1427{ 1428 CGContextDrawImage(cgc, CGRectMake(0, offset, imageWidth, imageHeight), imageRef); 1429} 1430 1431 1432static void releaseImage(int malloced) 1433{ 1434 CGImageRelease(imageRef); 1435 CGDataProviderRelease(imageDataProvider); 1436 if (malloced) 1437 free(imageData); 1438} 1439 1440 1441#ifdef FULLSCREEN_FADE 1442 1443// YES, I know there's a CG API to do this. But it sucks. 1444 1445static struct 1446{ 1447 CGGammaValue r[256], g[256], b[256]; 1448} dpyGamma; 1449 1450static void fadeOut(float delta) 1451{ 1452 CGGammaValue r[256], g[256], b[256]; 1453 int sz; 1454 1455 if ((CGDisplayNoErr == CGGetDisplayTransferByTable 1456 (dpy, 256, dpyGamma.r, dpyGamma.g, dpyGamma.b, &sz)) 1457 && (256 == sz)) 1458 { 1459 float scale; 1460 memcpy(r, dpyGamma.r, sizeof(r)); 1461 memcpy(g, dpyGamma.g, sizeof(g)); 1462 memcpy(b, dpyGamma.b, sizeof(b)); 1463 for (scale= 1.0; scale >= 0.0; scale -= delta) 1464 { 1465 int i; 1466 for (i= 256; i--;) 1467 { 1468 r[i]= dpyGamma.r[i] * scale; 1469 g[i]= dpyGamma.g[i] * scale; 1470 b[i]= dpyGamma.b[i] * scale; 1471 } 1472 if (CGDisplayNoErr != CGSetDisplayTransferByTable(dpy, 256, r, g, b)) 1473 { 1474 printf("failed to set transfer table\n"); 1475 CGDisplayRestoreColorSyncSettings(); 1476 return; 1477 } 1478 usleep(10000); 1479 } 1480 } 1481 else 1482 { 1483 printf("failed to get display transfer table (%d)\n", sz); 1484 } 1485} 1486 1487static void fadeIn(float delta) 1488{ 1489 CGGammaValue r[256], g[256], b[256]; 1490 float scale; 1491 memset(r, 0, sizeof(r)); 1492 memset(g, 0, sizeof(g)); 1493 memset(b, 0, sizeof(b)); 1494 for (scale= 0.0; scale <= 1.0; scale += delta) 1495 { 1496 int i; 1497 for (i= 256; i--;) 1498 { 1499 r[i] = dpyGamma.r[i] * scale; 1500 g[i] = dpyGamma.g[i] * scale; 1501 b[i] = dpyGamma.b[i] * scale; 1502 } 1503 if (CGDisplayNoErr != CGSetDisplayTransferByTable(dpy, 256, r, g, b)) 1504 break; 1505 usleep(10000); 1506 } 1507 CGDisplayRestoreColorSyncSettings(); 1508} 1509 1510#endif 1511 1512 1513#if 1 1514 1515static sqInt display_ioSetFullScreen(sqInt flag) 1516{ 1517 static sqInt originalWindowSize= 0; 1518 SqueakWindow *old; 1519 1520 debugf(("ioSetFullScreen(%d)\n", flag)); 1521 1522 if (headless || (fullscreen == flag)) 1523 return 0; // nothing to do 1524 old= win; 1525 win= 0; view= 0; topView= 0; pixBase= 0; pixWidth= 0; pixHeight= 0; pixPitch= 0; 1526 if (flag) 1527 originalWindowSize= getSavedWindowSize(); 1528 else if (originalWindowSize) 1529 setSavedWindowSize(originalWindowSize); 1530 setFullScreenFlag(fullscreen= flag); 1531 setUpWindow(flag); 1532 reframeRenderers(); 1533 [old close]; 1534 return 1; 1535} 1536 1537#else 1538 1539static sqInt display_ioSetFullScreen(sqInt flag) 1540{ 1541 static sqInt originalWindowSize= (800 << 16) | 600; 1542 1543 debugf(("ioSetFullScreen(%d)\n", flag)); 1544 1545 if (headless || (fullscreen == flag) || glActive) 1546 return 0; // nothing to do 1547 1548 if (flag) // switch to fullscreen 1549 { 1550 CGDisplayHideCursor(dpy); 1551# ifdef FULLSCREEN_FADE 1552 captureImage(0); 1553 fadeOut(FULLSCREEN_FADE); 1554# endif 1555 if (CGDisplayNoErr != CGDisplayCapture(dpy)) 1556 debugf(("failed to capture display\n")); 1557 else 1558 { 1559# ifdef FULLSCREEN_FADE 1560 CGContextRef cgc; 1561 memset(dpyPixels, -1U, dpyPitch * dpyHeight); 1562 cgc= CGBitmapContextCreate(dpyPixels, dpyWidth, dpyHeight, 1563 8, dpyPitch, 1564 CGColorSpaceCreateDeviceRGB(), 1565 kCGImageAlphaNoneSkipFirst); 1566 drawImage(cgc, dpyHeight - pixHeight); 1567 CGContextRelease(cgc); 1568# endif 1569 lock(display); 1570 originalWindowSize= getSavedWindowSize(); 1571 pixWidth= dpyWidth; 1572 pixHeight= dpyHeight; 1573 fullscreen= 1; 1574 updatePix(); 1575 unlock(display); 1576 [NSMenu setMenuBarVisible: NO]; 1577 } 1578# ifdef FULLSCREEN_FADE 1579 fadeIn(FULLSCREEN_FADE); 1580 releaseImage(0); 1581# endif 1582 mousePosition.x= mousePosition.y= -1; 1583 CGDisplayShowCursor(dpy); 1584 } 1585 else // switch to windowed 1586 { 1587# ifdef FULLSCREEN_FADE 1588 fadeOut(FULLSCREEN_FADE); 1589# endif 1590 [NSMenu setMenuBarVisible: YES]; 1591 CGDisplayRelease(dpy); 1592 fullscreen= 0; 1593 lock(display); 1594 setSavedWindowSize(originalWindowSize); 1595 pixWidth= originalWindowSize >> 16; 1596 pixHeight= originalWindowSize & 0xffff; 1597 updatePix(); 1598 unlock(display); 1599# ifdef FULLSCREEN_FADE 1600 fadeIn(FULLSCREEN_FADE); 1601# endif 1602 } 1603 1604 return 1; 1605} 1606 1607#endif 1608 1609 1610 1611@implementation Squeak 1612 1613 1614+ (void) initialize 1615{ 1616 NSMutableDictionary *dict; 1617 NSUserDefaults *defaults; 1618 1619 defaults= [NSUserDefaults standardUserDefaults]; 1620 dict= [NSMutableDictionary dictionary]; 1621 1622 [dict setObject: @"YES" forKey: @"AppleDockIconEnabled"]; 1623 [defaults registerDefaults: dict]; 1624} 1625 1626 1627static char *documentName= 0; 1628 1629 1630-(BOOL) application: (NSApplication *) theApplication 1631 openFile: (NSString *) filename 1632{ 1633 if (fromFinder) 1634 documentName= strdup([filename cString]); 1635 return YES; 1636} 1637 1638 1639#if 0 // only for running with increased stack size 1640static void *runInterpreter(void *arg) 1641{ 1642 [(id)arg interpret: nil]; 1643} 1644#endif 1645 1646 1647-(void) applicationDidFinishLaunching: (NSNotification *)note 1648{ 1649 int fds[2]; 1650 1651 // this saves an awful lot of tedious mutex contention (and besides 1652 // is essentially free, since there's no way to avoid writing a 1653 // socket to inform aio of the availability of the event) 1654#if 0 1655 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) 1656 { 1657 perror("socketpair"); 1658 exit(1); 1659 } 1660 osXfd= fds[0]; 1661 stXfd= fds[1]; 1662#else 1663 if (pipe(fds)) 1664 { 1665 perror("pipe"); 1666 exit(1); 1667 } 1668 stXfd= fds[0]; 1669 osXfd= fds[1]; 1670#endif 1671 aioEnable(stXfd, 0, 0); 1672 aioHandle(stXfd, evtHandler, AIO_RX); 1673#if (!USE_SPINLOCK) 1674 { 1675 pthread_mutexattr_t attr; 1676 pthread_mutexattr_init(&attr); 1677# ifndef NDEBUG 1678 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK); 1679# endif 1680 if (pthread_mutex_init(&displayMx, &attr)) 1681 { 1682 perror("pthread_mutex_init"); 1683 exit(1); 1684 } 1685 pthread_mutexattr_destroy(&attr); 1686 } 1687#endif 1688 1689 if (fromFinder) 1690 { 1691 char *ptr= 0; 1692 strncpy(resourcePath, argVec[0], sizeof(resourcePath)); // .app/Contents/MacOS/squeak 1693 if ((ptr= strrchr(resourcePath, '/'))) 1694 { 1695 *ptr= '\0'; // .app/Contents/MacOS 1696 if ((ptr= strrchr(resourcePath, '/'))) 1697 { 1698 *ptr= '\0'; // .app/Contents 1699 strcpy(ptr, "/Resources/"); // .app/Contents/Resources/ 1700 } 1701 else 1702 resourcePath[0]= '\0'; 1703 } 1704 else 1705 resourcePath[0]= '\0'; 1706 } 1707 1708 imgInit(); 1709 setUpDisplay(); 1710 setUpWindow(fullscreen= getFullScreenFlag()); 1711 1712#if 1 1713 [NSThread 1714 detachNewThreadSelector: @selector(interpret:) 1715 toTarget: self 1716 withObject: nil]; 1717#else 1718 // ensure cocoa is initialised for threads 1719 { 1720 id obj= [NSObject new]; 1721 [NSThread detachNewThreadSelector: @selector(self) toTarget: obj withObject: nil]; 1722 [obj release]; 1723 } 1724 // run interpreter with stack size > default 1725 { 1726 pthread_t thread; 1727 pthread_attr_t attr; 1728 pthread_attr_init(&attr); 1729 pthread_attr_setstacksize(&attr, 8192*1024); 1730 pthread_create(&thread, &attr, runInterpreter, (void *)self); 1731 } 1732#endif 1733} 1734 1735 1736- (void) interpret: (id)context 1737{ 1738 [[NSAutoreleasePool alloc] init]; // running in new thread 1739 interpret(); 1740 (void)recordMouseEvent; 1741 (void)recordKeyboardEvent; 1742 (void)recordDragEvent; 1743 (void)recordWindowEvent; 1744} 1745 1746 1747- (void) applicationDidChangeScreenParameters: (NSNotification *)note 1748{ 1749 //xxx this one might be tricky in the absence of appWillChangeScreenParams: 1750 fprintf(stderr, "\nDISPLAY PARAMETERS CHANGED\n\n"); 1751 // lock(display); 1752 pixWidth= pixHeight= pixDepth= 0; 1753 setUpDisplay(); 1754 //setUpWindow(getFullScreenFlag()); 1755 updatePix(); 1756 // unlock(display); 1757 //setUpMenus(); 1758 displayChanged= 1; 1759 //fullDisplayUpdate(); 1760} 1761 1762 1763- (void) unhideAllApplications: (id)sender 1764{ 1765 [super unhideAllApplications: sender]; 1766 [win orderFront: self]; // so that unhinding once more will reveal the Sq window 1767} 1768 1769 1770- (BOOL) windowShouldClose: (id)sender 1771{ 1772 return NO; 1773} 1774 1775 1776- (void) terminate: (id)sender 1777{ 1778 [super terminate: sender]; 1779 exit(0); 1780} 1781 1782- (void) maybeTerminate: (id)sender 1783{ 1784 switch (NSRunAlertPanel(@"Really quit?", 1785 @"All changes since your last save will be lost.\n\nIf you want to save your changes, press `Cancel' and then choose `save and quit' from the background menu in the Squeak window.", 1786 @"Quit", 1787 @"Cancel", 1788 nil)) 1789 { 1790 case NSAlertDefaultReturn: [self terminate: self]; 1791 } 1792} 1793 1794 1795- (void) performAbout: (id)sender 1796{ 1797 extern char *getVersionInfo(int verbose); 1798 char *info= getVersionInfo(1); 1799 NSPanel *panel= NSGetInformationalAlertPanel(@"About Squeak", 1800 @"%s", 1801 @"Dismiss", 1802 nil, 1803 nil, 1804 info); 1805 NSRect frame= [panel frame]; 1806 frame.size.width *= 1.5; 1807 [panel setFrame: frame display: NO]; 1808 [NSApp runModalForWindow: panel]; 1809 [panel close]; 1810 free(info); 1811} 1812 1813 1814 1815//xxx why does rebuilding the menu lose boldface on the Apple menu item??? 1816 1817- (void) performEnableKeys: (id)sender { cmdKeys= 1; setUpMenus(); } 1818- (void) performDisableKeys: (id)sender { cmdKeys= 0; setUpMenus(); } 1819 1820 1821- (void) windowWillMove: (NSNotification *)note 1822{ 1823 //xxx FIXME SOON: there are other ways to enter this (and ways other than 1824 // noteEvent to escape from it) 1825 inModalLoop= 1; 1826} 1827 1828 1829- (NSSize) windowWillResize: (NSWindow *)sender toSize: (NSSize)size 1830{ 1831 return glActive ? [sender frame].size : size; 1832} 1833 1834 1835- (void) windowDidResize: (NSNotification *)note 1836{ 1837 reframeRenderers(); 1838} 1839 1840 1841-(void) sendEvent: (NSEvent *)event 1842{ 1843 int type= [event type]; 1844 NSPoint loc= [event locationInWindow]; 1845 NSWindow *evtWin= [event window]; 1846#if 0 1847 NSPoint loc= (fullscreen 1848 ? [NSEvent mouseLocation] //xxx should use deltas 1849 : [event locationInWindow]); 1850#endif 1851 1852 if (evtWin && ((NSWindow *)win != [event window])) 1853 { 1854 //printf("evtWin not local\n"); 1855 [super sendEvent: event]; 1856 return; 1857 } 1858 1859 switch (type) 1860 { 1861# define down buttonState |= qz2sqButton([event buttonNumber]) 1862# define move 1863# define up buttonState &= ~qz2sqButton([event buttonNumber]) 1864 1865# define recordEvent(delta) \ 1866 if (fullscreen || NSPointInRect(loc, [view frame])) \ 1867 { \ 1868 noteMousePoint(loc); \ 1869 delta; \ 1870 modifierState= qz2sqModifiers([event modifierFlags]); \ 1871 noteMouseEvent(); \ 1872 } \ 1873 else \ 1874 { \ 1875 /* printf("recordEvent fullscreen %d inRect %d\n", fullscreen, NSPointInRect(loc, [view frame])); */ \ 1876 [super sendEvent: event]; /* don't track outside window */ \ 1877 } 1878 1879 case NSLeftMouseDown: case NSOtherMouseDown: case NSRightMouseDown: 1880 if ((!active) || NSPointInRect(loc, resizeRect)) 1881 { 1882 //printf("evt down active %d inRect %d\n", active, NSPointInRect(loc, resizeRect)); 1883 [super sendEvent: event]; // first click, or start resize 1884 } 1885 else 1886 recordEvent(down); 1887 break; 1888 1889 case NSLeftMouseDragged: case NSRightMouseDragged: case NSOtherMouseDragged: 1890 if (!(buttonState & qz2sqButton([event buttonNumber]))) 1891 { 1892 [super sendEvent: event]; // already tracking window move 1893 break; 1894 } 1895 // fall through... 1896 case NSMouseMoved: 1897 recordEvent(move); 1898 break; 1899 1900 case NSLeftMouseUp: case NSOtherMouseUp: case NSRightMouseUp: 1901 recordEvent(up); 1902 break; 1903 1904# undef recordEvent 1905# undef down 1906# undef move 1907# undef up 1908 1909 case NSKeyDown: 1910 { 1911 int keyCode; 1912 modifierState= qz2sqModifiers([event modifierFlags]); 1913 keyCode= [view composeKeyDown: event]; //qz2sqKey(event); 1914 if (keyCode >= 0) 1915 { 1916 if (cmdKeys) 1917 { 1918 if ((modifierState == CommandKeyBit) || (modifierState == CommandKeyBit + ShiftKeyBit)) 1919 switch (keyCode) 1920 { 1921 case '?': [NSApp showHelp: self]; keyCode= -1; break; 1922 case 'h': [NSApp hide: self]; keyCode= -1; break; 1923 case 'k': [NSApp performDisableKeys: self]; keyCode= -1; break; 1924 case 'm': [win performMiniaturize: self]; keyCode= -1; break; 1925 case 'q': [NSApp maybeTerminate: self]; keyCode= -1; break; 1926 } 1927 else if (modifierState == CommandKeyBit + OptionKeyBit) 1928 switch (keyCode) 1929 { 1930 case 'h': [NSApp hideOtherApplications: self]; keyCode= -1; break; 1931 } 1932 } 1933 if (keyCode >= 0) 1934 { 1935 if (![event isARepeat]) 1936 noteKeyboardEvent(keyCode, EventKeyDown, modifierState); 1937 noteKeyboardEvent(keyCode, EventKeyChar, modifierState); 1938 recordKeystroke(keyCode); /* DEPRECATED */ 1939 } 1940 else // key up not interesting 1941 [view composeKeyUp: event]; 1942 } 1943 } 1944 break; 1945 1946 case NSKeyUp: 1947 { 1948 int keyCode; 1949 modifierState= qz2sqModifiers([event modifierFlags]); 1950 keyCode= [view composeKeyUp: event]; //qz2sqKey(event); 1951 if (keyCode >= 0) 1952 { 1953 noteKeyboardEvent(keyCode, EventKeyUp, modifierState); 1954 //accentMap= 0; 1955 } 1956 } 1957 break; 1958 1959 case NSScrollWheel: 1960 { 1961 int keyCode, modifiers; 1962 keyCode= ([event deltaY] >= 0.0) ? 30 : 31; 1963 modifierState= qz2sqModifiers([event modifierFlags]); 1964 modifiers= modifierState ^ CtrlKeyBit; 1965 noteKeyboardEvent(keyCode, EventKeyDown, modifiers); 1966 noteKeyboardEvent(keyCode, EventKeyChar, modifiers); 1967 noteKeyboardEvent(keyCode, EventKeyUp, modifiers); 1968 } 1969 break; 1970 1971 case NSAppKitDefined: 1972 switch ([event subtype]) 1973 { 1974 case NSApplicationActivatedEventType: 1975 active= 1; 1976 break; 1977 1978 case NSApplicationDeactivatedEventType: 1979 active= 0; 1980 break; 1981 // case NSScreenChangedEventType: //xxx this means the window 1982 // changed to a different physical screen, which is useless 1983 // info (we'd far rather be informed that the current screen's 1984 // depth has changed) 1985 } 1986 //debugf(("AppKitDefinedEvent subtype %d\n", [event subtype])); 1987 [super sendEvent: event]; 1988 break; 1989 1990 // case NSFlagsChanged: 1991 // case NSApplicationDefined: break; 1992 // case NSPeriodic: break; 1993 // case NSCursorUpdate: break; 1994 1995 default: // almost always NSSystemDefined 1996 //debugf(("Event type %d subtype %d\n", [event type], [event subtype])); 1997 [super sendEvent: event]; 1998 } 1999} 2000 2001 2002@end // Squeak 2003 2004 2005 2006@implementation SqueakWindow 2007 2008- (BOOL) isOpaque { return YES; } 2009- (BOOL) canBecomeKeyWindow { return YES; } 2010 2011static NSImage *tryLoadingIcon(char *dir) 2012{ 2013 char buf[MAXPATHLEN]; 2014 sprintf(buf, "%s/SqueakVM.icns", dir); 2015 return [[NSImage alloc] 2016 initWithContentsOfFile: 2017 [NSString stringWithCString: buf]]; 2018} 2019 2020- (void) setIcon 2021{ 2022 icon= 0; 2023 if (( icon= tryLoadingIcon(".")) 2024 || (icon= tryLoadingIcon("/usr/local/lib/squeak")) 2025 || (icon= tryLoadingIcon(resourcePath))) 2026 [NSApp setApplicationIconImage: icon]; 2027} 2028 2029#if 0 2030 2031- (NSImage *) dockImage 2032{ 2033 NSBitmapImageRep *rep= [NSBitmapImageRep alloc]; 2034 if ([rep initWithFocusedViewRect: topRect]) 2035 { 2036 NSImage *image= [[NSImage alloc] init]; 2037 [image addRepresentation: rep]; 2038 if (icon) 2039 { 2040 [image lockFocus]; 2041 [icon drawInRect: NSMakeRect(0, 0, [image size].width, [image size].height) 2042 fromRect: NSMakeRect(0, 0, [icon size].width, [icon size].height) 2043 operation: NSCompositeSourceOver 2044 fraction: 1.0]; 2045 [image unlockFocus]; 2046 } 2047 return image; 2048 } 2049 return nil; 2050} 2051 2052- (void) miniaturize: (id)sender 2053{ 2054 NSImage *image= [self dockImage]; 2055 if (image) 2056 [self setMiniwindowImage: image]; 2057 [image release]; 2058 [super miniaturize: sender]; 2059} 2060 2061#endif 2062 2063 2064- (void) performMiniaturize: (id)sender 2065{ 2066 if (!glActive) 2067 [super performMiniaturize: sender]; 2068} 2069 2070 2071@end // SqueakWindow 2072 2073 2074 2075@implementation SqueakView 2076 2077- (BOOL) isOpaque { return YES; } 2078- (BOOL) isFlipped { return YES; } 2079- (BOOL) acceptsFirstResponder { return YES; } 2080- (BOOL) becomeFirstResponder { return YES; } 2081- (BOOL) resignFirstResponder { return NO; } 2082 2083#if 0 2084- (void) renewGState 2085{ 2086 printf("\nRENEW GSTATE\n\n"); 2087 [super renewGState]; 2088} 2089#endif 2090 2091static NSRange inputMark; 2092static NSRange inputSelection; 2093static int inputCharCode; 2094 2095- (id) initWithFrame: (NSRect)frame 2096{ 2097 id result= [super initWithFrame: frame]; 2098 if (self == result) 2099 [self registerForDraggedTypes: 2100 [NSArray arrayWithObjects: 2101 NSFilenamesPboardType, nil]]; 2102 inputCharCode= -1; 2103 inputMark= NSMakeRange(NSNotFound, 0); 2104 inputSelection= NSMakeRange(0, 0); 2105 return result; 2106} 2107 2108 2109- (void) setFrame: (NSRect)rect 2110{ 2111 lock(display); 2112 [super setFrame: rect]; 2113 if ([self inLiveResize]) 2114 { 2115# if (RESIZE_IN_TITLE) 2116 display_winSetName(shortImageName); 2117# endif 2118 } 2119 else 2120 if ([self qdPort]) 2121 updatePix(); 2122 unlock(display); 2123} 2124 2125 2126- (void) drawRect: (NSRect)rect // view already has focus 2127{ 2128#if 0 2129 printf("drawRect:\n"); 2130#endif 2131 if ([self inLiveResize]) 2132 { 2133 [[NSColor whiteColor] set]; 2134 NSRectFill(rect); 2135 drawImage([[NSGraphicsContext currentContext] graphicsPort], 0); 2136 } 2137 else 2138 { 2139 if (!pixBase) 2140 { 2141# if 0 2142 printf("drawRect: calling updatePix\n"); 2143# endif 2144 assert([self qdPort]); 2145 updatePix(); 2146 } 2147 fullDisplayUpdate(); 2148 } 2149} 2150 2151- (void) viewWillStartLiveResize 2152{ 2153 captureImage(1); 2154 [win setShowsResizeIndicator: YES]; 2155 2156#if (RESIZE_IN_TITLE) 2157 showExtent= 1; 2158 display_winSetName(shortImageName); 2159#endif 2160 pixWidth= 0; 2161 pixHeight= 0; 2162} 2163 2164- (void) viewDidEndLiveResize 2165{ 2166 releaseImage(1); 2167 [win setShowsResizeIndicator: NO]; 2168#if (RESIZE_IN_TITLE) 2169 showExtent= 0; 2170 display_winSetName(shortImageName); 2171#endif 2172 updatePix(); 2173 fullDisplayUpdate(); // gets rid of the resize icon if window didn't resize 2174} 2175 2176 2177- (int) draggingEntered: (id<NSDraggingInfo>)info 2178{ 2179 if ((dragCount == 0) // cannot drag again until previous drag completes 2180 && ([info draggingSourceOperationMask] & NSDragOperationCopy)) 2181 { 2182 int count= [[[info draggingPasteboard] 2183 propertyListForType: NSFilenamesPboardType] count]; 2184 noteMousePoint([info draggingLocation]); 2185 noteDragEvent(DragEnter, dragCount= count); 2186 return NSDragOperationCopy; 2187 } 2188 return NSDragOperationNone; 2189} 2190 2191- (int) draggingUpdated: (id<NSDraggingInfo>)info 2192{ 2193 noteMousePoint([info draggingLocation]); 2194 noteDragEvent(DragMove, dragCount); 2195 return NSDragOperationCopy; 2196} 2197 2198- (void) draggingExited: (id<NSDraggingInfo>)info 2199{ 2200 noteMousePoint([info draggingLocation]); 2201 noteDragEvent(DragLeave, dragCount); 2202 dragCount= 0; 2203} 2204 2205- (BOOL) performDragOperation: (id<NSDraggingInfo>)info 2206{ 2207 NSPasteboard *pboard= [info draggingPasteboard]; 2208 noteMousePoint([info draggingLocation]); 2209 if ([[pboard types] containsObject: NSFilenamesPboardType]) 2210 { 2211 NSArray *files= [pboard propertyListForType: NSFilenamesPboardType]; 2212 int i; 2213 if (uxDropFileCount) 2214 { 2215 assert(uxDropFileNames); 2216 for (i= 0; i < uxDropFileCount; ++i) 2217 free(uxDropFileNames[i]); 2218 free(uxDropFileNames); 2219 uxDropFileNames= 0; 2220 } 2221 if (( (!(uxDropFileCount= [files count]))) 2222 || (!(uxDropFileNames= (char **)malloc(uxDropFileCount * sizeof(char *))))) 2223 { 2224 uxDropFileCount= 0; 2225 return NO; 2226 } 2227 for (i= 0; i < uxDropFileCount; ++i) 2228 uxDropFileNames[i]= strdup([[files objectAtIndex: i] cString]); 2229 } 2230 noteDragEvent(DragDrop, uxDropFileCount); 2231 dragCount= 0; 2232 2233 return YES; // under some duress, I might add (see sqUxDragDrop.c) 2234} 2235 2236 2237enum { KeyMapSize= 32 }; 2238 2239typedef struct 2240{ 2241 int keyCode; 2242 int keyChar; 2243} KeyMapping; 2244 2245static KeyMapping keyMap[KeyMapSize]; 2246 2247static int keyMapSize= 0; 2248static int inputCharCode= -1; 2249 2250static int addToKeyMap(int keyCode, int keyChar) 2251{ 2252 if (keyMapSize > KeyMapSize) { fprintf(stderr, "keymap overflow\n"); return -1; } 2253 keyMap[keyMapSize++]= (KeyMapping){ keyCode, keyChar }; 2254 return keyChar; 2255} 2256 2257static int indexInKeyMap(int keyCode) 2258{ 2259 int i; 2260 for (i= 0; i < keyMapSize; ++i) 2261 if (keyMap[i].keyCode == keyCode) 2262 return i; 2263 return -1; 2264} 2265 2266static int findInKeyMap(int keyCode) 2267{ 2268 int idx= indexInKeyMap(keyCode); 2269 return (idx >= 0) ? keyMap[idx].keyChar : -1; 2270} 2271 2272static int removeFromKeyMap(int keyCode) 2273{ 2274 int idx= indexInKeyMap(keyCode); 2275 int keyChar= -1; 2276 if (idx < 0) { fprintf(stderr, "keymap underflow\n"); return -1; } 2277 keyChar= keyMap[idx].keyChar; 2278 for (; idx < keyMapSize - 1; ++idx) 2279 keyMap[idx]= keyMap[idx + 1]; 2280 --keyMapSize; 2281 return keyChar; 2282} 2283 2284 2285// the following (to @end) must be installed in the first responder 2286 2287- (int) composeKeyDown: (NSEvent *)event 2288{ 2289 int keyCode= [event keyCode]; 2290 inputCharCode= -1; 2291 2292 if (modifierState & CommandKeyBit) 2293 inputCharCode= qz2sqKey(event); 2294 else 2295 { 2296 if ([event isARepeat]) 2297 return findInKeyMap(keyCode); 2298 else 2299 { 2300 [self interpretKeyEvents: [NSArray arrayWithObject: event]]; 2301 if (inputCharCode < 0) 2302 inputCharCode= qz2sqKey(event); 2303 } 2304 } 2305 2306 if (inputCharCode >= 0) 2307 addToKeyMap(keyCode, inputCharCode); 2308 2309 return inputCharCode; 2310} 2311 2312- (int) composeKeyUp: (NSEvent *)event 2313{ 2314 return removeFromKeyMap([event keyCode]); 2315} 2316 2317- (void) insertText: text 2318{ 2319 inputMark= NSMakeRange(NSNotFound, 0); 2320 inputSelection= NSMakeRange(0, 0); 2321 if ([text length]) 2322 { 2323 UInt8 buf[4]; 2324 CFIndex nUsed; 2325 if (CFStringGetBytes((CFStringRef)text, CFRangeMake(0, CFStringGetLength((CFStringRef)text)), 2326 (CFStringEncoding)sqTextEncoding, 0, FALSE, 2327 buf, sizeof(buf), &nUsed)) 2328 inputCharCode= buf[0]; 2329 } 2330} 2331 2332// ParagraphEditor's map looks like this: 2333// 2334// 0 noop cursorHome noop noop cursorEnd noop noop noop 2335// 8 backspace noop noop cursorPageUp cursorPageDown crWithIndent noop noop 2336// 16 noop noop noop noop noop noop noop noop 2337// 24 noop noop noop offerMenuFromEsc cursorLeft cursorRight cursorUp cursorDown 2338// 127 forwardDelete 2339 2340- (void) doCommandBySelector: (SEL)aSelector 2341{ 2342 // why doesn't @selector() reduce to a constant?? 2343# define encode(c, s) if (aSelector == @selector(s)) inputCharCode= c 2344 // my (subjective) approximation of usage frequency... 2345 encode( 8, deleteBackward:); 2346 else encode( 13, insertNewline:); 2347 else encode( 9, insertTab:); 2348 else encode( 28, moveLeft:); 2349 else encode( 29, moveRight:); 2350 else encode( 30, moveUp:); 2351 else encode( 31, moveDown:); 2352 else encode( 11, pageUp:); 2353 else encode( 12, pageDown:); 2354 else encode( 1, moveToBeginningOfDocument:); 2355 else encode( 4, moveToEndOfDocument:); 2356 else encode(127, deleteForward:); 2357 else encode( 27, _cancelKey:); 2358 else 2359 printf("doCommandBySelector: %s\n", sel_getName(aSelector)); 2360# undef encode 2361} 2362 2363- (void) setMarkedText: (id)aString selectedRange: (NSRange)selRange 2364{ 2365 inputMark= NSMakeRange(0, 1); 2366 inputSelection= NSMakeRange(NSNotFound, 0); 2367} 2368 2369- (void) unmarkText { inputMark= NSMakeRange(NSNotFound, 0); } 2370- (BOOL) hasMarkedText { return inputMark.location != NSNotFound; } 2371- (long) conversationIdentifier { return (long)self; } 2372- (NSAttributedString *) attributedSubstringFromRange: (NSRange)theRange { return nil; } 2373- (NSRange) markedRange { return inputMark; } 2374- (NSRange) selectedRange { return inputSelection; } 2375- (NSRect) firstRectForCharacterRange: (NSRange)theRange { return NSMakeRect(0,0, 0,0); } 2376- (unsigned int) characterIndexForPoint: (NSPoint)thePoint { return 0; } 2377- (NSArray *) validAttributesForMarkedText { return nil; } 2378 2379@end // SqueakView 2380 2381 2382 2383/// 2384/// Dialogues for sqUnixMain 2385/// 2386 2387 2388@interface ProgressBar : NSPanel 2389{ 2390 NSText *message; 2391 NSProgressIndicator *indicator; 2392 int value; 2393 NSModalSession session; 2394} 2395+(ProgressBar *) openWithTitle: (NSString *) title message: (NSString *) message; 2396-(void) displayProgressFrom: (int) min to: (int) max during: (void (*)(ProgressBar *)) thunk; 2397-(id) value: (int) value; 2398-(id) setMinValue: (int) value; 2399-(id) setMaxValue: (int) value; 2400-(void) close; 2401@end 2402 2403@implementation ProgressBar 2404 2405-(id) initWithTitle: (NSString *) titleString message: (NSString *) messageString 2406{ 2407 NSSize messageSize; 2408 NSProgressIndicator *ind; 2409 NSText *text; 2410 int inset, y, w; 2411 2412 message= 0; 2413 indicator= 0; 2414 value= 0; 2415 messageSize= (nil == messageString) 2416 ? NSMakeSize(0,0) 2417 : [messageString sizeWithAttributes: nil]; 2418 inset= 10; 2419 y= inset; 2420 w= max(100, messageSize.width + 50); 2421 ind= [[NSProgressIndicator alloc] 2422 initWithFrame: NSMakeRect(inset, y, w, NSProgressIndicatorPreferredThickness)]; 2423 [ind setIndeterminate: NO]; 2424 y += NSProgressIndicatorPreferredThickness + inset; 2425 text= [[NSText alloc] initWithFrame: NSMakeRect(inset, y, w, messageSize.height)]; 2426 [text setString: messageString]; 2427 [text setEditable: NO]; 2428 y += messageSize.height + inset; 2429 if ((self= [super initWithContentRect: NSMakeRect(0, 0, w + inset * 2, y) 2430 styleMask: ((nil == titleString) 2431 ? NSBorderlessWindowMask 2432 : NSTitledWindowMask) 2433 backing: NSBackingStoreBuffered 2434 defer: NO])) 2435 { 2436 [[self contentView] addSubview: (indicator= ind)]; 2437 [[self contentView] addSubview: (message= text)]; 2438 if (nil != titleString) 2439 [self setTitle: titleString]; 2440 session= [NSApp beginModalSessionForWindow: self]; 2441 } 2442 return self; 2443} 2444 2445+(ProgressBar *) openWithTitle: (NSString *) titleString 2446 message: (NSString *) messageString 2447{ 2448 ProgressBar *bar= [[ProgressBar alloc] initWithTitle: titleString message: messageString]; 2449 [bar center]; 2450 [bar makeKeyAndOrderFront: nil]; 2451 return bar; 2452} 2453 2454-(id) setMinValue: (int) min 2455{ 2456 [indicator setMinValue: (double)min]; 2457 return self; 2458} 2459 2460-(id) setMaxValue: (int) max 2461{ 2462 [indicator setMaxValue: (double)max]; 2463 return self; 2464} 2465 2466-(id) value: (int) newValue 2467{ 2468 if (newValue != value) 2469 { 2470 value= newValue; 2471 [indicator setDoubleValue: (double) value]; 2472 [indicator displayIfNeeded]; 2473 [NSApp runModalSession: session]; 2474 } 2475 return self; 2476} 2477 2478-(void) dealloc 2479{ 2480 if (message) [message release]; 2481 if (indicator) [indicator release]; 2482 [super dealloc]; 2483} 2484 2485-(void) close 2486{ 2487 [NSApp endModalSession: session]; 2488 [super close]; 2489 [self release]; 2490} 2491 2492-(void) displayProgressFrom: (int) min to: (int) max during: (void (*)(ProgressBar *)) thunk 2493{ 2494 [indicator setMinValue: (double)min]; 2495 [indicator setMaxValue: (double)max]; 2496 thunk(self); 2497} 2498 2499@end // ProgressBar 2500 2501 2502static int fileCopy(char *src, char *dst) 2503{ 2504 int in, out, r= -1; 2505 struct stat st; 2506 if (stat(src, &st)) return (errno= ENOENT); 2507 if ((in= open(src, O_RDONLY)) < 0) return (errno= ENOENT); 2508 if ((out= open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0755)) >= 0) 2509 { 2510 char *buf; 2511 int done; 2512 ProgressBar *bar= [ProgressBar openWithTitle: @"Writing..." 2513 message: [NSString stringWithCString: dst]]; 2514 [bar setMaxValue: (double)st.st_size]; 2515 buf= (char *)alloca(st.st_blksize); 2516 done= 0; 2517 while ((r= read(in, buf, st.st_blksize)) > 0) 2518 if (r == write(out, buf, r)) 2519 { 2520 done += r; 2521 [bar value: done]; 2522 } 2523 else 2524 { 2525 r= -1; 2526 break; 2527 } 2528 [bar close]; 2529 close(out); 2530 } 2531 close(in); 2532 return (r == 0) ? 0 : errno; 2533} 2534 2535 2536static void copyFile(const char *filename, char *ext, char *source) 2537{ 2538 char dest[MAXPATHLEN], *ptr= 0; 2539 strncpy(dest, filename, sizeof(dest)); 2540 if ((ptr= strrchr(dest, '.'))) 2541 { 2542 strcpy(ptr, ext); 2543 if (fileCopy(source, dest)) 2544 { 2545 perror("FileCopy"); 2546 NSRunCriticalAlertPanel(@"Oops...", 2547 @"I encountered an error while copying the image/changes files. The system told me `%s'. Sorry." 2548 @"Quit", 2549 nil, 2550 nil, 2551 [NSString stringWithCString: strerror(errno)]); 2552 exit(1); 2553 } 2554 } 2555} 2556 2557 2558static void display_winImageNotFound(void) {} 2559 2560 2561static int winCopyOrOpen(void) 2562{ 2563 switch (NSRunAlertPanel(@"Create a new image?", 2564 @"You have started Squeak without specifying an image file. Would you like to create a new image or open an image that you saved earlier?", 2565 @"Open", 2566 @"Cancel", 2567 @"New")) 2568 { 2569 case NSAlertDefaultReturn: return 0; // open 2570 case NSAlertOtherReturn: return 1; // new 2571 default: // cancel or error 2572 exit(0); 2573 } 2574 return 0; 2575} 2576 2577 2578static int winImageCopy(char *buf, int len, char *image, char *changes) 2579{ 2580 NSSavePanel *panel= [NSSavePanel savePanel]; 2581 NSString *home= [NSString stringWithCString: getenv("HOME")]; 2582 int reply; 2583 //xxx release the string 2584 2585 [panel setTitle: @"Where should I save the new image file?"]; 2586 [panel setRequiredFileType: @"image"]; 2587 [panel setFloatingPanel: YES]; 2588 [panel setOneShot: YES]; 2589 [panel setReleasedWhenClosed: YES]; //xxx does the previous imply this??? 2590//[panel setContentSize: NSMakeSize(400, 350)]; 2591 [panel center]; 2592 2593 reply= [panel runModalForDirectory: home file: @"squeak.image"]; 2594//[home release]; 2595 2596 if (NSFileHandlingPanelOKButton == reply) 2597 { 2598 const char *path= [[panel filename] cString]; 2599 copyFile(path, ".image", image); 2600 copyFile(path, ".changes", changes); 2601 strncpy(buf, path, len); 2602 return 1; 2603 } 2604 return 0; 2605} 2606 2607 2608static int winImageOpen(char *buf, int len) 2609{ 2610 NSOpenPanel *panel= [NSOpenPanel openPanel]; 2611 2612 [panel setTitle: @"Which image file should I open?"]; 2613 [panel setFloatingPanel: YES]; 2614 [panel setOneShot: YES]; 2615 [panel setReleasedWhenClosed: YES]; //xxx does the previous imply this??? 2616//[panel setContentSize: NSMakeSize(400, 350)]; 2617 [panel center]; 2618 2619 if (NSOKButton == [panel runModalForTypes: [NSArray arrayWithObject: @"image"]]) 2620 { 2621 NSArray *files= [panel filenames]; 2622 if (1 == [files count]) 2623 { 2624 strncpy(buf, [[files objectAtIndex: 0] cString], len); 2625 return 1; 2626 } 2627 } 2628 return 0; 2629} 2630 2631 2632static int display_winImageFind(char *buf, int len) 2633{ 2634 if (documentName) 2635 { 2636 strncpy(buf, documentName, len); 2637 free(documentName); 2638 documentName= 0; 2639 return 1; 2640 } 2641 else 2642 { 2643 char image[MAXPATHLEN], changes[MAXPATHLEN]; 2644 strlcat(strncpy(image, resourcePath, sizeof(image)), 2645 "squeak.image", 2646 sizeof(image)); 2647 strlcat(strncpy(changes, resourcePath, sizeof(changes)), 2648 "squeak.changes", 2649 sizeof(changes)); 2650 return (( (0 == access(image, R_OK))) 2651 && (0 == access(changes, R_OK)) 2652 && winCopyOrOpen()) 2653 ? winImageCopy(buf, len, image, changes) 2654 : winImageOpen(buf, len); 2655 } 2656 return 0; 2657} 2658 2659 2660static sqInt display_primitivePluginBrowserReady(void) { return primitiveFail(); } 2661static sqInt display_primitivePluginRequestURLStream(void) { return primitiveFail(); } 2662static sqInt display_primitivePluginRequestURL(void) { return primitiveFail(); } 2663static sqInt display_primitivePluginPostURL(void) { return primitiveFail(); } 2664static sqInt display_primitivePluginRequestFileHandle(void) { return primitiveFail(); } 2665static sqInt display_primitivePluginDestroyRequest(void) { return primitiveFail(); } 2666static sqInt display_primitivePluginRequestState(void) { return primitiveFail(); } 2667 2668 2669/// 2670/// OpenGL stuff 2671/// 2672 2673 2674#include <OpenGL/OpenGL.h> 2675 2676#include "B3DAcceleratorPlugin.h" 2677#include "sqOpenGLRenderer.h" 2678#include "sqUnixQuartzGL.h" 2679 2680#define renderView(R) (assert(R), (NSOpenGLView *)((R)->drawable)) 2681#define renderContext(R) (assert(R), (NSOpenGLContext *)((R)->context)) 2682 2683static glRenderer *renderers[MAX_RENDERER]; 2684 2685static sqInt display_ioGLinitialise(void) 2686{ 2687 int i; 2688 for (i= 0; i < MAX_RENDERER; ++i) 2689 renderers[i]= 0; 2690 glActive= 0; 2691 return 1; 2692} 2693 2694static void addRenderer(glRenderer *r) 2695{ 2696 int i; 2697 for (i= 0; i < MAX_RENDERER; ++i) 2698 if (!renderers[i]) 2699 { 2700 renderers[i]= r; 2701 ++glActive; 2702 return; 2703 } 2704 assert(!"this cannot happen"); 2705} 2706 2707static void removeRenderer(glRenderer *r) 2708{ 2709 int i; 2710 for (i= 0; i < MAX_RENDERER; ++i) 2711 if (renderers[i] == r) 2712 { 2713 renderers[i]= 0; 2714 --glActive; 2715 return; 2716 } 2717 assert(!"this cannot happen"); 2718} 2719 2720// fix dumb inverted coordinates after window geometry change 2721 2722static void reframeRenderer(glRenderer *r) 2723{ 2724 NSRect frame= NSMakeRect(r->bufferRect[0], r->bufferRect[1], 2725 r->bufferRect[2], r->bufferRect[3]); 2726 frame.origin.y= [topView bounds].size.height - frame.size.height - frame.origin.y; 2727 [renderView(r) removeFromSuperview]; 2728 [renderView(r) setFrame: frame]; 2729 [topView addSubview: renderView(r)]; 2730} 2731 2732static void reframeRenderers(void) 2733{ 2734 int i; 2735 for (i= 0; i < MAX_RENDERER; ++i) 2736 if (renderers[i]) 2737 reframeRenderer(renderers[i]); 2738} 2739 2740#if 0 2741 2742static void updateRenderer(glRenderer *r) 2743{ 2744 [[renderView(r) openGLContext] makeCurrentContext]; 2745} 2746 2747static void updateRenderers(void) 2748{ 2749 int i; 2750 for (i= 0; i < MAX_RENDERER; ++i) 2751 if (renderers[i]) 2752 updateRenderer(renderers[i]); 2753} 2754 2755#endif 2756 2757 2758static sqInt display_ioGLcreateRenderer(glRenderer *r, sqInt x, sqInt y, sqInt w, sqInt h, sqInt flags) 2759{ 2760 long swapInterval; 2761 NSOpenGLView *drawable; 2762 NSOpenGLPixelFormatAttribute attrs[]= 2763 { 2764 NSOpenGLPFANoRecovery, 2765 NSOpenGLPFAWindow, 2766 NSOpenGLPFAAccelerated, 2767 NSOpenGLPFADoubleBuffer, 2768 //NSOpenGLPFAColorSize, 16, //24 2769 NSOpenGLPFAAlphaSize, 8, //8 2770 NSOpenGLPFADepthSize, 24, //16 2771 NSOpenGLPFAStencilSize, ((flags & B3D_STENCIL_BUFFER) ? 8 : 0), 2772 NSOpenGLPFAAccumSize, 0, 2773 0 2774 }; 2775 NSOpenGLPixelFormat *fmt= [[NSOpenGLPixelFormat alloc] initWithAttributes: attrs]; 2776 if (!fmt) 2777 { 2778 fprintf(stderr, "ioGLcreateRenderer: illegal pixel format\n"); 2779 return 0; 2780 } 2781 2782 if (verboseLevel >= 3) 2783 printFormatInfo(fmt); 2784 2785 drawable= [[NSOpenGLView alloc] 2786 initWithFrame: NSMakeRect(x, [topView bounds].size.height - h - y, w, h) 2787 pixelFormat: fmt]; 2788 [fmt release]; 2789 if (!drawable) 2790 { 2791 fprintf(stderr, "ioGLcreateRenderer: could not create view\n"); 2792 return 0; 2793 } 2794 r->drawable= drawable; 2795 r->context= [drawable openGLContext]; 2796 addRenderer(r); 2797 2798 swapInterval= 0; 2799 2800 [renderContext(r) setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; 2801 [topView addSubview: drawable]; 2802 2803 return 1; 2804 2805 (void)glErrString; // declared static in sqOpenGLRenderer.h, but never used 2806} 2807 2808 2809static sqInt display_ioGLmakeCurrentRenderer(glRenderer *r) 2810{ 2811 if (r) 2812 { 2813 assert(r->context); 2814 [renderContext(r) makeCurrentContext]; 2815 } 2816 else 2817 [NSOpenGLContext clearCurrentContext]; 2818 2819 return 1; 2820} 2821 2822 2823static void display_ioGLdestroyRenderer(glRenderer *r) 2824{ 2825 [NSOpenGLContext clearCurrentContext]; 2826 assert(r->drawable); 2827 [renderView(r) removeFromSuperview]; 2828 [renderView(r) release]; 2829 removeRenderer(r); 2830} 2831 2832 2833static void display_ioGLswapBuffers(glRenderer *r) 2834{ 2835 assert(r->context); 2836 [renderContext(r) flushBuffer]; 2837} 2838 2839 2840static void display_ioGLsetBufferRect(glRenderer *r, sqInt x, sqInt y, sqInt w, sqInt h) 2841{ 2842 NSRect frame= NSMakeRect(x, y, w, h); 2843 fprintf(stderr, "ioGLsetBufferRect(%p, %d, %d, %d, %d)\n", r->context, x, y, w, h); 2844 assert(r->context); 2845 frame.origin.y= [topView bounds].size.height - frame.size.height - frame.origin.y; 2846 fprintf(stderr, "view setFrame: %d %d %d %d\n", 2847 (int)frame.origin.x, (int)frame.origin.y, (int)frame.size.width, (int)frame.size.height); 2848 [renderView(r) setFrame: frame]; 2849} 2850 2851// 2852// Host Window support 2853// 2854 2855#if (SqDisplayVersionMajor >= 1 && SqDisplayVersionMinor >= 2) 2856static int display_hostWindowClose(int index) { return 0; } 2857static int display_hostWindowCreate(int w, int h, int x, int y, 2858 char *list, int attributeListLength) { return 0; } 2859static int display_hostWindowShowDisplay(unsigned *dispBitsIndex, int width, int height, int depth, 2860 int affectedL, int affectedR, int affectedT, int affectedB, int windowIndex) { return 0; } 2861static int display_hostWindowGetSize(int windowIndex) { return -1; } 2862static int display_hostWindowSetSize(int windowIndex, int w, int h) { return -1; } 2863static int display_hostWindowGetPosition(int windowIndex) { return -1; } 2864static int display_hostWindowSetPosition(int windowIndex, int x, int y) { return -1; } 2865static int display_hostWindowSetTitle(int windowIndex, char *newTitle, int sizeOfTitle) { return -1; } 2866static int display_hostWindowCloseAll(void) { return 0; } 2867#endif 2868 2869 2870SqDisplayDefine(Quartz); 2871 2872 2873#include "SqModule.h" 2874 2875static void *display_makeInterface(void) 2876{ 2877 return &display_Quartz_itf; 2878} 2879 2880SqModuleDefine(display, Quartz); 2881