1/* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */ 2 3#import <UIKit/UIKit.h> 4 5#include "ui_window.h" 6#include "ui_scrollbar.h" 7 8#include <pobl/bl_privilege.h> 9#include <pobl/bl_unistd.h> /* bl_getuid/bl_getgid */ 10#include <pobl/bl_mem.h> 11#include <pobl/bl_str.h> /* bl_compare_str */ 12#include "../ui_screen_manager.h" 13#include "../ui_event_source.h" 14#include "../ui_selection_encoding.h" 15 16@interface Application : UIApplication 17@end 18 19@interface AppDelegate : NSObject <UIApplicationDelegate> { 20 UIWindow *window; 21} 22 23@property (nonatomic, retain) IBOutlet UIWindow *window; 24@end 25 26@interface TextPosition : UITextPosition { 27 int position; 28} 29@property (nonatomic) int position; 30@end 31 32@interface TextRange : UITextRange { 33 TextPosition *start; 34 TextPosition *end; 35} 36@property (nonatomic, readonly) UITextPosition *start; 37@property (nonatomic, readonly) UITextPosition *end; 38@end 39 40@interface MLTermView : UIView<UITextInput> { 41 ui_window_t *uiwindow; 42 CGContextRef ctx; 43 CGLayerRef layer; 44 int forceExpose; /* 2 = visual bell */ 45 46 BOOL ignoreKeyDown; 47 NSString *markedText; 48 TextRange *selectedTextRange; 49 TextRange *markedTextRange; 50 51 int cand_x; 52 int cand_y; 53 54 NSArray *cmds; 55} 56 57@property (readwrite, copy) UITextRange *selectedTextRange; 58@property (nonatomic, readonly) UITextRange *markedTextRange; 59 60- (void)drawString:(ui_font_t *)font 61 :(ui_color_t *)fg_color 62 :(int)x 63 :(int)y 64 :(u_char *)str 65 :(size_t)len; 66- (void)drawString16:(ui_font_t *)font 67 :(ui_color_t *)fg_color 68 :(int)x 69 :(int)y 70 :(XChar2b *)str 71 :(size_t)len; 72- (void)fillWith:(ui_color_t *)color:(int)x:(int)y:(u_int)width:(u_int)height; 73- (void)drawRectFrame:(ui_color_t *)color:(int)x1:(int)y1:(int)x2:(int)y2; 74- (void)copyArea:(Pixmap)src 75 :(int)src_x 76 :(int)src_y 77 :(u_int)width 78 :(u_int)height 79 :(int)dst_x 80 :(int)dst_y; 81#if 0 82- (void)scroll:(int)src_x:(int)src_y:(u_int)width:(u_int)height:(int)dst_x:(int)dst_y; 83#endif 84- (void)setClip:(int)x:(int)y:(u_int)width:(u_int)height; 85- (void)unsetClip; 86- (void)update:(int)flag; 87- (void)bgColorChanged; 88@end 89 90/* --- static variables --- */ 91 92static ui_window_t *uiwindow_for_mlterm_view; 93static int keyboard_margin; 94 95static u_int key_code; 96static u_int key_mod; 97 98/* --- static functions --- */ 99 100#define set_fill_color(color) \ 101 CGContextSetRGBFillColor(ctx, (((color)->pixel >> 16) & 0xff) / 255.0, \ 102 (((color)->pixel >> 8) & 0xff) / 255.0, \ 103 ((color)->pixel & 0xff) / 255.0, 1.0); 104 105#if 0 106#define IS_OPAQUE \ 107 ((uiwindow->bg_color.pixel & 0xff000000) == 0xff000000 || \ 108 ui_window_has_wall_picture(uiwindow)) 109#else 110#define IS_OPAQUE 1 111#endif 112 113#ifdef DEBUG 114int main_loop_final(void); 115#endif 116 117static void exit_program(void) { 118#ifdef DEBUG 119 main_loop_final(); 120 bl_alloca_garbage_collect(); 121 bl_mem_free_all(); 122 bl_dl_close_all(); 123#endif 124} 125 126static void monitor_pty(void) { 127#if 0 128 /* normal user (Don't call before UIApplicationMain()) */ 129 bl_priv_change_euid(bl_getuid()); 130 bl_priv_change_egid(bl_getgid()); 131#endif 132 133 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 134 ui_event_source_process(); 135 }); 136} 137 138/* Undocumented */ 139bool CGFontGetGlyphsForUnichars(CGFontRef, unichar[], CGGlyph[], size_t); 140 141static void drawUnistr(CGContextRef ctx, ui_font_t *font, unichar *str, 142 u_int len, int x, int y) { 143 CGGlyph glyphs_buf[len]; 144 CGGlyph *glyphs; 145 146#ifdef USE_OT_LAYOUT 147 if (font->use_ot_layout /* && font->otf */) { 148 glyphs = str; 149 } else 150#endif 151 { 152 glyphs = memset(glyphs_buf, 0, sizeof(CGGlyph) * len); 153 CGFontGetGlyphsForUnichars(font->xfont->cg_font, str, glyphs_buf, len); 154 155 for (; len > 0 && glyphs[len - 1] == 0; len--) ; 156 } 157 158 CGContextSetFont(ctx, font->xfont->cg_font); 159 160 CGAffineTransform t; 161 162 if (font->xfont->is_italic) { 163 CGFloat f = -tanf(-12.0 * acosf(0) / 90); 164 t = CGAffineTransformMake(1.0, 0.0, f, 1.0, -y * f, 0.0); 165 } else { 166 t = CGAffineTransformIdentity; 167 } 168 169 u_int width = font->width; 170 171 u_int fontsize = font->xfont->size; 172 switch (font->size_attr) { 173 case DOUBLE_WIDTH: 174 width /= 2; 175 x = (x + 1) / 2; 176 t = CGAffineTransformScale(t, 2.0, 1.0); 177 break; 178 179 case DOUBLE_HEIGHT_TOP: 180 case DOUBLE_HEIGHT_BOTTOM: 181 fontsize *= 2; 182 break; 183 } 184 185 CGContextSetTextMatrix(ctx, t); 186 187 CGPoint points[len]; 188 189 if (font->is_proportional) { 190 int advances[len]; 191 if (!CGFontGetGlyphAdvances(font->xfont->cg_font, glyphs, len, advances)) { 192 return; 193 } 194 195 int units = CGFontGetUnitsPerEm(font->xfont->cg_font); 196 int cur_x = x; 197 u_int count; 198 for (count = 0; count < len; count++) { 199 points[count] = CGPointMake(cur_x, y); 200 201 if (advances[count] > 0) { 202 cur_x += (advances[count] * fontsize / units); 203 } 204 } 205 } else { 206 u_int count; 207 208 x += font->x_off; 209 210 for (count = 0; count < len; count++) { 211 points[count] = CGPointMake((x + width * count), y); 212 } 213 } 214 215 CGContextSetFontSize(ctx, fontsize); 216 217 CGContextShowGlyphsAtPositions(ctx, glyphs, points, len); 218 219 if (font->double_draw_gap) { 220 int gap = font->double_draw_gap; 221 222 font->double_draw_gap = 0; 223 drawUnistr(ctx, font, str, len, x + font->double_draw_gap, y); 224 font->double_draw_gap = gap; 225 } 226} 227 228static void update_ime_text(ui_window_t *uiwindow, const char *preedit_text, 229 const char *cur_preedit_text) { 230 (*uiwindow->preedit)(uiwindow, preedit_text, cur_preedit_text); 231} 232 233static void show_dialog(const char *msg) { 234 if (![NSThread isMainThread]) { 235 return; 236 } 237 238 NSString *ns_msg = [NSString stringWithCString:msg encoding:NSUTF8StringEncoding]; 239 240 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" 241 message:ns_msg 242 delegate:nil 243 cancelButtonTitle:nil 244 otherButtonTitles:@"OK", nil]; 245 [alert autorelease]; 246 [alert show]; /* XXX This doesn't stop. */ 247} 248 249static ui_window_t *search_focused_window(ui_window_t *win) { 250 u_int count; 251 ui_window_t *focused; 252 253 /* 254 * *parent* - *child* 255 * ^^^^^^^ => Hit this window instead of the parent window. 256 * - child 257 * - child 258 * (**: is_focused == 1) 259 */ 260 for (count = 0; count < win->num_children; count++) { 261 if ((focused = search_focused_window(win->children[count]))) { 262 return focused; 263 } 264 } 265 266 if (win->is_focused) { 267 return win; 268 } 269 270 return NULL; 271} 272 273/* --- class --- */ 274 275int cocoa_dialog_alert(const char *msg); 276 277@implementation Application 278 279- (void)sendEvent:(UIEvent *)event { 280 [super sendEvent:event]; 281 282 if ([event respondsToSelector:@selector(_gsEvent)]) { 283 u_int32_t *buf = [event performSelector:@selector(_gsEvent)]; 284 285 if (buf && buf[2] == 10 /* Event type */) { 286 u_int num; 287 ui_display_t **disps = ui_get_opened_displays(&num); 288 ui_window_t *win = search_focused_window(disps[0]->roots[0]); 289 290 if (win) { 291 MLTermView *view = win->my_window; 292 293 if (![view hasText]) { 294 key_mod = buf[12]; 295 key_code = (buf[15] >> 16) & 0xffff; 296 [self sendAction:@selector(keyEvent) to:view from:nil forEvent:nil]; 297 } 298 } 299 } 300 } 301} 302 303@end 304 305@implementation AppDelegate 306 307@synthesize window; 308 309#pragma mark - 310#pragma mark Application lifecycle 311 312- (BOOL)application:(UIApplication *)application 313 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 314 self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 315 [self.window makeKeyAndVisible]; 316 317 [[NSNotificationCenter defaultCenter] addObserver:self 318 selector:@selector(keyboardDidShow:) 319 name:UIKeyboardDidShowNotification 320 object:nil]; 321 [[NSNotificationCenter defaultCenter] addObserver:self 322 selector:@selector(keyboardDidHide:) 323 name:UIKeyboardDidHideNotification 324 object:nil]; 325 326 CGRect r = [self.window screen].applicationFrame; 327 MLTermView *view = [[MLTermView alloc] initWithFrame:CGRectMake(0, 0, 328 r.size.width, r.size.height)]; 329 [self.window addSubview:view]; 330 [self.window makeKeyAndVisible]; 331 332 return YES; 333} 334 335- (void)keyboardDidShow:(NSNotification *)note { 336 CGRect r = [[[note userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; 337 keyboard_margin = r.size.height; 338 self.window.frame = self.window.frame; /* call observeValueForKeyPath */ 339} 340 341- (void)keyboardDidHide:(NSNotification *)note { 342 keyboard_margin = 0; 343 self.window.frame = self.window.frame; 344} 345 346- (void)applicationWillResignActive:(UIApplication *)application { 347} 348 349 350- (void)applicationDidEnterBackground:(UIApplication *)application { 351} 352 353 354- (void)applicationWillEnterForeground:(UIApplication *)application { 355} 356 357 358- (void)applicationDidBecomeActive:(UIApplication *)application { 359} 360 361 362- (void)applicationWillTerminate:(UIApplication *)application { 363} 364 365#pragma mark - 366#pragma mark Memory management 367 368- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { 369} 370 371- (void)dealloc { 372 [[NSNotificationCenter defaultCenter] removeObserver:self]; 373 exit_program(); 374 [super dealloc]; 375} 376 377@end 378 379@implementation TextPosition 380@synthesize position; 381@end 382 383@implementation TextRange 384@synthesize start; 385@synthesize end; 386 387- (id)init { 388 [super init]; 389 390 start = [TextPosition alloc]; 391 end = [TextPosition alloc]; 392 393 return self; 394} 395 396- (void)dealloc { 397 [super dealloc]; 398 399 [start release]; 400 [end release]; 401} 402@end 403 404@implementation MLTermView 405 406@synthesize selectedTextRange; 407@synthesize markedTextRange; 408@synthesize tokenizer; 409@synthesize inputDelegate; 410@synthesize endOfDocument; 411@synthesize beginningOfDocument; 412@synthesize markedTextStyle; 413 414- (id)initWithFrame:(CGRect)frame { 415 if (uiwindow_for_mlterm_view) { 416 uiwindow = uiwindow_for_mlterm_view; 417 } else { 418 char args[] = "mlclient"; 419 ui_mlclient(args, NULL); 420 421 ui_screen_t **screens; 422 u_int num = ui_get_all_screens(&screens); 423 if (num == 0) { 424 cocoa_dialog_alert("Failed to open screen"); 425 exit(1); 426 } 427 428 uiwindow = &screens[num - 1]->window; 429 } 430 431 uiwindow->my_window = (UIView *)self; 432 forceExpose = 1; 433 434 self.clearsContextBeforeDrawing = NO; 435 436 [super initWithFrame:frame]; 437 438 ignoreKeyDown = FALSE; 439 markedText = nil; 440 markedTextRange = [UITextRange alloc]; 441 selectedTextRange = [UITextRange alloc]; 442 443 UILongPressGestureRecognizer *longpress = 444 [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)]; 445 longpress.minimumPressDuration = 2.0; 446 [longpress autorelease]; 447 [self addGestureRecognizer:longpress]; 448 449 if (uiwindow_for_mlterm_view) { 450 uiwindow_for_mlterm_view = NULL; 451 } 452 453 static int app_init; 454 if (!app_init) { 455 app_init = 1; 456 monitor_pty(); 457 } 458 459 return self; 460} 461 462- (void)dealloc { 463 [[NSNotificationCenter defaultCenter] removeObserver:self]; 464 [self.window removeObserver:self forKeyPath:@"frame"]; 465 466 [markedTextRange release]; 467 [selectedTextRange release]; 468 469 if (layer) { 470 CGLayerRelease(layer); 471 layer = nil; 472 } 473 474 if (cmds) { 475 [cmds release]; 476 } 477 478 [super dealloc]; 479} 480 481- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { 482 if (action == @selector(configMenu:) || action == @selector(pasteMenu:) || 483 action == @selector(keyEvent:)) { 484 return YES; 485 } else { 486 return NO; 487 } 488} 489 490- (void)configMenu:(id)sender { 491 cocoa_dialog_alert("Configuration menu is not supported."); 492} 493 494- (void)pasteMenu:(id)sender { 495 /* if by any change */ 496 if (((ui_screen_t *)uiwindow)->term) { 497 ui_screen_exec_cmd((ui_screen_t *)uiwindow, "paste"); 498 } 499} 500 501- (void)setFrame:(CGRect)r { 502 if (layer) { 503 CGLayerRelease(layer); 504 layer = nil; 505 } 506 507 CGRect sr = [self.window screen].applicationFrame; 508 509 r.origin.x += sr.origin.x; 510 r.origin.y += sr.origin.y; 511 512#if 0 513 NSLog(@"setFrame %@ %f %f %f %f", self, r.origin.x, r.origin.y, r.size.width, r.size.height); 514#endif 515 516 [super setFrame:r]; 517} 518 519- (void)windowResized { 520 if (!uiwindow->parent || !((ui_screen_t *)uiwindow)->term) { 521 /* It has been already removed from ui_layout or term has been detached. */ 522 return; 523 } 524 525 CGRect sr = [self.window screen].applicationFrame; 526 527 uiwindow->parent->width = sr.size.width - uiwindow->parent->hmargin * 2; 528 uiwindow->parent->height = sr.size.height - uiwindow->parent->vmargin * 2 - keyboard_margin; 529 530 (*uiwindow->parent->window_resized)(uiwindow->parent); 531 532 u_int count; 533 for (count = 0; count < uiwindow->num_children; count++) { 534 ui_window_t *child = uiwindow->children[count]; 535 536 if (child->my_window) { 537 [((UIView *)child->my_window) setFrame:CGRectMake(child->x, child->y, 538 ACTUAL_WIDTH(child), ACTUAL_HEIGHT(child))]; 539 } 540 } 541} 542 543- (void)observeValueForKeyPath:(NSString *)keyPath 544 ofObject:(id)object 545 change:(NSDictionary *)change 546 context:(void *)context { 547 [self windowResized]; 548} 549 550- (void)didMoveToWindow { 551 if ([self window] == nil) { 552 /* just before being deallocated */ 553 return; 554 } 555 556#if 0 557 if (!uiwindow->parent->my_window) { 558 [[self window] orderOut:self]; 559 560 if (uiwindow->event_mask & PointerMotionMask) { 561 [self window].acceptsMouseMovedEvents = YES; 562 } 563 } 564#endif 565 566 [self.window addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew 567 context:nil]; 568 569 /* Change view size */ 570 571 if (!uiwindow->parent->my_window) { 572 CGRect sr = [self.window screen].applicationFrame; 573 574 uiwindow->disp->width = sr.size.width; 575 uiwindow->disp->height = sr.size.height; 576 577#if 0 578 [[self window] useOptimizedDrawing:YES]; 579#endif 580 581 uiwindow->parent->my_window = [self window]; 582 583 if (!IS_OPAQUE) { 584 [self bgColorChanged]; 585 } 586 587 /* XXX TODO: Support color change */ 588 u_long pixel = uiwindow->fg_color.pixel; /* See window_exposed() in ui_layout.c */ 589 self.window.backgroundColor = [UIColor colorWithRed:((pixel >> 16) & 0xff) / 255.0 590 green:((pixel >> 8) & 0xff) / 255.0 591 blue:(pixel & 0xff) / 255.0 592 alpha:((pixel >> 24) & 0xff) / 255.0]; 593 } 594 595 [self windowResized]; 596 [self becomeFirstResponder]; 597} 598 599- (void)drawRect:(CGRect)rect { 600 if (!uiwindow->parent || !((ui_screen_t *)uiwindow)->term) { 601 /* It has been already removed from ui_layout or term has been detached. */ 602 return; 603 } 604 605 XExposeEvent ev; 606 607 CGContextRef screen_ctx = UIGraphicsGetCurrentContext(); 608 CGContextSaveGState(screen_ctx); 609 CGContextTranslateCTM(screen_ctx, 0.0, self.bounds.size.height); 610 CGContextScaleCTM(screen_ctx, 1.0, -1.0); 611 CGContextSetBlendMode(screen_ctx, kCGBlendModeCopy); 612 613#if 0 614 CGAffineTransform t = CGContextGetCTM(ctx); 615 bl_debug_printf("%f %f %f %f %f %f\n", t.a, t.b, t.c, t.d, t.tx, t.ty); 616#endif 617 618 if (!layer) { 619 layer = CGLayerCreateWithContext(screen_ctx, self.bounds.size, NULL); 620 ctx = CGLayerGetContext(layer); 621 CGContextSetBlendMode(ctx, kCGBlendModeCopy); 622 623 if (uiwindow->update_window_flag == 0) { 624 uiwindow->update_window_flag = 3; /* UPDATE_SCREEN|UPDATE_CURSOR (ui_screen.c) */ 625 } 626 forceExpose = 1; 627 } 628 629 CGPoint p = CGPointMake(0, 0); 630 631 if (forceExpose & 2) { 632 /* Visual bell */ 633 [self fillWith:&uiwindow->fg_color 634 :uiwindow->hmargin 635 :uiwindow->vmargin 636 :uiwindow->width 637 :uiwindow->height]; 638 CGContextFlush(ctx); 639 CGContextDrawLayerAtPoint(screen_ctx, p, layer); 640 641 [[NSRunLoop currentRunLoop] 642 runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 643 644 forceExpose &= ~2; 645 uiwindow->update_window_flag = 0; 646 } 647 648 ev.type = UI_EXPOSE; 649 ev.x = rect.origin.x; 650 ev.width = rect.size.width; 651 ev.height = rect.size.height; 652 ev.y = ACTUAL_HEIGHT(uiwindow) - rect.origin.y - ev.height; 653 ev.force_expose = forceExpose; 654 655 ui_window_receive_event(uiwindow, (XEvent *)&ev); 656 657 forceExpose = 0; 658 uiwindow->update_window_flag = 0; 659 660 CGContextDrawLayerAtPoint(screen_ctx, p, layer); 661 662 CGContextRestoreGState(screen_ctx); 663} 664 665- (BOOL)isOpaque { 666 return IS_OPAQUE ? YES : NO; 667} 668 669- (BOOL)wantsDefaultClipping { 670 return IS_OPAQUE ? YES : NO; 671} 672 673static ui_window_t *get_current_window(ui_window_t *win) { 674 u_int count; 675 676 if (win->inputtable > 0) { 677 return win; 678 } 679 680 for (count = 0; count < win->num_children; count++) { 681 ui_window_t *hit; 682 683 if ((hit = get_current_window(win->children[count]))) { 684 return hit; 685 } 686 } 687 688 return NULL; 689} 690 691- (BOOL)acceptsFirstResponder { 692 return YES; 693} 694 695- (BOOL)becomeFirstResponder { 696 if ([super becomeFirstResponder] != YES) { 697 return NO; 698 } 699 700 [self.window bringSubviewToFront:self]; 701 702 XEvent ev; 703 ev.type = UI_KEY_FOCUS_IN; 704 705 ui_window_receive_event(uiwindow, &ev); 706 707 return YES; 708} 709 710- (BOOL)canBecomeFirstResponder { 711 return YES; 712} 713 714- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 715 UITouch *touch = [touches anyObject]; 716 CGPoint loc = [touch locationInView:self]; 717 718 XButtonEvent bev; 719 bev.type = UI_BUTTON_PRESS; 720 bev.time = touch.timestamp * 1000; 721 bev.x = loc.x; 722 bev.y = loc.y; 723 bev.state = 0; 724 bev.button = 1; 725 bev.click_count = touch.tapCount; 726 727 ui_window_receive_event(uiwindow, (XEvent *)&bev); 728 729 if (!uiwindow->is_focused || keyboard_margin == 0) { 730 [self becomeFirstResponder]; 731 } 732} 733 734- (void)longPress:(id)sender { 735 UIMenuController *menuctl = [UIMenuController sharedMenuController]; 736 CGPoint loc = [sender locationOfTouch:0 inView:self]; 737 [menuctl setTargetRect:CGRectMake(loc.x, loc.y, 0, 0) inView:self]; 738 menuctl.arrowDirection = UIMenuControllerArrowDown; 739 740 NSMutableArray *items = [NSMutableArray array]; 741 UIMenuItem *item; 742 item = [[[UIMenuItem alloc] initWithTitle:@"Paste" action:@selector(pasteMenu:)] autorelease]; 743 [items addObject:item]; 744 item = [[[UIMenuItem alloc] initWithTitle:@"Config" action:@selector(configMenu:)] autorelease]; 745 [items addObject:item]; 746 menuctl.menuItems = items; 747 [menuctl setMenuVisible:NO animated:NO]; 748 [menuctl setMenuVisible:YES animated:YES]; 749} 750 751- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 752 UITouch *touch = [touches anyObject]; 753 CGPoint loc = [touch locationInView:self]; 754 755 XButtonEvent bev; 756 bev.type = UI_BUTTON_RELEASE; 757 bev.time = touch.timestamp * 1000; 758 bev.x = loc.x; 759 bev.y = loc.y; 760 bev.state = 0; 761 bev.button = 1; 762 bev.click_count = touch.tapCount; 763 764 ui_window_receive_event(uiwindow, (XEvent *)&bev); 765} 766 767- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 768 UITouch *touch = [touches anyObject]; 769 CGPoint loc = [touch locationInView:self]; 770 771 XMotionEvent mev; 772 mev.type = UI_BUTTON_MOTION; 773 mev.time = touch.timestamp * 1000; 774 mev.x = loc.x; 775 mev.y = loc.y; 776 mev.state = Button1Mask; 777 778 ui_window_receive_event(uiwindow, (XEvent *)&mev); 779} 780 781#if 0 782- (void)scrollWheel:(NSEvent *)event { 783 NSPoint loc = [event locationInWindow]; 784 XButtonEvent bevPress; 785 XButtonEvent bevRelease; 786 787 bevPress.type = UI_BUTTON_PRESS; 788 bevRelease.type = UI_BUTTON_RELEASE; 789 790 bevPress.time = event.timestamp * 1000; 791 bevRelease.time = (event.timestamp * 1000) + 1; 792 793 bevPress.x = loc.x - self.frame.origin.x; 794 bevRelease.x = loc.x - self.frame.origin.x; 795 796 bevPress.y = 797 ACTUAL_HEIGHT(uiwindow->parent) - loc.y - /* self.frame.origin.y - */ 1; 798 bevRelease.y = 799 ACTUAL_HEIGHT(uiwindow->parent) - loc.y - /* self.frame.origin.y - */ 1; 800 801 bevPress.state = event.modifierFlags & 802 (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask); 803 bevRelease.state = event.modifierFlags & 804 (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask); 805 806 bevPress.click_count = 1; 807 808 if (event.deltaY > 1) { 809 bevPress.button = 4; 810 bevRelease.button = 4; 811 } 812 813 if (event.deltaY < -1) { 814 bevPress.button = 5; 815 bevRelease.button = 5; 816 } 817 818 if (event.deltaY < -1 || event.deltaY > 1) { 819 ui_window_receive_event(uiwindow, (XEvent *)&bevPress); 820 ui_window_receive_event(uiwindow, (XEvent *)&bevRelease); 821 } 822} 823#endif 824 825- (void)keyEvent { 826 XKeyEvent kev; 827 828#if 0 829 NSLog(@"Key event: mod %x keycode %x", key_mod, key_code); 830#endif 831 832 if (0xf700 <= key_code && key_code <= 0xf8ff) { 833 /* do nothing (Function keys) */ 834 } else if (key_code == 0x1b) { 835 /* do nothing */ 836 } else if ((key_mod & NSControlKeyMask) || (key_mod & NSCommandKeyMask)) { 837 if ('a' <= key_code && key_code <= 'z') { 838 key_code -= 0x60; 839 } else if (0x40 <= key_code && key_code < 0x60) { 840 key_code -= 0x40; 841 } else { 842 return; 843 } 844 } else { 845 return; 846 } 847 848 kev.type = UI_KEY_PRESS; 849 kev.state = key_mod; 850 kev.keysym = key_code; 851 kev.utf8 = NULL; 852 ui_window_receive_event(uiwindow, (XEvent *)&kev); 853} 854 855#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 /* iOS 7.0 or later */ 856- (NSArray *)keyCommands { 857 if (!cmds) { 858 UIKeyModifierFlags flags[] = { 859 0, 860 UIKeyModifierShift, 861 UIKeyModifierShift | UIKeyModifierControl, 862 UIKeyModifierShift | UIKeyModifierAlternate, 863 UIKeyModifierShift | UIKeyModifierCommand, 864 UIKeyModifierShift | UIKeyModifierControl | UIKeyModifierAlternate, 865 UIKeyModifierShift | UIKeyModifierControl | UIKeyModifierAlternate | UIKeyModifierCommand, 866 UIKeyModifierShift | UIKeyModifierControl | UIKeyModifierCommand, 867 UIKeyModifierShift | UIKeyModifierAlternate | UIKeyModifierCommand, 868 UIKeyModifierShift | UIKeyModifierCommand, 869 UIKeyModifierControl, 870 UIKeyModifierControl | UIKeyModifierAlternate, 871 UIKeyModifierControl | UIKeyModifierAlternate | UIKeyModifierCommand, 872 UIKeyModifierControl | UIKeyModifierCommand, 873 UIKeyModifierAlternate, 874 UIKeyModifierAlternate | UIKeyModifierCommand, 875 UIKeyModifierCommand }; 876 NSMutableArray *mutable = [[NSMutableArray alloc] init]; 877 u_char c[] = "\x60"; 878 size_t count; 879 880 for (; c[0] < 0x80; c[0]++) { 881 [mutable addObject:[UIKeyCommand keyCommandWithInput:[NSString stringWithUTF8String:c] 882 modifierFlags:UIKeyModifierControl 883 action:@selector(keyEvent:)]]; 884 } 885 886 for (count = 0; count < sizeof(flags) / sizeof(flags[0]); count++) { 887 [mutable addObject:[UIKeyCommand keyCommandWithInput:UIKeyInputUpArrow 888 modifierFlags:flags[count] 889 action:@selector(keyEvent:)]]; 890 [mutable addObject:[UIKeyCommand keyCommandWithInput:UIKeyInputDownArrow 891 modifierFlags:flags[count] 892 action:@selector(keyEvent:)]]; 893 [mutable addObject:[UIKeyCommand keyCommandWithInput:UIKeyInputLeftArrow 894 modifierFlags:flags[count] 895 action:@selector(keyEvent:)]]; 896 [mutable addObject:[UIKeyCommand keyCommandWithInput:UIKeyInputRightArrow 897 modifierFlags:flags[count] 898 action:@selector(keyEvent:)]]; 899 [mutable addObject:[UIKeyCommand keyCommandWithInput:UIKeyInputEscape 900 modifierFlags:flags[count] 901 action:@selector(keyEvent:)]]; 902 903 [mutable addObject:[UIKeyCommand keyCommandWithInput:@"\x01" 904 modifierFlags:flags[count] 905 action:@selector(keyEvent:)]]; 906 [mutable addObject:[UIKeyCommand keyCommandWithInput:@"\x04" 907 modifierFlags:flags[count] 908 action:@selector(keyEvent:)]]; 909 [mutable addObject:[UIKeyCommand keyCommandWithInput:@"\x0b" 910 modifierFlags:flags[count] 911 action:@selector(keyEvent:)]]; 912 [mutable addObject:[UIKeyCommand keyCommandWithInput:@"\x0c" 913 modifierFlags:flags[count] 914 action:@selector(keyEvent:)]]; 915 [mutable addObject:[UIKeyCommand keyCommandWithInput:@"\x10" 916 modifierFlags:flags[count] 917 action:@selector(keyEvent:)]]; 918 } 919 920 cmds = mutable; 921 } 922 923 return cmds; 924} 925 926- (void)keyEvent:(UIKeyCommand *)keyCommand { 927 key_mod = keyCommand.modifierFlags; 928 929#if 0 930 NSLog(@"KeyCmd: %x %x\n", key_mod, [keyCommand.input characterAtIndex:0]); 931 NSLog(keyCommand.input); 932#endif 933 934 if ([keyCommand.input compare:UIKeyInputUpArrow] == NSOrderedSame) { 935 key_code = NSUpArrowFunctionKey; 936 } else if ([keyCommand.input compare:UIKeyInputDownArrow] == NSOrderedSame) { 937 key_code = NSDownArrowFunctionKey; 938 } else if ([keyCommand.input compare:UIKeyInputLeftArrow] == NSOrderedSame) { 939 key_code = NSLeftArrowFunctionKey; 940 } else if ([keyCommand.input compare:UIKeyInputRightArrow] == NSOrderedSame) { 941 key_code = NSRightArrowFunctionKey; 942 } else if ([keyCommand.input compare:UIKeyInputEscape] == NSOrderedSame) { 943 key_code = 0x1b; 944 } else { 945 key_code = [keyCommand.input characterAtIndex:0]; 946 947 switch (key_code) { 948 case 0x1: 949 key_code = NSHomeFunctionKey; 950 break; 951 952 case 0x4: 953 key_code = NSEndFunctionKey; 954 break; 955 956 case 0xb: 957 key_code = NSPageUpFunctionKey; 958 break; 959 960 case 0xc: 961 key_code = NSPageDownFunctionKey; 962 break; 963 964 case 0x10: 965 /* iOS sends 0x10 for all function keys. It's impossible to distinguish them. */ 966 key_code = NSF1FunctionKey; 967 break; 968 969 default: 970 break; 971 } 972 } 973 974 [self keyEvent]; 975} 976#endif 977 978- (UITextRange *)characterRangeAtPoint:(CGPoint)point { 979 return nil; 980} 981 982- (UITextPosition *)closestPositionToPoint:(CGPoint)point { 983 return nil; 984} 985 986- (UITextPosition *)closestPositionToPoint:(CGPoint)point withinRange:(UITextRange *)range { 987 return nil; 988} 989 990- (CGRect)firstRectForRange:(UITextRange *)range { 991#if 0 992 int x = cand_x + uiwindow->x + uiwindow->hmargin; 993 int y = ACTUAL_HEIGHT(uiwindow->parent) - (cand_y + uiwindow->y + uiwindow->vmargin); 994 995 if (vt_term_get_vertical_mode(((ui_screen_t*)uiwindow)->term)) { 996 /* 997 * XXX Adjust candidate window position. 998 * 999 * +-+-+------ 1000 * | |1|ABCDE 1001 * 1002 * <-->^ 1003 * 25 x 1004 */ 1005 x += 25; 1006 } 1007 1008 CGRect r = CGRectMake(x, y, ui_col_width((ui_screen_t *)uiwindow), 1009 ui_line_height((ui_screen_t *)uiwindow)); 1010#endif 1011 1012 return CGRectMake(0, 0, 1, 1); 1013} 1014 1015- (CGRect)caretRectForPosition:(UITextPosition *)position { 1016 return CGRectMake(0, 0, 1, 1); 1017} 1018 1019- (void)setBaseWritingDirection:(UITextWritingDirection)writingDirection 1020 forRange:(UITextRange *)range { 1021} 1022 1023- (UITextWritingDirection)baseWritingDirectionForPosition:(UITextPosition *)position 1024 inDirection:(UITextStorageDirection)direction { 1025 return UITextWritingDirectionLeftToRight; 1026} 1027 1028- (UITextRange *)characterRangeByExtendingPosition:(UITextPosition *)position 1029 inDirection:(UITextLayoutDirection)direction { 1030 return nil; 1031} 1032 1033- (UITextPosition *)positionWithinRange:(UITextRange *)range 1034 farthestInDirection:(UITextLayoutDirection)direction { 1035 return nil; 1036} 1037 1038- (NSInteger)offsetFromPosition:(UITextPosition *)from 1039 toPosition:(UITextPosition *)toPosition { 1040 return ((TextPosition*)toPosition).position - ((TextPosition*)from).position; 1041} 1042 1043- (NSComparisonResult)comparePosition:(UITextPosition *)position 1044 toPosition:(UITextPosition *)other { 1045 int p = ((TextPosition *)position).position; 1046 int o = ((TextPosition *)other).position; 1047 1048 if (p < o) { 1049 return NSOrderedAscending; 1050 } else if (p > 0) { 1051 return NSOrderedDescending; 1052 } else { 1053 return NSOrderedSame; 1054 } 1055} 1056 1057- (UITextPosition *)positionFromPosition:(UITextPosition *)position 1058 offset:(NSInteger)offset { 1059 TextPosition *pos = [[TextPosition alloc] autorelease]; 1060 pos.position = ((TextPosition *)position).position + offset; 1061 1062 return pos; 1063} 1064 1065- (UITextPosition *)positionFromPosition:(UITextPosition *)position 1066 inDirection:(UITextLayoutDirection)direction 1067 offset:(NSInteger)offset { 1068 return nil; 1069} 1070 1071- (UITextRange *)textRangeFromPosition:(UITextPosition *)fromPosition 1072 toPosition:(UITextPosition *)toPosition { 1073 TextRange *range = [[TextRange alloc] autorelease]; 1074 ((TextPosition *)range.start).position = ((TextPosition *)fromPosition).position; 1075 ((TextPosition *)range.end).position = ((TextPosition *)toPosition).position; 1076 1077 return range; 1078} 1079 1080- (void)showMarkedText:(id)string 1081 selectedRange:(NSRange)selectedRange { 1082 if ([string length] > 0) { 1083 char *p; 1084 1085 if (!(p = alloca(strlen([string UTF8String]) + 10))) { 1086 return; 1087 } 1088 *p = '\0'; 1089 1090 if (selectedRange.location > 0) { 1091 strcpy(p, [[string substringWithRange: 1092 NSMakeRange(0, selectedRange.location)] UTF8String]); 1093 } 1094 1095 if (selectedRange.length > 0) { 1096 sprintf(p + strlen(p), "\x1b[7m%s\x1b[27m", 1097 [[string substringWithRange:selectedRange] UTF8String]); 1098 } 1099 1100 if (selectedRange.location + selectedRange.length < [string length]) { 1101 strcat(p, [[string substringWithRange: 1102 NSMakeRange( 1103 selectedRange.location + selectedRange.length, 1104 [string length] - selectedRange.location - 1105 selectedRange.length)] UTF8String]); 1106 } 1107 1108 if (!markedText) { 1109 if (!uiwindow->xim_listener || 1110 !(*uiwindow->xim_listener->get_spot)(uiwindow->xim_listener->self, &cand_x, &cand_y)) { 1111 cand_x = cand_y = 0; 1112 } 1113 } 1114 1115 update_ime_text(uiwindow, p, markedText ? markedText.UTF8String : NULL); 1116 } else if (markedText) { 1117 update_ime_text(uiwindow, "", markedText.UTF8String); 1118 } 1119} 1120 1121- (void)setMarkedText:(id)string 1122 selectedRange:(NSRange)selectedRange { 1123 if ([string isKindOfClass:[NSAttributedString class]]) { 1124 string = [string string]; 1125 } 1126 1127 ((TextPosition *)selectedTextRange.start).position = 0; 1128 ((TextPosition *)selectedTextRange.end).position = selectedRange.location + 1129 selectedRange.length; 1130 1131 [self showMarkedText:string selectedRange:selectedRange]; 1132 1133 if (markedText) { 1134 [markedText release]; 1135 markedText = nil; 1136 } 1137 1138 if ([string length] > 0) { 1139 markedText = [string copy]; 1140 ((TextPosition *)markedTextRange.end).position = [string length]; 1141 } else { 1142 ((TextPosition *)markedTextRange.end).position = 0; 1143 } 1144 ((TextPosition *)markedTextRange.start).position = 0; 1145} 1146 1147- (void)unmarkText { 1148 if (markedText) { 1149 update_ime_text(uiwindow, "", NULL); 1150 [self insertText:markedText]; 1151 [markedText release]; 1152 markedText = nil; 1153 } 1154} 1155 1156- (void)replaceRange:(UITextRange *)range withText:(NSString *)text { 1157 if (!markedText) { 1158 NSRange range = NSMakeRange(0, [text length]); 1159 [self setMarkedText:text selectedRange:range]; 1160 1161 return; 1162 } 1163 1164 int start = ((TextPosition *)range.start).position; 1165 int length = ((TextPosition *)range.end).position - start; 1166 NSMutableString *nsstr = [NSMutableString stringWithString:markedText]; 1167 [nsstr replaceCharactersInRange:NSMakeRange(start, length) withString:text]; 1168 [markedText release]; 1169 markedText = [NSString stringWithString:nsstr]; 1170 [nsstr release]; 1171 ((TextPosition *)selectedTextRange.start).position = start; 1172 ((TextPosition *)selectedTextRange.start).position = start + [text length]; 1173 1174 [self showMarkedText:markedText selectedRange:NSMakeRange(start, [text length])]; 1175} 1176 1177- (NSString *)textInRange:(UITextRange *)range { 1178 return markedText; 1179} 1180 1181- (BOOL)hasText { 1182 if (markedText) { 1183 return YES; 1184 } else { 1185 return NO; 1186 } 1187} 1188 1189- (void)insertText:(NSString *)string { 1190 if ([string length] > 0) { 1191 unichar c = [string characterAtIndex:0]; 1192 1193 if (0xf700 <= c && c <= 0xf8ff) { 1194 /* Function keys (See keyEvent or keyEvent:) */ 1195 return; 1196 } 1197 1198 XKeyEvent kev; 1199 kev.type = UI_KEY_PRESS; 1200 kev.state = 0; 1201 kev.keysym = c; 1202 kev.utf8 = [string UTF8String]; 1203 1204 ui_window_receive_event(uiwindow, (XEvent *)&kev); 1205 1206 ignoreKeyDown = TRUE; 1207 } 1208} 1209 1210- (void)deleteBackward { 1211 XKeyEvent kev; 1212 1213 kev.type = UI_KEY_PRESS; 1214 kev.state = 0; 1215 kev.keysym = 0x08; 1216 kev.utf8 = "\x08"; 1217 1218 ui_window_receive_event(uiwindow, (XEvent *)&kev); 1219} 1220 1221- (void)drawString:(ui_font_t *)font 1222 :(ui_color_t *)fg_color 1223 :(int)x 1224 :(int)y 1225 :(u_char *)str 1226 :(size_t)len { 1227 set_fill_color(fg_color); 1228 1229#if 0 1230 u_char *p = alloca(len + 1); 1231 memcpy(p, str, len); 1232 p[len] = '\0'; 1233 bl_debug_printf("%d %d %s %x\n", x, y, p, p[len - 1]); 1234#endif 1235 1236#if 0 1237 CGContextSelectFont(ctx, "Menlo", 16, kCGEncodingMacRoman); 1238 CGContextShowTextAtPoint(ctx, x, ACTUAL_HEIGHT(uiwindow) - y - 1, str, len); 1239#else 1240 unichar ustr[len]; 1241 int count; 1242 for (count = 0; count < len; count++) { 1243 ustr[count] = str[count]; 1244 } 1245 1246 drawUnistr(ctx, font, ustr, len, x, ACTUAL_HEIGHT(uiwindow) - y - 1); 1247#endif 1248} 1249 1250- (void)drawString16:(ui_font_t *)font 1251 :(ui_color_t *)fg_color 1252 :(int)x 1253 :(int)y 1254 :(XChar2b *)str 1255 :(size_t)len { 1256 set_fill_color(fg_color); 1257 1258 drawUnistr(ctx, font, (unichar *)str, len, x, ACTUAL_HEIGHT(uiwindow) - y - 1); 1259} 1260 1261- (void)fillWith:(ui_color_t *)color:(int)x:(int)y:(u_int)width:(u_int)height { 1262#if 0 1263 static int count = 0; 1264 color->pixel += (0x10 * (count++)); 1265#endif 1266 1267 if (IS_OPAQUE) { 1268 set_fill_color(color); 1269 1270 CGRect rect = 1271 CGRectMake(x, ACTUAL_HEIGHT(uiwindow) - y - height, width, height); 1272 CGContextAddRect(ctx, rect); 1273 CGContextFillPath(ctx); 1274 } else { 1275 [[UIColor colorWithRed:((color->pixel >> 16) & 0xff) / 255.0 1276 green:((color->pixel >> 8) & 0xff) / 255.0 1277 blue:(color->pixel & 0xff) / 255.0 1278 alpha:((color->pixel >> 24) & 0xff) / 255.0] set]; 1279 1280#if 0 1281 NSRectFillUsingOperation( 1282 NSMakeRect(x, ACTUAL_HEIGHT(uiwindow) - y - height, width, height), 1283 NSCompositeCopy); 1284#endif 1285 } 1286} 1287 1288- (void)drawRectFrame:(ui_color_t *)color:(int)x1:(int)y1:(int)x2:(int)y2 { 1289 set_fill_color(color); 1290 1291 CGRect rect = CGRectMake(x1, ACTUAL_HEIGHT(uiwindow) - y2 - 1, 1, y2 - y1); 1292 CGContextAddRect(ctx, rect); 1293 rect = CGRectMake(x1, ACTUAL_HEIGHT(uiwindow) - y2 - 1, x2 - x1, 1); 1294 CGContextAddRect(ctx, rect); 1295 rect = CGRectMake(x2, ACTUAL_HEIGHT(uiwindow) - y2 - 1, 1, y2 - y1); 1296 CGContextAddRect(ctx, rect); 1297 rect = CGRectMake(x1, ACTUAL_HEIGHT(uiwindow) - y1 - 1, x2 - x1 + 1, 1); 1298 CGContextAddRect(ctx, rect); 1299 CGContextFillPath(ctx); 1300} 1301 1302- (void)copyArea:(Pixmap)src 1303 :(int)src_x 1304 :(int)src_y 1305 :(u_int)width 1306 :(u_int)height 1307 :(int)dst_x 1308 :(int)dst_y { 1309 CGImageRef clipped = CGImageCreateWithImageInRect( 1310 src, CGRectMake(src_x, src_y, width, height)); 1311 CGContextDrawImage( 1312 ctx, 1313 CGRectMake(dst_x, ACTUAL_HEIGHT(uiwindow) - dst_y - height, width, height), 1314 clipped); 1315 CGImageRelease(clipped); 1316} 1317 1318#if 0 1319- (void)scroll:(int)src_x:(int)src_y:(u_int)width:(u_int)height:(int)dst_x:(int)dst_y { 1320 CGContextFlush(ctx); 1321 1322 /* Don't release this CGImage */ 1323 CGRect src_r = CGRectMake(src_x, ACTUAL_HEIGHT(uiwindow) - src_y - height, 1324 width, height); 1325 UIBitmapImageRep *bir = [self bitmapImageRepForCachingDisplayInRect:src_r]; 1326 [self cacheDisplayInRect:src_r toBitmapImageRep:bir]; 1327 CGImageRef image = bir.CGImage; 1328 1329 CGRect dst_r = CGRectMake(dst_x, ACTUAL_HEIGHT(uiwindow) - dst_y - height, 1330 width, height); 1331 CGContextDrawImage(ctx, dst_r, image); 1332 1333 static int i; 1334 if (i == 0) { 1335 CFURLRef url = [UIURL fileURLWithPath:@"/Users/ken/kallist/log.png"]; 1336 CGImageDestinationRef dest = CGImageDestinationCreateWithURL( 1337 url, kUTTypePNG, 1, NULL); 1338 CGImageDestinationAddImage(dest, image, nil); 1339 CGImageDestinationFinalize(dest); 1340 CFRelease( dest); 1341 i++; 1342 } 1343 else if (i == 1) { 1344 UIImage * nsimage = [[[UIImage alloc]initWithSize:src_r.size] autorelease]; 1345 [nsimage addRepresentation:bir]; 1346 [[nsimage TIFFRepresentation] writeToFile:@"/Users/ken/kallist/log.tiff" 1347 atomically:YES]; 1348 1349 i++; 1350 } 1351} 1352#endif 1353 1354- (void)update:(int)flag { 1355 forceExpose |= flag; 1356 1357 if (IS_OPAQUE || forceExpose) { 1358 [self setNeedsDisplay]; 1359 } else { 1360 int x; 1361 int y; 1362 1363 if (!uiwindow->xim_listener || 1364 !(*uiwindow->xim_listener->get_spot)(uiwindow->xim_listener->self, &x, &y)) { 1365 x = y = 0; 1366 } 1367 1368 x += (uiwindow->hmargin); 1369 y += (uiwindow->vmargin); 1370 1371 [self setNeedsDisplayInRect:CGRectMake(x, ACTUAL_HEIGHT(uiwindow) - y, 1, 1)]; 1372 } 1373} 1374 1375- (void)setClip:(int)x:(int)y:(u_int)width:(u_int)height { 1376 CGContextSaveGState(ctx); 1377 1378 y = ACTUAL_HEIGHT(uiwindow) - y; 1379 1380 CGContextBeginPath(ctx); 1381 CGContextMoveToPoint(ctx, x, y); 1382 CGContextAddLineToPoint(ctx, x + width, y); 1383 CGContextAddLineToPoint(ctx, x + width, y - height); 1384 CGContextAddLineToPoint(ctx, x, y - height); 1385 CGContextClosePath(ctx); 1386 CGContextClip(ctx); 1387} 1388 1389- (void)unsetClip { 1390 CGContextRestoreGState(ctx); 1391} 1392 1393- (void)bgColorChanged { 1394 if (IS_OPAQUE) { 1395 [[self window] setBackgroundColor:[UIColor whiteColor]]; 1396 [[self window] setOpaque:YES]; 1397 } else { 1398 [[self window] setBackgroundColor:[UIColor clearColor]]; 1399 [[self window] setOpaque:NO]; 1400 } 1401} 1402@end 1403 1404/* --- global functions --- */ 1405 1406void view_alloc(ui_window_t *uiwindow) { 1407 uiwindow_for_mlterm_view = uiwindow; 1408 1409 MLTermView *view = 1410 [[MLTermView alloc] initWithFrame:CGRectMake(0, 0, 400, 400)]; 1411 [((UIWindow *)uiwindow->parent->my_window) addSubview:view]; 1412} 1413 1414void view_dealloc(UIView *view) { 1415 /* removeFromSuperview() can hide keyboard and change the frame of UIWindow. */ 1416 [view.window removeObserver:view forKeyPath:@"frame"]; 1417 [view removeFromSuperview]; 1418 [view release]; 1419} 1420 1421void view_update(MLTermView *view, int flag) { [view update:flag]; } 1422 1423void view_set_clip(MLTermView *view, int x, int y, u_int width, u_int height) { 1424 [view setClip:x:y:width:height]; 1425} 1426 1427void view_unset_clip(MLTermView *view) { [view unsetClip]; } 1428 1429void view_draw_string(MLTermView *view, ui_font_t *font, ui_color_t *fg_color, 1430 int x, int y, char *str, size_t len) { 1431 [view drawString:font:fg_color:x:y:str:len]; 1432} 1433 1434void view_draw_string16(MLTermView *view, ui_font_t *font, ui_color_t *fg_color, 1435 int x, int y, XChar2b *str, size_t len) { 1436 [view drawString16:font:fg_color:x:y:str:len]; 1437} 1438 1439void view_fill_with(MLTermView *view, ui_color_t *color, int x, int y, 1440 u_int width, u_int height) { 1441 [view fillWith:color:x:y:width:height]; 1442} 1443 1444void view_draw_rect_frame(MLTermView *view, ui_color_t *color, int x1, int y1, 1445 int x2, int y2) { 1446 [view drawRectFrame:color:x1:y1:x2:y2]; 1447} 1448 1449void view_copy_area(MLTermView *view, Pixmap src, int src_x, int src_y, 1450 u_int width, u_int height, int dst_x, int dst_y) { 1451 [view copyArea:src:src_x:src_y:width:height:dst_x:dst_y]; 1452} 1453 1454void view_scroll(MLTermView *view, int src_x, int src_y, u_int width, 1455 u_int height, int dst_x, int dst_y) { 1456#if 0 1457 [view scroll:src_x:src_y:width:height:dst_x:dst_y]; 1458#endif 1459} 1460 1461void view_bg_color_changed(MLTermView *view) { [view bgColorChanged]; } 1462 1463void view_visual_bell(MLTermView *view) { [view update:2]; } 1464 1465void view_set_input_focus(UIView *view) { 1466 [view becomeFirstResponder]; 1467} 1468 1469void view_set_rect(UIView *view, int x, int y, /* The origin is left-botom. */ 1470 u_int width, u_int height) { 1471 [view setFrame:CGRectMake(x,y,width,height)]; 1472} 1473 1474void view_set_hidden(UIView *view, int flag) { [view setHidden:flag]; } 1475 1476void window_alloc(ui_window_t *root) { 1477 uiwindow_for_mlterm_view = root->children[1]; 1478 1479 UINib *nib = [[UINib alloc] nibWithNibName:@"Main" bundle:nil]; 1480 [nib instantiateWithOwner:nil options:nil]; 1481 [nib release]; 1482} 1483 1484void window_dealloc(UIWindow *window) { [window release]; } 1485 1486void window_resize(UIWindow *window, int width, int height) {} 1487 1488void window_move_resize(UIWindow *window, int x, int y, int width, int height) {} 1489 1490void window_accepts_mouse_moved_events(UIWindow *window, int accept) { 1491#if 0 1492 window.acceptsMouseMovedEvents = (accept ? YES : NO); 1493#endif 1494} 1495 1496void window_set_normal_hints(UIWindow *window, u_int width_inc, 1497 u_int height_inc) { 1498#if 0 1499 [window setResizeIncrements:NSMakeSize(width_inc, height_inc)]; 1500#endif 1501} 1502 1503void window_get_position(UIWindow *window, int *x, int *y) { 1504 *x = 0; 1505 *y = 0; 1506} 1507 1508void window_set_title(UIWindow *window, const char *title /* utf8 */) { 1509#if 0 1510 NSString *ns_title = [NSString stringWithCString:title encoding:NSUTF8StringEncoding]; 1511 [window setTitle:ns_title]; 1512#endif 1513} 1514 1515void app_urgent_bell(int on) { 1516#if 0 1517 if (on) { 1518 [[NSApplication sharedApplication] requestUserAttention:NSCriticalRequest]; 1519 } else { 1520 [[NSApplication sharedApplication] 1521 cancelUserAttentionRequest:NSCriticalRequest]; 1522 } 1523#endif 1524} 1525 1526void scroller_update(UIScrollView *scroller, float pos, float knob) { 1527#if 0 1528#if 1 1529 [scroller setFloatValue:pos knobProportion:knob]; /* Deprecated since 10.6 */ 1530#else 1531 scroller.knobProportion = knob; 1532 scroller.doubleValue = pos; 1533#endif 1534#endif 1535} 1536 1537CGFontRef cocoa_create_font(const char *font_family) { 1538 NSString *ns_font_family = 1539 [NSString stringWithCString:font_family encoding:NSUTF8StringEncoding]; 1540 1541 return CGFontCreateWithFontName(ns_font_family); 1542} 1543 1544#ifdef USE_OT_LAYOUT 1545char *cocoa_get_font_path(CGFontRef cg_font) { 1546#if 0 1547 CTFontDescriptorRef desc = 1548 CTFontDescriptorCreateWithNameAndSize(CGFontCopyFullName(cg_font), 14); 1549 CFURLRef url = 1550 (CFURLRef)CTFontDescriptorCopyAttribute(desc, kCTFontURLAttribute); 1551 const char *urlstr = [((NSString *)CFURLGetString(url))UTF8String]; 1552 if (strncmp(urlstr, "file://localhost", 16) == 0) { 1553 urlstr += 16; 1554 } 1555 1556 char *path = strdup(urlstr); 1557 1558 CFRelease(url); 1559 CFRelease(desc); 1560 1561 return path; 1562#else 1563 return NULL; 1564#endif 1565} 1566#endif /* USE_OT_LAYOUT */ 1567 1568void cocoa_release_font(CGFontRef cg_font) { CFRelease(cg_font); } 1569 1570u_int cocoa_font_get_advance(CGFontRef cg_font, u_int fontsize, int size_attr, 1571 unichar *utf16, u_int len, CGGlyph glyph) { 1572 if (utf16) { 1573 CGFontGetGlyphsForUnichars(cg_font, &utf16, &glyph, 1); 1574 } 1575 1576 int advance; 1577 if (!CGFontGetGlyphAdvances(cg_font, &glyph, 1, &advance) || advance < 0) { 1578 return 0; 1579 } 1580 1581 if (size_attr >= DOUBLE_HEIGHT_TOP) { 1582 fontsize *= 2; 1583 } 1584 1585 return advance * fontsize / CGFontGetUnitsPerEm(cg_font); 1586} 1587 1588void cocoa_clipboard_own(MLTermView *view) { 1589#if 0 1590 UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; 1591 [pasteboard declareTypes:[NSArray arrayWithObject:NSPasteboardTypeString] 1592 owner:view]; 1593#endif 1594} 1595 1596void cocoa_clipboard_set(const u_char *utf8, size_t len) { 1597 UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; 1598 NSString *str = [[NSString alloc] initWithBytes:utf8 1599 length:len 1600 encoding:NSUTF8StringEncoding]; 1601 pasteboard.string = str; 1602 [str release]; 1603} 1604 1605const char *cocoa_clipboard_get(void) { 1606 UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; 1607 1608 NSString *str = pasteboard.string; 1609 if (str != nil) { 1610 return [str UTF8String]; 1611 } 1612 1613 return NULL; 1614} 1615 1616void cocoa_beep(void) {} 1617 1618CGImageRef cocoa_load_image(const char *path, u_int *width, u_int *height) { 1619 NSString *nspath = 1620 [NSString stringWithCString:path encoding:NSUTF8StringEncoding]; 1621 UIImage *uiimg = [[UIImage alloc] initWithContentsOfFile:nspath]; 1622 if (!uiimg) { 1623 return nil; 1624 } 1625 1626 CGImageRef cgimg = uiimg.CGImage; 1627 1628 CGImageRetain(cgimg); 1629 1630 *width = uiimg.size.width; 1631 *height = uiimg.size.height; 1632 [uiimg release]; 1633 1634 return cgimg; 1635} 1636 1637const char *cocoa_get_bundle_path(void) { 1638 return [[[NSBundle mainBundle] bundlePath] UTF8String]; 1639} 1640 1641char *cocoa_dialog_password(const char *msg) { 1642#if 0 1643 NSAlert *alert = create_dialog(msg, 1); 1644 if (alert == nil) { 1645 return NULL; 1646 } 1647 1648 NSTextField *text = [[MLSecureTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 20)]; 1649 [text autorelease]; 1650 [alert setAccessoryView:text]; 1651 1652 if ([alert runModal] == NSAlertFirstButtonReturn) { 1653 return strdup([[text stringValue] UTF8String]); 1654 } else 1655#endif 1656 { 1657 return NULL; 1658 } 1659} 1660 1661int cocoa_dialog_okcancel(const char *msg) { 1662 return -1; 1663} 1664 1665int cocoa_dialog_alert(const char *msg) { 1666 show_dialog(msg); 1667 1668 return 1; 1669} 1670