1/* Functions for the NeXT/Open/GNUstep and macOS window system. 2 3Copyright (C) 1989, 1992-1994, 2005-2006, 2008-2021 Free Software 4Foundation, Inc. 5 6This file is part of GNU Emacs. 7 8GNU Emacs is free software: you can redistribute it and/or modify 9it under the terms of the GNU General Public License as published by 10the Free Software Foundation, either version 3 of the License, or (at 11your option) any later version. 12 13GNU Emacs is distributed in the hope that it will be useful, 14but WITHOUT ANY WARRANTY; without even the implied warranty of 15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16GNU General Public License for more details. 17 18You should have received a copy of the GNU General Public License 19along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ 20 21/* 22Originally by Carl Edman 23Updated by Christian Limpach (chris@nice.ch) 24OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com) 25macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net) 26GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) 27*/ 28 29/* This should be the first include, as it may set up #defines affecting 30 interpretation of even the system includes. */ 31#include <config.h> 32 33#include <math.h> 34#include <c-strcase.h> 35 36#include "lisp.h" 37#include "blockinput.h" 38#include "nsterm.h" 39#include "window.h" 40#include "character.h" 41#include "buffer.h" 42#include "keyboard.h" 43#include "termhooks.h" 44#include "fontset.h" 45#include "font.h" 46 47#ifdef NS_IMPL_COCOA 48#include <IOKit/graphics/IOGraphicsLib.h> 49#include "macfont.h" 50#endif 51 52#ifdef HAVE_NS 53 54static EmacsTooltip *ns_tooltip = nil; 55 56/* Static variables to handle AppleScript execution. */ 57static Lisp_Object as_script, *as_result; 58static int as_status; 59 60static ptrdiff_t image_cache_refcount; 61 62static struct ns_display_info *ns_display_info_for_name (Lisp_Object); 63 64/* ========================================================================== 65 66 Internal utility functions 67 68 ========================================================================== */ 69 70/* Let the user specify a Nextstep display with a Lisp object. 71 OBJECT may be nil, a frame or a terminal object. 72 nil stands for the selected frame--or, if that is not a Nextstep frame, 73 the first Nextstep display on the list. */ 74 75static struct ns_display_info * 76check_ns_display_info (Lisp_Object object) 77{ 78 struct ns_display_info *dpyinfo = NULL; 79 80 if (NILP (object)) 81 { 82 struct frame *sf = XFRAME (selected_frame); 83 84 if (FRAME_NS_P (sf) && FRAME_LIVE_P (sf)) 85 dpyinfo = FRAME_DISPLAY_INFO (sf); 86 else if (x_display_list != 0) 87 dpyinfo = x_display_list; 88 else 89 error ("Nextstep windows are not in use or not initialized"); 90 } 91 else if (TERMINALP (object)) 92 { 93 struct terminal *t = decode_live_terminal (object); 94 95 if (t->type != output_ns) 96 error ("Terminal %d is not a Nextstep display", t->id); 97 98 dpyinfo = t->display_info.ns; 99 } 100 else if (STRINGP (object)) 101 dpyinfo = ns_display_info_for_name (object); 102 else 103 { 104 struct frame *f = decode_window_system_frame (object); 105 dpyinfo = FRAME_DISPLAY_INFO (f); 106 } 107 108 return dpyinfo; 109} 110 111 112static id 113ns_get_window (Lisp_Object maybeFrame) 114{ 115 id view =nil, window =nil; 116 117 if (!FRAMEP (maybeFrame) || !FRAME_NS_P (XFRAME (maybeFrame))) 118 maybeFrame = selected_frame; /* wrong_type_argument (Qframep, maybeFrame); */ 119 120 if (!NILP (maybeFrame)) 121 view = FRAME_NS_VIEW (XFRAME (maybeFrame)); 122 if (view) window =[view window]; 123 124 return window; 125} 126 127 128/* Return the X display structure for the display named NAME. 129 Open a new connection if necessary. */ 130static struct ns_display_info * 131ns_display_info_for_name (Lisp_Object name) 132{ 133 struct ns_display_info *dpyinfo; 134 135 CHECK_STRING (name); 136 137 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) 138 if (!NILP (Fstring_equal (XCAR (dpyinfo->name_list_element), name))) 139 return dpyinfo; 140 141 error ("Emacs for Nextstep does not yet support multi-display"); 142 143 Fx_open_connection (name, Qnil, Qnil); 144 dpyinfo = x_display_list; 145 146 if (dpyinfo == 0) 147 error ("Display on %s not responding.\n", SDATA (name)); 148 149 return dpyinfo; 150} 151 152static NSString * 153ns_filename_from_panel (NSSavePanel *panel) 154{ 155#ifdef NS_IMPL_COCOA 156 NSURL *url = [panel URL]; 157 NSString *str = [url path]; 158 return str; 159#else 160 return [panel filename]; 161#endif 162} 163 164static NSString * 165ns_directory_from_panel (NSSavePanel *panel) 166{ 167#ifdef NS_IMPL_COCOA 168 NSURL *url = [panel directoryURL]; 169 NSString *str = [url path]; 170 return str; 171#else 172 return [panel directory]; 173#endif 174} 175 176#ifndef NS_IMPL_COCOA 177static Lisp_Object 178interpret_services_menu (NSMenu *menu, Lisp_Object prefix, Lisp_Object old) 179/* -------------------------------------------------------------------------- 180 Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. 181 -------------------------------------------------------------------------- */ 182{ 183 int i, count; 184 NSMenuItem *item; 185 const char *name; 186 Lisp_Object nameStr; 187 unsigned short key; 188 NSString *keys; 189 Lisp_Object res; 190 191 count = [menu numberOfItems]; 192 for (i = 0; i<count; i++) 193 { 194 item = [menu itemAtIndex: i]; 195 name = [[item title] UTF8String]; 196 if (!name) continue; 197 198 nameStr = build_string (name); 199 200 if ([item hasSubmenu]) 201 { 202 old = interpret_services_menu ([item submenu], 203 Fcons (nameStr, prefix), old); 204 } 205 else 206 { 207 keys = [item keyEquivalent]; 208 if (keys && [keys length] ) 209 { 210 key = [keys characterAtIndex: 0]; 211 res = make_fixnum (key|super_modifier); 212 } 213 else 214 { 215 res = Qundefined; 216 } 217 old = Fcons (Fcons (res, 218 Freverse (Fcons (nameStr, 219 prefix))), 220 old); 221 } 222 } 223 return old; 224} 225#endif 226 227 228/* ========================================================================== 229 230 Frame parameter setters 231 232 ========================================================================== */ 233 234 235static void 236ns_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 237{ 238 NSColor *col; 239 EmacsCGFloat r, g, b, alpha; 240 241 /* Must block_input, because ns_lisp_to_color does block/unblock_input 242 which means that col may be deallocated in its unblock_input if there 243 is user input, unless we also block_input. */ 244 block_input (); 245 if (ns_lisp_to_color (arg, &col)) 246 { 247 store_frame_param (f, Qforeground_color, oldval); 248 unblock_input (); 249 error ("Unknown color"); 250 } 251 252 [col retain]; 253 [f->output_data.ns->foreground_color release]; 254 f->output_data.ns->foreground_color = col; 255 256 [col getRed: &r green: &g blue: &b alpha: &alpha]; 257 FRAME_FOREGROUND_PIXEL (f) = 258 ARGB_TO_ULONG ((int)(alpha*0xff), (int)(r*0xff), (int)(g*0xff), (int)(b*0xff)); 259 260 if (FRAME_NS_VIEW (f)) 261 { 262 update_face_from_frame_parameter (f, Qforeground_color, arg); 263 /* recompute_basic_faces (f); */ 264 if (FRAME_VISIBLE_P (f)) 265 SET_FRAME_GARBAGED (f); 266 } 267 unblock_input (); 268} 269 270 271static void 272ns_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 273{ 274 struct face *face; 275 NSColor *col; 276 NSView *view = FRAME_NS_VIEW (f); 277 EmacsCGFloat r, g, b, alpha; 278 279 block_input (); 280 if (ns_lisp_to_color (arg, &col)) 281 { 282 store_frame_param (f, Qbackground_color, oldval); 283 unblock_input (); 284 error ("Unknown color"); 285 } 286 287 /* Clear the frame; in some instances the NS-internal GC appears not 288 to update, or it does update and cannot clear old text 289 properly. */ 290 if (FRAME_VISIBLE_P (f)) 291 ns_clear_frame (f); 292 293 [col retain]; 294 [f->output_data.ns->background_color release]; 295 f->output_data.ns->background_color = col; 296 297 [col getRed: &r green: &g blue: &b alpha: &alpha]; 298 FRAME_BACKGROUND_PIXEL (f) = 299 ARGB_TO_ULONG ((int)(alpha*0xff), (int)(r*0xff), (int)(g*0xff), (int)(b*0xff)); 300 301 if (view != nil) 302 { 303 [[view window] setBackgroundColor: col]; 304 305 if (alpha != (EmacsCGFloat) 1.0) 306 [[view window] setOpaque: NO]; 307 else 308 [[view window] setOpaque: YES]; 309 310 face = FRAME_DEFAULT_FACE (f); 311 if (face) 312 { 313 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f); 314 face->background = ns_index_color 315 ([col colorWithAlphaComponent: alpha], f); 316 317 update_face_from_frame_parameter (f, Qbackground_color, arg); 318 } 319 320 if (FRAME_VISIBLE_P (f)) 321 SET_FRAME_GARBAGED (f); 322 } 323 unblock_input (); 324} 325 326 327static void 328ns_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 329{ 330 NSColor *col; 331 332 block_input (); 333 if (ns_lisp_to_color (arg, &col)) 334 { 335 store_frame_param (f, Qcursor_color, oldval); 336 unblock_input (); 337 error ("Unknown color"); 338 } 339 340 [FRAME_CURSOR_COLOR (f) release]; 341 FRAME_CURSOR_COLOR (f) = [col retain]; 342 343 if (FRAME_VISIBLE_P (f)) 344 { 345 gui_update_cursor (f, 0); 346 gui_update_cursor (f, 1); 347 } 348 update_face_from_frame_parameter (f, Qcursor_color, arg); 349 unblock_input (); 350} 351 352 353static void 354ns_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 355{ 356 NSView *view = FRAME_NS_VIEW (f); 357 NSTRACE ("ns_set_icon_name"); 358 359 /* See if it's changed. */ 360 if (STRINGP (arg)) 361 { 362 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt)) 363 return; 364 } 365 else if (!STRINGP (oldval) && NILP (oldval) == NILP (arg)) 366 return; 367 368 fset_icon_name (f, arg); 369 370 if (NILP (arg)) 371 { 372 if (!NILP (f->title)) 373 arg = f->title; 374 else 375 /* Explicit name and no icon-name -> explicit_name. */ 376 if (f->explicit_name) 377 arg = f->name; 378 else 379 { 380 /* No explicit name and no icon-name -> 381 name has to be rebuild from icon_title_format. */ 382 windows_or_buffers_changed = 62; 383 return; 384 } 385 } 386 387 /* Don't change the name if it's already NAME. */ 388 if ([[view window] miniwindowTitle] 389 && ([[[view window] miniwindowTitle] 390 isEqualToString: [NSString stringWithUTF8String: 391 SSDATA (arg)]])) 392 return; 393 394 [[view window] setMiniwindowTitle: 395 [NSString stringWithUTF8String: SSDATA (arg)]]; 396} 397 398static void 399ns_set_name_internal (struct frame *f, Lisp_Object name) 400{ 401 Lisp_Object encoded_name, encoded_icon_name; 402 NSString *str; 403 NSView *view = FRAME_NS_VIEW (f); 404 405 406 encoded_name = ENCODE_UTF_8 (name); 407 408 str = [NSString stringWithUTF8String: SSDATA (encoded_name)]; 409 410 411 /* Don't change the name if it's already NAME. */ 412 if (! [[[view window] title] isEqualToString: str]) 413 [[view window] setTitle: str]; 414 415 if (!STRINGP (f->icon_name)) 416 encoded_icon_name = encoded_name; 417 else 418 encoded_icon_name = ENCODE_UTF_8 (f->icon_name); 419 420 str = [NSString stringWithUTF8String: SSDATA (encoded_icon_name)]; 421 422 if ([[view window] miniwindowTitle] 423 && ! [[[view window] miniwindowTitle] isEqualToString: str]) 424 [[view window] setMiniwindowTitle: str]; 425 426} 427 428static void 429ns_set_name (struct frame *f, Lisp_Object name, int explicit) 430{ 431 NSTRACE ("ns_set_name"); 432 433 /* Make sure that requests from lisp code override requests from 434 Emacs redisplay code. */ 435 if (explicit) 436 { 437 /* If we're switching from explicit to implicit, we had better 438 update the mode lines and thereby update the title. */ 439 if (f->explicit_name && NILP (name)) 440 update_mode_lines = 21; 441 442 f->explicit_name = ! NILP (name); 443 } 444 else if (f->explicit_name) 445 return; 446 447 if (NILP (name)) 448 name = build_string ([ns_app_name UTF8String]); 449 else 450 CHECK_STRING (name); 451 452 /* Don't change the name if it's already NAME. */ 453 if (! NILP (Fstring_equal (name, f->name))) 454 return; 455 456 fset_name (f, name); 457 458 /* Title overrides explicit name. */ 459 if (! NILP (f->title)) 460 name = f->title; 461 462 ns_set_name_internal (f, name); 463} 464 465static void 466ns_set_represented_filename (struct frame *f) 467{ 468 Lisp_Object filename, encoded_filename; 469 Lisp_Object buf = XWINDOW (f->selected_window)->contents; 470 NSAutoreleasePool *pool; 471 NSString *fstr; 472 NSView *view = FRAME_NS_VIEW (f); 473 474 NSTRACE ("ns_set_represented_filename"); 475 476 if (f->explicit_name || ! NILP (f->title)) 477 return; 478 479 block_input (); 480 pool = [[NSAutoreleasePool alloc] init]; 481 filename = BVAR (XBUFFER (buf), filename); 482 483 if (! NILP (filename)) 484 { 485 encoded_filename = ENCODE_UTF_8 (filename); 486 487 fstr = [NSString stringWithUTF8String: SSDATA (encoded_filename)]; 488 if (fstr == nil) fstr = @""; 489 } 490 else 491 fstr = @""; 492 493#if defined (NS_IMPL_COCOA) && defined (MAC_OS_X_VERSION_10_7) 494 /* Work around for Mach port leaks on macOS 10.15 (bug#38618). */ 495 NSURL *fileURL = [NSURL fileURLWithPath:fstr isDirectory:NO]; 496 NSNumber *isUbiquitousItem = [NSNumber numberWithBool:YES]; 497 [fileURL getResourceValue:(id *)&isUbiquitousItem 498 forKey:NSURLIsUbiquitousItemKey 499 error:nil]; 500 if ([isUbiquitousItem boolValue]) 501 fstr = @""; 502#endif 503 504#ifdef NS_IMPL_COCOA 505 /* Work around a bug observed on 10.3 and later where 506 setTitleWithRepresentedFilename does not clear out previous state 507 if given filename does not exist. */ 508 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr]) 509 [[view window] setRepresentedFilename: @""]; 510#endif 511 [[view window] setRepresentedFilename: fstr]; 512 513 [pool release]; 514 unblock_input (); 515} 516 517 518/* This function should be called when the user's lisp code has 519 specified a name for the frame; the name will override any set by the 520 redisplay code. */ 521static void 522ns_explicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 523{ 524 NSTRACE ("ns_explicitly_set_name"); 525 ns_set_name (f, arg, 1); 526} 527 528 529/* This function should be called by Emacs redisplay code to set the 530 name; names set this way will never override names set by the user's 531 lisp code. */ 532void 533ns_implicitly_set_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 534{ 535 NSTRACE ("ns_implicitly_set_name"); 536 537 if (ns_use_proxy_icon) 538 ns_set_represented_filename (f); 539 540 ns_set_name (f, arg, 0); 541} 542 543 544/* Change the title of frame F to NAME. 545 If NAME is nil, use the frame name as the title. */ 546 547static void 548ns_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name) 549{ 550 NSTRACE ("ns_set_title"); 551 /* Don't change the title if it's already NAME. */ 552 if (EQ (name, f->title)) 553 return; 554 555 update_mode_lines = 22; 556 557 fset_title (f, name); 558 559 if (NILP (name)) 560 name = f->name; 561 else 562 CHECK_STRING (name); 563 564 ns_set_name_internal (f, name); 565} 566 567void 568ns_set_doc_edited (void) 569{ 570 NSAutoreleasePool *pool; 571 Lisp_Object tail, frame; 572 block_input (); 573 pool = [[NSAutoreleasePool alloc] init]; 574 FOR_EACH_FRAME (tail, frame) 575 { 576 BOOL edited = NO; 577 struct frame *f = XFRAME (frame); 578 struct window *w; 579 NSView *view; 580 581 if (! FRAME_NS_P (f)) continue; 582 w = XWINDOW (FRAME_SELECTED_WINDOW (f)); 583 view = FRAME_NS_VIEW (f); 584 if (!MINI_WINDOW_P (w)) 585 edited = ! NILP (Fbuffer_modified_p (w->contents)) && 586 ! NILP (Fbuffer_file_name (w->contents)); 587 [[view window] setDocumentEdited: edited]; 588 } 589 590 [pool release]; 591 unblock_input (); 592} 593 594 595static void 596ns_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) 597{ 598 int nlines; 599 if (FRAME_MINIBUF_ONLY_P (f)) 600 return; 601 602 if (TYPE_RANGED_FIXNUMP (int, value)) 603 nlines = XFIXNUM (value); 604 else 605 nlines = 0; 606 607 FRAME_MENU_BAR_LINES (f) = 0; 608 if (nlines) 609 { 610 FRAME_EXTERNAL_MENU_BAR (f) = 1; 611 /* Does for all frames, whereas we just want for one frame 612 [NSMenu setMenuBarVisible: YES]; */ 613 } 614 else 615 { 616 if (FRAME_EXTERNAL_MENU_BAR (f) == 1) 617 free_frame_menubar (f); 618 /* [NSMenu setMenuBarVisible: NO]; */ 619 FRAME_EXTERNAL_MENU_BAR (f) = 0; 620 } 621} 622 623 624/* tabbar support */ 625static void 626ns_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) 627{ 628 /* Currently unimplemented. */ 629 NSTRACE ("ns_set_tab_bar_lines"); 630} 631 632 633/* toolbar support */ 634static void 635ns_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) 636{ 637 /* Currently, when the tool bar changes state, the frame is resized. 638 639 TODO: It would be better if this didn't occur when 1) the frame 640 is full height or maximized or 2) when specified by 641 `frame-inhibit-implied-resize'. */ 642 int nlines; 643 644 NSTRACE ("ns_set_tool_bar_lines"); 645 646 if (FRAME_MINIBUF_ONLY_P (f)) 647 return; 648 649 if (RANGED_FIXNUMP (0, value, INT_MAX)) 650 nlines = XFIXNAT (value); 651 else 652 nlines = 0; 653 654 if (nlines) 655 { 656 FRAME_EXTERNAL_TOOL_BAR (f) = 1; 657 update_frame_tool_bar (f); 658 } 659 else 660 { 661 if (FRAME_EXTERNAL_TOOL_BAR (f)) 662 { 663 free_frame_tool_bar (f); 664 FRAME_EXTERNAL_TOOL_BAR (f) = 0; 665 666 { 667 EmacsView *view = FRAME_NS_VIEW (f); 668 int fs_state = [view fullscreenState]; 669 670 if (fs_state == FULLSCREEN_MAXIMIZED) 671 { 672 [view setFSValue:FULLSCREEN_WIDTH]; 673 } 674 else if (fs_state == FULLSCREEN_HEIGHT) 675 { 676 [view setFSValue:FULLSCREEN_NONE]; 677 } 678 } 679 } 680 } 681 682 { 683 int inhibit 684 = ((f->after_make_frame 685 && !f->tool_bar_resized 686 && (EQ (frame_inhibit_implied_resize, Qt) 687 || (CONSP (frame_inhibit_implied_resize) 688 && !NILP (Fmemq (Qtool_bar_lines, 689 frame_inhibit_implied_resize)))) 690 && NILP (get_frame_param (f, Qfullscreen))) 691 ? 0 692 : 2); 693 694 NSTRACE_MSG ("inhibit:%d", inhibit); 695 696 frame_size_history_add (f, Qupdate_frame_tool_bar, 0, 0, Qnil); 697 adjust_frame_size (f, -1, -1, inhibit, 0, Qtool_bar_lines); 698 } 699} 700 701 702static void 703ns_set_internal_border_width (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 704{ 705 int old_width = FRAME_INTERNAL_BORDER_WIDTH (f); 706 707 CHECK_TYPE_RANGED_INTEGER (int, arg); 708 f->internal_border_width = XFIXNUM (arg); 709 if (FRAME_INTERNAL_BORDER_WIDTH (f) < 0) 710 f->internal_border_width = 0; 711 712 if (FRAME_INTERNAL_BORDER_WIDTH (f) == old_width) 713 return; 714 715 if (FRAME_NATIVE_WINDOW (f) != 0) 716 adjust_frame_size (f, -1, -1, 3, 0, Qinternal_border_width); 717 718 SET_FRAME_GARBAGED (f); 719} 720 721 722static void 723ns_implicitly_set_icon_type (struct frame *f) 724{ 725 Lisp_Object tem; 726 EmacsView *view = FRAME_NS_VIEW (f); 727 id image = nil; 728 Lisp_Object chain, elt; 729 NSAutoreleasePool *pool; 730 BOOL setMini = YES; 731 732 NSTRACE ("ns_implicitly_set_icon_type"); 733 734 block_input (); 735 pool = [[NSAutoreleasePool alloc] init]; 736 if (f->output_data.ns->miniimage 737 && [[NSString stringWithUTF8String: SSDATA (f->name)] 738 isEqualToString: [(NSImage *)f->output_data.ns->miniimage name]]) 739 { 740 [pool release]; 741 unblock_input (); 742 return; 743 } 744 745 tem = assq_no_quit (Qicon_type, f->param_alist); 746 if (CONSP (tem) && ! NILP (XCDR (tem))) 747 { 748 [pool release]; 749 unblock_input (); 750 return; 751 } 752 753 for (chain = Vns_icon_type_alist; 754 image == nil && CONSP (chain); 755 chain = XCDR (chain)) 756 { 757 elt = XCAR (chain); 758 /* Special case: t means go by file type. */ 759 if (SYMBOLP (elt) && EQ (elt, Qt) && SSDATA (f->name)[0] == '/') 760 { 761 NSString *str 762 = [NSString stringWithUTF8String: SSDATA (f->name)]; 763 if ([[NSFileManager defaultManager] fileExistsAtPath: str]) 764 image = [[[NSWorkspace sharedWorkspace] iconForFile: str] retain]; 765 } 766 else if (CONSP (elt) && 767 STRINGP (XCAR (elt)) && 768 STRINGP (XCDR (elt)) && 769 fast_string_match (XCAR (elt), f->name) >= 0) 770 { 771 image = [EmacsImage allocInitFromFile: XCDR (elt)]; 772 if (image == nil) 773 image = [[NSImage imageNamed: 774 [NSString stringWithUTF8String: 775 SSDATA (XCDR (elt))]] retain]; 776 } 777 } 778 779 if (image == nil) 780 { 781 image = [[[NSWorkspace sharedWorkspace] iconForFileType: @"text"] retain]; 782 setMini = NO; 783 } 784 785 [f->output_data.ns->miniimage release]; 786 f->output_data.ns->miniimage = image; 787 [view setMiniwindowImage: setMini]; 788 [pool release]; 789 unblock_input (); 790} 791 792 793static void 794ns_set_icon_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 795{ 796 EmacsView *view = FRAME_NS_VIEW (f); 797 id image = nil; 798 BOOL setMini = YES; 799 800 NSTRACE ("ns_set_icon_type"); 801 802 if (!NILP (arg) && SYMBOLP (arg)) 803 { 804 arg =build_string (SSDATA (SYMBOL_NAME (arg))); 805 store_frame_param (f, Qicon_type, arg); 806 } 807 808 /* Do it the implicit way. */ 809 if (NILP (arg)) 810 { 811 ns_implicitly_set_icon_type (f); 812 return; 813 } 814 815 CHECK_STRING (arg); 816 817 image = [EmacsImage allocInitFromFile: arg]; 818 if (image == nil) 819 image =[NSImage imageNamed: [NSString stringWithUTF8String: 820 SSDATA (arg)]]; 821 822 if (image == nil) 823 { 824 image = [NSImage imageNamed: @"text"]; 825 setMini = NO; 826 } 827 828 f->output_data.ns->miniimage = image; 829 [view setMiniwindowImage: setMini]; 830} 831 832/* This is the same as the xfns.c definition. */ 833static void 834ns_set_cursor_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 835{ 836 set_frame_cursor_types (f, arg); 837} 838 839/* called to set mouse pointer color, but all other terms use it to 840 initialize pointer types (and don't set the color ;) */ 841static void 842ns_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) 843{ 844 /* Don't think we can do this on Nextstep. */ 845} 846 847 848#define Str(x) #x 849#define Xstr(x) Str(x) 850 851static Lisp_Object 852ns_appkit_version_str (void) 853{ 854 char tmp[256]; 855 856#ifdef NS_IMPL_GNUSTEP 857 sprintf(tmp, "gnustep-gui-%s", Xstr(GNUSTEP_GUI_VERSION)); 858#elif defined (NS_IMPL_COCOA) 859 NSString *osversion 860 = [[NSProcessInfo processInfo] operatingSystemVersionString]; 861 sprintf(tmp, "appkit-%.2f %s", 862 NSAppKitVersionNumber, 863 [osversion UTF8String]); 864#else 865 tmp = "ns-unknown"; 866#endif 867 return build_string (tmp); 868} 869 870 871/* This is for use by x-server-version and collapses all version info we 872 have into a single int. For a better picture of the implementation 873 running, use ns_appkit_version_str. */ 874static int 875ns_appkit_version_int (void) 876{ 877#ifdef NS_IMPL_GNUSTEP 878 return GNUSTEP_GUI_MAJOR_VERSION * 100 + GNUSTEP_GUI_MINOR_VERSION; 879#elif defined (NS_IMPL_COCOA) 880 return (int)NSAppKitVersionNumber; 881#endif 882 return 0; 883} 884 885 886static void 887ns_icon (struct frame *f, Lisp_Object parms) 888/* -------------------------------------------------------------------------- 889 Strangely-named function to set icon position parameters in frame. 890 This is irrelevant under macOS, but might be needed under GNUstep, 891 depending on the window manager used. Note, this is not a standard 892 frame parameter-setter; it is called directly from x-create-frame. 893 -------------------------------------------------------------------------- */ 894{ 895 Lisp_Object icon_x, icon_y; 896 struct ns_display_info *dpyinfo = check_ns_display_info (Qnil); 897 898 f->output_data.ns->icon_top = -1; 899 f->output_data.ns->icon_left = -1; 900 901 /* Set the position of the icon. */ 902 icon_x = gui_display_get_arg (dpyinfo, parms, Qicon_left, 0, 0, 903 RES_TYPE_NUMBER); 904 icon_y = gui_display_get_arg (dpyinfo, parms, Qicon_top, 0, 0, 905 RES_TYPE_NUMBER); 906 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound)) 907 { 908 CHECK_FIXNUM (icon_x); 909 CHECK_FIXNUM (icon_y); 910 f->output_data.ns->icon_top = XFIXNUM (icon_y); 911 f->output_data.ns->icon_left = XFIXNUM (icon_x); 912 } 913 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound)) 914 error ("Both left and top icon corners of icon must be specified"); 915} 916 917 918/* Note: see frame.c for template, also where generic functions are 919 implemented. */ 920frame_parm_handler ns_frame_parm_handlers[] = 921{ 922 gui_set_autoraise, /* generic OK */ 923 gui_set_autolower, /* generic OK */ 924 ns_set_background_color, 925 0, /* x_set_border_color, may be impossible under Nextstep */ 926 0, /* x_set_border_width, may be impossible under Nextstep */ 927 ns_set_cursor_color, 928 ns_set_cursor_type, 929 gui_set_font, /* generic OK */ 930 ns_set_foreground_color, 931 ns_set_icon_name, 932 ns_set_icon_type, 933 ns_set_internal_border_width, 934 gui_set_right_divider_width, /* generic OK */ 935 gui_set_bottom_divider_width, /* generic OK */ 936 ns_set_menu_bar_lines, 937 ns_set_mouse_color, 938 ns_explicitly_set_name, 939 gui_set_scroll_bar_width, /* generic OK */ 940 gui_set_scroll_bar_height, /* generic OK */ 941 ns_set_title, 942 gui_set_unsplittable, /* generic OK */ 943 gui_set_vertical_scroll_bars, /* generic OK */ 944 gui_set_horizontal_scroll_bars, /* generic OK */ 945 gui_set_visibility, /* generic OK */ 946 ns_set_tab_bar_lines, 947 ns_set_tool_bar_lines, 948 0, /* x_set_scroll_bar_foreground, will ignore (not possible on NS) */ 949 0, /* x_set_scroll_bar_background, will ignore (not possible on NS) */ 950 gui_set_screen_gamma, /* generic OK */ 951 gui_set_line_spacing, /* generic OK, sets f->extra_line_spacing to int */ 952 gui_set_left_fringe, /* generic OK */ 953 gui_set_right_fringe, /* generic OK */ 954 0, /* x_set_wait_for_wm, will ignore */ 955 gui_set_fullscreen, /* generic OK */ 956 gui_set_font_backend, /* generic OK */ 957 gui_set_alpha, 958 0, /* x_set_sticky */ 959 0, /* x_set_tool_bar_position */ 960 0, /* x_set_inhibit_double_buffering */ 961#ifdef NS_IMPL_COCOA 962 ns_set_undecorated, 963#else 964 0, /* ns_set_undecorated */ 965#endif 966 ns_set_parent_frame, 967 0, /* x_set_skip_taskbar */ 968 ns_set_no_focus_on_map, 969 ns_set_no_accept_focus, 970 ns_set_z_group, 971 0, /* x_set_override_redirect */ 972 gui_set_no_special_glyphs, 973#ifdef NS_IMPL_COCOA 974 ns_set_appearance, 975 ns_set_transparent_titlebar, 976#endif 977}; 978 979 980/* Handler for signals raised during x_create_frame. 981 FRAME is the frame which is partially constructed. */ 982 983static void 984unwind_create_frame (Lisp_Object frame) 985{ 986 struct frame *f = XFRAME (frame); 987 988 /* If frame is already dead, nothing to do. This can happen if the 989 display is disconnected after the frame has become official, but 990 before x_create_frame removes the unwind protect. */ 991 if (!FRAME_LIVE_P (f)) 992 return; 993 994 /* If frame is ``official'', nothing to do. */ 995 if (NILP (Fmemq (frame, Vframe_list))) 996 { 997#if defined GLYPH_DEBUG && defined ENABLE_CHECKING 998 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); 999#endif 1000 1001 /* If the frame's image cache refcount is still the same as our 1002 private shadow variable, it means we are unwinding a frame 1003 for which we didn't yet call init_frame_faces, where the 1004 refcount is incremented. Therefore, we increment it here, so 1005 that free_frame_faces, called in ns_free_frame_resources 1006 below, will not mistakenly decrement the counter that was not 1007 incremented yet to account for this new frame. */ 1008 if (FRAME_IMAGE_CACHE (f) != NULL 1009 && FRAME_IMAGE_CACHE (f)->refcount == image_cache_refcount) 1010 FRAME_IMAGE_CACHE (f)->refcount++; 1011 1012 ns_free_frame_resources (f); 1013 free_glyphs (f); 1014 1015#if defined GLYPH_DEBUG && defined ENABLE_CHECKING 1016 /* Check that reference counts are indeed correct. */ 1017 eassert (dpyinfo->terminal->image_cache->refcount == image_cache_refcount); 1018#endif 1019 } 1020} 1021 1022/* 1023 * Read geometry related parameters from preferences if not in PARMS. 1024 * Returns the union of parms and any preferences read. 1025 */ 1026 1027static Lisp_Object 1028get_geometry_from_preferences (struct ns_display_info *dpyinfo, 1029 Lisp_Object parms) 1030{ 1031 struct { 1032 const char *val; 1033 const char *cls; 1034 Lisp_Object tem; 1035 } r[] = { 1036 { "width", "Width", Qwidth }, 1037 { "height", "Height", Qheight }, 1038 { "left", "Left", Qleft }, 1039 { "top", "Top", Qtop }, 1040 }; 1041 1042 int i; 1043 for (i = 0; i < ARRAYELTS (r); ++i) 1044 { 1045 if (NILP (Fassq (r[i].tem, parms))) 1046 { 1047 Lisp_Object value 1048 = gui_display_get_arg (dpyinfo, parms, r[i].tem, r[i].val, r[i].cls, 1049 RES_TYPE_NUMBER); 1050 if (! EQ (value, Qunbound)) 1051 parms = Fcons (Fcons (r[i].tem, value), parms); 1052 } 1053 } 1054 1055 return parms; 1056} 1057 1058/* ========================================================================== 1059 1060 Lisp definitions 1061 1062 ========================================================================== */ 1063 1064DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame, 1065 1, 1, 0, 1066 doc: /* SKIP: real doc in xfns.c. */) 1067 (Lisp_Object parms) 1068{ 1069 struct frame *f; 1070 Lisp_Object frame, tem; 1071 Lisp_Object name; 1072 int minibuffer_only = 0; 1073 long window_prompting = 0; 1074 ptrdiff_t count = specpdl_ptr - specpdl; 1075 Lisp_Object display; 1076 struct ns_display_info *dpyinfo = NULL; 1077 Lisp_Object parent, parent_frame; 1078 struct kboard *kb; 1079 static int desc_ctr = 1; 1080 int x_width = 0, x_height = 0; 1081 1082 /* gui_display_get_arg modifies parms. */ 1083 parms = Fcopy_alist (parms); 1084 1085 /* Use this general default value to start with 1086 until we know if this frame has a specified name. */ 1087 Vx_resource_name = Vinvocation_name; 1088 1089 display = gui_display_get_arg (dpyinfo, parms, Qterminal, 0, 0, 1090 RES_TYPE_STRING); 1091 if (EQ (display, Qunbound)) 1092 display = Qnil; 1093 dpyinfo = check_ns_display_info (display); 1094 kb = dpyinfo->terminal->kboard; 1095 1096 if (!dpyinfo->terminal->name) 1097 error ("Terminal is not live, can't create new frames on it"); 1098 1099 name = gui_display_get_arg (dpyinfo, parms, Qname, 0, 0, 1100 RES_TYPE_STRING); 1101 if (!STRINGP (name) 1102 && ! EQ (name, Qunbound) 1103 && ! NILP (name)) 1104 error ("Invalid frame name--not a string or nil"); 1105 1106 if (STRINGP (name)) 1107 Vx_resource_name = name; 1108 1109 parent = gui_display_get_arg (dpyinfo, parms, Qparent_id, 0, 0, 1110 RES_TYPE_NUMBER); 1111 if (EQ (parent, Qunbound)) 1112 parent = Qnil; 1113 if (! NILP (parent)) 1114 CHECK_FIXNUM (parent); 1115 1116 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */ 1117 /* No need to protect DISPLAY because that's not used after passing 1118 it to make_frame_without_minibuffer. */ 1119 frame = Qnil; 1120 tem = gui_display_get_arg (dpyinfo, parms, Qminibuffer, 1121 "minibuffer", "Minibuffer", 1122 RES_TYPE_SYMBOL); 1123 if (EQ (tem, Qnone) || NILP (tem)) 1124 f = make_frame_without_minibuffer (Qnil, kb, display); 1125 else if (EQ (tem, Qonly)) 1126 { 1127 f = make_minibuffer_frame (); 1128 minibuffer_only = 1; 1129 } 1130 else if (WINDOWP (tem)) 1131 f = make_frame_without_minibuffer (tem, kb, display); 1132 else 1133 f = make_frame (1); 1134 1135 XSETFRAME (frame, f); 1136 1137 f->terminal = dpyinfo->terminal; 1138 1139 f->output_method = output_ns; 1140 f->output_data.ns = xzalloc (sizeof *f->output_data.ns); 1141 1142 FRAME_FONTSET (f) = -1; 1143 1144 fset_icon_name (f, gui_display_get_arg (dpyinfo, parms, Qicon_name, 1145 "iconName", "Title", 1146 RES_TYPE_STRING)); 1147 if (! STRINGP (f->icon_name)) 1148 fset_icon_name (f, Qnil); 1149 1150 FRAME_DISPLAY_INFO (f) = dpyinfo; 1151 1152 /* With FRAME_DISPLAY_INFO set up, this unwind-protect is safe. */ 1153 record_unwind_protect (unwind_create_frame, frame); 1154 1155 f->output_data.ns->window_desc = desc_ctr++; 1156 if (TYPE_RANGED_FIXNUMP (Window, parent)) 1157 { 1158 f->output_data.ns->parent_desc = XFIXNAT (parent); 1159 f->output_data.ns->explicit_parent = 1; 1160 } 1161 else 1162 { 1163 f->output_data.ns->parent_desc = FRAME_DISPLAY_INFO (f)->root_window; 1164 f->output_data.ns->explicit_parent = 0; 1165 } 1166 1167 /* Set the name; the functions to which we pass f expect the name to 1168 be set. */ 1169 if (EQ (name, Qunbound) || NILP (name) || ! STRINGP (name)) 1170 { 1171 fset_name (f, build_string ([ns_app_name UTF8String])); 1172 f->explicit_name = 0; 1173 } 1174 else 1175 { 1176 fset_name (f, name); 1177 f->explicit_name = 1; 1178 specbind (Qx_resource_name, name); 1179 } 1180 1181 block_input (); 1182 1183#ifdef NS_IMPL_COCOA 1184 mac_register_font_driver (f); 1185#else 1186 register_font_driver (&nsfont_driver, f); 1187#endif 1188 1189 image_cache_refcount = 1190 FRAME_IMAGE_CACHE (f) ? FRAME_IMAGE_CACHE (f)->refcount : 0; 1191 1192 gui_default_parameter (f, parms, Qfont_backend, Qnil, 1193 "fontBackend", "FontBackend", RES_TYPE_STRING); 1194 1195 { 1196 /* use for default font name */ 1197 id font = [NSFont userFixedPitchFontOfSize: -1.0]; /* default */ 1198 gui_default_parameter (f, parms, Qfontsize, 1199 make_fixnum (0 /* (int)[font pointSize] */), 1200 "fontSize", "FontSize", RES_TYPE_NUMBER); 1201 // Remove ' Regular', not handled by backends. 1202 char *fontname = xstrdup ([[font displayName] UTF8String]); 1203 int len = strlen (fontname); 1204 if (len > 8 && strcmp (fontname + len - 8, " Regular") == 0) 1205 fontname[len-8] = '\0'; 1206 gui_default_parameter (f, parms, Qfont, 1207 build_string (fontname), 1208 "font", "Font", RES_TYPE_STRING); 1209 xfree (fontname); 1210 } 1211 unblock_input (); 1212 1213 gui_default_parameter (f, parms, Qborder_width, make_fixnum (0), 1214 "borderwidth", "BorderWidth", RES_TYPE_NUMBER); 1215 gui_default_parameter (f, parms, Qinternal_border_width, make_fixnum (2), 1216 "internalBorderWidth", "InternalBorderWidth", 1217 RES_TYPE_NUMBER); 1218 gui_default_parameter (f, parms, Qright_divider_width, make_fixnum (0), 1219 NULL, NULL, RES_TYPE_NUMBER); 1220 gui_default_parameter (f, parms, Qbottom_divider_width, make_fixnum (0), 1221 NULL, NULL, RES_TYPE_NUMBER); 1222 1223 /* default vertical scrollbars on right on Mac */ 1224 { 1225 Lisp_Object spos 1226#ifdef NS_IMPL_GNUSTEP 1227 = Qt; 1228#else 1229 = Qright; 1230#endif 1231 gui_default_parameter (f, parms, Qvertical_scroll_bars, spos, 1232 "verticalScrollBars", "VerticalScrollBars", 1233 RES_TYPE_SYMBOL); 1234 } 1235 gui_default_parameter (f, parms, Qhorizontal_scroll_bars, Qnil, 1236 "horizontalScrollBars", "HorizontalScrollBars", 1237 RES_TYPE_SYMBOL); 1238 gui_default_parameter (f, parms, Qforeground_color, build_string ("Black"), 1239 "foreground", "Foreground", RES_TYPE_STRING); 1240 gui_default_parameter (f, parms, Qbackground_color, build_string ("White"), 1241 "background", "Background", RES_TYPE_STRING); 1242 gui_default_parameter (f, parms, Qline_spacing, Qnil, 1243 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER); 1244 gui_default_parameter (f, parms, Qleft_fringe, Qnil, 1245 "leftFringe", "LeftFringe", RES_TYPE_NUMBER); 1246 gui_default_parameter (f, parms, Qright_fringe, Qnil, 1247 "rightFringe", "RightFringe", RES_TYPE_NUMBER); 1248 gui_default_parameter (f, parms, Qno_special_glyphs, Qnil, 1249 NULL, NULL, RES_TYPE_BOOLEAN); 1250 1251 init_frame_faces (f); 1252 1253 /* Read comment about this code in corresponding place in xfns.c. */ 1254 tem = gui_display_get_arg (dpyinfo, parms, Qmin_width, NULL, NULL, 1255 RES_TYPE_NUMBER); 1256 if (FIXNUMP (tem)) 1257 store_frame_param (f, Qmin_width, tem); 1258 tem = gui_display_get_arg (dpyinfo, parms, Qmin_height, NULL, NULL, 1259 RES_TYPE_NUMBER); 1260 if (FIXNUMP (tem)) 1261 store_frame_param (f, Qmin_height, tem); 1262 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), 1263 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 5, 1, 1264 Qx_create_frame_1); 1265 1266 tem = gui_display_get_arg (dpyinfo, parms, Qundecorated, NULL, NULL, 1267 RES_TYPE_BOOLEAN); 1268 FRAME_UNDECORATED (f) = !NILP (tem) && !EQ (tem, Qunbound); 1269 store_frame_param (f, Qundecorated, FRAME_UNDECORATED (f) ? Qt : Qnil); 1270 1271#ifdef NS_IMPL_COCOA 1272 tem = gui_display_get_arg (dpyinfo, parms, Qns_appearance, NULL, NULL, 1273 RES_TYPE_SYMBOL); 1274 FRAME_NS_APPEARANCE (f) = EQ (tem, Qdark) 1275 ? ns_appearance_vibrant_dark : ns_appearance_aqua; 1276 store_frame_param (f, Qns_appearance, tem); 1277 1278 tem = gui_display_get_arg (dpyinfo, parms, Qns_transparent_titlebar, 1279 NULL, NULL, RES_TYPE_BOOLEAN); 1280 FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (tem) && !EQ (tem, Qunbound); 1281 store_frame_param (f, Qns_transparent_titlebar, tem); 1282#endif 1283 1284 parent_frame = gui_display_get_arg (dpyinfo, parms, Qparent_frame, NULL, NULL, 1285 RES_TYPE_SYMBOL); 1286 /* Accept parent-frame iff parent-id was not specified. */ 1287 if (!NILP (parent) 1288 || EQ (parent_frame, Qunbound) 1289 || NILP (parent_frame) 1290 || !FRAMEP (parent_frame) 1291 || !FRAME_LIVE_P (XFRAME (parent_frame))) 1292 parent_frame = Qnil; 1293 1294 fset_parent_frame (f, parent_frame); 1295 store_frame_param (f, Qparent_frame, parent_frame); 1296 1297 gui_default_parameter (f, parms, Qz_group, Qnil, NULL, NULL, RES_TYPE_SYMBOL); 1298 gui_default_parameter (f, parms, Qno_focus_on_map, Qnil, 1299 NULL, NULL, RES_TYPE_BOOLEAN); 1300 gui_default_parameter (f, parms, Qno_accept_focus, Qnil, 1301 NULL, NULL, RES_TYPE_BOOLEAN); 1302 1303 /* The resources controlling the menu-bar and tool-bar are 1304 processed specially at startup, and reflected in the mode 1305 variables; ignore them here. */ 1306 gui_default_parameter (f, parms, Qmenu_bar_lines, 1307 NILP (Vmenu_bar_mode) 1308 ? make_fixnum (0) : make_fixnum (1), 1309 NULL, NULL, RES_TYPE_NUMBER); 1310 gui_default_parameter (f, parms, Qtool_bar_lines, 1311 NILP (Vtool_bar_mode) 1312 ? make_fixnum (0) : make_fixnum (1), 1313 NULL, NULL, RES_TYPE_NUMBER); 1314 1315 gui_default_parameter (f, parms, Qbuffer_predicate, Qnil, "bufferPredicate", 1316 "BufferPredicate", RES_TYPE_SYMBOL); 1317 gui_default_parameter (f, parms, Qtitle, Qnil, "title", "Title", 1318 RES_TYPE_STRING); 1319 1320 parms = get_geometry_from_preferences (dpyinfo, parms); 1321 window_prompting = gui_figure_window_size (f, parms, false, true, 1322 &x_width, &x_height); 1323 1324 tem = gui_display_get_arg (dpyinfo, parms, Qunsplittable, 0, 0, 1325 RES_TYPE_BOOLEAN); 1326 f->no_split = minibuffer_only || (!EQ (tem, Qunbound) && !NILP (tem)); 1327 1328 /* NOTE: on other terms, this is done in set_mouse_color, however this 1329 was not getting called under Nextstep. */ 1330 f->output_data.ns->text_cursor = [NSCursor IBeamCursor]; 1331 f->output_data.ns->nontext_cursor = [NSCursor arrowCursor]; 1332 f->output_data.ns->modeline_cursor = [NSCursor pointingHandCursor]; 1333 f->output_data.ns->hand_cursor = [NSCursor pointingHandCursor]; 1334 f->output_data.ns->hourglass_cursor = [NSCursor disappearingItemCursor]; 1335 f->output_data.ns->horizontal_drag_cursor = [NSCursor resizeLeftRightCursor]; 1336 f->output_data.ns->vertical_drag_cursor = [NSCursor resizeUpDownCursor]; 1337 f->output_data.ns->left_edge_cursor = [NSCursor resizeLeftRightCursor]; 1338 f->output_data.ns->top_left_corner_cursor = [NSCursor arrowCursor]; 1339 f->output_data.ns->top_edge_cursor = [NSCursor resizeUpDownCursor]; 1340 f->output_data.ns->top_right_corner_cursor = [NSCursor arrowCursor]; 1341 f->output_data.ns->right_edge_cursor = [NSCursor resizeLeftRightCursor]; 1342 f->output_data.ns->bottom_right_corner_cursor = [NSCursor arrowCursor]; 1343 f->output_data.ns->bottom_edge_cursor = [NSCursor resizeUpDownCursor]; 1344 f->output_data.ns->bottom_left_corner_cursor = [NSCursor arrowCursor]; 1345 1346 FRAME_DISPLAY_INFO (f)->vertical_scroll_bar_cursor 1347 = [NSCursor arrowCursor]; 1348 FRAME_DISPLAY_INFO (f)->horizontal_scroll_bar_cursor 1349 = [NSCursor arrowCursor]; 1350 f->output_data.ns->current_pointer = f->output_data.ns->text_cursor; 1351 1352 f->output_data.ns->in_animation = NO; 1353 1354 [[EmacsView alloc] initFrameFromEmacs: f]; 1355 1356 ns_icon (f, parms); 1357 1358 /* ns_display_info does not have a reference_count. */ 1359 f->terminal->reference_count++; 1360 1361 /* It is now ok to make the frame official even if we get an error 1362 below. The frame needs to be on Vframe_list or making it visible 1363 won't work. */ 1364 Vframe_list = Fcons (frame, Vframe_list); 1365 1366 gui_default_parameter (f, parms, Qicon_type, Qnil, 1367 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL); 1368 1369 gui_default_parameter (f, parms, Qauto_raise, Qnil, 1370 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN); 1371 gui_default_parameter (f, parms, Qauto_lower, Qnil, 1372 "autoLower", "AutoLower", RES_TYPE_BOOLEAN); 1373 gui_default_parameter (f, parms, Qcursor_type, Qbox, 1374 "cursorType", "CursorType", RES_TYPE_SYMBOL); 1375 gui_default_parameter (f, parms, Qscroll_bar_width, Qnil, 1376 "scrollBarWidth", "ScrollBarWidth", 1377 RES_TYPE_NUMBER); 1378 gui_default_parameter (f, parms, Qscroll_bar_height, Qnil, 1379 "scrollBarHeight", "ScrollBarHeight", 1380 RES_TYPE_NUMBER); 1381 gui_default_parameter (f, parms, Qalpha, Qnil, 1382 "alpha", "Alpha", RES_TYPE_NUMBER); 1383 gui_default_parameter (f, parms, Qfullscreen, Qnil, 1384 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL); 1385 1386 /* Allow set_window_size_hook, now. */ 1387 f->can_set_window_size = true; 1388 1389 if (x_width > 0) 1390 SET_FRAME_WIDTH (f, x_width); 1391 if (x_height > 0) 1392 SET_FRAME_HEIGHT (f, x_height); 1393 1394 adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f), 0, 1, 1395 Qx_create_frame_2); 1396 1397 if (! f->output_data.ns->explicit_parent) 1398 { 1399 Lisp_Object visibility; 1400 1401 visibility = gui_display_get_arg (dpyinfo, parms, Qvisibility, 0, 0, 1402 RES_TYPE_SYMBOL); 1403 if (EQ (visibility, Qunbound)) 1404 visibility = Qt; 1405 1406 if (EQ (visibility, Qicon)) 1407 ns_iconify_frame (f); 1408 else if (! NILP (visibility)) 1409 { 1410 ns_make_frame_visible (f); 1411 [[FRAME_NS_VIEW (f) window] makeKeyWindow]; 1412 } 1413 else 1414 { 1415 /* Must have been Qnil. */ 1416 } 1417 } 1418 1419 if (FRAME_HAS_MINIBUF_P (f) 1420 && (!FRAMEP (KVAR (kb, Vdefault_minibuffer_frame)) 1421 || !FRAME_LIVE_P (XFRAME (KVAR (kb, Vdefault_minibuffer_frame))))) 1422 kset_default_minibuffer_frame (kb, frame); 1423 1424 /* All remaining specified parameters, which have not been "used" by 1425 gui_display_get_arg and friends, now go in the misc. alist of the 1426 frame. */ 1427 for (tem = parms; CONSP (tem); tem = XCDR (tem)) 1428 if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem)))) 1429 fset_param_alist (f, Fcons (XCAR (tem), f->param_alist)); 1430 1431 if (window_prompting & USPosition) 1432 ns_set_offset (f, f->left_pos, f->top_pos, 1); 1433 1434 /* Make sure windows on this frame appear in calls to next-window 1435 and similar functions. */ 1436 Vwindow_list = Qnil; 1437 1438 return unbind_to (count, frame); 1439} 1440 1441static BOOL 1442ns_window_is_ancestor (NSWindow *win, NSWindow *candidate) 1443/* Test whether CANDIDATE is an ancestor window of WIN. */ 1444{ 1445 if (candidate == NULL) 1446 return NO; 1447 else if (win == candidate) 1448 return YES; 1449 else 1450 return ns_window_is_ancestor(win, [candidate parentWindow]); 1451} 1452 1453DEFUN ("ns-frame-list-z-order", Fns_frame_list_z_order, 1454 Sns_frame_list_z_order, 0, 1, 0, 1455 doc: /* Return list of Emacs' frames, in Z (stacking) order. 1456If TERMINAL is non-nil and specifies a live frame, return the child 1457frames of that frame in Z (stacking) order. 1458 1459Frames are listed from topmost (first) to bottommost (last). */) 1460 (Lisp_Object terminal) 1461{ 1462 Lisp_Object frames = Qnil; 1463 NSWindow *parent = nil; 1464 1465 if (FRAMEP (terminal) && FRAME_LIVE_P (XFRAME (terminal))) 1466 parent = [FRAME_NS_VIEW (XFRAME (terminal)) window]; 1467 1468 for (NSWindow *win in [[NSApp orderedWindows] reverseObjectEnumerator]) 1469 { 1470 Lisp_Object frame; 1471 1472 /* Check against [win parentWindow] so that it doesn't match itself. */ 1473 if ([[win delegate] isKindOfClass:[EmacsView class]] 1474 && (parent == nil || ns_window_is_ancestor (parent, [win parentWindow]))) 1475 { 1476 XSETFRAME (frame, ((EmacsView *)[win delegate])->emacsframe); 1477 frames = Fcons(frame, frames); 1478 } 1479 } 1480 1481 return frames; 1482} 1483 1484DEFUN ("ns-frame-restack", Fns_frame_restack, Sns_frame_restack, 2, 3, 0, 1485 doc: /* Restack FRAME1 below FRAME2. 1486This means that if both frames are visible and the display areas of 1487these frames overlap, FRAME2 (partially) obscures FRAME1. If optional 1488third argument ABOVE is non-nil, restack FRAME1 above FRAME2. This 1489means that if both frames are visible and the display areas of these 1490frames overlap, FRAME1 (partially) obscures FRAME2. 1491 1492Some window managers may refuse to restack windows. */) 1493 (Lisp_Object frame1, Lisp_Object frame2, Lisp_Object above) 1494{ 1495 struct frame *f1 = decode_live_frame (frame1); 1496 struct frame *f2 = decode_live_frame (frame2); 1497 1498 if (FRAME_NS_VIEW (f1) && FRAME_NS_VIEW (f2)) 1499 { 1500 NSWindow *window = [FRAME_NS_VIEW (f1) window]; 1501 NSInteger window2 = [[FRAME_NS_VIEW (f2) window] windowNumber]; 1502 NSWindowOrderingMode flag = NILP (above) ? NSWindowBelow : NSWindowAbove; 1503 1504 [window orderWindow: flag 1505 relativeTo: window2]; 1506 1507 return Qt; 1508 } 1509 else 1510 { 1511 error ("Cannot restack frames"); 1512 return Qnil; 1513 } 1514} 1515 1516DEFUN ("ns-popup-font-panel", Fns_popup_font_panel, Sns_popup_font_panel, 1517 0, 1, "", 1518 doc: /* Pop up the font panel. */) 1519 (Lisp_Object frame) 1520{ 1521 struct frame *f = decode_window_system_frame (frame); 1522 id fm = [NSFontManager sharedFontManager]; 1523 struct font *font = f->output_data.ns->font; 1524 NSFont *nsfont; 1525#ifdef NS_IMPL_GNUSTEP 1526 nsfont = ((struct nsfont_info *)font)->nsfont; 1527#endif 1528#ifdef NS_IMPL_COCOA 1529 nsfont = (NSFont *) macfont_get_nsctfont (font); 1530#endif 1531 [fm setSelectedFont: nsfont isMultiple: NO]; 1532 [fm orderFrontFontPanel: NSApp]; 1533 return Qnil; 1534} 1535 1536 1537DEFUN ("ns-popup-color-panel", Fns_popup_color_panel, Sns_popup_color_panel, 1538 0, 1, "", 1539 doc: /* Pop up the color panel. */) 1540 (Lisp_Object frame) 1541{ 1542 check_window_system (NULL); 1543 [NSApp orderFrontColorPanel: NSApp]; 1544 return Qnil; 1545} 1546 1547static struct 1548{ 1549 id panel; 1550 BOOL ret; 1551#ifdef NS_IMPL_GNUSTEP 1552 NSString *dirS, *initS; 1553 BOOL no_types; 1554#endif 1555} ns_fd_data; 1556 1557void 1558ns_run_file_dialog (void) 1559{ 1560 if (ns_fd_data.panel == nil) return; 1561#ifdef NS_IMPL_COCOA 1562 ns_fd_data.ret = [ns_fd_data.panel runModal]; 1563#else 1564 if (ns_fd_data.no_types) 1565 { 1566 ns_fd_data.ret = [ns_fd_data.panel 1567 runModalForDirectory: ns_fd_data.dirS 1568 file: ns_fd_data.initS]; 1569 } 1570 else 1571 { 1572 ns_fd_data.ret = [ns_fd_data.panel 1573 runModalForDirectory: ns_fd_data.dirS 1574 file: ns_fd_data.initS 1575 types: nil]; 1576 } 1577#endif 1578 ns_fd_data.panel = nil; 1579} 1580 1581#ifdef NS_IMPL_COCOA 1582#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090 1583#define MODAL_OK_RESPONSE NSModalResponseOK 1584#endif 1585#endif 1586#ifndef MODAL_OK_RESPONSE 1587#define MODAL_OK_RESPONSE NSOKButton 1588#endif 1589 1590DEFUN ("ns-read-file-name", Fns_read_file_name, Sns_read_file_name, 1, 5, 0, 1591 doc: /* Use a graphical panel to read a file name, using prompt PROMPT. 1592Optional arg DIR, if non-nil, supplies a default directory. 1593Optional arg MUSTMATCH, if non-nil, means the returned file or 1594directory must exist. 1595Optional arg INIT, if non-nil, provides a default file name to use. 1596Optional arg DIR_ONLY_P, if non-nil, means choose only directories. */) 1597 (Lisp_Object prompt, Lisp_Object dir, Lisp_Object mustmatch, 1598 Lisp_Object init, Lisp_Object dir_only_p) 1599{ 1600 static id fileDelegate = nil; 1601 BOOL isSave = NILP (mustmatch) && NILP (dir_only_p); 1602 id panel; 1603 Lisp_Object fname = Qnil; 1604 1605 NSString *promptS = NILP (prompt) || !STRINGP (prompt) ? nil : 1606 [NSString stringWithUTF8String: SSDATA (prompt)]; 1607 NSString *dirS = NILP (dir) || !STRINGP (dir) ? 1608 [NSString stringWithUTF8String: SSDATA (BVAR (current_buffer, directory))] : 1609 [NSString stringWithUTF8String: SSDATA (dir)]; 1610 NSString *initS = NILP (init) || !STRINGP (init) ? nil : 1611 [NSString stringWithUTF8String: SSDATA (init)]; 1612 NSEvent *nxev; 1613 1614 check_window_system (NULL); 1615 1616 if (fileDelegate == nil) 1617 fileDelegate = [EmacsFileDelegate new]; 1618 1619 [NSCursor setHiddenUntilMouseMoves: NO]; 1620 1621 if ([dirS characterAtIndex: 0] == '~') 1622 dirS = [dirS stringByExpandingTildeInPath]; 1623 1624 panel = isSave ? 1625 (id)[NSSavePanel savePanel] : (id)[NSOpenPanel openPanel]; 1626 1627 [panel setTitle: promptS]; 1628 1629 [panel setAllowsOtherFileTypes: YES]; 1630 [panel setTreatsFilePackagesAsDirectories: YES]; 1631 [panel setDelegate: fileDelegate]; 1632 1633 if (! NILP (dir_only_p)) 1634 { 1635 [panel setCanChooseDirectories: YES]; 1636 [panel setCanChooseFiles: NO]; 1637 } 1638 else if (! isSave) 1639 { 1640 /* This is not quite what the documentation says, but it is compatible 1641 with the Gtk+ code. Also, the menu entry says "Open File...". */ 1642 [panel setCanChooseDirectories: NO]; 1643 [panel setCanChooseFiles: YES]; 1644 } 1645 1646 block_input (); 1647 ns_fd_data.panel = panel; 1648 ns_fd_data.ret = NO; 1649#ifdef NS_IMPL_COCOA 1650 if (! NILP (mustmatch) || ! NILP (dir_only_p)) 1651 [panel setAllowedFileTypes: nil]; 1652 if (dirS) [panel setDirectoryURL: [NSURL fileURLWithPath: dirS]]; 1653 if (initS && NILP (Ffile_directory_p (init))) 1654 [panel setNameFieldStringValue: [initS lastPathComponent]]; 1655 else 1656 [panel setNameFieldStringValue: @""]; 1657 1658#else 1659 ns_fd_data.no_types = NILP (mustmatch) && NILP (dir_only_p); 1660 ns_fd_data.dirS = dirS; 1661 ns_fd_data.initS = initS; 1662#endif 1663 1664 /* runModalForDirectory/runModal restarts the main event loop when done, 1665 so we must start an event loop and then pop up the file dialog. 1666 The file dialog may pop up a confirm dialog after Ok has been pressed, 1667 so we can not simply pop down on the Ok/Cancel press. 1668 */ 1669 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined 1670 location: NSMakePoint (0, 0) 1671 modifierFlags: 0 1672 timestamp: 0 1673 windowNumber: [[NSApp mainWindow] windowNumber] 1674 context: [NSApp context] 1675 subtype: 0 1676 data1: 0 1677 data2: NSAPP_DATA2_RUNFILEDIALOG]; 1678 1679 [NSApp postEvent: nxev atStart: NO]; 1680 while (ns_fd_data.panel != nil) 1681 [NSApp run]; 1682 1683 if (ns_fd_data.ret == MODAL_OK_RESPONSE) 1684 { 1685 NSString *str = ns_filename_from_panel (panel); 1686 if (! str) str = ns_directory_from_panel (panel); 1687 if (str) fname = build_string ([str UTF8String]); 1688 } 1689 1690 [[FRAME_NS_VIEW (SELECTED_FRAME ()) window] makeKeyWindow]; 1691 unblock_input (); 1692 1693 return fname; 1694} 1695 1696const char * 1697ns_get_defaults_value (const char *key) 1698{ 1699 NSObject *obj = [[NSUserDefaults standardUserDefaults] 1700 objectForKey: [NSString stringWithUTF8String: key]]; 1701 1702 if (!obj) return NULL; 1703 1704 return [[NSString stringWithFormat: @"%@", obj] UTF8String]; 1705} 1706 1707 1708DEFUN ("ns-get-resource", Fns_get_resource, Sns_get_resource, 2, 2, 0, 1709 doc: /* Return the value of the property NAME of OWNER from the defaults database. 1710If OWNER is nil, Emacs is assumed. */) 1711 (Lisp_Object owner, Lisp_Object name) 1712{ 1713 const char *value; 1714 1715 check_window_system (NULL); 1716 if (NILP (owner)) 1717 owner = build_string([ns_app_name UTF8String]); 1718 CHECK_STRING (name); 1719 1720 value = ns_get_defaults_value (SSDATA (name)); 1721 1722 if (value) 1723 return build_string (value); 1724 return Qnil; 1725} 1726 1727 1728DEFUN ("ns-set-resource", Fns_set_resource, Sns_set_resource, 3, 3, 0, 1729 doc: /* Set property NAME of OWNER to VALUE, from the defaults database. 1730If OWNER is nil, Emacs is assumed. 1731If VALUE is nil, the default is removed. */) 1732 (Lisp_Object owner, Lisp_Object name, Lisp_Object value) 1733{ 1734 check_window_system (NULL); 1735 if (NILP (owner)) 1736 owner = build_string ([ns_app_name UTF8String]); 1737 CHECK_STRING (name); 1738 if (NILP (value)) 1739 { 1740 [[NSUserDefaults standardUserDefaults] removeObjectForKey: 1741 [NSString stringWithUTF8String: SSDATA (name)]]; 1742 } 1743 else 1744 { 1745 CHECK_STRING (value); 1746 [[NSUserDefaults standardUserDefaults] setObject: 1747 [NSString stringWithUTF8String: SSDATA (value)] 1748 forKey: [NSString stringWithUTF8String: 1749 SSDATA (name)]]; 1750 } 1751 1752 return Qnil; 1753} 1754 1755 1756DEFUN ("x-server-max-request-size", Fx_server_max_request_size, 1757 Sx_server_max_request_size, 1758 0, 1, 0, 1759 doc: /* SKIP: real doc in xfns.c. */) 1760 (Lisp_Object terminal) 1761{ 1762 check_ns_display_info (terminal); 1763 /* This function has no real equivalent under Nextstep. Return nil to 1764 indicate this. */ 1765 return Qnil; 1766} 1767 1768 1769DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0, 1770 doc: /* SKIP: real doc in xfns.c. */) 1771 (Lisp_Object terminal) 1772{ 1773 check_ns_display_info (terminal); 1774#ifdef NS_IMPL_GNUSTEP 1775 return build_string ("GNU"); 1776#else 1777 return build_string ("Apple"); 1778#endif 1779} 1780 1781 1782DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0, 1783 doc: /* SKIP: real doc in xfns.c. */) 1784 (Lisp_Object terminal) 1785{ 1786 check_ns_display_info (terminal); 1787 /* NOTE: it is unclear what would best correspond with "protocol"; 1788 we return 10.3, meaning Panther, since this is roughly the 1789 level that GNUstep's APIs correspond to. The last number 1790 is where we distinguish between the Apple and GNUstep 1791 implementations ("distributor-specific release number") and 1792 give int'ized versions of major.minor. */ 1793 return list3i (10, 3, ns_appkit_version_int ()); 1794} 1795 1796 1797DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0, 1798 doc: /* SKIP: real doc in xfns.c. */) 1799 (Lisp_Object terminal) 1800{ 1801 check_ns_display_info (terminal); 1802 return make_fixnum (1); 1803} 1804 1805 1806DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0, 1807 doc: /* SKIP: real doc in xfns.c. */) 1808 (Lisp_Object terminal) 1809{ 1810 struct ns_display_info *dpyinfo = check_ns_display_info (terminal); 1811 1812 return make_fixnum (ns_display_pixel_height (dpyinfo) / (92.0/25.4)); 1813} 1814 1815 1816DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0, 1817 doc: /* SKIP: real doc in xfns.c. */) 1818 (Lisp_Object terminal) 1819{ 1820 struct ns_display_info *dpyinfo = check_ns_display_info (terminal); 1821 1822 return make_fixnum (ns_display_pixel_width (dpyinfo) / (92.0/25.4)); 1823} 1824 1825 1826DEFUN ("x-display-backing-store", Fx_display_backing_store, 1827 Sx_display_backing_store, 0, 1, 0, 1828 doc: /* SKIP: real doc in xfns.c. */) 1829 (Lisp_Object terminal) 1830{ 1831 check_ns_display_info (terminal); 1832 /* Note that the xfns.c version has different return values. */ 1833 switch ([ns_get_window (terminal) backingType]) 1834 { 1835 case NSBackingStoreBuffered: 1836 return intern ("buffered"); 1837#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300 1838 case NSBackingStoreRetained: 1839 return intern ("retained"); 1840 case NSBackingStoreNonretained: 1841 return intern ("non-retained"); 1842#endif 1843 default: 1844 error ("Strange value for backingType parameter of frame"); 1845 } 1846 return Qnil; /* not reached, shut compiler up */ 1847} 1848 1849 1850DEFUN ("x-display-visual-class", Fx_display_visual_class, 1851 Sx_display_visual_class, 0, 1, 0, 1852 doc: /* SKIP: real doc in xfns.c. */) 1853 (Lisp_Object terminal) 1854{ 1855 NSWindowDepth depth; 1856 1857 check_ns_display_info (terminal); 1858 depth = [[[NSScreen screens] objectAtIndex:0] depth]; 1859 1860 if ( depth == NSBestDepth (NSCalibratedWhiteColorSpace, 2, 2, YES, NULL)) 1861 return intern ("static-gray"); 1862 else if (depth == NSBestDepth (NSCalibratedWhiteColorSpace, 8, 8, YES, NULL)) 1863 return intern ("gray-scale"); 1864 else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 8, 8, YES, NULL)) 1865 return intern ("pseudo-color"); 1866 else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 4, 12, NO, NULL)) 1867 return intern ("true-color"); 1868 else if ( depth == NSBestDepth (NSCalibratedRGBColorSpace, 8, 24, NO, NULL)) 1869 return intern ("direct-color"); 1870 else 1871 /* Color management as far as we do it is really handled by 1872 Nextstep itself anyway. */ 1873 return intern ("direct-color"); 1874} 1875 1876 1877DEFUN ("x-display-save-under", Fx_display_save_under, 1878 Sx_display_save_under, 0, 1, 0, 1879 doc: /* SKIP: real doc in xfns.c. */) 1880 (Lisp_Object terminal) 1881{ 1882 check_ns_display_info (terminal); 1883 switch ([ns_get_window (terminal) backingType]) 1884 { 1885 case NSBackingStoreBuffered: 1886 return Qt; 1887 1888#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300 1889 case NSBackingStoreRetained: 1890 case NSBackingStoreNonretained: 1891 return Qnil; 1892#endif 1893 1894 default: 1895 error ("Strange value for backingType parameter of frame"); 1896 } 1897 return Qnil; /* not reached, shut compiler up */ 1898} 1899 1900 1901DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection, 1902 1, 3, 0, 1903 doc: /* SKIP: real doc in xfns.c. */) 1904 (Lisp_Object display, Lisp_Object resource_string, Lisp_Object must_succeed) 1905{ 1906 struct ns_display_info *dpyinfo; 1907 1908 CHECK_STRING (display); 1909 1910 nxatoms_of_nsselect (); 1911 dpyinfo = ns_term_init (display); 1912 if (dpyinfo == 0) 1913 { 1914 if (!NILP (must_succeed)) 1915 fatal ("Display on %s not responding.\n", 1916 SSDATA (display)); 1917 else 1918 error ("Display on %s not responding.\n", 1919 SSDATA (display)); 1920 } 1921 1922 return Qnil; 1923} 1924 1925 1926DEFUN ("x-close-connection", Fx_close_connection, Sx_close_connection, 1927 1, 1, 0, 1928 doc: /* SKIP: real doc in xfns.c. */) 1929 (Lisp_Object terminal) 1930{ 1931 check_ns_display_info (terminal); 1932 [NSApp terminate: NSApp]; 1933 return Qnil; 1934} 1935 1936 1937DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0, 1938 doc: /* SKIP: real doc in xfns.c. */) 1939 (void) 1940{ 1941 Lisp_Object result = Qnil; 1942 struct ns_display_info *ndi; 1943 1944 for (ndi = x_display_list; ndi; ndi = ndi->next) 1945 result = Fcons (XCAR (ndi->name_list_element), result); 1946 1947 return result; 1948} 1949 1950 1951DEFUN ("ns-hide-others", Fns_hide_others, Sns_hide_others, 1952 0, 0, 0, 1953 doc: /* Hides all applications other than Emacs. */) 1954 (void) 1955{ 1956 check_window_system (NULL); 1957 [NSApp hideOtherApplications: NSApp]; 1958 return Qnil; 1959} 1960 1961DEFUN ("ns-hide-emacs", Fns_hide_emacs, Sns_hide_emacs, 1962 1, 1, 0, 1963 doc: /* If ON is non-nil, the entire Emacs application is hidden. 1964Otherwise if Emacs is hidden, it is unhidden. 1965If ON is equal to `activate', Emacs is unhidden and becomes 1966the active application. */) 1967 (Lisp_Object on) 1968{ 1969 check_window_system (NULL); 1970 if (EQ (on, intern ("activate"))) 1971 { 1972 [NSApp unhide: NSApp]; 1973 [NSApp activateIgnoringOtherApps: YES]; 1974 } 1975 else if (NILP (on)) 1976 [NSApp unhide: NSApp]; 1977 else 1978 [NSApp hide: NSApp]; 1979 return Qnil; 1980} 1981 1982 1983DEFUN ("ns-emacs-info-panel", Fns_emacs_info_panel, Sns_emacs_info_panel, 1984 0, 0, 0, 1985 doc: /* Shows the `Info' or `About' panel for Emacs. */) 1986 (void) 1987{ 1988 check_window_system (NULL); 1989 [NSApp orderFrontStandardAboutPanel: nil]; 1990 return Qnil; 1991} 1992 1993 1994DEFUN ("ns-font-name", Fns_font_name, Sns_font_name, 1, 1, 0, 1995 doc: /* Determine font PostScript or family name for font NAME. 1996NAME should be a string containing either the font name or an XLFD 1997font descriptor. If string contains `fontset' and not 1998`fontset-startup', it is left alone. */) 1999 (Lisp_Object name) 2000{ 2001 char *nm; 2002 CHECK_STRING (name); 2003 nm = SSDATA (name); 2004 2005 if (nm[0] != '-') 2006 return name; 2007 if (strstr (nm, "fontset") && !strstr (nm, "fontset-startup")) 2008 return name; 2009 2010 return build_string (ns_xlfd_to_fontname (SSDATA (name))); 2011} 2012 2013 2014DEFUN ("ns-list-colors", Fns_list_colors, Sns_list_colors, 0, 1, 0, 2015 doc: /* Return a list of all available colors. 2016The optional argument FRAME is currently ignored. */) 2017 (Lisp_Object frame) 2018{ 2019 Lisp_Object list = Qnil; 2020 NSEnumerator *colorlists; 2021 NSColorList *clist; 2022 2023 if (!NILP (frame)) 2024 { 2025 CHECK_FRAME (frame); 2026 if (! FRAME_NS_P (XFRAME (frame))) 2027 error ("non-Nextstep frame used in `ns-list-colors'"); 2028 } 2029 2030 block_input (); 2031 2032 colorlists = [[NSColorList availableColorLists] objectEnumerator]; 2033 while ((clist = [colorlists nextObject])) 2034 { 2035 if ([[clist name] length] < 7 || 2036 [[clist name] rangeOfString: @"PANTONE"].location == 0) 2037 { 2038 NSEnumerator *cnames = [[clist allKeys] reverseObjectEnumerator]; 2039 NSString *cname; 2040 while ((cname = [cnames nextObject])) 2041 list = Fcons (build_string ([cname UTF8String]), list); 2042/* for (i = [[clist allKeys] count] - 1; i >= 0; i--) 2043 list = Fcons (build_string ([[[clist allKeys] objectAtIndex: i] 2044 UTF8String]), list); */ 2045 } 2046 } 2047 2048 unblock_input (); 2049 2050 return list; 2051} 2052 2053 2054DEFUN ("ns-list-services", Fns_list_services, Sns_list_services, 0, 0, 0, 2055 doc: /* List available Nextstep services by querying NSApp. */) 2056 (void) 2057{ 2058#ifdef NS_IMPL_COCOA 2059 /* You can't get services like this in 10.6+. */ 2060 return Qnil; 2061#else 2062 Lisp_Object ret = Qnil; 2063 NSMenu *svcs; 2064 2065 check_window_system (NULL); 2066 svcs = [[NSMenu alloc] initWithTitle: @"Services"]; 2067 [NSApp setServicesMenu: svcs]; 2068 [NSApp registerServicesMenuSendTypes: ns_send_types 2069 returnTypes: ns_return_types]; 2070 2071 [svcs setAutoenablesItems: NO]; 2072 2073 ret = interpret_services_menu (svcs, Qnil, ret); 2074 return ret; 2075#endif 2076} 2077 2078 2079DEFUN ("ns-perform-service", Fns_perform_service, Sns_perform_service, 2080 2, 2, 0, 2081 doc: /* Perform Nextstep SERVICE on SEND. 2082SEND should be either a string or nil. 2083The return value is the result of the service, as string, or nil if 2084there was no result. */) 2085 (Lisp_Object service, Lisp_Object send) 2086{ 2087 id pb; 2088 NSString *svcName; 2089 char *utfStr; 2090 2091 CHECK_STRING (service); 2092 check_window_system (NULL); 2093 2094 utfStr = SSDATA (service); 2095 svcName = [NSString stringWithUTF8String: utfStr]; 2096 2097 pb =[NSPasteboard pasteboardWithUniqueName]; 2098 ns_string_to_pasteboard (pb, send); 2099 2100 if (NSPerformService (svcName, pb) == NO) 2101 Fsignal (Qquit, list1 (build_string ("service not available"))); 2102 2103 if ([[pb types] count] == 0) 2104 return build_string (""); 2105 return ns_string_from_pasteboard (pb); 2106} 2107 2108 2109#ifdef NS_IMPL_COCOA 2110 2111/* Compile and execute the AppleScript SCRIPT and return the error 2112 status as function value. A zero is returned if compilation and 2113 execution is successful, in which case *RESULT is set to a Lisp 2114 string or a number containing the resulting script value. Otherwise, 2115 1 is returned. */ 2116static int 2117ns_do_applescript (Lisp_Object script, Lisp_Object *result) 2118{ 2119 NSAppleEventDescriptor *desc; 2120 NSDictionary *errorDict; 2121 NSAppleEventDescriptor *returnDescriptor = NULL; 2122 2123 NSAppleScript *scriptObject = 2124 [[NSAppleScript alloc] initWithSource: 2125 [NSString stringWithUTF8String: SSDATA (script)]]; 2126 2127 returnDescriptor = [scriptObject executeAndReturnError: &errorDict]; 2128 [scriptObject release]; 2129 *result = Qnil; 2130 2131 if (returnDescriptor != NULL) 2132 { 2133 // successful execution 2134 if (kAENullEvent != [returnDescriptor descriptorType]) 2135 { 2136 *result = Qt; 2137 // script returned an AppleScript result 2138 if ((typeUnicodeText == [returnDescriptor descriptorType]) || 2139#if defined (NS_IMPL_COCOA) 2140 (typeUTF16ExternalRepresentation 2141 == [returnDescriptor descriptorType]) || 2142#endif 2143 (typeUTF8Text == [returnDescriptor descriptorType]) || 2144 (typeCString == [returnDescriptor descriptorType])) 2145 { 2146 desc = [returnDescriptor coerceToDescriptorType: typeUTF8Text]; 2147 if (desc) 2148 *result = build_string([[desc stringValue] UTF8String]); 2149 } 2150 else 2151 { 2152 /* use typeUTF16ExternalRepresentation? */ 2153 // coerce the result to the appropriate ObjC type 2154 desc = [returnDescriptor coerceToDescriptorType: typeUTF8Text]; 2155 if (desc) 2156 *result = make_fixnum([desc int32Value]); 2157 } 2158 } 2159 } 2160 else 2161 { 2162 // no script result, return error 2163 return 1; 2164 } 2165 return 0; 2166} 2167 2168/* Helper function called from sendEvent to run AppleScript 2169 from within the main event loop. */ 2170 2171void 2172ns_run_ascript (void) 2173{ 2174 if (! NILP (as_script)) 2175 as_status = ns_do_applescript (as_script, as_result); 2176 as_script = Qnil; 2177} 2178 2179DEFUN ("ns-do-applescript", Fns_do_applescript, Sns_do_applescript, 1, 1, 0, 2180 doc: /* Execute AppleScript SCRIPT and return the result. 2181If compilation and execution are successful, the resulting script value 2182is returned as a string, a number or, in the case of other constructs, t. 2183In case the execution fails, an error is signaled. */) 2184 (Lisp_Object script) 2185{ 2186 Lisp_Object result; 2187 int status; 2188 NSEvent *nxev; 2189 struct input_event ev; 2190 2191 CHECK_STRING (script); 2192 check_window_system (NULL); 2193 2194 block_input (); 2195 2196 as_script = script; 2197 as_result = &result; 2198 2199 /* Executing AppleScript requires the event loop to run, otherwise 2200 errors aren't returned and executeAndReturnError hangs forever. 2201 Post an event that runs AppleScript and then start the event 2202 loop. The event loop is exited when the script is done. */ 2203 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined 2204 location: NSMakePoint (0, 0) 2205 modifierFlags: 0 2206 timestamp: 0 2207 windowNumber: [[NSApp mainWindow] windowNumber] 2208 context: [NSApp context] 2209 subtype: 0 2210 data1: 0 2211 data2: NSAPP_DATA2_RUNASSCRIPT]; 2212 2213 [NSApp postEvent: nxev atStart: NO]; 2214 2215 /* If there are other events, the event loop may exit. Keep running 2216 until the script has been handled. */ 2217 ns_init_events (&ev); 2218 while (! NILP (as_script)) 2219 [NSApp run]; 2220 ns_finish_events (); 2221 2222 status = as_status; 2223 as_status = 0; 2224 as_result = 0; 2225 unblock_input (); 2226 if (status == 0) 2227 return result; 2228 else if (!STRINGP (result)) 2229 error ("AppleScript error %d", status); 2230 else 2231 error ("%s", SSDATA (result)); 2232} 2233#endif 2234 2235 2236 2237/* ========================================================================== 2238 2239 Miscellaneous functions not called through hooks 2240 2241 ========================================================================== */ 2242 2243/* called from frame.c */ 2244struct ns_display_info * 2245check_x_display_info (Lisp_Object frame) 2246{ 2247 return check_ns_display_info (frame); 2248} 2249 2250 2251void 2252ns_set_scroll_bar_default_width (struct frame *f) 2253{ 2254 int wid = FRAME_COLUMN_WIDTH (f); 2255 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = NS_SCROLL_BAR_WIDTH_DEFAULT; 2256 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + 2257 wid - 1) / wid; 2258} 2259 2260void 2261ns_set_scroll_bar_default_height (struct frame *f) 2262{ 2263 int height = FRAME_LINE_HEIGHT (f); 2264 FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) = NS_SCROLL_BAR_WIDTH_DEFAULT; 2265 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + 2266 height - 1) / height; 2267} 2268 2269/* Terms implement this instead of x-get-resource directly. */ 2270const char * 2271ns_get_string_resource (void *_rdb, const char *name, const char *class) 2272{ 2273 /* remove appname prefix; TODO: allow for !="Emacs" */ 2274 const char *res, *toCheck = class + (!strncmp (class, "Emacs.", 6) ? 6 : 0); 2275 2276 check_window_system (NULL); 2277 2278 if (inhibit_x_resources) 2279 /* --quick was passed, so this is a no-op. */ 2280 return NULL; 2281 2282 res = ns_get_defaults_value (toCheck); 2283 return (const char *) (!res ? NULL 2284 : !c_strncasecmp (res, "YES", 3) ? "true" 2285 : !c_strncasecmp (res, "NO", 2) ? "false" 2286 : res); 2287} 2288 2289/* ========================================================================== 2290 2291 Lisp definitions that, for whatever reason, we can't alias as 'ns-XXX'. 2292 2293 ========================================================================== */ 2294 2295 2296DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0, 2297 doc: /* SKIP: real doc in xfns.c. */) 2298 (Lisp_Object color, Lisp_Object frame) 2299{ 2300 NSColor * col; 2301 check_window_system (NULL); 2302 return ns_lisp_to_color (color, &col) ? Qnil : Qt; 2303} 2304 2305 2306DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0, 2307 doc: /* SKIP: real doc in xfns.c. */) 2308 (Lisp_Object color, Lisp_Object frame) 2309{ 2310 NSColor * col; 2311 EmacsCGFloat red, green, blue, alpha; 2312 2313 check_window_system (NULL); 2314 CHECK_STRING (color); 2315 2316 block_input (); 2317 if (ns_lisp_to_color (color, &col)) 2318 { 2319 unblock_input (); 2320 return Qnil; 2321 } 2322 2323 [[col colorUsingDefaultColorSpace] 2324 getRed: &red green: &green blue: &blue alpha: &alpha]; 2325 unblock_input (); 2326 return list3i (lrint (red * 65280), lrint (green * 65280), 2327 lrint (blue * 65280)); 2328} 2329 2330 2331DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0, 2332 doc: /* SKIP: real doc in xfns.c. */) 2333 (Lisp_Object terminal) 2334{ 2335 NSWindowDepth depth; 2336 NSString *colorSpace; 2337 2338 check_ns_display_info (terminal); 2339 depth = [[[NSScreen screens] objectAtIndex:0] depth]; 2340 colorSpace = NSColorSpaceFromDepth (depth); 2341 2342 return [colorSpace isEqualToString: NSDeviceWhiteColorSpace] 2343 || [colorSpace isEqualToString: NSCalibratedWhiteColorSpace] 2344 ? Qnil : Qt; 2345} 2346 2347 2348DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p, 2349 0, 1, 0, 2350 doc: /* SKIP: real doc in xfns.c. */) 2351 (Lisp_Object terminal) 2352{ 2353 NSWindowDepth depth; 2354 2355 check_ns_display_info (terminal); 2356 depth = [[[NSScreen screens] objectAtIndex:0] depth]; 2357 2358 return NSBitsPerPixelFromDepth (depth) > 1 ? Qt : Qnil; 2359} 2360 2361 2362DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width, 2363 0, 1, 0, 2364 doc: /* SKIP: real doc in xfns.c. */) 2365 (Lisp_Object terminal) 2366{ 2367 struct ns_display_info *dpyinfo = check_ns_display_info (terminal); 2368 2369 return make_fixnum (ns_display_pixel_width (dpyinfo)); 2370} 2371 2372 2373DEFUN ("x-display-pixel-height", Fx_display_pixel_height, 2374 Sx_display_pixel_height, 0, 1, 0, 2375 doc: /* SKIP: real doc in xfns.c. */) 2376 (Lisp_Object terminal) 2377{ 2378 struct ns_display_info *dpyinfo = check_ns_display_info (terminal); 2379 2380 return make_fixnum (ns_display_pixel_height (dpyinfo)); 2381} 2382 2383#ifdef NS_IMPL_COCOA 2384 2385/* Returns the name for the screen that OBJ represents, or NULL. 2386 Caller must free return value. 2387*/ 2388 2389static char * 2390ns_get_name_from_ioreg (io_object_t obj) 2391{ 2392 char *name = NULL; 2393 2394 NSDictionary *info = (NSDictionary *) 2395 IODisplayCreateInfoDictionary (obj, kIODisplayOnlyPreferredName); 2396 NSDictionary *names = [info objectForKey: 2397 [NSString stringWithUTF8String: 2398 kDisplayProductName]]; 2399 2400 if ([names count] > 0) 2401 { 2402 NSString *n = [names objectForKey: [[names allKeys] 2403 objectAtIndex:0]]; 2404 if (n != nil) name = xstrdup ([n UTF8String]); 2405 } 2406 2407 [info release]; 2408 2409 return name; 2410} 2411 2412/* Returns the name for the screen that DID came from, or NULL. 2413 Caller must free return value. 2414*/ 2415 2416static char * 2417ns_screen_name (CGDirectDisplayID did) 2418{ 2419 char *name = NULL; 2420 2421#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 2422#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 2423 if (CGDisplayIOServicePort == NULL) 2424#endif 2425 { 2426 mach_port_t masterPort; 2427 io_iterator_t it; 2428 io_object_t obj; 2429 2430 /* CGDisplayIOServicePort is deprecated. Do it another (harder) way. 2431 2432 Is this code OK for macOS < 10.9, and GNUstep? I suspect it is, 2433 in which case is it worth keeping the other method in here? */ 2434 2435 if (IOMasterPort (MACH_PORT_NULL, &masterPort) != kIOReturnSuccess 2436 || IOServiceGetMatchingServices (masterPort, 2437 IOServiceMatching ("IONDRVDevice"), 2438 &it) != kIOReturnSuccess) 2439 return name; 2440 2441 /* Must loop until we find a name. Many devices can have the same unit 2442 number (represents different GPU parts), but only one has a name. */ 2443 while (! name && (obj = IOIteratorNext (it))) 2444 { 2445 CFMutableDictionaryRef props; 2446 const void *val; 2447 2448 if (IORegistryEntryCreateCFProperties (obj, 2449 &props, 2450 kCFAllocatorDefault, 2451 kNilOptions) == kIOReturnSuccess 2452 && props != nil 2453 && (val = CFDictionaryGetValue(props, @"IOFBDependentIndex"))) 2454 { 2455 unsigned nr = [(NSNumber *)val unsignedIntegerValue]; 2456 if (nr == CGDisplayUnitNumber (did)) 2457 name = ns_get_name_from_ioreg (obj); 2458 } 2459 2460 CFRelease (props); 2461 IOObjectRelease (obj); 2462 } 2463 2464 IOObjectRelease (it); 2465 } 2466#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 2467 else 2468#endif 2469#endif /* #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */ 2470#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 2471 name = ns_get_name_from_ioreg (CGDisplayIOServicePort (did)); 2472#endif 2473 return name; 2474} 2475#endif /* NS_IMPL_COCOA */ 2476 2477static Lisp_Object 2478ns_make_monitor_attribute_list (struct MonitorInfo *monitors, 2479 int n_monitors, 2480 int primary_monitor, 2481 const char *source) 2482{ 2483 Lisp_Object monitor_frames = make_nil_vector (n_monitors); 2484 Lisp_Object frame, rest; 2485 NSArray *screens = [NSScreen screens]; 2486 int i; 2487 2488 FOR_EACH_FRAME (rest, frame) 2489 { 2490 struct frame *f = XFRAME (frame); 2491 2492 if (FRAME_NS_P (f)) 2493 { 2494 NSView *view = FRAME_NS_VIEW (f); 2495 NSScreen *screen = [[view window] screen]; 2496 NSUInteger k; 2497 2498 i = -1; 2499 for (k = 0; i == -1 && k < [screens count]; ++k) 2500 { 2501 if ([screens objectAtIndex: k] == screen) 2502 i = (int)k; 2503 } 2504 2505 if (i > -1) 2506 ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i))); 2507 } 2508 } 2509 2510 return make_monitor_attribute_list (monitors, n_monitors, primary_monitor, 2511 monitor_frames, source); 2512} 2513 2514DEFUN ("ns-display-monitor-attributes-list", 2515 Fns_display_monitor_attributes_list, 2516 Sns_display_monitor_attributes_list, 2517 0, 1, 0, 2518 doc: /* Return a list of physical monitor attributes on the X display TERMINAL. 2519 2520The optional argument TERMINAL specifies which display to ask about. 2521TERMINAL should be a terminal object, a frame or a display name (a string). 2522If omitted or nil, that stands for the selected frame's display. 2523 2524In addition to the standard attribute keys listed in 2525`display-monitor-attributes-list', the following keys are contained in 2526the attributes: 2527 2528 source -- String describing the source from which multi-monitor 2529 information is obtained, \"NS\" is always the source." 2530 2531Internal use only, use `display-monitor-attributes-list' instead. */) 2532 (Lisp_Object terminal) 2533{ 2534 struct terminal *term = decode_live_terminal (terminal); 2535 NSArray *screens; 2536 NSUInteger i, n_monitors; 2537 struct MonitorInfo *monitors; 2538 Lisp_Object attributes_list = Qnil; 2539 CGFloat primary_display_height = 0; 2540 2541 if (term->type != output_ns) 2542 return Qnil; 2543 2544 screens = [NSScreen screens]; 2545 n_monitors = [screens count]; 2546 if (n_monitors == 0) 2547 return Qnil; 2548 2549 monitors = xzalloc (n_monitors * sizeof *monitors); 2550 2551 for (i = 0; i < [screens count]; ++i) 2552 { 2553 NSScreen *s = [screens objectAtIndex:i]; 2554 struct MonitorInfo *m = &monitors[i]; 2555 NSRect fr = [s frame]; 2556 NSRect vfr = [s visibleFrame]; 2557 short y, vy; 2558 2559#ifdef NS_IMPL_COCOA 2560 NSDictionary *dict = [s deviceDescription]; 2561 NSNumber *nid = [dict objectForKey:@"NSScreenNumber"]; 2562 CGDirectDisplayID did = [nid unsignedIntValue]; 2563#endif 2564 if (i == 0) 2565 { 2566 primary_display_height = fr.size.height; 2567 y = (short) fr.origin.y; 2568 vy = (short) vfr.origin.y; 2569 } 2570 else 2571 { 2572 // Flip y coordinate as NS has y starting from the bottom. 2573 y = (short) (primary_display_height - fr.size.height - fr.origin.y); 2574 vy = (short) (primary_display_height - 2575 vfr.size.height - vfr.origin.y); 2576 } 2577 2578 m->geom.x = (short) fr.origin.x; 2579 m->geom.y = y; 2580 m->geom.width = (unsigned short) fr.size.width; 2581 m->geom.height = (unsigned short) fr.size.height; 2582 2583 m->work.x = (short) vfr.origin.x; 2584 // y is flipped on NS, so vy - y are pixels missing at the bottom, 2585 // and fr.size.height - vfr.size.height are pixels missing in total. 2586 // Pixels missing at top are 2587 // fr.size.height - vfr.size.height - vy + y. 2588 // work.y is then pixels missing at top + y. 2589 m->work.y = (short) (fr.size.height - vfr.size.height) - vy + y + y; 2590 m->work.width = (unsigned short) vfr.size.width; 2591 m->work.height = (unsigned short) vfr.size.height; 2592 2593#ifdef NS_IMPL_COCOA 2594 m->name = ns_screen_name (did); 2595 2596 { 2597 CGSize mms = CGDisplayScreenSize (did); 2598 m->mm_width = (int) mms.width; 2599 m->mm_height = (int) mms.height; 2600 } 2601 2602#else 2603 // Assume 92 dpi as x-display-mm-height/x-display-mm-width does. 2604 m->mm_width = (int) (25.4 * fr.size.width / 92.0); 2605 m->mm_height = (int) (25.4 * fr.size.height / 92.0); 2606#endif 2607 } 2608 2609 // Primary monitor is always first for NS. 2610 attributes_list = ns_make_monitor_attribute_list (monitors, n_monitors, 2611 0, "NS"); 2612 2613 free_monitors (monitors, n_monitors); 2614 return attributes_list; 2615} 2616 2617 2618DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes, 2619 0, 1, 0, 2620 doc: /* SKIP: real doc in xfns.c. */) 2621 (Lisp_Object terminal) 2622{ 2623 check_ns_display_info (terminal); 2624 return make_fixnum 2625 (NSBitsPerPixelFromDepth ([[[NSScreen screens] objectAtIndex:0] depth])); 2626} 2627 2628 2629DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells, 2630 0, 1, 0, 2631 doc: /* SKIP: real doc in xfns.c. */) 2632 (Lisp_Object terminal) 2633{ 2634 struct ns_display_info *dpyinfo = check_ns_display_info (terminal); 2635 /* We force 24+ bit depths to 24-bit to prevent an overflow. */ 2636 return make_fixnum (1 << min (dpyinfo->n_planes, 24)); 2637} 2638 2639/* TODO: move to xdisp or similar */ 2640static void 2641compute_tip_xy (struct frame *f, 2642 Lisp_Object parms, 2643 Lisp_Object dx, 2644 Lisp_Object dy, 2645 int width, 2646 int height, 2647 int *root_x, 2648 int *root_y) 2649{ 2650 Lisp_Object left, top, right, bottom; 2651 NSPoint pt; 2652 NSScreen *screen; 2653 2654 /* Start with user-specified or mouse position. */ 2655 left = Fcdr (Fassq (Qleft, parms)); 2656 top = Fcdr (Fassq (Qtop, parms)); 2657 right = Fcdr (Fassq (Qright, parms)); 2658 bottom = Fcdr (Fassq (Qbottom, parms)); 2659 2660 if ((!FIXNUMP (left) && !FIXNUMP (right)) 2661 || (!FIXNUMP (top) && !FIXNUMP (bottom))) 2662 pt = [NSEvent mouseLocation]; 2663 else 2664 { 2665 /* Absolute coordinates. */ 2666 pt.x = FIXNUMP (left) ? XFIXNUM (left) : XFIXNUM (right); 2667 pt.y = (ns_display_pixel_height (FRAME_DISPLAY_INFO (f)) 2668 - (FIXNUMP (top) ? XFIXNUM (top) : XFIXNUM (bottom)) 2669 - height); 2670 } 2671 2672 /* Find the screen that pt is on. */ 2673 for (screen in [NSScreen screens]) 2674 if (pt.x >= screen.frame.origin.x 2675 && pt.x < screen.frame.origin.x + screen.frame.size.width 2676 && pt.y >= screen.frame.origin.y 2677 && pt.y < screen.frame.origin.y + screen.frame.size.height) 2678 break; 2679 2680 /* We could use this instead of the if above: 2681 2682 if (CGRectContainsPoint ([screen frame], pt)) 2683 2684 which would be neater, but it causes problems building on old 2685 versions of macOS and in GNUstep. */ 2686 2687 /* Ensure in bounds. (Note, screen origin = lower left.) */ 2688 if (FIXNUMP (left) || FIXNUMP (right)) 2689 *root_x = pt.x; 2690 else if (pt.x + XFIXNUM (dx) <= screen.frame.origin.x) 2691 *root_x = screen.frame.origin.x; 2692 else if (pt.x + XFIXNUM (dx) + width 2693 <= screen.frame.origin.x + screen.frame.size.width) 2694 /* It fits to the right of the pointer. */ 2695 *root_x = pt.x + XFIXNUM (dx); 2696 else if (width + XFIXNUM (dx) <= pt.x) 2697 /* It fits to the left of the pointer. */ 2698 *root_x = pt.x - width - XFIXNUM (dx); 2699 else 2700 /* Put it left justified on the screen -- it ought to fit that way. */ 2701 *root_x = screen.frame.origin.x; 2702 2703 if (FIXNUMP (top) || FIXNUMP (bottom)) 2704 *root_y = pt.y; 2705 else if (pt.y - XFIXNUM (dy) - height >= screen.frame.origin.y) 2706 /* It fits below the pointer. */ 2707 *root_y = pt.y - height - XFIXNUM (dy); 2708 else if (pt.y + XFIXNUM (dy) + height 2709 <= screen.frame.origin.y + screen.frame.size.height) 2710 /* It fits above the pointer. */ 2711 *root_y = pt.y + XFIXNUM (dy); 2712 else 2713 /* Put it on the top. */ 2714 *root_y = screen.frame.origin.y + screen.frame.size.height - height; 2715} 2716 2717 2718DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0, 2719 doc: /* SKIP: real doc in xfns.c. */) 2720 (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy) 2721{ 2722 int root_x, root_y; 2723 ptrdiff_t count = SPECPDL_INDEX (); 2724 struct frame *f; 2725 char *str; 2726 NSSize size; 2727 NSColor *color; 2728 Lisp_Object t; 2729 2730 specbind (Qinhibit_redisplay, Qt); 2731 2732 CHECK_STRING (string); 2733 str = SSDATA (string); 2734 f = decode_window_system_frame (frame); 2735 if (NILP (timeout)) 2736 timeout = make_fixnum (5); 2737 else 2738 CHECK_FIXNAT (timeout); 2739 2740 if (NILP (dx)) 2741 dx = make_fixnum (5); 2742 else 2743 CHECK_FIXNUM (dx); 2744 2745 if (NILP (dy)) 2746 dy = make_fixnum (-10); 2747 else 2748 CHECK_FIXNUM (dy); 2749 2750 block_input (); 2751 if (ns_tooltip == nil) 2752 ns_tooltip = [[EmacsTooltip alloc] init]; 2753 else 2754 Fx_hide_tip (); 2755 2756 t = gui_display_get_arg (NULL, parms, Qbackground_color, NULL, NULL, 2757 RES_TYPE_STRING); 2758 if (ns_lisp_to_color (t, &color) == 0) 2759 [ns_tooltip setBackgroundColor: color]; 2760 2761 t = gui_display_get_arg (NULL, parms, Qforeground_color, NULL, NULL, 2762 RES_TYPE_STRING); 2763 if (ns_lisp_to_color (t, &color) == 0) 2764 [ns_tooltip setForegroundColor: color]; 2765 2766 [ns_tooltip setText: str]; 2767 size = [ns_tooltip frame].size; 2768 2769 /* Move the tooltip window where the mouse pointer is. Resize and 2770 show it. */ 2771 compute_tip_xy (f, parms, dx, dy, (int)size.width, (int)size.height, 2772 &root_x, &root_y); 2773 2774 [ns_tooltip showAtX: root_x Y: root_y for: XFIXNUM (timeout)]; 2775 unblock_input (); 2776 2777 return unbind_to (count, Qnil); 2778} 2779 2780 2781DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0, 2782 doc: /* SKIP: real doc in xfns.c. */) 2783 (void) 2784{ 2785 if (ns_tooltip == nil || ![ns_tooltip isActive]) 2786 return Qnil; 2787 [ns_tooltip hide]; 2788 return Qt; 2789} 2790 2791/* Return geometric attributes of FRAME. According to the value of 2792 ATTRIBUTES return the outer edges of FRAME (Qouter_edges), the inner 2793 edges of FRAME, the root window edges of frame (Qroot_edges). Any 2794 other value means to return the geometry as returned by 2795 Fx_frame_geometry. */ 2796static Lisp_Object 2797frame_geometry (Lisp_Object frame, Lisp_Object attribute) 2798{ 2799 struct frame *f = decode_live_frame (frame); 2800 Lisp_Object fullscreen_symbol = Fframe_parameter (frame, Qfullscreen); 2801 bool fullscreen = (EQ (fullscreen_symbol, Qfullboth) 2802 || EQ (fullscreen_symbol, Qfullscreen)); 2803 int border = fullscreen ? 0 : f->border_width; 2804 int title_height = fullscreen ? 0 : FRAME_NS_TITLEBAR_HEIGHT (f); 2805 int native_width = FRAME_PIXEL_WIDTH (f); 2806 int native_height = FRAME_PIXEL_HEIGHT (f); 2807 int outer_width = native_width + 2 * border; 2808 int outer_height = native_height + 2 * border + title_height; 2809 int native_left = f->left_pos + border; 2810 int native_top = f->top_pos + border + title_height; 2811 int native_right = f->left_pos + outer_width - border; 2812 int native_bottom = f->top_pos + outer_height - border; 2813 int internal_border_width = FRAME_INTERNAL_BORDER_WIDTH (f); 2814 int tool_bar_height = FRAME_TOOLBAR_HEIGHT (f); 2815 int tool_bar_width = (tool_bar_height 2816 ? outer_width - 2 * internal_border_width 2817 : 0); 2818 2819 /* Construct list. */ 2820 if (EQ (attribute, Qouter_edges)) 2821 return list4i (f->left_pos, f->top_pos, 2822 f->left_pos + outer_width, 2823 f->top_pos + outer_height); 2824 else if (EQ (attribute, Qnative_edges)) 2825 return list4i (native_left, native_top, 2826 native_right, native_bottom); 2827 else if (EQ (attribute, Qinner_edges)) 2828 return list4i (native_left + internal_border_width, 2829 native_top + tool_bar_height + internal_border_width, 2830 native_right - internal_border_width, 2831 native_bottom - internal_border_width); 2832 else 2833 return 2834 list (Fcons (Qouter_position, 2835 Fcons (make_fixnum (f->left_pos), 2836 make_fixnum (f->top_pos))), 2837 Fcons (Qouter_size, 2838 Fcons (make_fixnum (outer_width), 2839 make_fixnum (outer_height))), 2840 Fcons (Qexternal_border_size, 2841 (fullscreen 2842 ? Fcons (make_fixnum (0), make_fixnum (0)) 2843 : Fcons (make_fixnum (border), make_fixnum (border)))), 2844 Fcons (Qtitle_bar_size, 2845 Fcons (make_fixnum (0), make_fixnum (title_height))), 2846 Fcons (Qmenu_bar_external, Qnil), 2847 Fcons (Qmenu_bar_size, Fcons (make_fixnum (0), make_fixnum (0))), 2848 Fcons (Qtool_bar_external, 2849 FRAME_EXTERNAL_TOOL_BAR (f) ? Qt : Qnil), 2850 Fcons (Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f)), 2851 Fcons (Qtool_bar_size, 2852 Fcons (make_fixnum (tool_bar_width), 2853 make_fixnum (tool_bar_height))), 2854 Fcons (Qinternal_border_width, 2855 make_fixnum (internal_border_width))); 2856} 2857 2858DEFUN ("ns-frame-geometry", Fns_frame_geometry, Sns_frame_geometry, 0, 1, 0, 2859 doc: /* Return geometric attributes of FRAME. 2860FRAME must be a live frame and defaults to the selected one. The return 2861value is an association list of the attributes listed below. All height 2862and width values are in pixels. 2863 2864`outer-position' is a cons of the outer left and top edges of FRAME 2865 relative to the origin - the position (0, 0) - of FRAME's display. 2866 2867`outer-size' is a cons of the outer width and height of FRAME. The 2868 outer size includes the title bar and the external borders as well as 2869 any menu and/or tool bar of frame. 2870 2871`external-border-size' is a cons of the horizontal and vertical width of 2872 FRAME's external borders as supplied by the window manager. 2873 2874`title-bar-size' is a cons of the width and height of the title bar of 2875 FRAME as supplied by the window manager. If both of them are zero, 2876 FRAME has no title bar. If only the width is zero, Emacs was not 2877 able to retrieve the width information. 2878 2879`menu-bar-external', if non-nil, means the menu bar is external (never 2880 included in the inner edges of FRAME). 2881 2882`menu-bar-size' is a cons of the width and height of the menu bar of 2883 FRAME. 2884 2885`tool-bar-external', if non-nil, means the tool bar is external (never 2886 included in the inner edges of FRAME). 2887 2888`tool-bar-position' tells on which side the tool bar on FRAME is and can 2889 be one of `left', `top', `right' or `bottom'. If this is nil, FRAME 2890 has no tool bar. 2891 2892`tool-bar-size' is a cons of the width and height of the tool bar of 2893 FRAME. 2894 2895`internal-border-width' is the width of the internal border of 2896 FRAME. */) 2897 (Lisp_Object frame) 2898{ 2899 return frame_geometry (frame, Qnil); 2900} 2901 2902DEFUN ("ns-frame-edges", Fns_frame_edges, Sns_frame_edges, 0, 2, 0, 2903 doc: /* Return edge coordinates of FRAME. 2904FRAME must be a live frame and defaults to the selected one. The return 2905value is a list of the form (LEFT, TOP, RIGHT, BOTTOM). All values are 2906in pixels relative to the origin - the position (0, 0) - of FRAME's 2907display. 2908 2909If optional argument TYPE is the symbol `outer-edges', return the outer 2910edges of FRAME. The outer edges comprise the decorations of the window 2911manager (like the title bar or external borders) as well as any external 2912menu or tool bar of FRAME. If optional argument TYPE is the symbol 2913`native-edges' or nil, return the native edges of FRAME. The native 2914edges exclude the decorations of the window manager and any external 2915menu or tool bar of FRAME. If TYPE is the symbol `inner-edges', return 2916the inner edges of FRAME. These edges exclude title bar, any borders, 2917menu bar or tool bar of FRAME. */) 2918 (Lisp_Object frame, Lisp_Object type) 2919{ 2920 return frame_geometry (frame, ((EQ (type, Qouter_edges) 2921 || EQ (type, Qinner_edges)) 2922 ? type 2923 : Qnative_edges)); 2924} 2925 2926DEFUN ("ns-set-mouse-absolute-pixel-position", 2927 Fns_set_mouse_absolute_pixel_position, 2928 Sns_set_mouse_absolute_pixel_position, 2, 2, 0, 2929 doc: /* Move mouse pointer to absolute pixel position (X, Y). 2930The coordinates X and Y are interpreted in pixels relative to a position 2931\(0, 0) of the selected frame's display. */) 2932 (Lisp_Object x, Lisp_Object y) 2933{ 2934#ifdef NS_IMPL_COCOA 2935 /* GNUstep doesn't support CGWarpMouseCursorPosition, so none of 2936 this will work. */ 2937 struct frame *f = SELECTED_FRAME (); 2938 EmacsView *view = FRAME_NS_VIEW (f); 2939 NSScreen *screen = [[view window] screen]; 2940 NSRect screen_frame = [screen frame]; 2941 int mouse_x, mouse_y; 2942 2943 NSScreen *primary_screen = [[NSScreen screens] objectAtIndex:0]; 2944 NSRect primary_screen_frame = [primary_screen frame]; 2945 CGFloat primary_screen_height = primary_screen_frame.size.height; 2946 2947 if (FRAME_INITIAL_P (f) || !FRAME_NS_P (f)) 2948 return Qnil; 2949 2950 CHECK_TYPE_RANGED_INTEGER (int, x); 2951 CHECK_TYPE_RANGED_INTEGER (int, y); 2952 2953 mouse_x = screen_frame.origin.x + XFIXNUM (x); 2954 2955 if (screen == primary_screen) 2956 mouse_y = screen_frame.origin.y + XFIXNUM (y); 2957 else 2958 mouse_y = (primary_screen_height - screen_frame.size.height 2959 - screen_frame.origin.y) + XFIXNUM (y); 2960 2961 CGPoint mouse_pos = CGPointMake(mouse_x, mouse_y); 2962 CGWarpMouseCursorPosition (mouse_pos); 2963#endif /* NS_IMPL_COCOA */ 2964 2965 return Qnil; 2966} 2967 2968DEFUN ("ns-mouse-absolute-pixel-position", 2969 Fns_mouse_absolute_pixel_position, 2970 Sns_mouse_absolute_pixel_position, 0, 0, 0, 2971 doc: /* Return absolute position of mouse cursor in pixels. 2972The position is returned as a cons cell (X . Y) of the 2973coordinates of the mouse cursor position in pixels relative to a 2974position (0, 0) of the selected frame's terminal. */) 2975 (void) 2976{ 2977 struct frame *f = SELECTED_FRAME (); 2978 EmacsView *view = FRAME_NS_VIEW (f); 2979 NSScreen *screen = [[view window] screen]; 2980 NSPoint pt = [NSEvent mouseLocation]; 2981 2982 return Fcons(make_fixnum(pt.x - screen.frame.origin.x), 2983 make_fixnum(screen.frame.size.height - 2984 (pt.y - screen.frame.origin.y))); 2985} 2986 2987DEFUN ("ns-show-character-palette", 2988 Fns_show_character_palette, 2989 Sns_show_character_palette, 0, 0, 0, 2990 doc: /* Show the macOS character palette. */) 2991 (void) 2992{ 2993 struct frame *f = SELECTED_FRAME (); 2994 EmacsView *view = FRAME_NS_VIEW (f); 2995 [NSApp orderFrontCharacterPalette:view]; 2996 2997 return Qnil; 2998} 2999 3000/* ========================================================================== 3001 3002 Class implementations 3003 3004 ========================================================================== */ 3005 3006/* 3007 Handle arrow/function/control keys and copy/paste/cut in file dialogs. 3008 Return YES if handled, NO if not. 3009 */ 3010static BOOL 3011handlePanelKeys (NSSavePanel *panel, NSEvent *theEvent) 3012{ 3013 NSString *s; 3014 int i; 3015 BOOL ret = NO; 3016 3017 if ([theEvent type] != NSEventTypeKeyDown) return NO; 3018 s = [theEvent characters]; 3019 3020 for (i = 0; i < [s length]; ++i) 3021 { 3022 int ch = (int) [s characterAtIndex: i]; 3023 switch (ch) 3024 { 3025 case NSHomeFunctionKey: 3026 case NSDownArrowFunctionKey: 3027 case NSUpArrowFunctionKey: 3028 case NSLeftArrowFunctionKey: 3029 case NSRightArrowFunctionKey: 3030 case NSPageUpFunctionKey: 3031 case NSPageDownFunctionKey: 3032 case NSEndFunctionKey: 3033 /* Don't send command modified keys, as those are handled in the 3034 performKeyEquivalent method of the super class. */ 3035 if (! ([theEvent modifierFlags] & NSEventModifierFlagCommand)) 3036 { 3037 [panel sendEvent: theEvent]; 3038 ret = YES; 3039 } 3040 break; 3041 /* As we don't have the standard key commands for 3042 copy/paste/cut/select-all in our edit menu, we must handle 3043 them here. TODO: handle Emacs key bindings for copy/cut/select-all 3044 here, paste works, because we have that in our Edit menu. 3045 I.e. refactor out code in nsterm.m, keyDown: to figure out the 3046 correct modifier. */ 3047 case 'x': // Cut 3048 case 'c': // Copy 3049 case 'v': // Paste 3050 case 'a': // Select all 3051 if ([theEvent modifierFlags] & NSEventModifierFlagCommand) 3052 { 3053 [NSApp sendAction: 3054 (ch == 'x' 3055 ? @selector(cut:) 3056 : (ch == 'c' 3057 ? @selector(copy:) 3058 : (ch == 'v' 3059 ? @selector(paste:) 3060 : @selector(selectAll:)))) 3061 to:nil from:panel]; 3062 ret = YES; 3063 } 3064 default: 3065 // Send all control keys, as the text field supports C-a, C-f, C-e 3066 // C-b and more. 3067 if ([theEvent modifierFlags] & NSEventModifierFlagControl) 3068 { 3069 [panel sendEvent: theEvent]; 3070 ret = YES; 3071 } 3072 break; 3073 } 3074 } 3075 3076 3077 return ret; 3078} 3079 3080@implementation EmacsFileDelegate 3081/* -------------------------------------------------------------------------- 3082 Delegate methods for Open/Save panels 3083 -------------------------------------------------------------------------- */ 3084- (BOOL)panel: (id)sender isValidFilename: (NSString *)filename 3085{ 3086 return YES; 3087} 3088- (BOOL)panel: (id)sender shouldShowFilename: (NSString *)filename 3089{ 3090 return YES; 3091} 3092- (NSString *)panel: (id)sender userEnteredFilename: (NSString *)filename 3093 confirmed: (BOOL)okFlag 3094{ 3095 return filename; 3096} 3097@end 3098 3099#endif 3100 3101 3102/* ========================================================================== 3103 3104 Lisp interface declaration 3105 3106 ========================================================================== */ 3107 3108void 3109syms_of_nsfns (void) 3110{ 3111 DEFSYM (Qfontsize, "fontsize"); 3112 DEFSYM (Qframe_title_format, "frame-title-format"); 3113 DEFSYM (Qicon_title_format, "icon-title-format"); 3114 DEFSYM (Qdark, "dark"); 3115 3116 DEFVAR_LISP ("ns-icon-type-alist", Vns_icon_type_alist, 3117 doc: /* Alist of elements (REGEXP . IMAGE) for images of icons associated to frames. 3118If the title of a frame matches REGEXP, then IMAGE.tiff is 3119selected as the image of the icon representing the frame when it's 3120miniaturized. If an element is t, then Emacs tries to select an icon 3121based on the filetype of the visited file. 3122 3123The images have to be installed in a folder called English.lproj in the 3124Emacs folder. You have to restart Emacs after installing new icons. 3125 3126Example: Install an icon Gnus.tiff and execute the following code 3127 3128 (setq ns-icon-type-alist 3129 (append ns-icon-type-alist 3130 \\='((\"^\\\\*\\\\(Group\\\\*$\\\\|Summary \\\\|Article\\\\*$\\\\)\" 3131 . \"Gnus\")))) 3132 3133When you miniaturize a Group, Summary or Article frame, Gnus.tiff will 3134be used as the image of the icon representing the frame. */); 3135 Vns_icon_type_alist = list1 (Qt); 3136 3137 DEFVAR_LISP ("ns-version-string", Vns_version_string, 3138 doc: /* Toolkit version for NS Windowing. */); 3139 Vns_version_string = ns_appkit_version_str (); 3140 3141 DEFVAR_BOOL ("ns-use-proxy-icon", ns_use_proxy_icon, 3142 doc: /* When non-nil display a proxy icon in the titlebar. 3143Default is t. */); 3144 ns_use_proxy_icon = true; 3145 3146 defsubr (&Sns_read_file_name); 3147 defsubr (&Sns_get_resource); 3148 defsubr (&Sns_set_resource); 3149 defsubr (&Sxw_display_color_p); /* this and next called directly by C code */ 3150 defsubr (&Sx_display_grayscale_p); 3151 defsubr (&Sns_font_name); 3152 defsubr (&Sns_list_colors); 3153#ifdef NS_IMPL_COCOA 3154 defsubr (&Sns_do_applescript); 3155#endif 3156 defsubr (&Sxw_color_defined_p); 3157 defsubr (&Sxw_color_values); 3158 defsubr (&Sx_server_max_request_size); 3159 defsubr (&Sx_server_vendor); 3160 defsubr (&Sx_server_version); 3161 defsubr (&Sx_display_pixel_width); 3162 defsubr (&Sx_display_pixel_height); 3163 defsubr (&Sns_display_monitor_attributes_list); 3164 defsubr (&Sns_frame_geometry); 3165 defsubr (&Sns_frame_edges); 3166 defsubr (&Sns_frame_list_z_order); 3167 defsubr (&Sns_frame_restack); 3168 defsubr (&Sns_set_mouse_absolute_pixel_position); 3169 defsubr (&Sns_mouse_absolute_pixel_position); 3170 defsubr (&Sns_show_character_palette); 3171 defsubr (&Sx_display_mm_width); 3172 defsubr (&Sx_display_mm_height); 3173 defsubr (&Sx_display_screens); 3174 defsubr (&Sx_display_planes); 3175 defsubr (&Sx_display_color_cells); 3176 defsubr (&Sx_display_visual_class); 3177 defsubr (&Sx_display_backing_store); 3178 defsubr (&Sx_display_save_under); 3179 defsubr (&Sx_create_frame); 3180 defsubr (&Sx_open_connection); 3181 defsubr (&Sx_close_connection); 3182 defsubr (&Sx_display_list); 3183 3184 defsubr (&Sns_hide_others); 3185 defsubr (&Sns_hide_emacs); 3186 defsubr (&Sns_emacs_info_panel); 3187 defsubr (&Sns_list_services); 3188 defsubr (&Sns_perform_service); 3189 defsubr (&Sns_popup_font_panel); 3190 defsubr (&Sns_popup_color_panel); 3191 3192 defsubr (&Sx_show_tip); 3193 defsubr (&Sx_hide_tip); 3194 3195 as_status = 0; 3196 as_script = Qnil; 3197 staticpro (&as_script); 3198 as_result = 0; 3199} 3200