1/* NeXT/Open/GNUstep / macOS communication module. -*- coding: utf-8 -*- 2 3Copyright (C) 1989, 1993-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 <fcntl.h> 34#include <math.h> 35#include <pthread.h> 36#include <sys/types.h> 37#include <time.h> 38#include <signal.h> 39#include <unistd.h> 40#include <stdbool.h> 41 42#include <c-ctype.h> 43#include <c-strcase.h> 44#include <ftoastr.h> 45 46#include "lisp.h" 47#include "blockinput.h" 48#include "sysselect.h" 49#include "nsterm.h" 50#include "systime.h" 51#include "character.h" 52#include "xwidget.h" 53#include "fontset.h" 54#include "composite.h" 55#include "ccl.h" 56 57#include "termhooks.h" 58#include "termchar.h" 59#include "menu.h" 60#include "window.h" 61#include "keyboard.h" 62#include "buffer.h" 63#include "font.h" 64#include "pdumper.h" 65 66#ifdef NS_IMPL_GNUSTEP 67#include "process.h" 68#import <GNUstepGUI/GSDisplayServer.h> 69#endif 70 71#ifdef NS_IMPL_COCOA 72#include "macfont.h" 73#include <Carbon/Carbon.h> 74#include <IOSurface/IOSurface.h> 75#endif 76 77static EmacsMenu *dockMenu; 78#ifdef NS_IMPL_COCOA 79static EmacsMenu *mainMenu; 80#endif 81 82/* ========================================================================== 83 84 NSTRACE, Trace support. 85 86 ========================================================================== */ 87 88#if NSTRACE_ENABLED 89 90/* The following use "volatile" since they can be accessed from 91 parallel threads. */ 92volatile int nstrace_num = 0; 93volatile int nstrace_depth = 0; 94 95/* When 0, no trace is emitted. This is used by NSTRACE_WHEN and 96 NSTRACE_UNLESS to silence functions called. 97 98 TODO: This should really be a thread-local variable, to avoid that 99 a function with disabled trace thread silence trace output in 100 another. However, in practice this seldom is a problem. */ 101volatile int nstrace_enabled_global = 1; 102 103/* Called when nstrace_enabled goes out of scope. */ 104void nstrace_leave(int * pointer_to_nstrace_enabled) 105{ 106 if (*pointer_to_nstrace_enabled) 107 { 108 --nstrace_depth; 109 } 110} 111 112 113/* Called when nstrace_saved_enabled_global goes out of scope. */ 114void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global) 115{ 116 nstrace_enabled_global = *pointer_to_saved_enabled_global; 117} 118 119 120char const * nstrace_fullscreen_type_name (int fs_type) 121{ 122 switch (fs_type) 123 { 124 case -1: return "-1"; 125 case FULLSCREEN_NONE: return "FULLSCREEN_NONE"; 126 case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH"; 127 case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT"; 128 case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH"; 129 case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED"; 130 default: return "FULLSCREEN_?????"; 131 } 132} 133#endif 134 135 136/* ========================================================================== 137 138 NSColor, EmacsColor category. 139 140 ========================================================================== */ 141@implementation NSColor (EmacsColor) 142+ (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green 143 blue:(CGFloat)blue alpha:(CGFloat)alpha 144{ 145#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 146 if (ns_use_srgb_colorspace 147 && NSAppKitVersionNumber >= NSAppKitVersionNumber10_7) 148 return [NSColor colorWithSRGBRed: red 149 green: green 150 blue: blue 151 alpha: alpha]; 152#endif 153 return [NSColor colorWithCalibratedRed: red 154 green: green 155 blue: blue 156 alpha: alpha]; 157} 158 159- (NSColor *)colorUsingDefaultColorSpace 160{ 161#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 162 if (ns_use_srgb_colorspace 163 && NSAppKitVersionNumber >= NSAppKitVersionNumber10_7) 164 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]]; 165#endif 166 return [self colorUsingColorSpace: [NSColorSpace deviceRGBColorSpace]]; 167} 168 169+ (NSColor *)colorWithUnsignedLong:(unsigned long)c 170{ 171 EmacsCGFloat a = (double)((c >> 24) & 0xff) / 255.0; 172 EmacsCGFloat r = (double)((c >> 16) & 0xff) / 255.0; 173 EmacsCGFloat g = (double)((c >> 8) & 0xff) / 255.0; 174 EmacsCGFloat b = (double)(c & 0xff) / 255.0; 175 176 return [NSColor colorForEmacsRed:r green:g blue:b alpha:a]; 177} 178 179- (unsigned long)unsignedLong 180{ 181 EmacsCGFloat r, g, b, a; 182 [self getRed:&r green:&g blue:&b alpha:&a]; 183 184 return (((unsigned long) (a * 255)) << 24) 185 | (((unsigned long) (r * 255)) << 16) 186 | (((unsigned long) (g * 255)) << 8) 187 | ((unsigned long) (b * 255)); 188} 189 190@end 191 192/* ========================================================================== 193 194 Local declarations 195 196 ========================================================================== */ 197 198/* Convert a symbol indexed with an NSxxx value to a value as defined 199 in keyboard.c (lispy_function_key). I hope this is a correct way 200 of doing things... */ 201static unsigned convert_ns_to_X_keysym[] = 202{ 203 NSHomeFunctionKey, 0x50, 204 NSLeftArrowFunctionKey, 0x51, 205 NSUpArrowFunctionKey, 0x52, 206 NSRightArrowFunctionKey, 0x53, 207 NSDownArrowFunctionKey, 0x54, 208 NSPageUpFunctionKey, 0x55, 209 NSPageDownFunctionKey, 0x56, 210 NSEndFunctionKey, 0x57, 211 NSBeginFunctionKey, 0x58, 212 NSSelectFunctionKey, 0x60, 213 NSPrintFunctionKey, 0x61, 214 NSClearLineFunctionKey, 0x0B, 215 NSExecuteFunctionKey, 0x62, 216 NSInsertFunctionKey, 0x63, 217 NSUndoFunctionKey, 0x65, 218 NSRedoFunctionKey, 0x66, 219 NSMenuFunctionKey, 0x67, 220 NSFindFunctionKey, 0x68, 221 NSHelpFunctionKey, 0x6A, 222 NSBreakFunctionKey, 0x6B, 223 224 NSF1FunctionKey, 0xBE, 225 NSF2FunctionKey, 0xBF, 226 NSF3FunctionKey, 0xC0, 227 NSF4FunctionKey, 0xC1, 228 NSF5FunctionKey, 0xC2, 229 NSF6FunctionKey, 0xC3, 230 NSF7FunctionKey, 0xC4, 231 NSF8FunctionKey, 0xC5, 232 NSF9FunctionKey, 0xC6, 233 NSF10FunctionKey, 0xC7, 234 NSF11FunctionKey, 0xC8, 235 NSF12FunctionKey, 0xC9, 236 NSF13FunctionKey, 0xCA, 237 NSF14FunctionKey, 0xCB, 238 NSF15FunctionKey, 0xCC, 239 NSF16FunctionKey, 0xCD, 240 NSF17FunctionKey, 0xCE, 241 NSF18FunctionKey, 0xCF, 242 NSF19FunctionKey, 0xD0, 243 NSF20FunctionKey, 0xD1, 244 NSF21FunctionKey, 0xD2, 245 NSF22FunctionKey, 0xD3, 246 NSF23FunctionKey, 0xD4, 247 NSF24FunctionKey, 0xD5, 248 249 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */ 250 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */ 251 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */ 252 253 NSTabCharacter, 0x09, 254 0x19, 0x09, /* left tab->regular since pass shift */ 255 NSCarriageReturnCharacter, 0x0D, 256 NSNewlineCharacter, 0x0D, 257 NSEnterCharacter, 0x8D, 258 259 0x41|NSEventModifierFlagNumericPad, 0xAE, /* KP_Decimal */ 260 0x43|NSEventModifierFlagNumericPad, 0xAA, /* KP_Multiply */ 261 0x45|NSEventModifierFlagNumericPad, 0xAB, /* KP_Add */ 262 0x4B|NSEventModifierFlagNumericPad, 0xAF, /* KP_Divide */ 263 0x4E|NSEventModifierFlagNumericPad, 0xAD, /* KP_Subtract */ 264 0x51|NSEventModifierFlagNumericPad, 0xBD, /* KP_Equal */ 265 0x52|NSEventModifierFlagNumericPad, 0xB0, /* KP_0 */ 266 0x53|NSEventModifierFlagNumericPad, 0xB1, /* KP_1 */ 267 0x54|NSEventModifierFlagNumericPad, 0xB2, /* KP_2 */ 268 0x55|NSEventModifierFlagNumericPad, 0xB3, /* KP_3 */ 269 0x56|NSEventModifierFlagNumericPad, 0xB4, /* KP_4 */ 270 0x57|NSEventModifierFlagNumericPad, 0xB5, /* KP_5 */ 271 0x58|NSEventModifierFlagNumericPad, 0xB6, /* KP_6 */ 272 0x59|NSEventModifierFlagNumericPad, 0xB7, /* KP_7 */ 273 0x5B|NSEventModifierFlagNumericPad, 0xB8, /* KP_8 */ 274 0x5C|NSEventModifierFlagNumericPad, 0xB9, /* KP_9 */ 275 276 0x1B, 0x1B /* escape */ 277}; 278 279/* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold, 280 the maximum font size to NOT antialias. On GNUstep there is currently 281 no way to control this behavior. */ 282float ns_antialias_threshold; 283 284NSArray *ns_send_types = 0, *ns_return_types = 0; 285static NSArray *ns_drag_types = 0; 286NSString *ns_app_name = @"Emacs"; /* default changed later */ 287 288/* Display variables */ 289struct ns_display_info *x_display_list; /* Chain of existing displays */ 290long context_menu_value = 0; 291 292/* display update */ 293static struct frame *ns_updating_frame; 294static int ns_window_num = 0; 295static BOOL gsaved = NO; 296#ifdef NS_IMPL_COCOA 297static BOOL ns_menu_bar_is_hidden = NO; 298#endif 299 300/* event loop */ 301static BOOL send_appdefined = YES; 302#define NO_APPDEFINED_DATA (-8) 303static int last_appdefined_event_data = NO_APPDEFINED_DATA; 304static NSTimer *timed_entry = 0; 305static NSTimer *scroll_repeat_entry = nil; 306static fd_set select_readfds, select_writefds; 307enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 }; 308static int select_nfds = 0, select_valid = 0; 309static struct timespec select_timeout = { 0, 0 }; 310static int selfds[2] = { -1, -1 }; 311static pthread_mutex_t select_mutex; 312static NSAutoreleasePool *outerpool; 313static struct input_event *emacs_event = NULL; 314static struct input_event *q_event_ptr = NULL; 315static int n_emacs_events_pending = 0; 316static NSMutableArray *ns_pending_files, *ns_pending_service_names, 317 *ns_pending_service_args; 318static BOOL ns_do_open_file = NO; 319static BOOL ns_last_use_native_fullscreen; 320 321/* Non-zero means that a HELP_EVENT has been generated since Emacs 322 start. */ 323 324static BOOL any_help_event_p = NO; 325 326static struct { 327 struct input_event *q; 328 int nr, cap; 329} hold_event_q = { 330 NULL, 0, 0 331}; 332 333/* Convert modifiers in a NeXTstep event to emacs style modifiers. */ 334#define NS_FUNCTION_KEY_MASK 0x800000 335#define NSLeftControlKeyMask (0x000001 | NSEventModifierFlagControl) 336#define NSRightControlKeyMask (0x002000 | NSEventModifierFlagControl) 337#define NSLeftCommandKeyMask (0x000008 | NSEventModifierFlagCommand) 338#define NSRightCommandKeyMask (0x000010 | NSEventModifierFlagCommand) 339#define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption) 340#define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption) 341 342/* MODIFIER if a symbol; otherwise its property KIND, if a symbol. */ 343static Lisp_Object 344mod_of_kind (Lisp_Object modifier, Lisp_Object kind) 345{ 346 if (SYMBOLP (modifier)) 347 return modifier; 348 else 349 { 350 Lisp_Object val = Fplist_get (modifier, kind); 351 return SYMBOLP (val) ? val : Qnil; 352 } 353} 354 355static unsigned int 356ev_modifiers_helper (unsigned int flags, unsigned int left_mask, 357 unsigned int right_mask, unsigned int either_mask, 358 Lisp_Object left_modifier, Lisp_Object right_modifier) 359{ 360 unsigned int modifiers = 0; 361 362 if (flags & either_mask) 363 { 364 BOOL left_key = (flags & left_mask) == left_mask; 365 BOOL right_key = (flags & right_mask) == right_mask 366 && ! EQ (right_modifier, Qleft); 367 368 if (right_key) 369 modifiers |= parse_solitary_modifier (right_modifier); 370 371 /* GNUstep (and possibly macOS in certain circumstances) doesn't 372 differentiate between the left and right keys, so if we can't 373 identify which key it is, we use the left key setting. */ 374 if (left_key || ! right_key) 375 modifiers |= parse_solitary_modifier (left_modifier); 376 } 377 378 return modifiers; 379} 380 381#define EV_MODIFIERS2(flags, kind) \ 382 (((flags & NSEventModifierFlagHelp) ? \ 383 hyper_modifier : 0) \ 384 | ((flags & NSEventModifierFlagShift) ? \ 385 shift_modifier : 0) \ 386 | ((flags & NS_FUNCTION_KEY_MASK) \ 387 ? parse_solitary_modifier (mod_of_kind (ns_function_modifier, \ 388 kind)) \ 389 : 0) \ 390 | ev_modifiers_helper (flags, NSLeftControlKeyMask, \ 391 NSRightControlKeyMask, \ 392 NSEventModifierFlagControl, \ 393 mod_of_kind (ns_control_modifier, kind), \ 394 mod_of_kind (ns_right_control_modifier, \ 395 kind)) \ 396 | ev_modifiers_helper (flags, NSLeftCommandKeyMask, \ 397 NSRightCommandKeyMask, \ 398 NSEventModifierFlagCommand, \ 399 mod_of_kind (ns_command_modifier, kind), \ 400 mod_of_kind (ns_right_command_modifier, \ 401 kind)) \ 402 | ev_modifiers_helper (flags, NSLeftAlternateKeyMask, \ 403 NSRightAlternateKeyMask, \ 404 NSEventModifierFlagOption, \ 405 mod_of_kind (ns_alternate_modifier, kind), \ 406 mod_of_kind (ns_right_alternate_modifier, \ 407 kind))) 408 409#define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags], QCmouse) 410 411#define EV_UDMODIFIERS(e) \ 412 ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0) \ 413 | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0) \ 414 | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0) \ 415 | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0) \ 416 | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \ 417 | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \ 418 | (([e type] == NSEventTypeLeftMouseUp) ? up_modifier : 0) \ 419 | (([e type] == NSEventTypeRightMouseUp) ? up_modifier : 0) \ 420 | (([e type] == NSEventTypeOtherMouseUp) ? up_modifier : 0)) 421 422#define EV_BUTTON(e) \ 423 ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 : \ 424 (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \ 425 [e buttonNumber] - 1) 426 427/* Convert the time field to a timestamp in milliseconds. */ 428#define EV_TIMESTAMP(e) ([e timestamp] * 1000) 429 430/* This is a piece of code which is common to all the event handling 431 methods. Maybe it should even be a function. */ 432#define EV_TRAILER(e) \ 433 { \ 434 XSETFRAME (emacs_event->frame_or_window, emacsframe); \ 435 EV_TRAILER2 (e); \ 436 } 437 438#define EV_TRAILER2(e) \ 439 { \ 440 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \ 441 if (q_event_ptr) \ 442 { \ 443 Lisp_Object tem = Vinhibit_quit; \ 444 Vinhibit_quit = Qt; \ 445 n_emacs_events_pending++; \ 446 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \ 447 Vinhibit_quit = tem; \ 448 } \ 449 else \ 450 hold_event (emacs_event); \ 451 EVENT_INIT (*emacs_event); \ 452 ns_send_appdefined (-1); \ 453 } 454 455 456/* TODO: Get rid of need for these forward declarations. */ 457static void ns_condemn_scroll_bars (struct frame *f); 458static void ns_judge_scroll_bars (struct frame *f); 459 460 461/* ========================================================================== 462 463 Utilities 464 465 ========================================================================== */ 466 467void 468ns_init_events (struct input_event *ev) 469{ 470 EVENT_INIT (*ev); 471 emacs_event = ev; 472} 473 474void 475ns_finish_events (void) 476{ 477 emacs_event = NULL; 478} 479 480static void 481hold_event (struct input_event *event) 482{ 483 if (hold_event_q.nr == hold_event_q.cap) 484 { 485 if (hold_event_q.cap == 0) hold_event_q.cap = 10; 486 else hold_event_q.cap *= 2; 487 hold_event_q.q = 488 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q); 489 } 490 491 hold_event_q.q[hold_event_q.nr++] = *event; 492 /* Make sure ns_read_socket is called, i.e. we have input. */ 493 raise (SIGIO); 494 send_appdefined = YES; 495} 496 497static Lisp_Object 498append2 (Lisp_Object list, Lisp_Object item) 499/* -------------------------------------------------------------------------- 500 Utility to append to a list 501 -------------------------------------------------------------------------- */ 502{ 503 return nconc2 (list, list (item)); 504} 505 506 507const char * 508ns_relocate (const char *epath) 509/* If we're running in a self-contained app bundle some hard-coded 510 paths are relative to the root of the bundle, so work out the full 511 path. 512 513 FIXME: I think this should be able to handle cases where multiple 514 directories are separated by colons. */ 515{ 516#ifdef NS_SELF_CONTAINED 517 NSBundle *bundle = [NSBundle mainBundle]; 518 NSString *root = [bundle bundlePath]; 519 NSString *original = [NSString stringWithUTF8String:epath]; 520 NSString *fixedPath = [NSString pathWithComponents: 521 [NSArray arrayWithObjects: 522 root, original, nil]]; 523 NSFileManager *fileManager = [NSFileManager defaultManager]; 524 525 if (![original isAbsolutePath] 526 && [fileManager fileExistsAtPath:fixedPath isDirectory:NULL]) 527 return [fixedPath UTF8String]; 528 529 /* If we reach here either the path is absolute and therefore we 530 don't need to complete it, or we're unable to relocate the 531 file/directory. If it's the latter it may be because the user is 532 trying to use a bundled app as though it's a Unix style install 533 and we have no way to guess what was intended, so return the 534 original string unaltered. */ 535 536#endif 537 538 return epath; 539} 540 541 542void 543ns_init_locale (void) 544/* macOS doesn't set any environment variables for the locale when run 545 from the GUI. Get the locale from the OS and set LANG. */ 546{ 547 NSLocale *locale = [NSLocale currentLocale]; 548 549 NSTRACE ("ns_init_locale"); 550 551 /* If we were run from a terminal then assume an unset LANG variable 552 is intentional and don't try to "fix" it. */ 553 if (!isatty (STDIN_FILENO)) 554 { 555 char *oldLocale = setlocale (LC_ALL, NULL); 556 /* It seems macOS should probably use UTF-8 everywhere. 557 'localeIdentifier' does not specify the encoding, and I can't 558 find any way to get the OS to tell us which encoding to use, 559 so hard-code '.UTF-8'. */ 560 NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8", 561 [locale localeIdentifier]]; 562 563 /* Check the locale ID is valid and if so set LANG, but not if 564 it is already set. */ 565 if (setlocale (LC_ALL, [localeID UTF8String])) 566 setenv("LANG", [localeID UTF8String], 0); 567 568 setlocale (LC_ALL, oldLocale); 569 } 570} 571 572 573void 574ns_release_object (void *obj) 575/* -------------------------------------------------------------------------- 576 Release an object (callable from C) 577 -------------------------------------------------------------------------- */ 578{ 579 [(id)obj release]; 580} 581 582 583void 584ns_retain_object (void *obj) 585/* -------------------------------------------------------------------------- 586 Retain an object (callable from C) 587 -------------------------------------------------------------------------- */ 588{ 589 [(id)obj retain]; 590} 591 592 593void * 594ns_alloc_autorelease_pool (void) 595/* -------------------------------------------------------------------------- 596 Allocate a pool for temporary objects (callable from C) 597 -------------------------------------------------------------------------- */ 598{ 599 return [[NSAutoreleasePool alloc] init]; 600} 601 602 603void 604ns_release_autorelease_pool (void *pool) 605/* -------------------------------------------------------------------------- 606 Free a pool and temporary objects it refers to (callable from C) 607 -------------------------------------------------------------------------- */ 608{ 609 ns_release_object (pool); 610} 611 612 613static BOOL 614ns_menu_bar_should_be_hidden (void) 615/* True, if the menu bar should be hidden. */ 616{ 617 return !NILP (ns_auto_hide_menu_bar) 618 && [NSApp respondsToSelector:@selector(setPresentationOptions:)]; 619} 620 621 622struct EmacsMargins 623{ 624 CGFloat top; 625 CGFloat bottom; 626 CGFloat left; 627 CGFloat right; 628}; 629 630 631static struct EmacsMargins 632ns_screen_margins (NSScreen *screen) 633/* The parts of SCREEN used by the operating system. */ 634{ 635 NSTRACE ("ns_screen_margins"); 636 637 struct EmacsMargins margins; 638 639 NSRect screenFrame = [screen frame]; 640 NSRect screenVisibleFrame = [screen visibleFrame]; 641 642 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden 643 menu bar, check this explicitly. */ 644 if (ns_menu_bar_should_be_hidden()) 645 { 646 margins.top = 0; 647 } 648 else 649 { 650 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height; 651 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y 652 + screenVisibleFrame.size.height); 653 654 margins.top = frameTop - visibleFrameTop; 655 } 656 657 { 658 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width; 659 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x 660 + screenVisibleFrame.size.width); 661 margins.right = frameRight - visibleFrameRight; 662 } 663 664 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y; 665 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x; 666 667 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g", 668 margins.left, 669 margins.right, 670 margins.top, 671 margins.bottom); 672 673 return margins; 674} 675 676 677/* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is 678 assumed to contain a hidden dock. macOS currently use 4 pixels for 679 this, however, to be future compatible, a larger value is used. */ 680#define DOCK_IGNORE_LIMIT 6 681 682static struct EmacsMargins 683ns_screen_margins_ignoring_hidden_dock (NSScreen *screen) 684/* The parts of SCREEN used by the operating system, excluding the parts 685 reserved for a hidden dock. */ 686{ 687 NSTRACE ("ns_screen_margins_ignoring_hidden_dock"); 688 689 struct EmacsMargins margins = ns_screen_margins(screen); 690 691 /* macOS (currently) reserved 4 pixels along the edge where a hidden 692 dock is located. Unfortunately, it's not possible to find the 693 location and information about if the dock is hidden. Instead, 694 it is assumed that if the margin of an edge is less than 695 DOCK_IGNORE_LIMIT, it contains a hidden dock. */ 696 if (margins.left <= DOCK_IGNORE_LIMIT) 697 { 698 margins.left = 0; 699 } 700 if (margins.right <= DOCK_IGNORE_LIMIT) 701 { 702 margins.right = 0; 703 } 704 if (margins.top <= DOCK_IGNORE_LIMIT) 705 { 706 margins.top = 0; 707 } 708 /* Note: This doesn't occur in current versions of macOS, but 709 included for completeness and future compatibility. */ 710 if (margins.bottom <= DOCK_IGNORE_LIMIT) 711 { 712 margins.bottom = 0; 713 } 714 715 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g", 716 margins.left, 717 margins.right, 718 margins.top, 719 margins.bottom); 720 721 return margins; 722} 723 724 725static CGFloat 726ns_menu_bar_height (NSScreen *screen) 727/* The height of the menu bar, if visible. 728 729 Note: Don't use this when fullscreen is enabled -- the screen 730 sometimes includes, sometimes excludes the menu bar area. */ 731{ 732 struct EmacsMargins margins = ns_screen_margins(screen); 733 734 CGFloat res = margins.top; 735 736 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res); 737 738 return res; 739} 740 741 742/* Get the frame rect, in system coordinates, of the parent window or, 743 if there is no parent window, the main screen. */ 744static inline NSRect 745ns_parent_window_rect (struct frame *f) 746{ 747 NSRect parentRect; 748 749 if (FRAME_PARENT_FRAME (f) != NULL) 750 { 751 EmacsView *parentView = FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)); 752 parentRect = [parentView convertRect:[parentView frame] 753 toView:nil]; 754 parentRect = [[parentView window] convertRectToScreen:parentRect]; 755 } 756 else 757 parentRect = [[[NSScreen screens] objectAtIndex:0] frame]; 758 759 return parentRect; 760} 761 762/* Calculate system coordinates of the left and top of the parent 763 window or, if there is no parent window, the main screen. */ 764#define NS_PARENT_WINDOW_LEFT_POS(f) NSMinX (ns_parent_window_rect (f)) 765#define NS_PARENT_WINDOW_TOP_POS(f) NSMaxY (ns_parent_window_rect (f)) 766 767 768static NSRect 769ns_row_rect (struct window *w, struct glyph_row *row, 770 enum glyph_row_area area) 771/* Get the row as an NSRect. */ 772{ 773 NSRect rect; 774 int window_x, window_y, window_width; 775 776 window_box (w, area, &window_x, &window_y, &window_width, 0); 777 778 rect.origin.x = window_x; 779 rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y)); 780 rect.origin.y = max (rect.origin.y, window_y); 781 rect.size.width = window_width; 782 rect.size.height = row->visible_height; 783 784 return rect; 785} 786 787 788double 789ns_frame_scale_factor (struct frame *f) 790{ 791#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > 1060 792 return [[FRAME_NS_VIEW (f) window] backingScaleFactor]; 793#else 794 return [[FRAME_NS_VIEW (f) window] userSpaceScaleFactor]; 795#endif 796} 797 798 799/* ========================================================================== 800 801 Focus (clipping) and screen update 802 803 ========================================================================== */ 804 805// 806// Window constraining 807// ------------------- 808// 809// To ensure that the windows are not placed under the menu bar, they 810// are typically moved by the call-back constrainFrameRect. However, 811// by overriding it, it's possible to inhibit this, leaving the window 812// in it's original position. 813// 814// It's possible to hide the menu bar. However, technically, it's only 815// possible to hide it when the application is active. To ensure that 816// this work properly, the menu bar and window constraining are 817// deferred until the application becomes active. 818// 819// Even though it's not possible to manually move a window above the 820// top of the screen, it is allowed if it's done programmatically, 821// when the menu is hidden. This allows the editable area to cover the 822// full screen height. 823// 824// Test cases 825// ---------- 826// 827// Use the following extra files: 828// 829// init.el: 830// ;; Hide menu and place frame slightly above the top of the screen. 831// (setq ns-auto-hide-menu-bar t) 832// (set-frame-position (selected-frame) 0 -20) 833// 834// Test 1: 835// 836// emacs -Q -l init.el 837// 838// Result: No menu bar, and the title bar should be above the screen. 839// 840// Test 2: 841// 842// emacs -Q 843// 844// Result: Menu bar visible, frame placed immediately below the menu. 845// 846 847static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) 848{ 849 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")", 850 NSTRACE_ARG_RECT (frameRect)); 851 852 // -------------------- 853 // Collect information about the screen the frame is covering. 854 // 855 856 NSArray *screens = [NSScreen screens]; 857 NSUInteger nr_screens = [screens count]; 858 859 int i; 860 861 // The height of the menu bar, if present in any screen the frame is 862 // displayed in. 863 int menu_bar_height = 0; 864 865 // A rectangle covering all the screen the frame is displayed in. 866 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0); 867 for (i = 0; i < nr_screens; ++i ) 868 { 869 NSScreen *s = [screens objectAtIndex: i]; 870 NSRect scrRect = [s frame]; 871 872 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT, 873 i, NSTRACE_ARG_RECT (scrRect)); 874 875 if (NSIntersectionRect (frameRect, scrRect).size.height != 0) 876 { 877 multiscreenRect = NSUnionRect (multiscreenRect, scrRect); 878 879 if (!isFullscreen) 880 { 881 CGFloat screen_menu_bar_height = ns_menu_bar_height (s); 882 menu_bar_height = max(menu_bar_height, screen_menu_bar_height); 883 } 884 } 885 } 886 887 NSTRACE_RECT ("multiscreenRect", multiscreenRect); 888 889 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height); 890 891 if (multiscreenRect.size.width == 0 892 || multiscreenRect.size.height == 0) 893 { 894 // Failed to find any monitor, give up. 895 NSTRACE_MSG ("multiscreenRect empty"); 896 NSTRACE_RETURN_RECT (frameRect); 897 return frameRect; 898 } 899 900 901 // -------------------- 902 // Find a suitable placement. 903 // 904 905 if (ns_menu_bar_should_be_hidden()) 906 { 907 // When the menu bar is hidden, the user may place part of the 908 // frame above the top of the screen, for example to hide the 909 // title bar. 910 // 911 // Hence, keep the original position. 912 } 913 else 914 { 915 // Ensure that the frame is below the menu bar, or below the top 916 // of the screen. 917 // 918 // This assume that the menu bar is placed at the top in the 919 // rectangle that covers the monitors. (It doesn't have to be, 920 // but if it's not it's hard to do anything useful.) 921 CGFloat topOfWorkArea = (multiscreenRect.origin.y 922 + multiscreenRect.size.height 923 - menu_bar_height); 924 925 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height; 926 if (topOfFrame > topOfWorkArea) 927 { 928 frameRect.origin.y -= topOfFrame - topOfWorkArea; 929 NSTRACE_RECT ("After placement adjust", frameRect); 930 } 931 } 932 933 // Include the following section to restrict frame to the screens. 934 // (If so, update it to allow the frame to stretch down below the 935 // screen.) 936#if 0 937 // -------------------- 938 // Ensure frame doesn't stretch below the screens. 939 // 940 941 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y; 942 943 if (diff > 0) 944 { 945 frameRect.origin.y = multiscreenRect.origin.y; 946 frameRect.size.height -= diff; 947 } 948#endif 949 950 NSTRACE_RETURN_RECT (frameRect); 951 return frameRect; 952} 953 954 955static void 956ns_constrain_all_frames (void) 957/* -------------------------------------------------------------------------- 958 Ensure that the menu bar doesn't cover any frames. 959 -------------------------------------------------------------------------- */ 960{ 961 Lisp_Object tail, frame; 962 963 NSTRACE ("ns_constrain_all_frames"); 964 965 block_input (); 966 967 FOR_EACH_FRAME (tail, frame) 968 { 969 struct frame *f = XFRAME (frame); 970 if (FRAME_NS_P (f)) 971 { 972 EmacsView *view = FRAME_NS_VIEW (f); 973 974 if (![view isFullscreen]) 975 { 976 [[view window] 977 setFrame:constrain_frame_rect([[view window] frame], false) 978 display:NO]; 979 } 980 } 981 } 982 983 unblock_input (); 984} 985 986 987static void 988ns_update_auto_hide_menu_bar (void) 989/* -------------------------------------------------------------------------- 990 Show or hide the menu bar, based on user setting. 991 -------------------------------------------------------------------------- */ 992{ 993#ifdef NS_IMPL_COCOA 994 NSTRACE ("ns_update_auto_hide_menu_bar"); 995 996 block_input (); 997 998 if (NSApp != nil && [NSApp isActive]) 999 { 1000 // Note, "setPresentationOptions" triggers an error unless the 1001 // application is active. 1002 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden (); 1003 1004 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden) 1005 { 1006 NSApplicationPresentationOptions options 1007 = NSApplicationPresentationDefault; 1008 1009 if (menu_bar_should_be_hidden) 1010 options |= NSApplicationPresentationAutoHideMenuBar 1011 | NSApplicationPresentationAutoHideDock; 1012 1013 [NSApp setPresentationOptions: options]; 1014 1015 ns_menu_bar_is_hidden = menu_bar_should_be_hidden; 1016 1017 if (!ns_menu_bar_is_hidden) 1018 { 1019 ns_constrain_all_frames (); 1020 } 1021 } 1022 } 1023 1024 unblock_input (); 1025#endif 1026} 1027 1028 1029static void 1030ns_update_begin (struct frame *f) 1031/* -------------------------------------------------------------------------- 1032 Prepare for a grouped sequence of drawing calls 1033 external (RIF) call; whole frame, called before gui_update_window_begin 1034 -------------------------------------------------------------------------- */ 1035{ 1036 EmacsView *view = FRAME_NS_VIEW (f); 1037 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin"); 1038 1039 ns_update_auto_hide_menu_bar (); 1040 1041 ns_updating_frame = f; 1042 [view lockFocus]; 1043} 1044 1045 1046static void 1047ns_update_end (struct frame *f) 1048/* -------------------------------------------------------------------------- 1049 Finished a grouped sequence of drawing calls 1050 external (RIF) call; for whole frame, called after gui_update_window_end 1051 -------------------------------------------------------------------------- */ 1052{ 1053 EmacsView *view = FRAME_NS_VIEW (f); 1054 1055 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end"); 1056 1057/* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */ 1058 MOUSE_HL_INFO (f)->mouse_face_defer = 0; 1059 1060 block_input (); 1061 1062 [view unlockFocus]; 1063#if defined (NS_IMPL_GNUSTEP) 1064 [[view window] flushWindow]; 1065#endif 1066 1067 unblock_input (); 1068 ns_updating_frame = NULL; 1069} 1070 1071static void 1072ns_focus (struct frame *f, NSRect *r, int n) 1073/* -------------------------------------------------------------------------- 1074 Internal: Focus on given frame. During small local updates this is used to 1075 draw, however during large updates, ns_update_begin and ns_update_end are 1076 called to wrap the whole thing, in which case these calls are stubbed out. 1077 Except, on GNUstep, we accumulate the rectangle being drawn into, because 1078 the back end won't do this automatically, and will just end up flushing 1079 the entire window. 1080 -------------------------------------------------------------------------- */ 1081{ 1082 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus"); 1083 if (r != NULL) 1084 { 1085 NSTRACE_RECT ("r", *r); 1086 } 1087 1088 if (f != ns_updating_frame) 1089 { 1090 EmacsView *view = FRAME_NS_VIEW (f); 1091 [view lockFocus]; 1092 } 1093 1094 /* clipping */ 1095 if (r) 1096 { 1097 NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; 1098 [ctx saveGraphicsState]; 1099#ifdef NS_IMPL_COCOA 1100 if (n == 2) 1101 NSRectClipList (r, 2); 1102 else 1103 NSRectClip (*r); 1104#else 1105 GSRectClipList (ctx, r, n); 1106#endif 1107 gsaved = YES; 1108 } 1109} 1110 1111 1112static void 1113ns_unfocus (struct frame *f) 1114/* -------------------------------------------------------------------------- 1115 Internal: Remove focus on given frame 1116 -------------------------------------------------------------------------- */ 1117{ 1118 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus"); 1119 1120 if (gsaved) 1121 { 1122 [[NSGraphicsContext currentContext] restoreGraphicsState]; 1123 gsaved = NO; 1124 } 1125 1126 if (f != ns_updating_frame) 1127 { 1128 EmacsView *view = FRAME_NS_VIEW (f); 1129 [view unlockFocus]; 1130#if defined (NS_IMPL_GNUSTEP) 1131 [[view window] flushWindow]; 1132#endif 1133 } 1134} 1135 1136 1137/* ========================================================================== 1138 1139 Visible bell and beep. 1140 1141 ========================================================================== */ 1142 1143 1144// This bell implementation shows the visual bell image asynchronously 1145// from the rest of Emacs. This is done by adding a NSView to the 1146// superview of the Emacs window and removing it using a timer. 1147// 1148// Unfortunately, some Emacs operations, like scrolling, is done using 1149// low-level primitives that copy the content of the window, including 1150// the bell image. To some extent, this is handled by removing the 1151// image prior to scrolling and marking that the window is in need for 1152// redisplay. 1153// 1154// To test this code, make sure that there is no artifacts of the bell 1155// image in the following situations. Use a non-empty buffer (like the 1156// tutorial) to ensure that a scroll is performed: 1157// 1158// * Single-window: C-g C-v 1159// 1160// * Side-by-windows: C-x 3 C-g C-v 1161// 1162// * Windows above each other: C-x 2 C-g C-v 1163 1164@interface EmacsBell : NSImageView 1165{ 1166 // Number of currently active bells. 1167 unsigned int nestCount; 1168 NSView * mView; 1169 bool isAttached; 1170} 1171- (void)show:(NSView *)view; 1172- (void)hide; 1173- (void)remove; 1174@end 1175 1176@implementation EmacsBell 1177 1178- (id)init 1179{ 1180 NSTRACE ("[EmacsBell init]"); 1181 if ((self = [super init])) 1182 { 1183 nestCount = 0; 1184 isAttached = false; 1185#ifdef NS_IMPL_GNUSTEP 1186 // GNUstep doesn't provide named images. This was reported in 1187 // 2011, see https://savannah.gnu.org/bugs/?33396 1188 // 1189 // As a drop in replacement, a semitransparent gray square is used. 1190 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)]; 1191 [self.image lockFocus]; 1192 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set]; 1193 NSRectFill(NSMakeRect(0, 0, 32, 32)); 1194 [self.image unlockFocus]; 1195#else 1196 self.image = [NSImage imageNamed:NSImageNameCaution]; 1197 [self.image setSize:NSMakeSize(self.image.size.width * 5, 1198 self.image.size.height * 5)]; 1199#endif 1200 } 1201 return self; 1202} 1203 1204- (void)show:(NSView *)view 1205{ 1206 NSTRACE ("[EmacsBell show:]"); 1207 NSTRACE_MSG ("nestCount: %u", nestCount); 1208 1209 // Show the image, unless it's already shown. 1210 if (nestCount == 0) 1211 { 1212 NSRect rect = [view bounds]; 1213 NSPoint pos; 1214 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2; 1215 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2; 1216 1217 [self setFrameOrigin:pos]; 1218 [self setFrameSize:self.image.size]; 1219 1220 isAttached = true; 1221 mView = view; 1222 [[[view window] contentView] addSubview:self 1223 positioned:NSWindowAbove 1224 relativeTo:nil]; 1225 } 1226 1227 ++nestCount; 1228 1229 [self performSelector:@selector(hide) withObject:self afterDelay:0.5]; 1230} 1231 1232 1233- (void)hide 1234{ 1235 // Note: Trace output from this method isn't shown, reason unknown. 1236 // NSTRACE ("[EmacsBell hide]"); 1237 1238 if (nestCount > 0) 1239 --nestCount; 1240 1241 // Remove the image once the last bell became inactive. 1242 if (nestCount == 0) 1243 { 1244 [self remove]; 1245 } 1246} 1247 1248 1249-(void)remove 1250{ 1251 NSTRACE ("[EmacsBell remove]"); 1252 if (isAttached) 1253 { 1254 NSTRACE_MSG ("removeFromSuperview"); 1255 [self removeFromSuperview]; 1256 mView.needsDisplay = YES; 1257 isAttached = false; 1258 } 1259} 1260 1261@end 1262 1263 1264static EmacsBell * bell_view = nil; 1265 1266static void 1267ns_ring_bell (struct frame *f) 1268/* -------------------------------------------------------------------------- 1269 "Beep" routine 1270 -------------------------------------------------------------------------- */ 1271{ 1272 NSTRACE ("ns_ring_bell"); 1273 if (visible_bell) 1274 { 1275 struct frame *frame = SELECTED_FRAME (); 1276 NSView *view; 1277 1278 if (bell_view == nil) 1279 { 1280 bell_view = [[EmacsBell alloc] init]; 1281 [bell_view retain]; 1282 } 1283 1284 block_input (); 1285 1286 view = FRAME_NS_VIEW (frame); 1287 if (view != nil) 1288 { 1289 [bell_view show:view]; 1290 } 1291 1292 unblock_input (); 1293 } 1294 else 1295 { 1296 NSBeep (); 1297 } 1298} 1299 1300#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 1301static void 1302hide_bell (void) 1303/* -------------------------------------------------------------------------- 1304 Ensure the bell is hidden. 1305 -------------------------------------------------------------------------- */ 1306{ 1307 NSTRACE ("hide_bell"); 1308 1309 if (bell_view != nil) 1310 { 1311 [bell_view remove]; 1312 } 1313} 1314#endif 1315 1316 1317/* ========================================================================== 1318 1319 Frame / window manager related functions 1320 1321 ========================================================================== */ 1322 1323static Lisp_Object 1324ns_get_focus_frame (struct frame *f) 1325/* -------------------------------------------------------------------------- 1326 External (hook) 1327 -------------------------------------------------------------------------- */ 1328{ 1329 Lisp_Object lisp_focus; 1330 1331 struct frame *focus = FRAME_DISPLAY_INFO (f)->ns_focus_frame; 1332 1333 if (!focus) 1334 return Qnil; 1335 1336 XSETFRAME (lisp_focus, focus); 1337 return lisp_focus; 1338} 1339 1340static void 1341ns_focus_frame (struct frame *f, bool noactivate) 1342/* -------------------------------------------------------------------------- 1343 External (hook) 1344 -------------------------------------------------------------------------- */ 1345{ 1346 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); 1347 1348 if (dpyinfo->ns_focus_frame != f) 1349 { 1350 EmacsView *view = FRAME_NS_VIEW (f); 1351 block_input (); 1352 [NSApp activateIgnoringOtherApps: YES]; 1353 [[view window] makeKeyAndOrderFront: view]; 1354 unblock_input (); 1355 } 1356} 1357 1358static void 1359ns_raise_frame (struct frame *f, BOOL make_key) 1360/* -------------------------------------------------------------------------- 1361 Bring window to foreground and if make_key is YES, give it focus. 1362 -------------------------------------------------------------------------- */ 1363{ 1364 NSView *view; 1365 1366 check_window_system (f); 1367 view = FRAME_NS_VIEW (f); 1368 block_input (); 1369 if (FRAME_VISIBLE_P (f)) 1370 { 1371 if (make_key) 1372 [[view window] makeKeyAndOrderFront: NSApp]; 1373 else 1374 [[view window] orderFront: NSApp]; 1375 } 1376 unblock_input (); 1377} 1378 1379 1380static void 1381ns_lower_frame (struct frame *f) 1382/* -------------------------------------------------------------------------- 1383 Send window to back 1384 -------------------------------------------------------------------------- */ 1385{ 1386 NSView *view; 1387 1388 check_window_system (f); 1389 view = FRAME_NS_VIEW (f); 1390 block_input (); 1391 [[view window] orderBack: NSApp]; 1392 unblock_input (); 1393} 1394 1395 1396static void 1397ns_frame_raise_lower (struct frame *f, bool raise) 1398/* -------------------------------------------------------------------------- 1399 External (hook) 1400 -------------------------------------------------------------------------- */ 1401{ 1402 NSTRACE ("ns_frame_raise_lower"); 1403 1404 if (raise) 1405 ns_raise_frame (f, YES); 1406 else 1407 ns_lower_frame (f); 1408} 1409 1410static void ns_set_frame_alpha (struct frame *f); 1411 1412static void 1413ns_frame_rehighlight (struct frame *frame) 1414/* -------------------------------------------------------------------------- 1415 External (hook): called on things like window switching within frame 1416 -------------------------------------------------------------------------- */ 1417{ 1418 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame); 1419 struct frame *old_highlight = dpyinfo->highlight_frame; 1420 1421 NSTRACE ("ns_frame_rehighlight"); 1422 if (dpyinfo->ns_focus_frame) 1423 { 1424 dpyinfo->highlight_frame 1425 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->ns_focus_frame)) 1426 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->ns_focus_frame)) 1427 : dpyinfo->ns_focus_frame); 1428 if (!FRAME_LIVE_P (dpyinfo->highlight_frame)) 1429 { 1430 fset_focus_frame (dpyinfo->ns_focus_frame, Qnil); 1431 dpyinfo->highlight_frame = dpyinfo->ns_focus_frame; 1432 } 1433 } 1434 else 1435 dpyinfo->highlight_frame = 0; 1436 1437 if (dpyinfo->highlight_frame && 1438 dpyinfo->highlight_frame != old_highlight) 1439 { 1440 if (old_highlight) 1441 { 1442 gui_update_cursor (old_highlight, 1); 1443 ns_set_frame_alpha (old_highlight); 1444 } 1445 if (dpyinfo->highlight_frame) 1446 { 1447 gui_update_cursor (dpyinfo->highlight_frame, 1); 1448 ns_set_frame_alpha (dpyinfo->highlight_frame); 1449 } 1450 } 1451} 1452 1453 1454void 1455ns_make_frame_visible (struct frame *f) 1456/* -------------------------------------------------------------------------- 1457 External: Show the window (X11 semantics) 1458 -------------------------------------------------------------------------- */ 1459{ 1460 NSTRACE ("ns_make_frame_visible"); 1461 /* XXX: at some points in past this was not needed, as the only place that 1462 called this (frame.c:Fraise_frame ()) also called raise_lower; 1463 if this ends up the case again, comment this out again. */ 1464 if (!FRAME_VISIBLE_P (f)) 1465 { 1466 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); 1467 EmacsWindow *window = (EmacsWindow *)[view window]; 1468 1469 SET_FRAME_VISIBLE (f, 1); 1470 ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f)); 1471 1472 /* Making a new frame from a fullscreen frame will make the new frame 1473 fullscreen also. So skip handleFS as this will print an error. */ 1474 if ([view fsIsNative] && [view isFullscreen]) 1475 { 1476 return; 1477 } 1478 1479 if (f->want_fullscreen != FULLSCREEN_NONE) 1480 { 1481 block_input (); 1482 [view handleFS]; 1483 unblock_input (); 1484 } 1485 1486 /* Making a frame invisible seems to break the parent->child 1487 relationship, so reinstate it. */ 1488 if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL) 1489 { 1490 block_input (); 1491 [window setParentChildRelationships]; 1492 unblock_input (); 1493 1494 /* If the parent frame moved while the child frame was 1495 invisible, the child frame's position won't have been 1496 updated. Make sure it's in the right place now. */ 1497 ns_set_offset(f, f->left_pos, f->top_pos, 0); 1498 } 1499 } 1500} 1501 1502 1503static void 1504ns_make_frame_invisible (struct frame *f) 1505/* -------------------------------------------------------------------------- 1506 Hide the window (X11 semantics) 1507 -------------------------------------------------------------------------- */ 1508{ 1509 NSView *view; 1510 NSTRACE ("ns_make_frame_invisible"); 1511 check_window_system (f); 1512 view = FRAME_NS_VIEW (f); 1513 [[view window] orderOut: NSApp]; 1514 SET_FRAME_VISIBLE (f, 0); 1515 SET_FRAME_ICONIFIED (f, 0); 1516} 1517 1518static void 1519ns_make_frame_visible_invisible (struct frame *f, bool visible) 1520/* -------------------------------------------------------------------------- 1521 External (hook) 1522 -------------------------------------------------------------------------- */ 1523{ 1524 if (visible) 1525 ns_make_frame_visible (f); 1526 else 1527 ns_make_frame_invisible (f); 1528} 1529 1530void 1531ns_iconify_frame (struct frame *f) 1532/* -------------------------------------------------------------------------- 1533 External (hook): Iconify window 1534 -------------------------------------------------------------------------- */ 1535{ 1536 NSView *view; 1537 struct ns_display_info *dpyinfo; 1538 1539 NSTRACE ("ns_iconify_frame"); 1540 check_window_system (f); 1541 view = FRAME_NS_VIEW (f); 1542 dpyinfo = FRAME_DISPLAY_INFO (f); 1543 1544 if (dpyinfo->highlight_frame == f) 1545 dpyinfo->highlight_frame = 0; 1546 1547 if ([[view window] windowNumber] <= 0) 1548 { 1549 /* The window is still deferred. Make it very small, bring it 1550 on screen and order it out. */ 1551 NSRect s = { { 100, 100}, {0, 0} }; 1552 NSRect t; 1553 t = [[view window] frame]; 1554 [[view window] setFrame: s display: NO]; 1555 [[view window] orderBack: NSApp]; 1556 [[view window] orderOut: NSApp]; 1557 [[view window] setFrame: t display: NO]; 1558 } 1559 1560 /* Processing input while Emacs is being minimized can cause a 1561 crash, so block it for the duration. */ 1562 block_input(); 1563 [[view window] miniaturize: NSApp]; 1564 unblock_input(); 1565} 1566 1567/* Free resources of frame F. */ 1568 1569void 1570ns_free_frame_resources (struct frame *f) 1571{ 1572 NSView *view; 1573 struct ns_display_info *dpyinfo; 1574 Mouse_HLInfo *hlinfo; 1575 1576 NSTRACE ("ns_free_frame_resources"); 1577 check_window_system (f); 1578 view = FRAME_NS_VIEW (f); 1579 dpyinfo = FRAME_DISPLAY_INFO (f); 1580 hlinfo = MOUSE_HL_INFO (f); 1581 1582 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */ 1583 1584 block_input (); 1585 1586 free_frame_menubar (f); 1587 free_frame_faces (f); 1588 1589 if (f == dpyinfo->ns_focus_frame) 1590 dpyinfo->ns_focus_frame = 0; 1591 if (f == dpyinfo->highlight_frame) 1592 dpyinfo->highlight_frame = 0; 1593 if (f == hlinfo->mouse_face_mouse_frame) 1594 reset_mouse_highlight (hlinfo); 1595 1596 if (f->output_data.ns->miniimage != nil) 1597 [f->output_data.ns->miniimage release]; 1598 1599 [[view window] close]; 1600 [view release]; 1601 1602 xfree (f->output_data.ns); 1603 f->output_data.ns = NULL; 1604 1605 unblock_input (); 1606} 1607 1608static void 1609ns_destroy_window (struct frame *f) 1610/* -------------------------------------------------------------------------- 1611 External: Delete the window 1612 -------------------------------------------------------------------------- */ 1613{ 1614 NSTRACE ("ns_destroy_window"); 1615 1616 check_window_system (f); 1617 1618 /* If this frame has a parent window, detach it as not doing so can 1619 cause a crash in GNUStep. */ 1620 if (FRAME_PARENT_FRAME (f) != NULL) 1621 { 1622 NSWindow *child = [FRAME_NS_VIEW (f) window]; 1623 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window]; 1624 1625 [parent removeChildWindow: child]; 1626 } 1627 1628 [[FRAME_NS_VIEW (f) window] close]; 1629 ns_free_frame_resources (f); 1630 ns_window_num--; 1631} 1632 1633 1634void 1635ns_set_offset (struct frame *f, int xoff, int yoff, int change_grav) 1636/* -------------------------------------------------------------------------- 1637 External: Position the window 1638 -------------------------------------------------------------------------- */ 1639{ 1640 NSView *view = FRAME_NS_VIEW (f); 1641 NSRect windowFrame = [[view window] frame]; 1642 NSPoint topLeft; 1643 1644 NSTRACE ("ns_set_offset"); 1645 1646 block_input (); 1647 1648 /* If there is no parent frame then just convert to screen 1649 coordinates, UNLESS we have negative values, in which case I 1650 think it's best to position from the bottom and right of the 1651 current screen rather than the main screen or whole display. */ 1652 1653 NSRect parentRect = ns_parent_window_rect (f); 1654 1655 if (f->size_hint_flags & XNegative) 1656 topLeft.x = NSMaxX (parentRect) - NSWidth (windowFrame) + xoff; 1657 else if (FRAME_PARENT_FRAME (f)) 1658 topLeft.x = NSMinX (parentRect) + xoff; 1659 else 1660 topLeft.x = xoff; 1661 1662 if (f->size_hint_flags & YNegative) 1663 topLeft.y = NSMinY (parentRect) + NSHeight (windowFrame) - yoff; 1664 else if (FRAME_PARENT_FRAME (f)) 1665 topLeft.y = NSMaxY (parentRect) - yoff; 1666 else 1667 topLeft.y = NSMaxY ([[[NSScreen screens] objectAtIndex:0] frame]) - yoff; 1668 1669#ifdef NS_IMPL_GNUSTEP 1670 /* Don't overlap the menu. 1671 1672 FIXME: Surely there's a better way than just hardcoding 100 in 1673 here? */ 1674 if (topLeft.x < 100) 1675 topLeft.x = 100; 1676#endif 1677 1678 NSTRACE_POINT ("setFrameTopLeftPoint", topLeft); 1679 [[view window] setFrameTopLeftPoint:topLeft]; 1680 f->size_hint_flags &= ~(XNegative|YNegative); 1681 1682 unblock_input (); 1683} 1684 1685 1686static void 1687ns_set_window_size (struct frame *f, 1688 bool change_gravity, 1689 int width, 1690 int height) 1691/* -------------------------------------------------------------------------- 1692 Adjust window pixel size based on native sizes WIDTH and HEIGHT. 1693 Impl is a bit more complex than other terms, need to do some 1694 internal clipping. 1695 -------------------------------------------------------------------------- */ 1696{ 1697 EmacsView *view = FRAME_NS_VIEW (f); 1698 NSWindow *window = [view window]; 1699 NSRect frameRect; 1700 1701 NSTRACE ("ns_set_window_size"); 1702 1703 if (view == nil) 1704 return; 1705 1706 NSTRACE_RECT ("current", [window frame]); 1707 NSTRACE_MSG ("Width:%d Height:%d", width, height); 1708 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); 1709 1710 block_input (); 1711 1712 frameRect = [window frameRectForContentRect:NSMakeRect (0, 0, width, height)]; 1713 1714 /* Set the origin so the top left of the frame doesn't move. */ 1715 frameRect.origin = [window frame].origin; 1716 frameRect.origin.y += NSHeight ([view frame]) - height; 1717 1718 if (f->output_data.ns->zooming) 1719 f->output_data.ns->zooming = 0; 1720 1721 /* Usually it seems safe to delay changing the frame size, but when a 1722 series of actions are taken with no redisplay between them then we 1723 can end up using old values so don't delay here. */ 1724 change_frame_size (f, width, height, false, NO, false); 1725 1726 [window setFrame:frameRect display:NO]; 1727 1728 unblock_input (); 1729} 1730 1731void 1732ns_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) 1733/* -------------------------------------------------------------------------- 1734 Set frame F's `undecorated' parameter. If non-nil, F's window-system 1735 window is drawn without decorations, title, minimize/maximize boxes 1736 and external borders. This usually means that the window cannot be 1737 dragged, resized, iconified, maximized or deleted with the mouse. If 1738 nil, draw the frame with all the elements listed above unless these 1739 have been suspended via window manager settings. 1740 -------------------------------------------------------------------------- */ 1741{ 1742 NSTRACE ("ns_set_undecorated"); 1743 1744 if (!EQ (new_value, old_value)) 1745 { 1746 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); 1747 NSWindow *oldWindow = [view window]; 1748 NSWindow *newWindow; 1749 1750 block_input (); 1751 1752 FRAME_UNDECORATED (f) = !NILP (new_value); 1753 1754 newWindow = [[EmacsWindow alloc] initWithEmacsFrame:f]; 1755 1756 if ([oldWindow isKeyWindow]) 1757 [newWindow makeKeyAndOrderFront:NSApp]; 1758 1759 [newWindow setIsVisible:[oldWindow isVisible]]; 1760 if ([oldWindow isMiniaturized]) 1761 [newWindow miniaturize:NSApp]; 1762 1763 [oldWindow close]; 1764 1765 unblock_input (); 1766 } 1767} 1768 1769void 1770ns_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) 1771/* -------------------------------------------------------------------------- 1772 Set frame F's `parent-frame' parameter. If non-nil, make F a child 1773 frame of the frame specified by that parameter. Technically, this 1774 makes F's window-system window a child window of the parent frame's 1775 window-system window. If nil, make F's window-system window a 1776 top-level window--a child of its display's root window. 1777 1778 A child frame's `left' and `top' parameters specify positions 1779 relative to the top-left corner of its parent frame's native 1780 rectangle. On macOS moving a parent frame moves all its child 1781 frames too, keeping their position relative to the parent 1782 unaltered. When a parent frame is iconified or made invisible, its 1783 child frames are made invisible. When a parent frame is deleted, 1784 its child frames are deleted too. 1785 1786 Whether a child frame has a tool bar may be window-system or window 1787 manager dependent. It's advisable to disable it via the frame 1788 parameter settings. 1789 1790 Some window managers may not honor this parameter. 1791 -------------------------------------------------------------------------- */ 1792{ 1793 struct frame *p = NULL; 1794 1795 NSTRACE ("ns_set_parent_frame"); 1796 1797 if (!NILP (new_value) 1798 && (!FRAMEP (new_value) 1799 || !FRAME_LIVE_P (p = XFRAME (new_value)) 1800 || !FRAME_NS_P (p))) 1801 { 1802 store_frame_param (f, Qparent_frame, old_value); 1803 error ("Invalid specification of `parent-frame'"); 1804 } 1805 1806 fset_parent_frame (f, new_value); 1807 1808 block_input (); 1809 [(EmacsWindow *)[FRAME_NS_VIEW (f) window] setParentChildRelationships]; 1810 unblock_input (); 1811} 1812 1813void 1814ns_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) 1815/* Set frame F's `no-focus-on-map' parameter which, if non-nil, means 1816 * that F's window-system window does not want to receive input focus 1817 * when it is mapped. (A frame's window is mapped when the frame is 1818 * displayed for the first time and when the frame changes its state 1819 * from `iconified' or `invisible' to `visible'.) 1820 * 1821 * Some window managers may not honor this parameter. */ 1822{ 1823 NSTRACE ("ns_set_no_focus_on_map"); 1824 1825 if (!EQ (new_value, old_value)) 1826 { 1827 FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value); 1828 } 1829} 1830 1831void 1832ns_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) 1833/* Set frame F's `no-accept-focus' parameter which, if non-nil, hints 1834 * that F's window-system window does not want to receive input focus 1835 * via mouse clicks or by moving the mouse into it. 1836 * 1837 * If non-nil, this may have the unwanted side-effect that a user cannot 1838 * scroll a non-selected frame with the mouse. 1839 * 1840 * Some window managers may not honor this parameter. */ 1841{ 1842 NSTRACE ("ns_set_no_accept_focus"); 1843 1844 if (!EQ (new_value, old_value)) 1845 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value); 1846} 1847 1848void 1849ns_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) 1850/* Set frame F's `z-group' parameter. If `above', F's window-system 1851 window is displayed above all windows that do not have the `above' 1852 property set. If nil, F's window is shown below all windows that 1853 have the `above' property set and above all windows that have the 1854 `below' property set. If `below', F's window is displayed below 1855 all windows that do. 1856 1857 Some window managers may not honor this parameter. */ 1858{ 1859 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); 1860 NSWindow *window = [view window]; 1861 1862 NSTRACE ("ns_set_z_group"); 1863 1864 if (NILP (new_value)) 1865 { 1866 window.level = NSNormalWindowLevel; 1867 FRAME_Z_GROUP (f) = z_group_none; 1868 } 1869 else if (EQ (new_value, Qabove)) 1870 { 1871 window.level = NSNormalWindowLevel + 1; 1872 FRAME_Z_GROUP (f) = z_group_above; 1873 } 1874 else if (EQ (new_value, Qabove_suspended)) 1875 { 1876 /* Not sure what level this should be. */ 1877 window.level = NSNormalWindowLevel + 1; 1878 FRAME_Z_GROUP (f) = z_group_above_suspended; 1879 } 1880 else if (EQ (new_value, Qbelow)) 1881 { 1882 window.level = NSNormalWindowLevel - 1; 1883 FRAME_Z_GROUP (f) = z_group_below; 1884 } 1885 else 1886 error ("Invalid z-group specification"); 1887} 1888 1889#ifdef NS_IMPL_COCOA 1890void 1891ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value) 1892{ 1893#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 1894 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); 1895 EmacsWindow *window = (EmacsWindow *)[view window]; 1896 1897 NSTRACE ("ns_set_appearance"); 1898 1899 if (NSAppKitVersionNumber < NSAppKitVersionNumber10_10) 1900 return; 1901 1902 if (EQ (new_value, Qdark)) 1903 FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark; 1904 else if (EQ (new_value, Qlight)) 1905 FRAME_NS_APPEARANCE (f) = ns_appearance_aqua; 1906 else 1907 FRAME_NS_APPEARANCE (f) = ns_appearance_system_default; 1908 1909 [window setAppearance]; 1910#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */ 1911} 1912 1913void 1914ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value, 1915 Lisp_Object old_value) 1916{ 1917#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 1918 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); 1919 NSWindow *window = [view window]; 1920 1921 NSTRACE ("ns_set_transparent_titlebar"); 1922 1923 if ([window respondsToSelector: @selector(titlebarAppearsTransparent)] 1924 && !EQ (new_value, old_value)) 1925 { 1926 window.titlebarAppearsTransparent = !NILP (new_value); 1927 FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (new_value); 1928 } 1929#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */ 1930} 1931#endif /* NS_IMPL_COCOA */ 1932 1933static void 1934ns_fullscreen_hook (struct frame *f) 1935{ 1936 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); 1937 1938 NSTRACE ("ns_fullscreen_hook"); 1939 1940 if (!FRAME_VISIBLE_P (f)) 1941 return; 1942 1943 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH) 1944 { 1945 /* Old style fs don't initiate correctly if created from 1946 init/default-frame alist, so use a timer (not nice...). */ 1947 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view 1948 selector: @selector (handleFS) 1949 userInfo: nil repeats: NO]; 1950 return; 1951 } 1952 1953 block_input (); 1954 [view handleFS]; 1955 unblock_input (); 1956} 1957 1958/* ========================================================================== 1959 1960 Color management 1961 1962 ========================================================================== */ 1963 1964 1965static int 1966ns_get_color (const char *name, NSColor **col) 1967/* -------------------------------------------------------------------------- 1968 Parse a color name 1969 -------------------------------------------------------------------------- */ 1970/* On *Step, we attempt to mimic the X11 platform here, down to installing an 1971 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()). 1972 See https://lists.gnu.org/r/emacs-devel/2009-07/msg01203.html. */ 1973{ 1974 NSColor *new = nil; 1975 NSString *nsname = [NSString stringWithUTF8String: name]; 1976 1977 NSTRACE ("ns_get_color(%s, **)", name); 1978 1979 block_input (); 1980 1981 if ([nsname isEqualToString: @"ns_selection_bg_color"]) 1982 { 1983#ifdef NS_IMPL_COCOA 1984 NSString *defname = [[NSUserDefaults standardUserDefaults] 1985 stringForKey: @"AppleHighlightColor"]; 1986 if (defname != nil) 1987 nsname = defname; 1988 else 1989#endif 1990 if ((new = [NSColor selectedTextBackgroundColor]) != nil) 1991 { 1992 *col = [new colorUsingDefaultColorSpace]; 1993 unblock_input (); 1994 return 0; 1995 } 1996 else 1997 nsname = NS_SELECTION_BG_COLOR_DEFAULT; 1998 1999 name = [nsname UTF8String]; 2000 } 2001 else if ([nsname isEqualToString: @"ns_selection_fg_color"]) 2002 { 2003 /* NOTE: macOS applications normally don't set foreground 2004 selection, but text may be unreadable if we don't. */ 2005 if ((new = [NSColor selectedTextColor]) != nil) 2006 { 2007 *col = [new colorUsingDefaultColorSpace]; 2008 unblock_input (); 2009 return 0; 2010 } 2011 2012 nsname = NS_SELECTION_FG_COLOR_DEFAULT; 2013 name = [nsname UTF8String]; 2014 } 2015 2016 /* First, check for some sort of numeric specification. */ 2017 unsigned short r16, g16, b16; 2018 if (parse_color_spec (name, &r16, &g16, &b16)) 2019 { 2020 *col = [NSColor colorForEmacsRed: r16 / 65535.0 2021 green: g16 / 65535.0 2022 blue: b16 / 65535.0 2023 alpha: 1.0]; 2024 unblock_input (); 2025 return 0; 2026 } 2027 else if (name[0] == '0' || name[0] == '1' || name[0] == '.') 2028 { 2029 /* RGB decimal */ 2030 NSScanner *scanner = [NSScanner scannerWithString: nsname]; 2031 float r, g, b; 2032 if ( [scanner scanFloat: &r] && r >= 0 && r <= 1 2033 && [scanner scanFloat: &g] && g >= 0 && g <= 1 2034 && [scanner scanFloat: &b] && b >= 0 && b <= 1) 2035 { 2036 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0]; 2037 unblock_input (); 2038 return 0; 2039 } 2040 } 2041 2042 /* Otherwise, color is expected to be from a list */ 2043 { 2044 NSEnumerator *lenum, *cenum; 2045 NSString *name; 2046 NSColorList *clist; 2047 2048#ifdef NS_IMPL_GNUSTEP 2049 /* XXX: who is wrong, the requestor or the implementation? */ 2050 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch] 2051 == NSOrderedSame) 2052 nsname = @"highlightColor"; 2053#endif 2054 2055 lenum = [[NSColorList availableColorLists] objectEnumerator]; 2056 while ( (clist = [lenum nextObject]) && new == nil) 2057 { 2058 cenum = [[clist allKeys] objectEnumerator]; 2059 while ( (name = [cenum nextObject]) && new == nil ) 2060 { 2061 if ([name compare: nsname 2062 options: NSCaseInsensitiveSearch] == NSOrderedSame ) 2063 new = [clist colorWithKey: name]; 2064 } 2065 } 2066 } 2067 2068 if (new) 2069 *col = [new colorUsingDefaultColorSpace]; 2070 unblock_input (); 2071 return new ? 0 : 1; 2072} 2073 2074 2075int 2076ns_lisp_to_color (Lisp_Object color, NSColor **col) 2077/* -------------------------------------------------------------------------- 2078 Convert a Lisp string object to a NS color. 2079 -------------------------------------------------------------------------- */ 2080{ 2081 NSTRACE ("ns_lisp_to_color"); 2082 if (STRINGP (color)) 2083 return ns_get_color (SSDATA (color), col); 2084 else if (SYMBOLP (color)) 2085 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col); 2086 return 1; 2087} 2088 2089void 2090ns_query_color(void *col, Emacs_Color *color_def) 2091/* -------------------------------------------------------------------------- 2092 Get ARGB values out of NSColor col and put them into color_def 2093 and set color_def pixel to the ARGB color. 2094 -------------------------------------------------------------------------- */ 2095{ 2096 EmacsCGFloat r, g, b, a; 2097 2098 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a]; 2099 color_def->red = r * 65535; 2100 color_def->green = g * 65535; 2101 color_def->blue = b * 65535; 2102 2103 color_def->pixel = [(NSColor *)col unsignedLong]; 2104} 2105 2106bool 2107ns_defined_color (struct frame *f, 2108 const char *name, 2109 Emacs_Color *color_def, 2110 bool alloc, 2111 bool _makeIndex) 2112/* -------------------------------------------------------------------------- 2113 Return true if named color found, and set color_def rgb accordingly. 2114 Return false if not found. 2115 -------------------------------------------------------------------------- */ 2116{ 2117 NSColor *col; 2118 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color"); 2119 2120 block_input (); 2121 if (ns_get_color (name, &col) != 0) /* Color not found */ 2122 { 2123 unblock_input (); 2124 return 0; 2125 } 2126 ns_query_color (col, color_def); 2127 unblock_input (); 2128 return 1; 2129} 2130 2131static void 2132ns_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor) 2133/* -------------------------------------------------------------------------- 2134 External (hook): Store F's background color into *BGCOLOR 2135 -------------------------------------------------------------------------- */ 2136{ 2137 ns_query_color (FRAME_BACKGROUND_COLOR (f), bgcolor); 2138} 2139 2140static void 2141ns_set_frame_alpha (struct frame *f) 2142/* -------------------------------------------------------------------------- 2143 change the entire-frame transparency 2144 -------------------------------------------------------------------------- */ 2145{ 2146 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); 2147 double alpha = 1.0; 2148 double alpha_min = 1.0; 2149 2150 NSTRACE ("ns_set_frame_alpha"); 2151 2152 if (dpyinfo->highlight_frame == f) 2153 alpha = f->alpha[0]; 2154 else 2155 alpha = f->alpha[1]; 2156 2157 if (FLOATP (Vframe_alpha_lower_limit)) 2158 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit); 2159 else if (FIXNUMP (Vframe_alpha_lower_limit)) 2160 alpha_min = (XFIXNUM (Vframe_alpha_lower_limit)) / 100.0; 2161 2162 if (alpha < 0.0) 2163 return; 2164 else if (1.0 < alpha) 2165 alpha = 1.0; 2166 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0) 2167 alpha = alpha_min; 2168 2169 { 2170 EmacsView *view = FRAME_NS_VIEW (f); 2171 [[view window] setAlphaValue: alpha]; 2172 } 2173} 2174 2175 2176/* ========================================================================== 2177 2178 Mouse handling 2179 2180 ========================================================================== */ 2181 2182 2183void 2184frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) 2185/* -------------------------------------------------------------------------- 2186 Programmatically reposition mouse pointer in pixel coordinates 2187 -------------------------------------------------------------------------- */ 2188{ 2189 NSTRACE ("frame_set_mouse_pixel_position"); 2190 2191#ifdef NS_IMPL_COCOA 2192 CGPoint mouse_pos = 2193 CGPointMake(f->left_pos + pix_x, 2194 f->top_pos + pix_y + 2195 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f)); 2196 CGWarpMouseCursorPosition (mouse_pos); 2197#else 2198 GSDisplayServer *server = GSServerForWindow ([FRAME_NS_VIEW (f) window]); 2199 [server setMouseLocation: NSMakePoint (f->left_pos + pix_x, 2200 f->top_pos + pix_y 2201 + FRAME_NS_TITLEBAR_HEIGHT(f) 2202 + FRAME_TOOLBAR_HEIGHT(f)) 2203 onScreen: [[[FRAME_NS_VIEW (f) window] screen] screenNumber]]; 2204#endif 2205} 2206 2207static int 2208ns_note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y, 2209 BOOL dragging) 2210/* ------------------------------------------------------------------------ 2211 Called by EmacsView on mouseMovement events. Passes on 2212 to emacs mainstream code if we moved off of a rect of interest 2213 known as last_mouse_glyph. 2214 ------------------------------------------------------------------------ */ 2215{ 2216 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame); 2217 NSRect *r; 2218 BOOL force_update = NO; 2219 2220 // NSTRACE ("note_mouse_movement"); 2221 2222 dpyinfo->last_mouse_motion_frame = frame; 2223 r = &dpyinfo->last_mouse_glyph; 2224 2225 /* If the last rect is too large (ex, xwidget webkit), update at 2226 every move, or resizing by dragging modeline or vertical split is 2227 very hard to make its way. */ 2228 if (dragging && (r->size.width > 32 || r->size.height > 32)) 2229 force_update = YES; 2230 2231 /* Note, this doesn't get called for enter/leave, since we don't have a 2232 position. Those are taken care of in the corresponding NSView methods. */ 2233 2234 /* Has movement gone beyond last rect we were tracking? */ 2235 if (force_update || x < r->origin.x || x >= r->origin.x + r->size.width 2236 || y < r->origin.y || y >= r->origin.y + r->size.height) 2237 { 2238 ns_update_begin (frame); 2239 frame->mouse_moved = 1; 2240 note_mouse_highlight (frame, x, y); 2241 remember_mouse_glyph (frame, x, y, r); 2242 ns_update_end (frame); 2243 return 1; 2244 } 2245 2246 return 0; 2247} 2248 2249 2250static void 2251ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, 2252 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y, 2253 Time *time) 2254/* -------------------------------------------------------------------------- 2255 External (hook): inform emacs about mouse position and hit parts. 2256 If a scrollbar is being dragged, set bar_window, part, x, y, time. 2257 x & y should be position in the scrollbar (the whole bar, not the handle) 2258 and length of scrollbar respectively. 2259 -------------------------------------------------------------------------- */ 2260{ 2261 id view; 2262 NSPoint view_position; 2263 Lisp_Object frame, tail; 2264 struct frame *f = NULL; 2265 struct ns_display_info *dpyinfo; 2266 2267 NSTRACE ("ns_mouse_position"); 2268 2269 if (*fp == NULL) 2270 { 2271 fputs ("Warning: ns_mouse_position () called with null *fp.\n", stderr); 2272 return; 2273 } 2274 2275 dpyinfo = FRAME_DISPLAY_INFO (*fp); 2276 2277 block_input (); 2278 2279 /* Clear the mouse-moved flag for every frame on this display. */ 2280 FOR_EACH_FRAME (tail, frame) 2281 if (FRAME_NS_P (XFRAME (frame))) 2282 XFRAME (frame)->mouse_moved = 0; 2283 2284 dpyinfo->last_mouse_scroll_bar = nil; 2285 2286#ifdef NS_IMPL_COCOA 2287 /* Find the uppermost Emacs frame under the mouse pointer. 2288 2289 This doesn't work on GNUstep, although in recent versions there 2290 is compatibility code that makes it a noop. */ 2291 2292 NSPoint screen_position = [NSEvent mouseLocation]; 2293 NSInteger window_number = 0; 2294 do 2295 { 2296 NSWindow *w; 2297 2298 window_number = [NSWindow windowNumberAtPoint:screen_position 2299 belowWindowWithWindowNumber:window_number]; 2300 w = [NSApp windowWithWindowNumber:window_number]; 2301 2302 if (w && [[w delegate] isKindOfClass:[EmacsView class]]) 2303 f = ((EmacsView *)[w delegate])->emacsframe; 2304 } 2305 while (window_number > 0 && !f); 2306#endif 2307 2308 if (!f) 2309 f = dpyinfo->ns_focus_frame ? dpyinfo->ns_focus_frame : SELECTED_FRAME (); 2310 2311 /* While dropping, use the last mouse frame only if there is no 2312 currently focused frame. */ 2313 if (!f 2314 && EQ (track_mouse, Qdropping) 2315 && dpyinfo->last_mouse_frame 2316 && FRAME_LIVE_P (dpyinfo->last_mouse_frame)) 2317 f = dpyinfo->last_mouse_frame; 2318 2319 if (f && FRAME_NS_P (f)) 2320 { 2321 view = FRAME_NS_VIEW (f); 2322 2323 view_position = [[view window] mouseLocationOutsideOfEventStream]; 2324 view_position = [view convertPoint: view_position fromView: nil]; 2325 remember_mouse_glyph (f, view_position.x, view_position.y, 2326 &dpyinfo->last_mouse_glyph); 2327 NSTRACE_POINT ("view_position", view_position); 2328 2329 if (bar_window) *bar_window = Qnil; 2330 if (part) *part = scroll_bar_above_handle; 2331 2332 if (x) XSETINT (*x, lrint (view_position.x)); 2333 if (y) XSETINT (*y, lrint (view_position.y)); 2334 if (time) 2335 *time = dpyinfo->last_mouse_movement_time; 2336 *fp = f; 2337 } 2338 2339 unblock_input (); 2340} 2341 2342 2343static void 2344ns_frame_up_to_date (struct frame *f) 2345/* -------------------------------------------------------------------------- 2346 External (hook): Fix up mouse highlighting right after a full update. 2347 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls. 2348 -------------------------------------------------------------------------- */ 2349{ 2350 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date"); 2351 2352 if (FRAME_NS_P (f)) 2353 { 2354 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f); 2355 if (f == hlinfo->mouse_face_mouse_frame) 2356 { 2357 block_input (); 2358 ns_update_begin(f); 2359 note_mouse_highlight (hlinfo->mouse_face_mouse_frame, 2360 hlinfo->mouse_face_mouse_x, 2361 hlinfo->mouse_face_mouse_y); 2362 ns_update_end(f); 2363 unblock_input (); 2364 } 2365 } 2366} 2367 2368 2369static void 2370ns_define_frame_cursor (struct frame *f, Emacs_Cursor cursor) 2371/* -------------------------------------------------------------------------- 2372 External (RIF): set frame mouse pointer type. 2373 -------------------------------------------------------------------------- */ 2374{ 2375 NSTRACE ("ns_define_frame_cursor"); 2376 if (FRAME_POINTER_TYPE (f) != cursor) 2377 { 2378 EmacsView *view = FRAME_NS_VIEW (f); 2379 FRAME_POINTER_TYPE (f) = cursor; 2380 [[view window] invalidateCursorRectsForView: view]; 2381 } 2382} 2383 2384 2385 2386/* ========================================================================== 2387 2388 Keyboard handling 2389 2390 ========================================================================== */ 2391 2392 2393static unsigned 2394ns_convert_key (unsigned code) 2395/* -------------------------------------------------------------------------- 2396 Internal call used by NSView-keyDown. 2397 -------------------------------------------------------------------------- */ 2398{ 2399 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym); 2400 unsigned keysym; 2401 /* An array would be faster, but less easy to read. */ 2402 for (keysym = 0; keysym < last_keysym; keysym += 2) 2403 if (code == convert_ns_to_X_keysym[keysym]) 2404 return 0xFF00 | convert_ns_to_X_keysym[keysym+1]; 2405 return 0; 2406/* if decide to use keyCode and Carbon table, use this line: 2407 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */ 2408} 2409 2410 2411char * 2412get_keysym_name (int keysym) 2413/* -------------------------------------------------------------------------- 2414 Called by keyboard.c. Not sure if the return val is important, except 2415 that it be unique. 2416 -------------------------------------------------------------------------- */ 2417{ 2418 static char value[16]; 2419 NSTRACE ("get_keysym_name"); 2420 sprintf (value, "%d", keysym); 2421 return value; 2422} 2423 2424#ifdef NS_IMPL_COCOA 2425static Lisp_Object 2426right_mod (Lisp_Object left, Lisp_Object right) 2427{ 2428 return EQ (right, Qleft) ? left : right; 2429} 2430 2431static bool 2432nil_or_none (Lisp_Object val) 2433{ 2434 return NILP (val) || EQ (val, Qnone); 2435} 2436 2437static UniChar 2438ns_get_shifted_character (NSEvent *event) 2439/* Look up the character corresponding to the key pressed on the 2440 current keyboard layout and the currently configured shift-like 2441 modifiers. This ignores the control-like modifiers that cause 2442 [event characters] to give us the wrong result. 2443 2444 Although UCKeyTranslate doesn't require the Carbon framework, some 2445 of the surrounding paraphernalia does, so this function makes 2446 Carbon a requirement. */ 2447{ 2448 static UInt32 dead_key_state; 2449 2450 /* UCKeyTranslate may return up to 255 characters. If the buffer 2451 isn't large enough then it produces an error. What kind of 2452 keyboard inputs 255 characters in a single keypress? */ 2453 UniChar buf[255]; 2454 UniCharCount max_string_length = 255; 2455 UniCharCount actual_string_length = 0; 2456 OSStatus result; 2457 2458 CFDataRef layout_ref = (CFDataRef) TISGetInputSourceProperty 2459 (TISCopyCurrentKeyboardLayoutInputSource (), kTISPropertyUnicodeKeyLayoutData); 2460 UCKeyboardLayout* layout = (UCKeyboardLayout*) CFDataGetBytePtr (layout_ref); 2461 2462 UInt32 flags = [event modifierFlags]; 2463 UInt32 modifiers = (flags & NSEventModifierFlagShift) ? shiftKey : 0; 2464 2465 NSTRACE ("ns_get_shifted_character"); 2466 2467 if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask 2468 && nil_or_none (mod_of_kind (right_mod (ns_alternate_modifier, 2469 ns_right_alternate_modifier), 2470 QCordinary))) 2471 modifiers |= rightOptionKey; 2472 2473 if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask 2474 && nil_or_none (mod_of_kind (ns_alternate_modifier, QCordinary))) 2475 modifiers |= optionKey; 2476 2477 if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask 2478 && nil_or_none (mod_of_kind (right_mod (ns_command_modifier, 2479 ns_right_command_modifier), 2480 QCordinary))) 2481 /* Carbon doesn't differentiate between left and right command 2482 keys. */ 2483 modifiers |= cmdKey; 2484 2485 if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask 2486 && nil_or_none (mod_of_kind (ns_command_modifier, QCordinary))) 2487 modifiers |= cmdKey; 2488 2489 result = UCKeyTranslate (layout, [event keyCode], kUCKeyActionDown, 2490 (modifiers >> 8) & 0xFF, LMGetKbdType (), 2491 kUCKeyTranslateNoDeadKeysBit, &dead_key_state, 2492 max_string_length, &actual_string_length, buf); 2493 2494 if (result != 0) 2495 { 2496 NSLog(@"Failed to translate character '%@' with modifiers %x", 2497 [event characters], modifiers); 2498 return 0; 2499 } 2500 2501 /* FIXME: What do we do if more than one code unit is returned? */ 2502 if (actual_string_length > 0) 2503 return buf[0]; 2504 2505 return 0; 2506} 2507#endif /* NS_IMPL_COCOA */ 2508 2509/* ========================================================================== 2510 2511 Block drawing operations 2512 2513 ========================================================================== */ 2514 2515 2516#ifdef NS_IMPL_GNUSTEP 2517static void 2518ns_redraw_scroll_bars (struct frame *f) 2519{ 2520 int i; 2521 id view; 2522 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews]; 2523 NSTRACE ("ns_redraw_scroll_bars"); 2524 for (i =[subviews count]-1; i >= 0; i--) 2525 { 2526 view = [subviews objectAtIndex: i]; 2527 if (![view isKindOfClass: [EmacsScroller class]]) continue; 2528 [view display]; 2529 } 2530} 2531#endif 2532 2533 2534void 2535ns_clear_frame (struct frame *f) 2536/* -------------------------------------------------------------------------- 2537 External (hook): Erase the entire frame 2538 -------------------------------------------------------------------------- */ 2539{ 2540 NSView *view = FRAME_NS_VIEW (f); 2541 NSRect r; 2542 2543 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame"); 2544 2545 /* comes on initial frame because we have 2546 after-make-frame-functions = select-frame */ 2547 if (!FRAME_DEFAULT_FACE (f)) 2548 return; 2549 2550 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); 2551 2552 r = [view bounds]; 2553 2554 block_input (); 2555 ns_focus (f, &r, 1); 2556 [[NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND 2557 (FACE_FROM_ID (f, DEFAULT_FACE_ID))] set]; 2558 NSRectFill (r); 2559 ns_unfocus (f); 2560 2561#ifdef NS_IMPL_GNUSTEP 2562 ns_redraw_scroll_bars (f); 2563#endif 2564 unblock_input (); 2565} 2566 2567 2568static void 2569ns_clear_frame_area (struct frame *f, int x, int y, int width, int height) 2570/* -------------------------------------------------------------------------- 2571 External (RIF): Clear section of frame 2572 -------------------------------------------------------------------------- */ 2573{ 2574 NSRect r = NSMakeRect (x, y, width, height); 2575 NSView *view = FRAME_NS_VIEW (f); 2576 struct face *face = FRAME_DEFAULT_FACE (f); 2577 2578 if (!view || !face) 2579 return; 2580 2581 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area"); 2582 2583 r = NSIntersectionRect (r, [view frame]); 2584 ns_focus (f, &r, 1); 2585 [[NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)] set]; 2586 2587 NSRectFill (r); 2588 2589 ns_unfocus (f); 2590 return; 2591} 2592 2593 2594static void 2595ns_scroll_run (struct window *w, struct run *run) 2596/* -------------------------------------------------------------------------- 2597 External (RIF): Insert or delete n lines at line vpos. 2598 -------------------------------------------------------------------------- */ 2599{ 2600 struct frame *f = XFRAME (w->frame); 2601 int x, y, width, height, from_y, to_y, bottom_y; 2602 2603 NSTRACE ("ns_scroll_run"); 2604 2605 /* begin copy from other terms */ 2606 /* Get frame-relative bounding box of the text display area of W, 2607 without mode lines. Include in this box the left and right 2608 fringe of W. */ 2609 window_box (w, ANY_AREA, &x, &y, &width, &height); 2610 2611 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y); 2612 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y); 2613 bottom_y = y + height; 2614 2615 if (to_y < from_y) 2616 { 2617 /* Scrolling up. Make sure we don't copy part of the mode 2618 line at the bottom. */ 2619 if (from_y + run->height > bottom_y) 2620 height = bottom_y - from_y; 2621 else 2622 height = run->height; 2623 } 2624 else 2625 { 2626 /* Scrolling down. Make sure we don't copy over the mode line. 2627 at the bottom. */ 2628 if (to_y + run->height > bottom_y) 2629 height = bottom_y - to_y; 2630 else 2631 height = run->height; 2632 } 2633 /* end copy from other terms */ 2634 2635 if (height == 0) 2636 return; 2637 2638 block_input (); 2639 2640 gui_clear_cursor (w); 2641 2642 { 2643 NSRect srcRect = NSMakeRect (x, from_y, width, height); 2644 NSPoint dest = NSMakePoint (x, to_y); 2645 EmacsView *view = FRAME_NS_VIEW (f); 2646 2647 [view copyRect:srcRect to:dest]; 2648#ifdef NS_IMPL_COCOA 2649 [view setNeedsDisplayInRect:srcRect]; 2650#endif 2651 } 2652 2653 unblock_input (); 2654} 2655 2656 2657static void 2658ns_clear_under_internal_border (struct frame *f) 2659{ 2660 NSTRACE ("ns_clear_under_internal_border"); 2661 2662 if (FRAME_LIVE_P (f) && FRAME_INTERNAL_BORDER_WIDTH (f) > 0) 2663 { 2664 int border = FRAME_INTERNAL_BORDER_WIDTH (f); 2665 int width = FRAME_PIXEL_WIDTH (f); 2666 int height = FRAME_PIXEL_HEIGHT (f); 2667 int margin = FRAME_TOP_MARGIN_HEIGHT (f); 2668 int face_id = 2669 (FRAME_PARENT_FRAME (f) 2670 ? (!NILP (Vface_remapping_alist) 2671 ? lookup_basic_face (NULL, f, CHILD_FRAME_BORDER_FACE_ID) 2672 : CHILD_FRAME_BORDER_FACE_ID) 2673 : (!NILP (Vface_remapping_alist) 2674 ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID) 2675 : INTERNAL_BORDER_FACE_ID)); 2676 struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); 2677 2678 if (!face) 2679 face = FRAME_DEFAULT_FACE (f); 2680 2681 /* Sometimes with new frames we reach this point and have no 2682 face. I'm not sure why we have a live frame but no face, so 2683 just give up. */ 2684 if (!face) 2685 return; 2686 2687 ns_focus (f, NULL, 1); 2688 [[NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)] set]; 2689 NSRectFill (NSMakeRect (0, margin, width, border)); 2690 NSRectFill (NSMakeRect (0, 0, border, height)); 2691 NSRectFill (NSMakeRect (0, margin, width, border)); 2692 NSRectFill (NSMakeRect (width - border, 0, border, height)); 2693 NSRectFill (NSMakeRect (0, height - border, width, border)); 2694 ns_unfocus (f); 2695 } 2696} 2697 2698 2699static void 2700ns_after_update_window_line (struct window *w, struct glyph_row *desired_row) 2701/* -------------------------------------------------------------------------- 2702 External (RIF): preparatory to fringe update after text was updated 2703 -------------------------------------------------------------------------- */ 2704{ 2705 struct frame *f; 2706 int width, height; 2707 2708 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line"); 2709 2710 /* begin copy from other terms */ 2711 eassert (w); 2712 2713 if (!desired_row->mode_line_p && !w->pseudo_window_p) 2714 desired_row->redraw_fringe_bitmaps_p = 1; 2715 2716 /* When a window has disappeared, make sure that no rest of 2717 full-width rows stays visible in the internal border. */ 2718 if (windows_or_buffers_changed 2719 && desired_row->full_width_p 2720 && (f = XFRAME (w->frame), 2721 width = FRAME_INTERNAL_BORDER_WIDTH (f), 2722 width != 0) 2723 && (height = desired_row->visible_height, 2724 height > 0)) 2725 { 2726 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y)); 2727 int face_id = 2728 !NILP (Vface_remapping_alist) 2729 ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID) 2730 : INTERNAL_BORDER_FACE_ID; 2731 struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); 2732 2733 block_input (); 2734 if (face) 2735 { 2736 NSRect r = NSMakeRect (0, y, FRAME_PIXEL_WIDTH (f), height); 2737 ns_focus (f, &r, 1); 2738 2739 [[NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)] set]; 2740 NSRectFill (NSMakeRect (0, y, width, height)); 2741 NSRectFill (NSMakeRect (FRAME_PIXEL_WIDTH (f) - width, 2742 y, width, height)); 2743 2744 ns_unfocus (f); 2745 } 2746 else 2747 { 2748 ns_clear_frame_area (f, 0, y, width, height); 2749 ns_clear_frame_area (f, 2750 FRAME_PIXEL_WIDTH (f) - width, 2751 y, width, height); 2752 } 2753 unblock_input (); 2754 } 2755} 2756 2757 2758static void 2759ns_shift_glyphs_for_insert (struct frame *f, 2760 int x, int y, int width, int height, 2761 int shift_by) 2762/* -------------------------------------------------------------------------- 2763 External (RIF): copy an area horizontally, don't worry about clearing src 2764 -------------------------------------------------------------------------- */ 2765{ 2766 NSRect srcRect = NSMakeRect (x, y, width, height); 2767 NSPoint dest = NSMakePoint (x+shift_by, y); 2768 2769 NSTRACE ("ns_shift_glyphs_for_insert"); 2770 2771 [FRAME_NS_VIEW (f) copyRect:srcRect to:dest]; 2772} 2773 2774 2775 2776/* ========================================================================== 2777 2778 Character encoding and metrics 2779 2780 ========================================================================== */ 2781 2782 2783static void 2784ns_compute_glyph_string_overhangs (struct glyph_string *s) 2785/* -------------------------------------------------------------------------- 2786 External (RIF); compute left/right overhang of whole string and set in s 2787 -------------------------------------------------------------------------- */ 2788{ 2789 if (s->cmp == NULL 2790 && (s->first_glyph->type == CHAR_GLYPH 2791 || s->first_glyph->type == COMPOSITE_GLYPH)) 2792 { 2793 struct font_metrics metrics; 2794 2795 if (s->first_glyph->type == CHAR_GLYPH) 2796 { 2797 struct font *font = s->font; 2798 font->driver->text_extents (font, s->char2b, s->nchars, &metrics); 2799 } 2800 else 2801 { 2802 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); 2803 2804 composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); 2805 } 2806 s->right_overhang = (metrics.rbearing > metrics.width 2807 ? metrics.rbearing - metrics.width : 0); 2808 s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; 2809 } 2810 else if (s->cmp) 2811 { 2812 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; 2813 s->left_overhang = - s->cmp->lbearing; 2814 } 2815} 2816 2817 2818 2819/* ========================================================================== 2820 2821 Fringe and cursor drawing 2822 2823 ========================================================================== */ 2824 2825static NSMutableDictionary *fringe_bmp; 2826 2827static void 2828ns_define_fringe_bitmap (int which, unsigned short *bits, int h, int w) 2829{ 2830 NSBezierPath *p = [NSBezierPath bezierPath]; 2831 2832 if (!fringe_bmp) 2833 fringe_bmp = [[NSMutableDictionary alloc] initWithCapacity:25]; 2834 2835 [p moveToPoint:NSMakePoint (0, 0)]; 2836 2837 for (int y = 0 ; y < h ; y++) 2838 for (int x = 0 ; x < w ; x++) 2839 { 2840 /* XBM rows are always round numbers of bytes, with any unused 2841 bits ignored. */ 2842 int byte = y * (w/8 + (w%8 ? 1 : 0)) + x/8; 2843 bool bit = bits[byte] & (0x80 >> x%8); 2844 if (bit) 2845 [p appendBezierPathWithRect:NSMakeRect (x, y, 1, 1)]; 2846 } 2847 2848 [fringe_bmp setObject:p forKey:[NSNumber numberWithInt:which]]; 2849} 2850 2851 2852static void 2853ns_destroy_fringe_bitmap (int which) 2854{ 2855 [fringe_bmp removeObjectForKey:[NSNumber numberWithInt:which]]; 2856} 2857 2858 2859static void 2860ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row, 2861 struct draw_fringe_bitmap_params *p) 2862/* -------------------------------------------------------------------------- 2863 External (RIF); fringe-related 2864 -------------------------------------------------------------------------- */ 2865{ 2866 /* Fringe bitmaps comes in two variants, normal and periodic. A 2867 periodic bitmap is used to create a continuous pattern. Since a 2868 bitmap is rendered one text line at a time, the start offset (dh) 2869 of the bitmap varies. Concretely, this is used for the empty 2870 line indicator. 2871 2872 For a bitmap, "h + dh" is the full height and is always 2873 invariant. For a normal bitmap "dh" is zero. 2874 2875 For example, when the period is three and the full height is 72 2876 the following combinations exists: 2877 2878 h=72 dh=0 2879 h=71 dh=1 2880 h=70 dh=2 */ 2881 2882 struct frame *f = XFRAME (WINDOW_FRAME (w)); 2883 struct face *face = p->face; 2884 NSRect clearRect = NSZeroRect; 2885 NSRect rowRect = ns_row_rect (w, row, ANY_AREA); 2886 2887 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap"); 2888 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d", 2889 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh); 2890 2891 /* Work out the rectangle we will need to clear. */ 2892 clearRect = NSMakeRect (p->x, p->y, p->wd, p->h); 2893 2894 if (p->bx >= 0 && !p->overlay_p) 2895 clearRect = NSUnionRect (clearRect, NSMakeRect (p->bx, p->by, p->nx, p->ny)); 2896 2897 /* Handle partially visible rows. */ 2898 clearRect = NSIntersectionRect (clearRect, rowRect); 2899 2900 /* The visible portion of imageRect will always be contained within 2901 clearRect. */ 2902 ns_focus (f, &clearRect, 1); 2903 if (! NSIsEmptyRect (clearRect)) 2904 { 2905 NSTRACE_RECT ("clearRect", clearRect); 2906 2907 [[NSColor colorWithUnsignedLong:face->background] set]; 2908 NSRectFill (clearRect); 2909 } 2910 2911 NSBezierPath *bmp = [fringe_bmp objectForKey:[NSNumber numberWithInt:p->which]]; 2912 if (bmp) 2913 { 2914 NSAffineTransform *transform = [NSAffineTransform transform]; 2915 NSColor *bm_color; 2916 2917 /* Because the image is defined at (0, 0) we need to take a copy 2918 and then transform that copy to the new origin. */ 2919 bmp = [bmp copy]; 2920 [transform translateXBy:p->x yBy:p->y - p->dh]; 2921 [bmp transformUsingAffineTransform:transform]; 2922 2923 if (!p->cursor_p) 2924 bm_color = [NSColor colorWithUnsignedLong:face->foreground]; 2925 else if (p->overlay_p) 2926 bm_color = [NSColor colorWithUnsignedLong:face->background]; 2927 else 2928 bm_color = f->output_data.ns->cursor_color; 2929 2930 [bm_color set]; 2931 [bmp fill]; 2932 2933 [bmp release]; 2934 } 2935 ns_unfocus (f); 2936} 2937 2938 2939static void 2940ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, 2941 int x, int y, enum text_cursor_kinds cursor_type, 2942 int cursor_width, bool on_p, bool active_p) 2943/* -------------------------------------------------------------------------- 2944 External call (RIF): draw cursor. 2945 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors. 2946 -------------------------------------------------------------------------- */ 2947{ 2948 NSRect r, s; 2949 int fx, fy, h, cursor_height; 2950 struct frame *f = WINDOW_XFRAME (w); 2951 struct glyph *phys_cursor_glyph; 2952 struct glyph *cursor_glyph; 2953 2954 /* If cursor is out of bounds, don't draw garbage. This can happen 2955 in mini-buffer windows when switching between echo area glyphs 2956 and mini-buffer. */ 2957 2958 NSTRACE ("ns_draw_window_cursor (on = %d, cursor_type = %d)", 2959 on_p, cursor_type); 2960 2961 if (!on_p) 2962 return; 2963 2964 w->phys_cursor_type = cursor_type; 2965 w->phys_cursor_on_p = on_p; 2966 2967 if (cursor_type == NO_CURSOR) 2968 { 2969 w->phys_cursor_width = 0; 2970 return; 2971 } 2972 2973 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL) 2974 { 2975 NSTRACE_MSG ("No phys cursor glyph was found!"); 2976 2977 if (glyph_row->exact_window_width_line_p 2978 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]) 2979 { 2980 glyph_row->cursor_in_fringe_p = 1; 2981 draw_fringe_bitmap (w, glyph_row, 0); 2982 } 2983 return; 2984 } 2985 2986 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h); 2987 2988 /* The above get_phys_cursor_geometry call set w->phys_cursor_width 2989 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */ 2990 if (cursor_type == BAR_CURSOR) 2991 { 2992 if (cursor_width < 1) 2993 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1); 2994 2995 /* The bar cursor should never be wider than the glyph. */ 2996 if (cursor_width < w->phys_cursor_width) 2997 w->phys_cursor_width = cursor_width; 2998 } 2999 /* If we have an HBAR, "cursor_width" MAY specify height. */ 3000 else if (cursor_type == HBAR_CURSOR) 3001 { 3002 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width; 3003 if (cursor_height > glyph_row->height) 3004 cursor_height = glyph_row->height; 3005 if (h > cursor_height) // Cursor smaller than line height, move down 3006 fy += h - cursor_height; 3007 h = cursor_height; 3008 } 3009 3010 r.origin.x = fx, r.origin.y = fy; 3011 r.size.height = h; 3012 r.size.width = w->phys_cursor_width; 3013 3014 /* Prevent the cursor from being drawn outside the text area. */ 3015 r = NSIntersectionRect (r, ns_row_rect (w, glyph_row, TEXT_AREA)); 3016 3017 ns_focus (f, NULL, 0); 3018 3019 NSGraphicsContext *ctx = [NSGraphicsContext currentContext]; 3020 [ctx saveGraphicsState]; 3021#ifdef NS_IMPL_GNUSTEP 3022 GSRectClipList (ctx, &r, 1); 3023#else 3024 NSRectClip (r); 3025#endif 3026 3027 [FRAME_CURSOR_COLOR (f) set]; 3028 3029 switch (cursor_type) 3030 { 3031 case DEFAULT_CURSOR: 3032 case NO_CURSOR: 3033 break; 3034 case FILLED_BOX_CURSOR: 3035 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); 3036 break; 3037 case HOLLOW_BOX_CURSOR: 3038 draw_phys_cursor_glyph (w, glyph_row, DRAW_NORMAL_TEXT); 3039 [NSBezierPath strokeRect: r]; 3040 break; 3041 case HBAR_CURSOR: 3042 NSRectFill (r); 3043 break; 3044 case BAR_CURSOR: 3045 s = r; 3046 /* If the character under cursor is R2L, draw the bar cursor 3047 on the right of its glyph, rather than on the left. */ 3048 cursor_glyph = get_phys_cursor_glyph (w); 3049 if ((cursor_glyph->resolved_level & 1) != 0) 3050 s.origin.x += cursor_glyph->pixel_width - s.size.width; 3051 3052 NSRectFill (s); 3053 break; 3054 } 3055 3056 [ctx restoreGraphicsState]; 3057 ns_unfocus (f); 3058} 3059 3060 3061static void 3062ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1) 3063/* -------------------------------------------------------------------------- 3064 External (RIF): Draw a vertical line. 3065 -------------------------------------------------------------------------- */ 3066{ 3067 struct frame *f = XFRAME (WINDOW_FRAME (w)); 3068 struct face *face; 3069 NSRect r = NSMakeRect (x, y0, 1, y1-y0); 3070 3071 NSTRACE ("ns_draw_vertical_window_border"); 3072 3073 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID); 3074 3075 ns_focus (f, &r, 1); 3076 if (face) 3077 [[NSColor colorWithUnsignedLong:face->foreground] set]; 3078 3079 NSRectFill(r); 3080 ns_unfocus (f); 3081} 3082 3083 3084static void 3085ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1) 3086/* -------------------------------------------------------------------------- 3087 External (RIF): Draw a window divider. 3088 -------------------------------------------------------------------------- */ 3089{ 3090 struct frame *f = XFRAME (WINDOW_FRAME (w)); 3091 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID); 3092 struct face *face_first 3093 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); 3094 struct face *face_last 3095 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); 3096 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f); 3097 unsigned long color_first = (face_first 3098 ? face_first->foreground 3099 : FRAME_FOREGROUND_PIXEL (f)); 3100 unsigned long color_last = (face_last 3101 ? face_last->foreground 3102 : FRAME_FOREGROUND_PIXEL (f)); 3103 NSRect divider = NSMakeRect (x0, y0, x1-x0, y1-y0); 3104 3105 NSTRACE ("ns_draw_window_divider"); 3106 3107 ns_focus (f, ÷r, 1); 3108 3109 if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3)) 3110 /* A vertical divider, at least three pixels wide: Draw first and 3111 last pixels differently. */ 3112 { 3113 [[NSColor colorWithUnsignedLong:color_first] set]; 3114 NSRectFill(NSMakeRect (x0, y0, 1, y1 - y0)); 3115 [[NSColor colorWithUnsignedLong:color] set]; 3116 NSRectFill(NSMakeRect (x0 + 1, y0, x1 - x0 - 2, y1 - y0)); 3117 [[NSColor colorWithUnsignedLong:color_last] set]; 3118 NSRectFill(NSMakeRect (x1 - 1, y0, 1, y1 - y0)); 3119 } 3120 else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3)) 3121 /* A horizontal divider, at least three pixels high: Draw first and 3122 last pixels differently. */ 3123 { 3124 [[NSColor colorWithUnsignedLong:color_first] set]; 3125 NSRectFill(NSMakeRect (x0, y0, x1 - x0, 1)); 3126 [[NSColor colorWithUnsignedLong:color] set]; 3127 NSRectFill(NSMakeRect (x0, y0 + 1, x1 - x0, y1 - y0 - 2)); 3128 [[NSColor colorWithUnsignedLong:color_last] set]; 3129 NSRectFill(NSMakeRect (x0, y1 - 1, x1 - x0, 1)); 3130 } 3131 else 3132 { 3133 /* In any other case do not draw the first and last pixels 3134 differently. */ 3135 [[NSColor colorWithUnsignedLong:color] set]; 3136 NSRectFill(divider); 3137 } 3138 3139 ns_unfocus (f); 3140} 3141 3142 3143static void 3144ns_show_hourglass (struct frame *f) 3145{ 3146 /* TODO: add NSProgressIndicator to all frames. */ 3147} 3148 3149static void 3150ns_hide_hourglass (struct frame *f) 3151{ 3152 /* TODO: remove NSProgressIndicator from all frames. */ 3153} 3154 3155/* ========================================================================== 3156 3157 Glyph drawing operations 3158 3159 ========================================================================== */ 3160 3161static int 3162ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr) 3163/* -------------------------------------------------------------------------- 3164 Wrapper utility to account for internal border width on full-width lines, 3165 and allow top full-width rows to hit the frame top. nr should be pointer 3166 to two successive NSRects. Number of rects actually used is returned. 3167 -------------------------------------------------------------------------- */ 3168{ 3169 int n = get_glyph_string_clip_rects (s, nr, 2); 3170 return n; 3171} 3172 3173/* -------------------------------------------------------------------- 3174 Draw a wavy line under glyph string s. The wave fills wave_height 3175 pixels from y. 3176 3177 x wave_length = 2 3178 -- 3179 y * * * * * 3180 |* * * * * * * * * 3181 wave_height = 3 | * * * * 3182 --------------------------------------------------------------------- */ 3183 3184static void 3185ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x) 3186{ 3187 int wave_height = 3, wave_length = 2; 3188 int y, dx, dy, odd, xmax; 3189 NSPoint a, b; 3190 NSRect waveClip; 3191 3192 dx = wave_length; 3193 dy = wave_height - 1; 3194 y = s->ybase - wave_height + 3; 3195 xmax = x + width; 3196 3197 /* Find and set clipping rectangle */ 3198 waveClip = NSMakeRect (x, y, width, wave_height); 3199 [[NSGraphicsContext currentContext] saveGraphicsState]; 3200 NSRectClip (waveClip); 3201 3202 /* Draw the waves */ 3203 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5; 3204 b.x = a.x + dx; 3205 odd = (int)(a.x/dx) % 2; 3206 a.y = b.y = y + 0.5; 3207 3208 if (odd) 3209 a.y += dy; 3210 else 3211 b.y += dy; 3212 3213 while (a.x <= xmax) 3214 { 3215 [NSBezierPath strokeLineFromPoint:a toPoint:b]; 3216 a.x = b.x, a.y = b.y; 3217 b.x += dx, b.y = y + 0.5 + odd*dy; 3218 odd = !odd; 3219 } 3220 3221 /* Restore previous clipping rectangle(s) */ 3222 [[NSGraphicsContext currentContext] restoreGraphicsState]; 3223} 3224 3225 3226 3227static void 3228ns_draw_text_decoration (struct glyph_string *s, struct face *face, 3229 NSColor *defaultCol, CGFloat width, CGFloat x) 3230/* -------------------------------------------------------------------------- 3231 Draw underline, overline, and strike-through on glyph string s. 3232 -------------------------------------------------------------------------- */ 3233{ 3234 if (s->for_overlaps) 3235 return; 3236 3237 if (s->hl == DRAW_CURSOR) 3238 [FRAME_BACKGROUND_COLOR (s->f) set]; 3239 else 3240 [defaultCol set]; 3241 3242 /* Do underline. */ 3243 if (face->underline) 3244 { 3245 if (s->face->underline == FACE_UNDER_WAVE) 3246 { 3247 if (!face->underline_defaulted_p) 3248 [[NSColor colorWithUnsignedLong:face->underline_color] set]; 3249 3250 ns_draw_underwave (s, width, x); 3251 } 3252 else if (s->face->underline == FACE_UNDER_LINE) 3253 { 3254 3255 NSRect r; 3256 unsigned long thickness, position; 3257 3258 /* If the prev was underlined, match its appearance. */ 3259 if (s->prev 3260 && s->prev->face->underline == FACE_UNDER_LINE 3261 && s->prev->underline_thickness > 0) 3262 { 3263 thickness = s->prev->underline_thickness; 3264 position = s->prev->underline_position; 3265 } 3266 else 3267 { 3268 struct font *font = font_for_underline_metrics (s); 3269 unsigned long descent = s->y + s->height - s->ybase; 3270 unsigned long minimum_offset; 3271 BOOL underline_at_descent_line, use_underline_position_properties; 3272 Lisp_Object val = (WINDOW_BUFFER_LOCAL_VALUE 3273 (Qunderline_minimum_offset, s->w)); 3274 3275 if (FIXNUMP (val)) 3276 minimum_offset = XFIXNAT (val); 3277 else 3278 minimum_offset = 1; 3279 3280 val = (WINDOW_BUFFER_LOCAL_VALUE 3281 (Qx_underline_at_descent_line, s->w)); 3282 underline_at_descent_line = !(NILP (val) || EQ (val, Qunbound)); 3283 3284 val = (WINDOW_BUFFER_LOCAL_VALUE 3285 (Qx_use_underline_position_properties, s->w)); 3286 use_underline_position_properties 3287 = !(NILP (val) || EQ (val, Qunbound)); 3288 3289 /* Use underline thickness of font, defaulting to 1. */ 3290 thickness = (font && font->underline_thickness > 0) 3291 ? font->underline_thickness : 1; 3292 3293 /* Determine the offset of underlining from the baseline. */ 3294 if (underline_at_descent_line) 3295 position = descent - thickness; 3296 else if (use_underline_position_properties 3297 && font && font->underline_position >= 0) 3298 position = font->underline_position; 3299 else if (font) 3300 position = lround (font->descent / 2); 3301 else 3302 position = minimum_offset; 3303 3304 position = max (position, minimum_offset); 3305 3306 /* Ensure underlining is not cropped. */ 3307 if (descent <= position) 3308 { 3309 position = descent - 1; 3310 thickness = 1; 3311 } 3312 else if (descent < position + thickness) 3313 thickness = 1; 3314 } 3315 3316 s->underline_thickness = thickness; 3317 s->underline_position = position; 3318 3319 r = NSMakeRect (x, s->ybase + position, width, thickness); 3320 3321 if (!face->underline_defaulted_p) 3322 [[NSColor colorWithUnsignedLong:face->underline_color] set]; 3323 3324 NSRectFill (r); 3325 } 3326 } 3327 /* Do overline. We follow other terms in using a thickness of 1 3328 and ignoring overline_margin. */ 3329 if (face->overline_p) 3330 { 3331 NSRect r; 3332 r = NSMakeRect (x, s->y, width, 1); 3333 3334 if (!face->overline_color_defaulted_p) 3335 [[NSColor colorWithUnsignedLong:face->overline_color] set]; 3336 3337 NSRectFill (r); 3338 } 3339 3340 /* Do strike-through. We follow other terms for thickness and 3341 vertical position. */ 3342 if (face->strike_through_p) 3343 { 3344 NSRect r; 3345 /* Y-coordinate and height of the glyph string's first glyph. 3346 We cannot use s->y and s->height because those could be 3347 larger if there are taller display elements (e.g., characters 3348 displayed with a larger font) in the same glyph row. */ 3349 int glyph_y = s->ybase - s->first_glyph->ascent; 3350 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent; 3351 /* Strike-through width and offset from the glyph string's 3352 top edge. */ 3353 unsigned long h = 1; 3354 unsigned long dy; 3355 3356 dy = lrint ((glyph_height - h) / 2); 3357 r = NSMakeRect (x, glyph_y + dy, width, 1); 3358 3359 if (!face->strike_through_color_defaulted_p) 3360 [[NSColor colorWithUnsignedLong:face->strike_through_color] set]; 3361 3362 NSRectFill (r); 3363 } 3364} 3365 3366static void 3367ns_draw_box (NSRect r, CGFloat hthickness, CGFloat vthickness, 3368 NSColor *col, char left_p, char right_p) 3369/* -------------------------------------------------------------------------- 3370 Draw an unfilled rect inside r, optionally leaving left and/or right open. 3371 Note we can't just use an NSDrawRect command, because of the possibility 3372 of some sides not being drawn, and because the rect will be filled. 3373 -------------------------------------------------------------------------- */ 3374{ 3375 NSRect s = r; 3376 [col set]; 3377 3378 /* top, bottom */ 3379 s.size.height = hthickness; 3380 NSRectFill (s); 3381 s.origin.y += r.size.height - hthickness; 3382 NSRectFill (s); 3383 3384 s.size.height = r.size.height; 3385 s.origin.y = r.origin.y; 3386 3387 /* left, right (optional) */ 3388 s.size.width = vthickness; 3389 if (left_p) 3390 NSRectFill (s); 3391 if (right_p) 3392 { 3393 s.origin.x += r.size.width - vthickness; 3394 NSRectFill (s); 3395 } 3396} 3397 3398 3399static void 3400ns_draw_relief (NSRect outer, int hthickness, int vthickness, char raised_p, 3401 char top_p, char bottom_p, char left_p, char right_p, 3402 struct glyph_string *s) 3403/* -------------------------------------------------------------------------- 3404 Draw a relief rect inside r, optionally leaving some sides open. 3405 Note we can't just use an NSDrawBezel command, because of the possibility 3406 of some sides not being drawn, and because the rect will be filled. 3407 -------------------------------------------------------------------------- */ 3408{ 3409 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil; 3410 NSColor *newBaseCol = nil; 3411 NSRect inner; 3412 3413 NSTRACE ("ns_draw_relief"); 3414 3415 /* set up colors */ 3416 3417 if (s->face->use_box_color_for_shadows_p) 3418 { 3419 newBaseCol = [NSColor colorWithUnsignedLong:s->face->box_color]; 3420 } 3421/* else if (s->first_glyph->type == IMAGE_GLYPH 3422 && s->img->pixmap 3423 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0)) 3424 { 3425 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0); 3426 } */ 3427 else 3428 { 3429 newBaseCol = [NSColor colorWithUnsignedLong:s->face->background]; 3430 } 3431 3432 if (newBaseCol == nil) 3433 newBaseCol = [NSColor grayColor]; 3434 3435 if (newBaseCol != baseCol) /* TODO: better check */ 3436 { 3437 [baseCol release]; 3438 baseCol = [newBaseCol retain]; 3439 [lightCol release]; 3440 lightCol = [[baseCol highlightWithLevel: 0.2] retain]; 3441 [darkCol release]; 3442 darkCol = [[baseCol shadowWithLevel: 0.3] retain]; 3443 } 3444 3445 /* Calculate the inner rectangle. */ 3446 inner = NSMakeRect (NSMinX (outer) + (left_p ? hthickness : 0), 3447 NSMinY (outer) + (top_p ? vthickness : 0), 3448 NSWidth (outer) - (left_p ? hthickness : 0) 3449 - (right_p ? hthickness : 0), 3450 NSHeight (outer) - (top_p ? vthickness : 0) 3451 - (bottom_p ? vthickness : 0)); 3452 3453 [(raised_p ? lightCol : darkCol) set]; 3454 3455 if (top_p || left_p) 3456 { 3457 NSBezierPath *p = [NSBezierPath bezierPath]; 3458 [p moveToPoint:NSMakePoint (NSMinX (outer), NSMinY (outer))]; 3459 if (top_p) 3460 { 3461 [p lineToPoint:NSMakePoint (NSMaxX (outer), NSMinY (outer))]; 3462 [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMinY (inner))]; 3463 } 3464 [p lineToPoint:NSMakePoint (NSMinX (inner), NSMinY (inner))]; 3465 if (left_p) 3466 { 3467 [p lineToPoint:NSMakePoint (NSMinX (inner), NSMaxY (inner))]; 3468 [p lineToPoint:NSMakePoint (NSMinX (outer), NSMaxY (outer))]; 3469 } 3470 [p closePath]; 3471 [p fill]; 3472 } 3473 3474 [(raised_p ? darkCol : lightCol) set]; 3475 3476 if (bottom_p || right_p) 3477 { 3478 NSBezierPath *p = [NSBezierPath bezierPath]; 3479 [p moveToPoint:NSMakePoint (NSMaxX (outer), NSMaxY (outer))]; 3480 if (right_p) 3481 { 3482 [p lineToPoint:NSMakePoint (NSMaxX (outer), NSMinY (outer))]; 3483 [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMinY (inner))]; 3484 } 3485 [p lineToPoint:NSMakePoint (NSMaxX (inner), NSMaxY (inner))]; 3486 if (bottom_p) 3487 { 3488 [p lineToPoint:NSMakePoint (NSMinX (inner), NSMaxY (inner))]; 3489 [p lineToPoint:NSMakePoint (NSMinX (outer), NSMaxY (outer))]; 3490 } 3491 [p closePath]; 3492 [p fill]; 3493 } 3494} 3495 3496 3497static void 3498ns_dumpglyphs_box_or_relief (struct glyph_string *s) 3499/* -------------------------------------------------------------------------- 3500 Function modeled after x_draw_glyph_string_box (). 3501 Sets up parameters for drawing. 3502 -------------------------------------------------------------------------- */ 3503{ 3504 int right_x, last_x; 3505 char left_p, right_p; 3506 struct glyph *last_glyph; 3507 NSRect r; 3508 int hthickness, vthickness; 3509 struct face *face = s->face; 3510 3511 vthickness = face->box_vertical_line_width; 3512 hthickness = face->box_horizontal_line_width; 3513 3514 NSTRACE ("ns_dumpglyphs_box_or_relief"); 3515 3516 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p) 3517 ? WINDOW_RIGHT_EDGE_X (s->w) 3518 : window_box_right (s->w, s->area)); 3519 if (s->cmp || s->img) 3520 last_glyph = s->first_glyph; 3521 else if (s->first_glyph->type == COMPOSITE_GLYPH 3522 && s->first_glyph->u.cmp.automatic) 3523 { 3524 struct glyph *end = s->row->glyphs[s->area] + s->row->used[s->area]; 3525 struct glyph *g = s->first_glyph; 3526 for (last_glyph = g++; 3527 g < end && g->u.cmp.automatic && g->u.cmp.id == s->cmp_id 3528 && g->slice.cmp.to < s->cmp_to; 3529 last_glyph = g++) 3530 ; 3531 } 3532 else 3533 last_glyph = s->first_glyph + s->nchars - 1; 3534 3535 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p 3536 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1)); 3537 3538 left_p = (s->first_glyph->left_box_line_p 3539 || (s->hl == DRAW_MOUSE_FACE 3540 && (s->prev == NULL || s->prev->hl != s->hl))); 3541 right_p = (last_glyph->right_box_line_p 3542 || (s->hl == DRAW_MOUSE_FACE 3543 && (s->next == NULL || s->next->hl != s->hl))); 3544 3545 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height); 3546 3547 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */ 3548 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color) 3549 { 3550 ns_draw_box (r, abs (hthickness), abs (vthickness), 3551 [NSColor colorWithUnsignedLong:face->box_color], 3552 left_p, right_p); 3553 } 3554 else 3555 { 3556 ns_draw_relief (r, abs (hthickness), abs (vthickness), 3557 s->face->box == FACE_RAISED_BOX, 3558 1, 1, left_p, right_p, s); 3559 } 3560} 3561 3562 3563static void 3564ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p) 3565/* -------------------------------------------------------------------------- 3566 Modeled after x_draw_glyph_string_background, which draws BG in 3567 certain cases. Others are left to the text rendering routine. 3568 -------------------------------------------------------------------------- */ 3569{ 3570 NSTRACE ("ns_maybe_dumpglyphs_background"); 3571 3572 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/) 3573 { 3574 int box_line_width = max (s->face->box_horizontal_line_width, 0); 3575 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width 3576 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font 3577 dimensions, since the actual glyphs might be much 3578 smaller. So in that case we always clear the rectangle 3579 with background color. */ 3580 || FONT_TOO_HIGH (s->font) 3581 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) 3582 { 3583 struct face *face = s->face; 3584 if (!face->stipple) 3585 { 3586 if (s->hl != DRAW_CURSOR) 3587 [(NS_FACE_BACKGROUND (face) != 0 3588 ? [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)] 3589 : FRAME_BACKGROUND_COLOR (s->f)) set]; 3590 else 3591 [FRAME_CURSOR_COLOR (s->f) set]; 3592 } 3593 else 3594 { 3595 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f); 3596 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set]; 3597 } 3598 3599 NSRect r = NSMakeRect (s->x, s->y + box_line_width, 3600 s->background_width, 3601 s->height-2*box_line_width); 3602 NSRectFill (r); 3603 3604 s->background_filled_p = 1; 3605 } 3606 } 3607} 3608 3609 3610static void 3611ns_dumpglyphs_image (struct glyph_string *s, NSRect r) 3612/* -------------------------------------------------------------------------- 3613 Renders an image and associated borders. 3614 -------------------------------------------------------------------------- */ 3615{ 3616 EmacsImage *img = s->img->pixmap; 3617 int box_line_vwidth = max (s->face->box_horizontal_line_width, 0); 3618 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice); 3619 int bg_x, bg_y, bg_height; 3620 int th; 3621 char raised_p; 3622 NSRect br; 3623 struct face *face = s->face; 3624 NSColor *tdCol; 3625 3626 NSTRACE ("ns_dumpglyphs_image"); 3627 3628 if (s->face->box != FACE_NO_BOX 3629 && s->first_glyph->left_box_line_p && s->slice.x == 0) 3630 x += max (s->face->box_vertical_line_width, 0); 3631 3632 bg_x = x; 3633 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth; 3634 bg_height = s->height; 3635 /* other terms have this, but was causing problems w/tabbar mode */ 3636 /* - 2 * box_line_vwidth; */ 3637 3638 if (s->slice.x == 0) x += s->img->hmargin; 3639 if (s->slice.y == 0) y += s->img->vmargin; 3640 3641 /* Draw BG: if we need larger area than image itself cleared, do that, 3642 otherwise, since we composite the image under NS (instead of mucking 3643 with its background color), we must clear just the image area. */ 3644 3645 [[NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)] set]; 3646 3647 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin 3648 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width) 3649 { 3650 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height); 3651 s->background_filled_p = 1; 3652 } 3653 else 3654 { 3655 br = NSMakeRect (x, y, s->slice.width, s->slice.height); 3656 } 3657 3658 NSRectFill (br); 3659 3660 /* Draw the image... do we need to draw placeholder if img == nil? */ 3661 if (img != nil) 3662 { 3663 /* The idea here is that the clipped area is set in the normal 3664 view coordinate system, then we transform the coordinate 3665 system so that when we draw the image it is rotated, resized 3666 or whatever as required. This is kind of backwards, but 3667 there's no way to apply the transform to the image without 3668 creating a whole new bitmap. */ 3669 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height); 3670 NSRect ir = NSMakeRect (0, 0, [img size].width, [img size].height); 3671 3672 NSAffineTransform *setOrigin = [NSAffineTransform transform]; 3673 3674 [[NSGraphicsContext currentContext] saveGraphicsState]; 3675 3676 /* Because of the transforms it's difficult to work out what 3677 portion of the original, untransformed, image will be drawn, 3678 so the clipping area will ensure we draw only the correct 3679 bit. */ 3680 NSRectClip (dr); 3681 3682 [setOrigin translateXBy:x - s->slice.x yBy:y - s->slice.y]; 3683 [setOrigin concat]; 3684 3685 NSAffineTransform *doTransform = [NSAffineTransform transform]; 3686 3687 /* ImageMagick images don't have transforms. */ 3688 if (img->transform) 3689 [doTransform appendTransform:img->transform]; 3690 3691 [doTransform concat]; 3692 3693 /* Smoothing is the default, so if we don't want smoothing we 3694 have to turn it off. */ 3695 if (! img->smoothing) 3696 [[NSGraphicsContext currentContext] 3697 setImageInterpolation:NSImageInterpolationNone]; 3698 3699 [img drawInRect:ir fromRect:ir 3700 operation:NSCompositingOperationSourceOver 3701 fraction:1.0 respectFlipped:YES hints:nil]; 3702 3703 /* Apparently image interpolation is not reset with 3704 restoreGraphicsState, so we have to manually reset it. */ 3705 if (! img->smoothing) 3706 [[NSGraphicsContext currentContext] 3707 setImageInterpolation:NSImageInterpolationDefault]; 3708 3709 [[NSGraphicsContext currentContext] restoreGraphicsState]; 3710 } 3711 3712 if (s->hl == DRAW_CURSOR) 3713 { 3714 [FRAME_CURSOR_COLOR (s->f) set]; 3715 tdCol = [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)]; 3716 } 3717 else 3718 { 3719 tdCol = [NSColor colorWithUnsignedLong:NS_FACE_FOREGROUND (face)]; 3720 } 3721 3722 /* Draw underline, overline, strike-through. */ 3723 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x); 3724 3725 /* Draw relief, if requested */ 3726 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN) 3727 { 3728 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED) 3729 { 3730 th = (tool_bar_button_relief < 0 3731 ? DEFAULT_TOOL_BAR_BUTTON_RELIEF 3732 : min (tool_bar_button_relief, 1000000)); 3733 raised_p = (s->hl == DRAW_IMAGE_RAISED); 3734 } 3735 else 3736 { 3737 th = abs (s->img->relief); 3738 raised_p = (s->img->relief > 0); 3739 } 3740 3741 r.origin.x = x - th; 3742 r.origin.y = y - th; 3743 r.size.width = s->slice.width + 2*th-1; 3744 r.size.height = s->slice.height + 2*th-1; 3745 ns_draw_relief (r, th, th, raised_p, 3746 s->slice.y == 0, 3747 s->slice.y + s->slice.height == s->img->height, 3748 s->slice.x == 0, 3749 s->slice.x + s->slice.width == s->img->width, s); 3750 } 3751 3752 /* If there is no mask, the background won't be seen, 3753 so draw a rectangle on the image for the cursor. 3754 Do this for all images, getting transparency right is not reliable. */ 3755 if (s->hl == DRAW_CURSOR) 3756 { 3757 int thickness = abs (s->img->relief); 3758 if (thickness == 0) thickness = 1; 3759 ns_draw_box (br, thickness, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1); 3760 } 3761} 3762 3763 3764static void 3765ns_dumpglyphs_stretch (struct glyph_string *s) 3766{ 3767 NSRect glyphRect; 3768 struct face *face = s->face; 3769 NSColor *fgCol, *bgCol; 3770 3771 if (!s->background_filled_p) 3772 { 3773 3774 face = s->face; 3775 3776 bgCol = [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND (face)]; 3777 fgCol = [NSColor colorWithUnsignedLong:NS_FACE_FOREGROUND (face)]; 3778 3779 if (s->hl == DRAW_CURSOR) 3780 { 3781 fgCol = bgCol; 3782 bgCol = FRAME_CURSOR_COLOR (s->f); 3783 } 3784 3785 glyphRect = NSMakeRect (s->x, s->y, s->background_width, s->height); 3786 3787 [bgCol set]; 3788 3789 NSRectFill (glyphRect); 3790 3791 /* Draw overlining, etc. on the stretch glyph (or the part of 3792 the stretch glyph after the cursor). If the glyph has a box, 3793 then decorations will be drawn after drawing the box in 3794 ns_draw_glyph_string, in order to prevent them from being 3795 overwritten by the box. */ 3796 if (s->face->box == FACE_NO_BOX) 3797 ns_draw_text_decoration (s, face, fgCol, NSWidth (glyphRect), 3798 NSMinX (glyphRect)); 3799 3800 s->background_filled_p = 1; 3801 } 3802} 3803 3804 3805static void 3806ns_draw_glyph_string_foreground (struct glyph_string *s) 3807{ 3808 int x; 3809 struct font *font = s->font; 3810 3811 /* If first glyph of S has a left box line, start drawing the text 3812 of S to the right of that box line. */ 3813 if (s->face && s->face->box != FACE_NO_BOX 3814 && s->first_glyph->left_box_line_p) 3815 x = s->x + max (s->face->box_vertical_line_width, 0); 3816 else 3817 x = s->x; 3818 3819 font->driver->draw 3820 (s, s->cmp_from, s->nchars, x, s->ybase, 3821 !s->for_overlaps && !s->background_filled_p); 3822} 3823 3824 3825static void 3826ns_draw_composite_glyph_string_foreground (struct glyph_string *s) 3827{ 3828 int i, j, x; 3829 struct font *font = s->font; 3830 3831 /* If first glyph of S has a left box line, start drawing the text 3832 of S to the right of that box line. */ 3833 if (s->face && s->face->box != FACE_NO_BOX 3834 && s->first_glyph->left_box_line_p) 3835 x = s->x + max (s->face->box_vertical_line_width, 0); 3836 else 3837 x = s->x; 3838 3839 /* S is a glyph string for a composition. S->cmp_from is the index 3840 of the first character drawn for glyphs of this composition. 3841 S->cmp_from == 0 means we are drawing the very first character of 3842 this composition. */ 3843 3844 /* Draw a rectangle for the composition if the font for the very 3845 first character of the composition could not be loaded. */ 3846 if (s->font_not_found_p) 3847 { 3848 if (s->cmp_from == 0) 3849 { 3850 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1); 3851 ns_draw_box (r, 1, 1, FRAME_CURSOR_COLOR (s->f), 1, 1); 3852 } 3853 } 3854 else if (! s->first_glyph->u.cmp.automatic) 3855 { 3856 int y = s->ybase; 3857 3858 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++) 3859 /* TAB in a composition means display glyphs with padding 3860 space on the left or right. */ 3861 if (COMPOSITION_GLYPH (s->cmp, j) != '\t') 3862 { 3863 int xx = x + s->cmp->offsets[j * 2]; 3864 int yy = y - s->cmp->offsets[j * 2 + 1]; 3865 3866 font->driver->draw (s, j, j + 1, xx, yy, false); 3867 if (s->face->overstrike) 3868 font->driver->draw (s, j, j + 1, xx + 1, yy, false); 3869 } 3870 } 3871 else 3872 { 3873 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); 3874 Lisp_Object glyph; 3875 int y = s->ybase; 3876 int width = 0; 3877 3878 for (i = j = s->cmp_from; i < s->cmp_to; i++) 3879 { 3880 glyph = LGSTRING_GLYPH (gstring, i); 3881 if (NILP (LGLYPH_ADJUSTMENT (glyph))) 3882 width += LGLYPH_WIDTH (glyph); 3883 else 3884 { 3885 int xoff, yoff, wadjust; 3886 3887 if (j < i) 3888 { 3889 font->driver->draw (s, j, i, x, y, false); 3890 if (s->face->overstrike) 3891 font->driver->draw (s, j, i, x + 1, y, false); 3892 x += width; 3893 } 3894 xoff = LGLYPH_XOFF (glyph); 3895 yoff = LGLYPH_YOFF (glyph); 3896 wadjust = LGLYPH_WADJUST (glyph); 3897 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false); 3898 if (s->face->overstrike) 3899 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff, 3900 false); 3901 x += wadjust; 3902 j = i + 1; 3903 width = 0; 3904 } 3905 } 3906 if (j < i) 3907 { 3908 font->driver->draw (s, j, i, x, y, false); 3909 if (s->face->overstrike) 3910 font->driver->draw (s, j, i, x + 1, y, false); 3911 } 3912 } 3913} 3914 3915static void 3916ns_draw_glyph_string (struct glyph_string *s) 3917/* -------------------------------------------------------------------------- 3918 External (RIF): Main draw-text call. 3919 -------------------------------------------------------------------------- */ 3920{ 3921 /* TODO (optimize): focus for box and contents draw */ 3922 NSRect r[2]; 3923 int n; 3924 char box_drawn_p = 0; 3925 struct font *font = s->face->font; 3926 if (! font) font = FRAME_FONT (s->f); 3927 3928 NSTRACE ("ns_draw_glyph_string (hl = %u)", s->hl); 3929 3930 if (s->next && s->right_overhang && !s->for_overlaps) 3931 { 3932 int width; 3933 struct glyph_string *next; 3934 3935 for (width = 0, next = s->next; 3936 next && width < s->right_overhang; 3937 width += next->width, next = next->next) 3938 if (next->first_glyph->type != IMAGE_GLYPH) 3939 { 3940 n = ns_get_glyph_string_clip_rect (s->next, r); 3941 ns_focus (s->f, r, n); 3942 if (next->first_glyph->type != STRETCH_GLYPH) 3943 { 3944 ns_maybe_dumpglyphs_background (s->next, 1); 3945 } 3946 else 3947 { 3948 ns_dumpglyphs_stretch (s->next); 3949 } 3950 ns_unfocus (s->f); 3951 next->num_clips = 0; 3952 } 3953 } 3954 3955 if (!s->for_overlaps && s->face->box != FACE_NO_BOX 3956 && (s->first_glyph->type == CHAR_GLYPH 3957 || s->first_glyph->type == COMPOSITE_GLYPH)) 3958 { 3959 n = ns_get_glyph_string_clip_rect (s, r); 3960 ns_focus (s->f, r, n); 3961 ns_maybe_dumpglyphs_background (s, 1); 3962 ns_dumpglyphs_box_or_relief (s); 3963 ns_unfocus (s->f); 3964 box_drawn_p = 1; 3965 } 3966 3967 n = ns_get_glyph_string_clip_rect (s, r); 3968 3969 if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ 3970 && !s->clip_tail 3971 && ((s->prev && s->prev->hl != s->hl && s->left_overhang) 3972 || (s->next && s->next->hl != s->hl && s->right_overhang))) 3973 r[0] = NSIntersectionRect (r[0], NSMakeRect (s->x, s->y, s->width, s->height)); 3974 3975 ns_focus (s->f, r, n); 3976 3977 switch (s->first_glyph->type) 3978 { 3979 3980 case IMAGE_GLYPH: 3981 ns_dumpglyphs_image (s, r[0]); 3982 break; 3983 3984 case XWIDGET_GLYPH: 3985 x_draw_xwidget_glyph_string (s); 3986 break; 3987 3988 case STRETCH_GLYPH: 3989 ns_dumpglyphs_stretch (s); 3990 break; 3991 3992 case CHAR_GLYPH: 3993 case COMPOSITE_GLYPH: 3994 { 3995 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH; 3996 if (s->for_overlaps || (isComposite 3997 && (s->cmp_from > 0 3998 && ! s->first_glyph->u.cmp.automatic))) 3999 s->background_filled_p = 1; 4000 else 4001 ns_maybe_dumpglyphs_background 4002 (s, s->first_glyph->type == COMPOSITE_GLYPH); 4003 4004 if (isComposite) 4005 ns_draw_composite_glyph_string_foreground (s); 4006 else 4007 ns_draw_glyph_string_foreground (s); 4008 4009 { 4010 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0 4011 ? [NSColor colorWithUnsignedLong:NS_FACE_FOREGROUND (s->face)] 4012 : FRAME_FOREGROUND_COLOR (s->f)); 4013 4014 /* Draw underline, overline, strike-through. */ 4015 ns_draw_text_decoration (s, s->face, col, s->width, s->x); 4016 } 4017 } 4018 4019 break; 4020 4021 case GLYPHLESS_GLYPH: 4022 if (s->for_overlaps || (s->cmp_from > 0 4023 && ! s->first_glyph->u.cmp.automatic)) 4024 s->background_filled_p = 1; 4025 else 4026 ns_maybe_dumpglyphs_background 4027 (s, s->first_glyph->type == COMPOSITE_GLYPH); 4028 /* ... */ 4029 /* Not yet implemented. */ 4030 /* ... */ 4031 break; 4032 4033 default: 4034 emacs_abort (); 4035 } 4036 4037 /* Draw box if not done already. */ 4038 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX) 4039 ns_dumpglyphs_box_or_relief (s); 4040 4041 if (s->face->box != FACE_NO_BOX 4042 && s->first_glyph->type == STRETCH_GLYPH) 4043 { 4044 NSColor *fg_color; 4045 4046 fg_color = [NSColor colorWithUnsignedLong:NS_FACE_FOREGROUND (s->face)]; 4047 ns_draw_text_decoration (s, s->face, fg_color, 4048 s->background_width, s->x); 4049 } 4050 4051 ns_unfocus (s->f); 4052 4053 /* Draw surrounding overhangs. */ 4054 if (s->prev) 4055 { 4056 ns_focus (s->f, NULL, 0); 4057 struct glyph_string *prev; 4058 4059 for (prev = s->prev; prev; prev = prev->prev) 4060 if (prev->hl != s->hl 4061 && prev->x + prev->width + prev->right_overhang > s->x) 4062 { 4063 /* As prev was drawn while clipped to its own area, we 4064 must draw the right_overhang part using s->hl now. */ 4065 enum draw_glyphs_face save = prev->hl; 4066 struct face *save_face = prev->face; 4067 4068 prev->face = s->face; 4069 NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); 4070 [[NSGraphicsContext currentContext] saveGraphicsState]; 4071 NSRectClip (r); 4072#ifdef NS_IMPL_GNUSTEP 4073 DPSgsave ([NSGraphicsContext currentContext]); 4074 DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, 4075 s->width, s->height); 4076#endif 4077 prev->num_clips = 1; 4078 prev->hl = s->hl; 4079 if (prev->first_glyph->type == CHAR_GLYPH) 4080 ns_draw_glyph_string_foreground (prev); 4081 else 4082 ns_draw_composite_glyph_string_foreground (prev); 4083#ifdef NS_IMPL_GNUSTEP 4084 DPSgrestore ([NSGraphicsContext currentContext]); 4085#endif 4086 [[NSGraphicsContext currentContext] restoreGraphicsState]; 4087 prev->hl = save; 4088 prev->face = save_face; 4089 prev->num_clips = 0; 4090 } 4091 ns_unfocus (s->f); 4092 } 4093 4094 if (s->next) 4095 { 4096 ns_focus (s->f, NULL, 0); 4097 struct glyph_string *next; 4098 4099 for (next = s->next; next; next = next->next) 4100 if (next->hl != s->hl 4101 && next->x - next->left_overhang < s->x + s->width) 4102 { 4103 /* As next will be drawn while clipped to its own area, 4104 we must draw the left_overhang part using s->hl now. */ 4105 enum draw_glyphs_face save = next->hl; 4106 struct face *save_face = next->face; 4107 4108 next->hl = s->hl; 4109 next->face = s->face; 4110 NSRect r = NSMakeRect (s->x, s->y, s->width, s->height); 4111 [[NSGraphicsContext currentContext] saveGraphicsState]; 4112 NSRectClip (r); 4113#ifdef NS_IMPL_GNUSTEP 4114 DPSgsave ([NSGraphicsContext currentContext]); 4115 DPSrectclip ([NSGraphicsContext currentContext], s->x, s->y, 4116 s->width, s->height); 4117#endif 4118 next->num_clips = 1; 4119 if (next->first_glyph->type == CHAR_GLYPH) 4120 ns_draw_glyph_string_foreground (next); 4121 else 4122 ns_draw_composite_glyph_string_foreground (next); 4123#ifdef NS_IMPL_GNUSTEP 4124 DPSgrestore ([NSGraphicsContext currentContext]); 4125#endif 4126 [[NSGraphicsContext currentContext] restoreGraphicsState]; 4127 next->hl = save; 4128 next->num_clips = 0; 4129 next->face = save_face; 4130 next->clip_head = next; 4131 next->background_filled_p = 0; 4132 } 4133 ns_unfocus (s->f); 4134 } 4135 s->num_clips = 0; 4136} 4137 4138 4139 4140/* ========================================================================== 4141 4142 Event loop 4143 4144 ========================================================================== */ 4145 4146 4147static void 4148ns_send_appdefined (int value) 4149/* -------------------------------------------------------------------------- 4150 Internal: post an appdefined event which EmacsApp-sendEvent will 4151 recognize and take as a command to halt the event loop. 4152 -------------------------------------------------------------------------- */ 4153{ 4154 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value); 4155 4156 // GNUstep needs postEvent to happen on the main thread. 4157 // Cocoa needs nextEventMatchingMask to happen on the main thread too. 4158 if (! [[NSThread currentThread] isMainThread]) 4159 { 4160 EmacsApp *app = (EmacsApp *)NSApp; 4161 app->nextappdefined = value; 4162 [app performSelectorOnMainThread:@selector (sendFromMainThread:) 4163 withObject:nil 4164 waitUntilDone:NO]; 4165 return; 4166 } 4167 4168 /* Only post this event if we haven't already posted one. This will end 4169 the [NXApp run] main loop after having processed all events queued at 4170 this moment. */ 4171 4172#ifdef NS_IMPL_COCOA 4173 if (! send_appdefined) 4174 { 4175 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves 4176 in certain situations (rapid incoming events). 4177 So check if we have one, if not add one. */ 4178 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined 4179 untilDate:[NSDate distantPast] 4180 inMode:NSDefaultRunLoopMode 4181 dequeue:NO]; 4182 if (! appev) send_appdefined = YES; 4183 } 4184#endif 4185 4186 if (send_appdefined) 4187 { 4188 NSEvent *nxev; 4189 4190 /* We only need one NX_APPDEFINED event to stop NXApp from running. */ 4191 send_appdefined = NO; 4192 4193 /* Don't need wakeup timer any more. */ 4194 if (timed_entry) 4195 { 4196 [timed_entry invalidate]; 4197 [timed_entry release]; 4198 timed_entry = nil; 4199 } 4200 4201 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined 4202 location: NSMakePoint (0, 0) 4203 modifierFlags: 0 4204 timestamp: 0 4205 windowNumber: [[NSApp mainWindow] windowNumber] 4206 context: [NSApp context] 4207 subtype: 0 4208 data1: value 4209 data2: 0]; 4210 4211 /* Post an application defined event on the event queue. When this is 4212 received the [NXApp run] will return, thus having processed all 4213 events which are currently queued. */ 4214 [NSApp postEvent: nxev atStart: NO]; 4215 } 4216} 4217 4218#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 4219static void 4220check_native_fs () 4221{ 4222 Lisp_Object frame, tail; 4223 4224 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen) 4225 return; 4226 4227 ns_last_use_native_fullscreen = ns_use_native_fullscreen; 4228 4229 FOR_EACH_FRAME (tail, frame) 4230 { 4231 struct frame *f = XFRAME (frame); 4232 if (FRAME_NS_P (f)) 4233 { 4234 EmacsView *view = FRAME_NS_VIEW (f); 4235 [view updateCollectionBehavior]; 4236 } 4237 } 4238} 4239#endif 4240 4241 4242static int 4243ns_read_socket (struct terminal *terminal, struct input_event *hold_quit) 4244/* -------------------------------------------------------------------------- 4245 External (hook): Post an event to ourself and keep reading events until 4246 we read it back again. In effect process all events which were waiting. 4247 From 21+ we have to manage the event buffer ourselves. 4248 -------------------------------------------------------------------------- */ 4249{ 4250 struct input_event ev; 4251 int nevents; 4252 4253 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket"); 4254 4255#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 4256 check_native_fs (); 4257#endif 4258 4259 if ([NSApp modalWindow] != nil) 4260 return -1; 4261 4262 if (hold_event_q.nr > 0) 4263 { 4264 int i; 4265 for (i = 0; i < hold_event_q.nr; ++i) 4266 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit); 4267 hold_event_q.nr = 0; 4268 return i; 4269 } 4270 4271 if ([NSThread isMainThread]) 4272 { 4273 block_input (); 4274 n_emacs_events_pending = 0; 4275 ns_init_events (&ev); 4276 q_event_ptr = hold_quit; 4277 4278 /* We manage autorelease pools by allocate/reallocate each time around 4279 the loop; strict nesting is occasionally violated but seems not to 4280 matter... earlier methods using full nesting caused major memory leaks. */ 4281 [outerpool release]; 4282 outerpool = [[NSAutoreleasePool alloc] init]; 4283 4284 /* If have pending open-file requests, attend to the next one of those. */ 4285 if (ns_pending_files && [ns_pending_files count] != 0 4286 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]]) 4287 { 4288 [ns_pending_files removeObjectAtIndex: 0]; 4289 } 4290 /* Deal with pending service requests. */ 4291 else if (ns_pending_service_names && [ns_pending_service_names count] != 0 4292 && [(EmacsApp *) 4293 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0] 4294 withArg: [ns_pending_service_args objectAtIndex: 0]]) 4295 { 4296 [ns_pending_service_names removeObjectAtIndex: 0]; 4297 [ns_pending_service_args removeObjectAtIndex: 0]; 4298 } 4299 else 4300 { 4301 /* Run and wait for events. We must always send one NX_APPDEFINED event 4302 to ourself, otherwise [NXApp run] will never exit. */ 4303 send_appdefined = YES; 4304 ns_send_appdefined (-1); 4305 4306 [NSApp run]; 4307 } 4308 4309 nevents = n_emacs_events_pending; 4310 n_emacs_events_pending = 0; 4311 ns_finish_events (); 4312 q_event_ptr = NULL; 4313 unblock_input (); 4314 } 4315 else 4316 return -1; 4317 4318 return nevents; 4319} 4320 4321 4322int 4323ns_select (int nfds, fd_set *readfds, fd_set *writefds, 4324 fd_set *exceptfds, struct timespec *timeout, 4325 sigset_t *sigmask) 4326/* -------------------------------------------------------------------------- 4327 Replacement for select, checking for events 4328 -------------------------------------------------------------------------- */ 4329{ 4330 int result; 4331 int t, k, nr = 0; 4332 struct input_event event; 4333 char c; 4334 4335 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select"); 4336 4337#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 4338 check_native_fs (); 4339#endif 4340 4341 if (hold_event_q.nr > 0) 4342 { 4343 /* We already have events pending. */ 4344 raise (SIGIO); 4345 errno = EINTR; 4346 return -1; 4347 } 4348 4349 eassert (nfds <= FD_SETSIZE); 4350 for (k = 0; k < nfds; k++) 4351 { 4352 if (readfds && FD_ISSET(k, readfds)) ++nr; 4353 if (writefds && FD_ISSET(k, writefds)) ++nr; 4354 } 4355 4356 if (NSApp == nil 4357 || ![NSThread isMainThread] 4358 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0)) 4359 return thread_select(pselect, nfds, readfds, writefds, 4360 exceptfds, timeout, sigmask); 4361 else 4362 { 4363 struct timespec t = {0, 0}; 4364 thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask); 4365 } 4366 4367 /* FIXME: This draining of outerpool causes a crash when a buffer 4368 running over tramp is displayed and the user tries to use the 4369 menus. I believe some other autorelease pool's lifetime 4370 straddles this call causing a violation of autorelease pool 4371 nesting. There's no good reason to keep these here since the 4372 pool will be drained some other time anyway, but removing them 4373 leaves the menus sometimes not opening until the user moves their 4374 mouse pointer, but that's better than a crash. 4375 4376 There must be something about running external processes like 4377 tramp that interferes with the modal menu code. 4378 4379 See bugs 24472, 37557, 37922. */ 4380 4381 // [outerpool release]; 4382 // outerpool = [[NSAutoreleasePool alloc] init]; 4383 4384 4385 send_appdefined = YES; 4386 if (nr > 0) 4387 { 4388 pthread_mutex_lock (&select_mutex); 4389 select_nfds = nfds; 4390 select_valid = 0; 4391 if (readfds) 4392 { 4393 select_readfds = *readfds; 4394 select_valid += SELECT_HAVE_READ; 4395 } 4396 if (writefds) 4397 { 4398 select_writefds = *writefds; 4399 select_valid += SELECT_HAVE_WRITE; 4400 } 4401 4402 if (timeout) 4403 { 4404 select_timeout = *timeout; 4405 select_valid += SELECT_HAVE_TMO; 4406 } 4407 4408 pthread_mutex_unlock (&select_mutex); 4409 4410 /* Inform fd_handler that select should be called. */ 4411 c = 'g'; 4412 emacs_write_sig (selfds[1], &c, 1); 4413 } 4414 else if (nr == 0 && timeout) 4415 { 4416 /* No file descriptor, just a timeout, no need to wake fd_handler. */ 4417 double time = timespectod (*timeout); 4418 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time 4419 target: NSApp 4420 selector: 4421 @selector (timeout_handler:) 4422 userInfo: 0 4423 repeats: NO] 4424 retain]; 4425 } 4426 else /* No timeout and no file descriptors, can this happen? */ 4427 { 4428 /* Send appdefined so we exit from the loop. */ 4429 ns_send_appdefined (-1); 4430 } 4431 4432 block_input (); 4433 ns_init_events (&event); 4434 4435 [NSApp run]; 4436 4437 ns_finish_events (); 4438 if (nr > 0 && readfds) 4439 { 4440 c = 's'; 4441 emacs_write_sig (selfds[1], &c, 1); 4442 } 4443 unblock_input (); 4444 4445 t = last_appdefined_event_data; 4446 4447 if (t != NO_APPDEFINED_DATA) 4448 { 4449 last_appdefined_event_data = NO_APPDEFINED_DATA; 4450 4451 if (t == -2) 4452 { 4453 /* The NX_APPDEFINED event we received was a timeout. */ 4454 result = 0; 4455 } 4456 else if (t == -1) 4457 { 4458 /* The NX_APPDEFINED event we received was the result of 4459 at least one real input event arriving. */ 4460 errno = EINTR; 4461 result = -1; 4462 } 4463 else 4464 { 4465 /* Received back from select () in fd_handler; copy the results. */ 4466 pthread_mutex_lock (&select_mutex); 4467 if (readfds) *readfds = select_readfds; 4468 if (writefds) *writefds = select_writefds; 4469 pthread_mutex_unlock (&select_mutex); 4470 result = t; 4471 } 4472 } 4473 else 4474 { 4475 errno = EINTR; 4476 result = -1; 4477 } 4478 4479 return result; 4480} 4481 4482#ifdef HAVE_PTHREAD 4483void 4484ns_run_loop_break () 4485/* Break out of the NS run loop in ns_select or ns_read_socket. */ 4486{ 4487 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break"); 4488 4489 /* If we don't have a GUI, don't send the event. */ 4490 if (NSApp != NULL) 4491 ns_send_appdefined(-1); 4492} 4493#endif 4494 4495 4496/* ========================================================================== 4497 4498 Scrollbar handling 4499 4500 ========================================================================== */ 4501 4502 4503static void 4504ns_set_vertical_scroll_bar (struct window *window, 4505 int portion, int whole, int position) 4506/* -------------------------------------------------------------------------- 4507 External (hook): Update or add scrollbar 4508 -------------------------------------------------------------------------- */ 4509{ 4510 Lisp_Object win; 4511 NSRect r, v; 4512 struct frame *f = XFRAME (WINDOW_FRAME (window)); 4513 EmacsView *view = FRAME_NS_VIEW (f); 4514 EmacsScroller *bar; 4515 int window_y, window_height; 4516 int top, left, height, width; 4517 BOOL update_p = YES; 4518 4519 /* Optimization; display engine sends WAY too many of these. */ 4520 if (!NILP (window->vertical_scroll_bar)) 4521 { 4522 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar); 4523 if ([bar checkSamePosition: position portion: portion whole: whole]) 4524 { 4525 if (view->scrollbarsNeedingUpdate == 0) 4526 { 4527 if (!windows_or_buffers_changed) 4528 return; 4529 } 4530 else 4531 view->scrollbarsNeedingUpdate--; 4532 update_p = NO; 4533 } 4534 } 4535 4536 NSTRACE ("ns_set_vertical_scroll_bar"); 4537 4538 /* Get dimensions. */ 4539 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height); 4540 top = window_y; 4541 height = window_height; 4542 width = NS_SCROLL_BAR_WIDTH (f); 4543 left = WINDOW_SCROLL_BAR_AREA_X (window); 4544 4545 r = NSMakeRect (left, top, width, height); 4546 /* The parent view is flipped, so we need to flip y value. */ 4547 v = [view frame]; 4548 r.origin.y = (v.size.height - r.size.height - r.origin.y); 4549 4550 XSETWINDOW (win, window); 4551 block_input (); 4552 4553 /* We want at least 5 lines to display a scrollbar. */ 4554 if (WINDOW_TOTAL_LINES (window) < 5) 4555 { 4556 if (!NILP (window->vertical_scroll_bar)) 4557 { 4558 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar); 4559 [bar removeFromSuperview]; 4560 wset_vertical_scroll_bar (window, Qnil); 4561 [bar release]; 4562 ns_clear_frame_area (f, left, top, width, height); 4563 } 4564 unblock_input (); 4565 return; 4566 } 4567 4568 if (NILP (window->vertical_scroll_bar)) 4569 { 4570 if (width > 0 && height > 0) 4571 ns_clear_frame_area (f, left, top, width, height); 4572 4573 bar = [[EmacsScroller alloc] initFrame: r window: win]; 4574 wset_vertical_scroll_bar (window, make_mint_ptr (bar)); 4575 update_p = YES; 4576 } 4577 else 4578 { 4579 NSRect oldRect; 4580 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar); 4581 oldRect = [bar frame]; 4582 r.size.width = oldRect.size.width; 4583 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r)) 4584 { 4585 if (! NSEqualRects (oldRect, r)) 4586 ns_clear_frame_area (f, left, top, width, height); 4587 [bar setFrame: r]; 4588 } 4589 } 4590 4591 if (update_p) 4592 [bar setPosition: position portion: portion whole: whole]; 4593 unblock_input (); 4594} 4595 4596 4597static void 4598ns_set_horizontal_scroll_bar (struct window *window, 4599 int portion, int whole, int position) 4600/* -------------------------------------------------------------------------- 4601 External (hook): Update or add scrollbar. 4602 -------------------------------------------------------------------------- */ 4603{ 4604 Lisp_Object win; 4605 NSRect r, v; 4606 struct frame *f = XFRAME (WINDOW_FRAME (window)); 4607 EmacsView *view = FRAME_NS_VIEW (f); 4608 EmacsScroller *bar; 4609 int top, height, left, width; 4610 int window_x, window_width; 4611 BOOL update_p = YES; 4612 4613 /* Optimization; display engine sends WAY too many of these. */ 4614 if (!NILP (window->horizontal_scroll_bar)) 4615 { 4616 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar); 4617 if ([bar checkSamePosition: position portion: portion whole: whole]) 4618 { 4619 if (view->scrollbarsNeedingUpdate == 0) 4620 { 4621 if (!windows_or_buffers_changed) 4622 return; 4623 } 4624 else 4625 view->scrollbarsNeedingUpdate--; 4626 update_p = NO; 4627 } 4628 } 4629 4630 NSTRACE ("ns_set_horizontal_scroll_bar"); 4631 4632 /* Get dimensions. */ 4633 window_box (window, ANY_AREA, &window_x, 0, &window_width, 0); 4634 left = window_x; 4635 width = window_width; 4636 height = NS_SCROLL_BAR_HEIGHT (f); 4637 top = WINDOW_SCROLL_BAR_AREA_Y (window); 4638 4639 r = NSMakeRect (left, top, width, height); 4640 /* The parent view is flipped, so we need to flip y value. */ 4641 v = [view frame]; 4642 r.origin.y = (v.size.height - r.size.height - r.origin.y); 4643 4644 XSETWINDOW (win, window); 4645 block_input (); 4646 4647 if (NILP (window->horizontal_scroll_bar)) 4648 { 4649 if (width > 0 && height > 0) 4650 ns_clear_frame_area (f, left, top, width, height); 4651 4652 bar = [[EmacsScroller alloc] initFrame: r window: win]; 4653 wset_horizontal_scroll_bar (window, make_mint_ptr (bar)); 4654 update_p = YES; 4655 } 4656 else 4657 { 4658 NSRect oldRect; 4659 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar); 4660 oldRect = [bar frame]; 4661 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r)) 4662 { 4663 ns_clear_frame_area (f, left, top, width, height); 4664 [bar setFrame: r]; 4665 update_p = YES; 4666 } 4667 } 4668 4669 /* If there are both horizontal and vertical scroll-bars they leave 4670 a square that belongs to neither. We need to clear it otherwise 4671 it fills with junk. */ 4672 if (!NILP (window->vertical_scroll_bar)) 4673 ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top, 4674 NS_SCROLL_BAR_HEIGHT (f), height); 4675 4676 if (update_p) 4677 [bar setPosition: position portion: portion whole: whole]; 4678 unblock_input (); 4679} 4680 4681 4682static void 4683ns_condemn_scroll_bars (struct frame *f) 4684/* -------------------------------------------------------------------------- 4685 External (hook): arrange for all frame's scrollbars to be removed 4686 at next call to judge_scroll_bars, except for those redeemed. 4687 -------------------------------------------------------------------------- */ 4688{ 4689 int i; 4690 id view; 4691 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews]; 4692 4693 NSTRACE ("ns_condemn_scroll_bars"); 4694 4695 for (i =[subviews count]-1; i >= 0; i--) 4696 { 4697 view = [subviews objectAtIndex: i]; 4698 if ([view isKindOfClass: [EmacsScroller class]]) 4699 [view condemn]; 4700 } 4701} 4702 4703 4704static void 4705ns_redeem_scroll_bar (struct window *window) 4706/* -------------------------------------------------------------------------- 4707 External (hook): arrange to spare this window's scrollbar 4708 at next call to judge_scroll_bars. 4709 -------------------------------------------------------------------------- */ 4710{ 4711 id bar; 4712 NSTRACE ("ns_redeem_scroll_bar"); 4713 if (!NILP (window->vertical_scroll_bar) 4714 && WINDOW_HAS_VERTICAL_SCROLL_BAR (window)) 4715 { 4716 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar); 4717 [bar reprieve]; 4718 } 4719 4720 if (!NILP (window->horizontal_scroll_bar) 4721 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window)) 4722 { 4723 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar); 4724 [bar reprieve]; 4725 } 4726} 4727 4728 4729static void 4730ns_judge_scroll_bars (struct frame *f) 4731/* -------------------------------------------------------------------------- 4732 External (hook): destroy all scrollbars on frame that weren't 4733 redeemed after call to condemn_scroll_bars. 4734 -------------------------------------------------------------------------- */ 4735{ 4736 int i; 4737 id view; 4738 EmacsView *eview = FRAME_NS_VIEW (f); 4739 NSArray *subviews = [[eview superview] subviews]; 4740 4741 NSTRACE ("ns_judge_scroll_bars"); 4742 for (i = [subviews count]-1; i >= 0; --i) 4743 { 4744 view = [subviews objectAtIndex: i]; 4745 if (![view isKindOfClass: [EmacsScroller class]]) continue; 4746 [view judge]; 4747 } 4748} 4749 4750/* ========================================================================== 4751 4752 Image Hooks 4753 4754 ========================================================================== */ 4755 4756static void 4757ns_free_pixmap (struct frame *_f, Emacs_Pixmap pixmap) 4758{ 4759 ns_release_object (pixmap); 4760} 4761 4762/* ========================================================================== 4763 4764 Initialization 4765 4766 ========================================================================== */ 4767 4768int 4769ns_display_pixel_height (struct ns_display_info *dpyinfo) 4770{ 4771 NSArray *screens = [NSScreen screens]; 4772 NSEnumerator *enumerator = [screens objectEnumerator]; 4773 NSScreen *screen; 4774 NSRect frame; 4775 4776 frame = NSZeroRect; 4777 while ((screen = [enumerator nextObject]) != nil) 4778 frame = NSUnionRect (frame, [screen frame]); 4779 4780 return NSHeight (frame); 4781} 4782 4783int 4784ns_display_pixel_width (struct ns_display_info *dpyinfo) 4785{ 4786 NSArray *screens = [NSScreen screens]; 4787 NSEnumerator *enumerator = [screens objectEnumerator]; 4788 NSScreen *screen; 4789 NSRect frame; 4790 4791 frame = NSZeroRect; 4792 while ((screen = [enumerator nextObject]) != nil) 4793 frame = NSUnionRect (frame, [screen frame]); 4794 4795 return NSWidth (frame); 4796} 4797 4798 4799static Lisp_Object ns_string_to_lispmod (const char *s) 4800/* -------------------------------------------------------------------------- 4801 Convert modifier name to lisp symbol. 4802 -------------------------------------------------------------------------- */ 4803{ 4804 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10)) 4805 return Qmeta; 4806 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10)) 4807 return Qsuper; 4808 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10)) 4809 return Qcontrol; 4810 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10)) 4811 return Qalt; 4812 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10)) 4813 return Qhyper; 4814 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10)) 4815 return Qnone; 4816 else 4817 return Qnil; 4818} 4819 4820 4821static void 4822ns_default (const char *parameter, Lisp_Object *result, 4823 Lisp_Object yesval, Lisp_Object noval, 4824 BOOL is_float, BOOL is_modstring) 4825/* -------------------------------------------------------------------------- 4826 Check a parameter value in user's preferences. 4827 -------------------------------------------------------------------------- */ 4828{ 4829 const char *value = ns_get_defaults_value (parameter); 4830 4831 if (value) 4832 { 4833 double f; 4834 char *pos; 4835 if (c_strcasecmp (value, "YES") == 0) 4836 *result = yesval; 4837 else if (c_strcasecmp (value, "NO") == 0) 4838 *result = noval; 4839 else if (is_float && (f = strtod (value, &pos), pos != value)) 4840 *result = make_float (f); 4841 else if (is_modstring && value) 4842 *result = ns_string_to_lispmod (value); 4843 else fprintf (stderr, 4844 "Bad value for default \"%s\": \"%s\"\n", parameter, value); 4845 } 4846} 4847 4848 4849static void 4850ns_initialize_display_info (struct ns_display_info *dpyinfo) 4851/* -------------------------------------------------------------------------- 4852 Initialize global info and storage for display. 4853 -------------------------------------------------------------------------- */ 4854{ 4855 NSScreen *screen = [NSScreen mainScreen]; 4856 NSWindowDepth depth = [screen depth]; 4857 4858 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */ 4859 dpyinfo->resy = 72.27; 4860 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString: 4861 NSColorSpaceFromDepth (depth)] 4862 && ![NSCalibratedWhiteColorSpace isEqualToString: 4863 NSColorSpaceFromDepth (depth)]; 4864 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth); 4865 dpyinfo->root_window = 42; /* A placeholder. */ 4866 dpyinfo->highlight_frame = dpyinfo->ns_focus_frame = NULL; 4867 dpyinfo->n_fonts = 0; 4868 dpyinfo->smallest_font_height = 1; 4869 dpyinfo->smallest_char_width = 1; 4870 4871 reset_mouse_highlight (&dpyinfo->mouse_highlight); 4872} 4873 4874/* This currently does nothing, since it's only really needed when 4875 changing the font-backend, but macOS currently only has one 4876 possible backend. This may change if we add HarfBuzz support. */ 4877static void 4878ns_default_font_parameter (struct frame *f, Lisp_Object parms) 4879{ 4880} 4881 4882#ifdef NS_IMPL_GNUSTEP 4883static void 4884ns_update_window_end (struct window *w, bool cursor_on_p, 4885 bool mouse_face_overwritten_p) 4886{ 4887 NSTRACE ("ns_update_window_end (cursor_on_p = %d)", cursor_on_p); 4888 4889 ns_redraw_scroll_bars (WINDOW_XFRAME (w)); 4890} 4891#endif 4892 4893/* This and next define (many of the) public functions in this file. */ 4894/* gui_* are generic versions in xdisp.c that we, and other terms, get away 4895 with using despite presence in the "system dependent" redisplay 4896 interface. In addition, many of the ns_ methods have code that is 4897 shared with all terms, indicating need for further refactoring. */ 4898extern frame_parm_handler ns_frame_parm_handlers[]; 4899static struct redisplay_interface ns_redisplay_interface = 4900{ 4901 ns_frame_parm_handlers, 4902 gui_produce_glyphs, 4903 gui_write_glyphs, 4904 gui_insert_glyphs, 4905 gui_clear_end_of_line, 4906 ns_scroll_run, 4907 ns_after_update_window_line, 4908 NULL, /* update_window_begin */ 4909#ifndef NS_IMPL_GNUSTEP 4910 NULL, /* update_window_end */ 4911#else 4912 ns_update_window_end, 4913#endif 4914 0, /* flush_display */ 4915 gui_clear_window_mouse_face, 4916 gui_get_glyph_overhangs, 4917 gui_fix_overlapping_area, 4918 ns_draw_fringe_bitmap, 4919 ns_define_fringe_bitmap, 4920 ns_destroy_fringe_bitmap, 4921 ns_compute_glyph_string_overhangs, 4922 ns_draw_glyph_string, 4923 ns_define_frame_cursor, 4924 ns_clear_frame_area, 4925 ns_clear_under_internal_border, /* clear_under_internal_border */ 4926 ns_draw_window_cursor, 4927 ns_draw_vertical_window_border, 4928 ns_draw_window_divider, 4929 ns_shift_glyphs_for_insert, 4930 ns_show_hourglass, 4931 ns_hide_hourglass, 4932 ns_default_font_parameter 4933}; 4934 4935 4936static void 4937ns_delete_display (struct ns_display_info *dpyinfo) 4938{ 4939 /* TODO... */ 4940} 4941 4942 4943/* This function is called when the last frame on a display is deleted. */ 4944static void 4945ns_delete_terminal (struct terminal *terminal) 4946{ 4947 struct ns_display_info *dpyinfo = terminal->display_info.ns; 4948 4949 NSTRACE ("ns_delete_terminal"); 4950 4951 /* Protect against recursive calls. delete_frame in 4952 delete_terminal calls us back when it deletes our last frame. */ 4953 if (!terminal->name) 4954 return; 4955 4956 block_input (); 4957 4958#ifdef NS_IMPL_COCOA 4959 /* Rather than try to clean up the NS environment we can just 4960 disable the app and leave it waiting for any new frames. */ 4961 [NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited]; 4962#endif 4963 4964 image_destroy_all_bitmaps (dpyinfo); 4965 ns_delete_display (dpyinfo); 4966 unblock_input (); 4967} 4968 4969static Lisp_Object ns_new_font (struct frame *f, Lisp_Object font_object, 4970 int fontset); 4971 4972static struct terminal * 4973ns_create_terminal (struct ns_display_info *dpyinfo) 4974/* -------------------------------------------------------------------------- 4975 Set up use of NS before we make the first connection. 4976 -------------------------------------------------------------------------- */ 4977{ 4978 struct terminal *terminal; 4979 4980 NSTRACE ("ns_create_terminal"); 4981 4982 terminal = create_terminal (output_ns, &ns_redisplay_interface); 4983 4984 terminal->display_info.ns = dpyinfo; 4985 dpyinfo->terminal = terminal; 4986 4987 terminal->clear_frame_hook = ns_clear_frame; 4988 terminal->ring_bell_hook = ns_ring_bell; 4989 terminal->update_begin_hook = ns_update_begin; 4990 terminal->update_end_hook = ns_update_end; 4991 terminal->read_socket_hook = ns_read_socket; 4992 terminal->frame_up_to_date_hook = ns_frame_up_to_date; 4993 terminal->defined_color_hook = ns_defined_color; 4994 terminal->query_frame_background_color = ns_query_frame_background_color; 4995 terminal->mouse_position_hook = ns_mouse_position; 4996 terminal->get_focus_frame = ns_get_focus_frame; 4997 terminal->focus_frame_hook = ns_focus_frame; 4998 terminal->frame_rehighlight_hook = ns_frame_rehighlight; 4999 terminal->frame_raise_lower_hook = ns_frame_raise_lower; 5000 terminal->frame_visible_invisible_hook = ns_make_frame_visible_invisible; 5001 terminal->fullscreen_hook = ns_fullscreen_hook; 5002 terminal->iconify_frame_hook = ns_iconify_frame; 5003 terminal->set_window_size_hook = ns_set_window_size; 5004 terminal->set_frame_offset_hook = ns_set_offset; 5005 terminal->set_frame_alpha_hook = ns_set_frame_alpha; 5006 terminal->set_new_font_hook = ns_new_font; 5007 terminal->implicit_set_name_hook = ns_implicitly_set_name; 5008 terminal->menu_show_hook = ns_menu_show; 5009 terminal->popup_dialog_hook = ns_popup_dialog; 5010 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar; 5011 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar; 5012 terminal->set_scroll_bar_default_width_hook = ns_set_scroll_bar_default_width; 5013 terminal->set_scroll_bar_default_height_hook = ns_set_scroll_bar_default_height; 5014 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars; 5015 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar; 5016 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars; 5017 terminal->get_string_resource_hook = ns_get_string_resource; 5018 terminal->free_pixmap = ns_free_pixmap; 5019 terminal->delete_frame_hook = ns_destroy_window; 5020 terminal->delete_terminal_hook = ns_delete_terminal; 5021 terminal->change_tab_bar_height_hook = ns_change_tab_bar_height; 5022 /* Other hooks are NULL by default. */ 5023 5024 return terminal; 5025} 5026 5027 5028struct ns_display_info * 5029ns_term_init (Lisp_Object display_name) 5030/* -------------------------------------------------------------------------- 5031 Start the Application and get things rolling. 5032 -------------------------------------------------------------------------- */ 5033{ 5034 struct terminal *terminal; 5035 struct ns_display_info *dpyinfo; 5036 static int ns_initialized = 0; 5037 Lisp_Object tmp; 5038 5039 if (ns_initialized) return x_display_list; 5040 ns_initialized = 1; 5041 5042 block_input (); 5043 5044 NSTRACE ("ns_term_init"); 5045 5046 [outerpool release]; 5047 outerpool = [[NSAutoreleasePool alloc] init]; 5048 5049 /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */ 5050 /*GSDebugAllocationActive (YES); */ 5051 block_input (); 5052 5053 baud_rate = 38400; 5054 Fset_input_interrupt_mode (Qnil); 5055 5056 if (selfds[0] == -1) 5057 { 5058 if (emacs_pipe (selfds) != 0) 5059 { 5060 fprintf (stderr, "Failed to create pipe: %s\n", 5061 emacs_strerror (errno)); 5062 emacs_abort (); 5063 } 5064 5065 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL)); 5066 FD_ZERO (&select_readfds); 5067 FD_ZERO (&select_writefds); 5068 pthread_mutex_init (&select_mutex, NULL); 5069 } 5070 5071 ns_pending_files = [[NSMutableArray alloc] init]; 5072 ns_pending_service_names = [[NSMutableArray alloc] init]; 5073 ns_pending_service_args = [[NSMutableArray alloc] init]; 5074 5075 /* Start app and create the main menu, window, view. 5076 Needs to be here because ns_initialize_display_info () uses AppKit classes. 5077 The view will then ask the NSApp to stop and return to Emacs. */ 5078 [EmacsApp sharedApplication]; 5079 if (NSApp == nil) 5080 return NULL; 5081 [NSApp setDelegate: NSApp]; 5082 5083 /* Start the select thread. */ 5084 [NSThread detachNewThreadSelector:@selector (fd_handler:) 5085 toTarget:NSApp 5086 withObject:nil]; 5087 5088 /* debugging: log all notifications */ 5089 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp 5090 selector: @selector (logNotification:) 5091 name: nil object: nil]; */ 5092 5093 dpyinfo = xzalloc (sizeof *dpyinfo); 5094 5095 ns_initialize_display_info (dpyinfo); 5096 terminal = ns_create_terminal (dpyinfo); 5097 5098 terminal->kboard = allocate_kboard (Qns); 5099 /* Don't let the initial kboard remain current longer than necessary. 5100 That would cause problems if a file loaded on startup tries to 5101 prompt in the mini-buffer. */ 5102 if (current_kboard == initial_kboard) 5103 current_kboard = terminal->kboard; 5104 terminal->kboard->reference_count++; 5105 5106 dpyinfo->next = x_display_list; 5107 x_display_list = dpyinfo; 5108 5109 dpyinfo->name_list_element = Fcons (display_name, Qnil); 5110 5111 terminal->name = xlispstrdup (display_name); 5112 5113 gui_init_fringe (terminal->rif); 5114 5115 unblock_input (); 5116 5117 if (!inhibit_x_resources) 5118 { 5119 ns_default ("GSFontAntiAlias", &ns_antialias_text, 5120 Qt, Qnil, NO, NO); 5121 tmp = Qnil; 5122 /* this is a standard variable */ 5123 ns_default ("AppleAntiAliasingThreshold", &tmp, 5124 make_float (10.0), make_float (6.0), YES, NO); 5125 ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp); 5126 } 5127 5128 NSTRACE_MSG ("Colors"); 5129 5130 { 5131 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"]; 5132 5133 /* There are 752 colors defined in rgb.txt. */ 5134 if ( cl == nil || [[cl allKeys] count] < 752) 5135 { 5136 Lisp_Object color_file, color_map, color, name; 5137 unsigned long c; 5138 5139 color_file = Fexpand_file_name (build_string ("rgb.txt"), 5140 Fsymbol_value (intern ("data-directory"))); 5141 5142 color_map = Fx_load_color_file (color_file); 5143 if (NILP (color_map)) 5144 fatal ("Could not read %s.\n", SDATA (color_file)); 5145 5146 cl = [[NSColorList alloc] initWithName: @"Emacs"]; 5147 for ( ; CONSP (color_map); color_map = XCDR (color_map)) 5148 { 5149 color = XCAR (color_map); 5150 name = XCAR (color); 5151 c = XFIXNUM (XCDR (color)); 5152 c |= 0xFF000000; 5153 [cl setColor: 5154 [NSColor colorWithUnsignedLong:c] 5155 forKey: [NSString stringWithLispString: name]]; 5156 } 5157 5158 /* FIXME: Report any errors writing the color file below. */ 5159#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 5160#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100 5161 if ([cl respondsToSelector:@selector(writeToURL:error:)]) 5162#endif 5163 [cl writeToURL:nil error:nil]; 5164#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100 5165 else 5166#endif 5167#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101100 */ 5168#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100 \ 5169 || defined (NS_IMPL_GNUSTEP) 5170 [cl writeToFile: nil]; 5171#endif 5172 } 5173 } 5174 5175 NSTRACE_MSG ("Versions"); 5176 5177 { 5178#ifdef NS_IMPL_GNUSTEP 5179 Vwindow_system_version = build_string (gnustep_base_version); 5180#else 5181 /* PSnextrelease (128, c); */ 5182 char c[DBL_BUFSIZE_BOUND]; 5183 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber); 5184 Vwindow_system_version = make_unibyte_string (c, len); 5185#endif 5186 } 5187 5188 delete_keyboard_wait_descriptor (0); 5189 5190 ns_app_name = [[NSProcessInfo processInfo] processName]; 5191 5192 /* Set up macOS app menu */ 5193 5194 NSTRACE_MSG ("Menu init"); 5195 5196#ifdef NS_IMPL_COCOA 5197 { 5198 NSMenu *appMenu; 5199 NSMenuItem *item; 5200 /* set up the application menu */ 5201 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"]; 5202 [svcsMenu setAutoenablesItems: NO]; 5203 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"]; 5204 [appMenu setAutoenablesItems: NO]; 5205 mainMenu = [[EmacsMenu alloc] initWithTitle: @""]; 5206 dockMenu = [[EmacsMenu alloc] initWithTitle: @""]; 5207 5208 [appMenu insertItemWithTitle: @"About Emacs" 5209 action: @selector (orderFrontStandardAboutPanel:) 5210 keyEquivalent: @"" 5211 atIndex: 0]; 5212 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1]; 5213 [appMenu insertItemWithTitle: @"Preferences..." 5214 action: @selector (showPreferencesWindow:) 5215 keyEquivalent: @"," 5216 atIndex: 2]; 5217 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3]; 5218 item = [appMenu insertItemWithTitle: @"Services" 5219 action: @selector (menuDown:) 5220 keyEquivalent: @"" 5221 atIndex: 4]; 5222 [appMenu setSubmenu: svcsMenu forItem: item]; 5223 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5]; 5224 [appMenu insertItemWithTitle: @"Hide Emacs" 5225 action: @selector (hide:) 5226 keyEquivalent: @"h" 5227 atIndex: 6]; 5228 item = [appMenu insertItemWithTitle: @"Hide Others" 5229 action: @selector (hideOtherApplications:) 5230 keyEquivalent: @"h" 5231 atIndex: 7]; 5232 [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption]; 5233 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8]; 5234 [appMenu insertItemWithTitle: @"Quit Emacs" 5235 action: @selector (terminate:) 5236 keyEquivalent: @"q" 5237 atIndex: 9]; 5238 5239 item = [mainMenu insertItemWithTitle: ns_app_name 5240 action: @selector (menuDown:) 5241 keyEquivalent: @"" 5242 atIndex: 0]; 5243 [mainMenu setSubmenu: appMenu forItem: item]; 5244 [dockMenu insertItemWithTitle: @"New Frame" 5245 action: @selector (newFrame:) 5246 keyEquivalent: @"" 5247 atIndex: 0]; 5248 5249 [NSApp setMainMenu: mainMenu]; 5250 [NSApp setAppleMenu: appMenu]; 5251 [NSApp setServicesMenu: svcsMenu]; 5252 /* Needed at least on Cocoa, to get dock menu to show windows */ 5253 [NSApp setWindowsMenu: [[NSMenu alloc] init]]; 5254 } 5255#endif /* macOS menu setup */ 5256 5257 /* Register our external input/output types, used for determining 5258 applicable services and also drag/drop eligibility. */ 5259 5260 NSTRACE_MSG ("Input/output types"); 5261 5262 ns_send_types = [[NSArray arrayWithObjects: NSPasteboardTypeString, nil] retain]; 5263 ns_return_types = [[NSArray arrayWithObjects: NSPasteboardTypeString, nil] 5264 retain]; 5265 ns_drag_types = [[NSArray arrayWithObjects: 5266 NSPasteboardTypeString, 5267 NSPasteboardTypeTabularText, 5268#if NS_USE_NSPasteboardTypeFileURL != 0 5269 NSPasteboardTypeFileURL, 5270#else 5271 NSFilenamesPboardType, 5272#endif 5273 NSPasteboardTypeURL, nil] retain]; 5274 5275 /* If fullscreen is in init/default-frame-alist, focus isn't set 5276 right for fullscreen windows, so set this. */ 5277 [NSApp activateIgnoringOtherApps:YES]; 5278 5279 NSTRACE_MSG ("Call NSApp run"); 5280 5281 [NSApp run]; 5282 ns_do_open_file = YES; 5283 5284#ifdef NS_IMPL_GNUSTEP 5285 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask. 5286 We must re-catch it so subprocess works. */ 5287 catch_child_signal (); 5288#endif 5289 5290 NSTRACE_MSG ("ns_term_init done"); 5291 5292 unblock_input (); 5293 5294 return dpyinfo; 5295} 5296 5297 5298void 5299ns_term_shutdown (int sig) 5300{ 5301 [[NSUserDefaults standardUserDefaults] synchronize]; 5302 5303 /* code not reached in emacs.c after this is called by shut_down_emacs: */ 5304 if (STRINGP (Vauto_save_list_file_name)) 5305 unlink (SSDATA (Vauto_save_list_file_name)); 5306 5307 if (sig == 0 || sig == SIGTERM) 5308 { 5309 [NSApp terminate: NSApp]; 5310 } 5311 else // force a stack trace to happen 5312 { 5313 emacs_abort (); 5314 } 5315} 5316 5317 5318/* ========================================================================== 5319 5320 EmacsApp implementation 5321 5322 ========================================================================== */ 5323 5324 5325@implementation EmacsApp 5326 5327- (id)init 5328{ 5329 NSTRACE ("[EmacsApp init]"); 5330 5331 if ((self = [super init])) 5332 { 5333#ifdef NS_IMPL_COCOA 5334 self->isFirst = YES; 5335#endif 5336#ifdef NS_IMPL_GNUSTEP 5337 self->applicationDidFinishLaunchingCalled = NO; 5338#endif 5339 } 5340 5341 return self; 5342} 5343 5344#ifdef NS_IMPL_COCOA 5345- (void)run 5346{ 5347 NSTRACE ("[EmacsApp run]"); 5348 5349#ifndef NSAppKitVersionNumber10_9 5350#define NSAppKitVersionNumber10_9 1265 5351#endif 5352 5353 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9) 5354 { 5355 [super run]; 5356 return; 5357 } 5358 5359 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 5360 5361 if (isFirst) [self finishLaunching]; 5362 isFirst = NO; 5363 5364 shouldKeepRunning = YES; 5365 do 5366 { 5367 [pool release]; 5368 pool = [[NSAutoreleasePool alloc] init]; 5369 5370 NSEvent *event = 5371 [self nextEventMatchingMask:NSEventMaskAny 5372 untilDate:[NSDate distantFuture] 5373 inMode:NSDefaultRunLoopMode 5374 dequeue:YES]; 5375 5376 [self sendEvent:event]; 5377 [self updateWindows]; 5378 } while (shouldKeepRunning); 5379 5380 [pool release]; 5381} 5382 5383- (void)stop: (id)sender 5384{ 5385 NSTRACE ("[EmacsApp stop:]"); 5386 5387 shouldKeepRunning = NO; 5388 // Stop possible dialog also. Noop if no dialog present. 5389 // The file dialog still leaks 7k - 10k on 10.9 though. 5390 [super stop:sender]; 5391} 5392#endif /* NS_IMPL_COCOA */ 5393 5394- (void)logNotification: (NSNotification *)notification 5395{ 5396 NSTRACE ("[EmacsApp logNotification:]"); 5397 5398 const char *name = [[notification name] UTF8String]; 5399 if (!strstr (name, "Update") && !strstr (name, "NSMenu") 5400 && !strstr (name, "WindowNumber")) 5401 NSLog (@"notification: '%@'", [notification name]); 5402} 5403 5404 5405- (void)sendEvent: (NSEvent *)theEvent 5406/* -------------------------------------------------------------------------- 5407 Called when NSApp is running for each event received. Used to stop 5408 the loop when we choose, since there's no way to just run one iteration. 5409 -------------------------------------------------------------------------- */ 5410{ 5411 int type = [theEvent type]; 5412 NSWindow *window = [theEvent window]; 5413 5414 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]"); 5415 NSTRACE_MSG ("Type: %d", type); 5416 5417#ifdef NS_IMPL_GNUSTEP 5418 // Keyboard events aren't propagated to file dialogs for some reason. 5419 if ([NSApp modalWindow] != nil && 5420 (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged)) 5421 { 5422 [[NSApp modalWindow] sendEvent: theEvent]; 5423 return; 5424 } 5425#endif 5426 5427 if (type == NSEventTypeApplicationDefined) 5428 { 5429 switch ([theEvent data2]) 5430 { 5431#ifdef NS_IMPL_COCOA 5432 case NSAPP_DATA2_RUNASSCRIPT: 5433 ns_run_ascript (); 5434 [self stop: self]; 5435 return; 5436#endif 5437 case NSAPP_DATA2_RUNFILEDIALOG: 5438 ns_run_file_dialog (); 5439 [self stop: self]; 5440 return; 5441 } 5442 } 5443 5444 if (type == NSEventTypeCursorUpdate && window == nil) 5445 { 5446 fputs ("Dropping external cursor update event.\n", stderr); 5447 return; 5448 } 5449 5450 if (type == NSEventTypeApplicationDefined) 5451 { 5452 /* Events posted by ns_send_appdefined interrupt the run loop here. 5453 But, if a modal window is up, an appdefined can still come through, 5454 (e.g., from a makeKeyWindow event) but stopping self also stops the 5455 modal loop. Just defer it until later. */ 5456 if ([NSApp modalWindow] == nil) 5457 { 5458 last_appdefined_event_data = [theEvent data1]; 5459 [self stop: self]; 5460 } 5461 else 5462 { 5463 send_appdefined = YES; 5464 } 5465 } 5466 5467 5468#ifdef NS_IMPL_COCOA 5469 /* If no dialog and none of our frames have focus and it is a move, skip it. 5470 It is a mouse move in an auxiliary menu, i.e. on the top right on macOS, 5471 such as Wifi, sound, date or similar. 5472 This prevents "spooky" highlighting in the frame under the menu. */ 5473 if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil) 5474 { 5475 struct ns_display_info *di; 5476 BOOL has_focus = NO; 5477 for (di = x_display_list; ! has_focus && di; di = di->next) 5478 has_focus = di->ns_focus_frame != 0; 5479 if (! has_focus) 5480 return; 5481 } 5482#endif 5483 5484 NSTRACE_UNSILENCE(); 5485 5486 [super sendEvent: theEvent]; 5487} 5488 5489 5490- (void)showPreferencesWindow: (id)sender 5491{ 5492 struct frame *emacsframe = SELECTED_FRAME (); 5493 NSEvent *theEvent = [NSApp currentEvent]; 5494 5495 if (!emacs_event) 5496 return; 5497 emacs_event->kind = NS_NONKEY_EVENT; 5498 emacs_event->code = KEY_NS_SHOW_PREFS; 5499 emacs_event->modifiers = 0; 5500 EV_TRAILER (theEvent); 5501} 5502 5503 5504- (void)newFrame: (id)sender 5505{ 5506 NSTRACE ("[EmacsApp newFrame:]"); 5507 5508 struct frame *emacsframe = SELECTED_FRAME (); 5509 NSEvent *theEvent = [NSApp currentEvent]; 5510 5511 if (!emacs_event) 5512 return; 5513 emacs_event->kind = NS_NONKEY_EVENT; 5514 emacs_event->code = KEY_NS_NEW_FRAME; 5515 emacs_event->modifiers = 0; 5516 EV_TRAILER (theEvent); 5517} 5518 5519 5520/* Open a file (used by below, after going into queue read by ns_read_socket). */ 5521- (BOOL) openFile: (NSString *)fileName 5522{ 5523 NSTRACE ("[EmacsApp openFile:]"); 5524 5525 struct frame *emacsframe = SELECTED_FRAME (); 5526 NSEvent *theEvent = [NSApp currentEvent]; 5527 5528 if (!emacs_event) 5529 return NO; 5530 5531 emacs_event->kind = NS_NONKEY_EVENT; 5532 emacs_event->code = KEY_NS_OPEN_FILE_LINE; 5533 ns_input_file = append2 (ns_input_file, [fileName lispString]); 5534 ns_input_line = Qnil; /* can be start or cons start,end */ 5535 emacs_event->modifiers =0; 5536 EV_TRAILER (theEvent); 5537 5538 return YES; 5539} 5540 5541 5542/* ************************************************************************** 5543 5544 EmacsApp delegate implementation 5545 5546 ************************************************************************** */ 5547 5548- (void)applicationDidFinishLaunching: (NSNotification *)notification 5549/* -------------------------------------------------------------------------- 5550 When application is loaded, terminate event loop in ns_term_init. 5551 -------------------------------------------------------------------------- */ 5552{ 5553 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]"); 5554 5555#ifdef NS_IMPL_GNUSTEP 5556 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES; 5557#endif 5558 [NSApp setServicesProvider: NSApp]; 5559 5560 [self antialiasThresholdDidChange:nil]; 5561#ifdef NS_IMPL_COCOA 5562 [[NSNotificationCenter defaultCenter] 5563 addObserver:self 5564 selector:@selector(antialiasThresholdDidChange:) 5565 name:NSAntialiasThresholdChangedNotification 5566 object:nil]; 5567#endif 5568 5569#ifdef NS_IMPL_COCOA 5570 /* Some functions/methods in CoreFoundation/Foundation increase the 5571 maximum number of open files for the process in their first call. 5572 We make dummy calls to them and then reduce the resource limit 5573 here, since pselect cannot handle file descriptors that are 5574 greater than or equal to FD_SETSIZE. */ 5575 CFSocketGetTypeID (); 5576 CFFileDescriptorGetTypeID (); 5577 [[NSFileHandle alloc] init]; 5578 struct rlimit rlim; 5579 if (getrlimit (RLIMIT_NOFILE, &rlim) == 0 5580 && rlim.rlim_cur > FD_SETSIZE) 5581 { 5582 rlim.rlim_cur = FD_SETSIZE; 5583 setrlimit (RLIMIT_NOFILE, &rlim); 5584 } 5585 if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) { 5586 /* Set the app's activation policy to regular when we run outside 5587 of a bundle. This is already done for us by Info.plist when we 5588 run inside a bundle. */ 5589 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; 5590 [NSApp setApplicationIconImage: 5591 [EmacsImage 5592 allocInitFromFile: 5593 build_string("icons/hicolor/128x128/apps/emacs.png")]]; 5594 } 5595#endif 5596 5597 ns_send_appdefined (-2); 5598} 5599 5600- (void)antialiasThresholdDidChange:(NSNotification *)notification 5601{ 5602#ifdef NS_IMPL_COCOA 5603 macfont_update_antialias_threshold (); 5604#endif 5605} 5606 5607 5608/* Termination sequences: 5609 C-x C-c: 5610 Cmd-Q: 5611 MenuBar | File | Exit: 5612 Select Quit from App menubar: 5613 -terminate 5614 KEY_NS_POWER_OFF, (save-buffers-kill-emacs) 5615 ns_term_shutdown() 5616 5617 Select Quit from Dock menu: 5618 Logout attempt: 5619 -appShouldTerminate 5620 Cancel -> Nothing else 5621 Accept -> 5622 5623 -terminate 5624 KEY_NS_POWER_OFF, (save-buffers-kill-emacs) 5625 ns_term_shutdown() 5626 5627*/ 5628 5629- (void) terminate: (id)sender 5630{ 5631 NSTRACE ("[EmacsApp terminate:]"); 5632 5633 struct frame *emacsframe = SELECTED_FRAME (); 5634 5635 if (!emacs_event) 5636 return; 5637 5638 emacs_event->kind = NS_NONKEY_EVENT; 5639 emacs_event->code = KEY_NS_POWER_OFF; 5640 emacs_event->arg = Qt; /* mark as non-key event */ 5641 EV_TRAILER ((id)nil); 5642} 5643 5644static bool 5645runAlertPanel(NSString *title, 5646 NSString *msgFormat, 5647 NSString *defaultButton, 5648 NSString *alternateButton) 5649{ 5650#ifdef NS_IMPL_GNUSTEP 5651 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil) 5652 == NSAlertDefaultReturn; 5653#else 5654 NSAlert *alert = [[NSAlert alloc] init]; 5655 [alert setAlertStyle: NSAlertStyleCritical]; 5656 [alert setMessageText: msgFormat]; 5657 [alert addButtonWithTitle: defaultButton]; 5658 [alert addButtonWithTitle: alternateButton]; 5659 NSInteger ret = [alert runModal]; 5660 [alert release]; 5661 return ret == NSAlertFirstButtonReturn; 5662#endif 5663} 5664 5665 5666- (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender 5667{ 5668 NSTRACE ("[EmacsApp applicationShouldTerminate:]"); 5669 5670 bool ret; 5671 5672 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO 5673 return NSTerminateNow; 5674 5675 ret = runAlertPanel(ns_app_name, 5676 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?", 5677 @"Save Buffers and Exit", @"Cancel"); 5678 5679 return ret ? NSTerminateNow : NSTerminateCancel; 5680} 5681 5682static int 5683not_in_argv (NSString *arg) 5684{ 5685 int k; 5686 const char *a = [arg UTF8String]; 5687 for (k = 1; k < initial_argc; ++k) 5688 if (strcmp (a, initial_argv[k]) == 0) return 0; 5689 return 1; 5690} 5691 5692/* Notification from the Workspace to open a file. */ 5693- (BOOL)application: sender openFile: (NSString *)file 5694{ 5695 if (ns_do_open_file || not_in_argv (file)) 5696 [ns_pending_files addObject: file]; 5697 return YES; 5698} 5699 5700 5701/* Open a file as a temporary file. */ 5702- (BOOL)application: sender openTempFile: (NSString *)file 5703{ 5704 if (ns_do_open_file || not_in_argv (file)) 5705 [ns_pending_files addObject: file]; 5706 return YES; 5707} 5708 5709 5710/* Notification from the Workspace to open a file noninteractively (?). */ 5711- (BOOL)application: sender openFileWithoutUI: (NSString *)file 5712{ 5713 if (ns_do_open_file || not_in_argv (file)) 5714 [ns_pending_files addObject: file]; 5715 return YES; 5716} 5717 5718/* Notification from the Workspace to open multiple files. */ 5719- (void)application: sender openFiles: (NSArray *)fileList 5720{ 5721 NSEnumerator *files = [fileList objectEnumerator]; 5722 NSString *file; 5723 /* Don't open files from the command line unconditionally, 5724 Cocoa parses the command line wrong, --option value tries to open value 5725 if --option is the last option. */ 5726 while ((file = [files nextObject]) != nil) 5727 if (ns_do_open_file || not_in_argv (file)) 5728 [ns_pending_files addObject: file]; 5729 5730 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess]; 5731 5732} 5733 5734 5735/* Handle dock menu requests. */ 5736- (NSMenu *)applicationDockMenu: (NSApplication *) sender 5737{ 5738 return dockMenu; 5739} 5740 5741 5742/* TODO: these may help w/IO switching between terminal and NSApp. */ 5743- (void)applicationWillBecomeActive: (NSNotification *)notification 5744{ 5745 NSTRACE ("[EmacsApp applicationWillBecomeActive:]"); 5746 // ns_app_active=YES; 5747} 5748 5749- (void)applicationDidBecomeActive: (NSNotification *)notification 5750{ 5751 NSTRACE ("[EmacsApp applicationDidBecomeActive:]"); 5752 5753#ifdef NS_IMPL_GNUSTEP 5754 if (! applicationDidFinishLaunchingCalled) 5755 [self applicationDidFinishLaunching:notification]; 5756#endif 5757 // ns_app_active=YES; 5758 5759 ns_update_auto_hide_menu_bar (); 5760 // No constraining takes place when the application is not active. 5761 ns_constrain_all_frames (); 5762} 5763- (void)applicationDidResignActive: (NSNotification *)notification 5764{ 5765 NSTRACE ("[EmacsApp applicationDidResignActive:]"); 5766 5767 // ns_app_active=NO; 5768 ns_send_appdefined (-1); 5769} 5770 5771 5772 5773/* ========================================================================== 5774 5775 EmacsApp aux handlers for managing event loop 5776 5777 ========================================================================== */ 5778 5779 5780- (void)timeout_handler: (NSTimer *)timedEntry 5781/* -------------------------------------------------------------------------- 5782 The timeout specified to ns_select has passed. 5783 -------------------------------------------------------------------------- */ 5784{ 5785 /* NSTRACE ("timeout_handler"); */ 5786 ns_send_appdefined (-2); 5787} 5788 5789- (void)sendFromMainThread:(id)unused 5790{ 5791 ns_send_appdefined (nextappdefined); 5792} 5793 5794- (void)fd_handler:(id)unused 5795/* -------------------------------------------------------------------------- 5796 Check data waiting on file descriptors and terminate if so. 5797 -------------------------------------------------------------------------- */ 5798{ 5799 int result; 5800 int waiting = 1, nfds; 5801 char c; 5802 5803 fd_set readfds, writefds, *wfds; 5804 struct timespec timeout, *tmo; 5805 NSAutoreleasePool *pool = nil; 5806 5807 /* NSTRACE ("fd_handler"); */ 5808 5809 for (;;) 5810 { 5811 [pool release]; 5812 pool = [[NSAutoreleasePool alloc] init]; 5813 5814 if (waiting) 5815 { 5816 fd_set fds; 5817 FD_ZERO (&fds); 5818 FD_SET (selfds[0], &fds); 5819 result = select (selfds[0]+1, &fds, NULL, NULL, NULL); 5820 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g') 5821 waiting = 0; 5822 } 5823 else 5824 { 5825 pthread_mutex_lock (&select_mutex); 5826 nfds = select_nfds; 5827 5828 if (select_valid & SELECT_HAVE_READ) 5829 readfds = select_readfds; 5830 else 5831 FD_ZERO (&readfds); 5832 5833 if (select_valid & SELECT_HAVE_WRITE) 5834 { 5835 writefds = select_writefds; 5836 wfds = &writefds; 5837 } 5838 else 5839 wfds = NULL; 5840 if (select_valid & SELECT_HAVE_TMO) 5841 { 5842 timeout = select_timeout; 5843 tmo = &timeout; 5844 } 5845 else 5846 tmo = NULL; 5847 5848 pthread_mutex_unlock (&select_mutex); 5849 5850 FD_SET (selfds[0], &readfds); 5851 if (selfds[0] >= nfds) nfds = selfds[0]+1; 5852 5853 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL); 5854 5855 if (result == 0) 5856 ns_send_appdefined (-2); 5857 else if (result > 0) 5858 { 5859 if (FD_ISSET (selfds[0], &readfds)) 5860 { 5861 if (read (selfds[0], &c, 1) == 1 && c == 's') 5862 waiting = 1; 5863 } 5864 else 5865 { 5866 pthread_mutex_lock (&select_mutex); 5867 if (select_valid & SELECT_HAVE_READ) 5868 select_readfds = readfds; 5869 if (select_valid & SELECT_HAVE_WRITE) 5870 select_writefds = writefds; 5871 if (select_valid & SELECT_HAVE_TMO) 5872 select_timeout = timeout; 5873 pthread_mutex_unlock (&select_mutex); 5874 5875 ns_send_appdefined (result); 5876 } 5877 } 5878 waiting = 1; 5879 } 5880 } 5881} 5882 5883 5884 5885/* ========================================================================== 5886 5887 Service provision 5888 5889 ========================================================================== */ 5890 5891/* Called from system: queue for next pass through event loop. */ 5892- (void)requestService: (NSPasteboard *)pboard 5893 userData: (NSString *)userData 5894 error: (NSString **)error 5895{ 5896 [ns_pending_service_names addObject: userData]; 5897 [ns_pending_service_args addObject: [NSString stringWithLispString:ns_string_from_pasteboard (pboard)]]; 5898} 5899 5900 5901/* Called from ns_read_socket to clear queue. */ 5902- (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg 5903{ 5904 struct frame *emacsframe = SELECTED_FRAME (); 5905 NSEvent *theEvent = [NSApp currentEvent]; 5906 5907 NSTRACE ("[EmacsApp fulfillService:withArg:]"); 5908 5909 if (!emacs_event) 5910 return NO; 5911 5912 emacs_event->kind = NS_NONKEY_EVENT; 5913 emacs_event->code = KEY_NS_SPI_SERVICE_CALL; 5914 ns_input_spi_name = [name lispString]; 5915 ns_input_spi_arg = [arg lispString]; 5916 emacs_event->modifiers = EV_MODIFIERS (theEvent); 5917 EV_TRAILER (theEvent); 5918 5919 return YES; 5920} 5921 5922 5923@end /* EmacsApp */ 5924 5925 5926/* ========================================================================== 5927 5928 EmacsView implementation 5929 5930 ========================================================================== */ 5931 5932 5933@implementation EmacsView 5934 5935/* Needed to inform when window closed from lisp. */ 5936- (void) setWindowClosing: (BOOL)closing 5937{ 5938 NSTRACE ("[EmacsView setWindowClosing:%d]", closing); 5939 5940 windowClosing = closing; 5941} 5942 5943 5944- (void)dealloc 5945{ 5946 NSTRACE ("[EmacsView dealloc]"); 5947 5948 /* Clear the view resize notification. */ 5949 [[NSNotificationCenter defaultCenter] 5950 removeObserver:self 5951 name:NSViewFrameDidChangeNotification 5952 object:nil]; 5953 5954 if (fs_state == FULLSCREEN_BOTH) 5955 [nonfs_window release]; 5956 [super dealloc]; 5957} 5958 5959 5960/* Called on font panel selection. */ 5961- (void)changeFont: (id)sender 5962{ 5963 NSEvent *e = [[self window] currentEvent]; 5964 struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID); 5965 struct font *font = face->font; 5966 id newFont; 5967 CGFloat size; 5968 NSFont *nsfont; 5969 5970 NSTRACE ("[EmacsView changeFont:]"); 5971 5972 if (!emacs_event) 5973 return; 5974 5975#ifdef NS_IMPL_GNUSTEP 5976 nsfont = ((struct nsfont_info *)font)->nsfont; 5977#endif 5978#ifdef NS_IMPL_COCOA 5979 nsfont = (NSFont *) macfont_get_nsctfont (font); 5980#endif 5981 5982 if ((newFont = [sender convertFont: nsfont])) 5983 { 5984 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */ 5985 5986 emacs_event->kind = NS_NONKEY_EVENT; 5987 emacs_event->modifiers = 0; 5988 emacs_event->code = KEY_NS_CHANGE_FONT; 5989 5990 size = [newFont pointSize]; 5991 ns_input_fontsize = make_fixnum (lrint (size)); 5992 ns_input_font = [[newFont familyName] lispString]; 5993 EV_TRAILER (e); 5994 } 5995} 5996 5997 5998- (BOOL)acceptsFirstResponder 5999{ 6000 NSTRACE ("[EmacsView acceptsFirstResponder]"); 6001 return YES; 6002} 6003 6004 6005- (void)resetCursorRects 6006{ 6007 NSRect visible = [self visibleRect]; 6008 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe); 6009 NSTRACE ("[EmacsView resetCursorRects]"); 6010 6011 if (currentCursor == nil) 6012 currentCursor = [NSCursor arrowCursor]; 6013 6014 if (!NSIsEmptyRect (visible)) 6015 [self addCursorRect: visible cursor: currentCursor]; 6016 6017#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300 6018#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 6019 if ([currentCursor respondsToSelector: @selector(setOnMouseEntered)]) 6020#endif 6021 [currentCursor setOnMouseEntered: YES]; 6022#endif 6023} 6024 6025 6026 6027/*****************************************************************************/ 6028/* Keyboard handling. */ 6029#define NS_KEYLOG 0 6030 6031- (void)keyDown: (NSEvent *)theEvent 6032{ 6033 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe); 6034 int code; 6035 unsigned fnKeysym = 0; 6036 static NSMutableArray *nsEvArray; 6037 unsigned int flags = [theEvent modifierFlags]; 6038 6039 NSTRACE ("[EmacsView keyDown:]"); 6040 6041 /* Rhapsody and macOS give up and down events for the arrow keys. */ 6042 if ([theEvent type] != NSEventTypeKeyDown) 6043 return; 6044 6045 if (!emacs_event) 6046 return; 6047 6048 if (![[self window] isKeyWindow] 6049 && [[theEvent window] isKindOfClass: [EmacsWindow class]] 6050 /* We must avoid an infinite loop here. */ 6051 && (EmacsView *)[[theEvent window] delegate] != self) 6052 { 6053 /* XXX: There is an occasional condition in which, when Emacs display 6054 updates a different frame from the current one, and temporarily 6055 selects it, then processes some interrupt-driven input 6056 (dispnew.c:3878), OS will send the event to the correct NSWindow, but 6057 for some reason that window has its first responder set to the NSView 6058 most recently updated (I guess), which is not the correct one. */ 6059 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent]; 6060 return; 6061 } 6062 6063 if (nsEvArray == nil) 6064 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1]; 6065 6066 [NSCursor setHiddenUntilMouseMoves:! NILP (Vmake_pointer_invisible)]; 6067 6068 if (hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight)) 6069 { 6070 clear_mouse_face (hlinfo); 6071 hlinfo->mouse_face_hidden = 1; 6072 } 6073 6074 if (!processingCompose) 6075 { 6076 /* FIXME: What should happen for key sequences with more than 6077 one character? */ 6078 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ? 6079 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0]; 6080 6081 /* Is it a "function key"? */ 6082 /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad 6083 flag set (this is probably a bug in the OS). */ 6084 if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad)) 6085 { 6086 fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad); 6087 } 6088 if (fnKeysym == 0) 6089 { 6090 fnKeysym = ns_convert_key (code); 6091 } 6092 6093 if (fnKeysym) 6094 { 6095 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace', 6096 because Emacs treats Delete and KP-Delete same (in simple.el). */ 6097 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33) 6098#ifdef NS_IMPL_GNUSTEP 6099 /* GNUstep uses incompatible keycodes, even for those that are 6100 supposed to be hardware independent. Just check for delete. 6101 Keypad delete does not have keysym 0xFFFF. 6102 See https://savannah.gnu.org/bugs/?25395 */ 6103 || (fnKeysym == 0xFFFF && code == 127) 6104#endif 6105 ) 6106 code = 0xFF08; /* backspace */ 6107 else 6108 code = fnKeysym; 6109 6110 /* Function keys (such as the F-keys, arrow keys, etc.) set 6111 modifiers as though the fn key has been pressed when it 6112 hasn't. Also some combinations of fn and a function key 6113 return a different key than was pressed (e.g. fn-<left> 6114 gives <home>). We need to unset the fn key flag in these 6115 cases. */ 6116 flags &= ~NS_FUNCTION_KEY_MASK; 6117 } 6118 6119 /* The ⌘ and ⌥ modifiers can be either shift-like (for alternate 6120 character input) or control-like (as command prefix). If we 6121 have only shift-like modifiers, then we should use the 6122 translated characters (returned by the characters method); if 6123 we have only control-like modifiers, then we should use the 6124 untranslated characters (returned by the 6125 charactersIgnoringModifiers method). An annoyance happens if 6126 we have both shift-like and control-like modifiers because 6127 the NSEvent API doesn’t let us ignore only some modifiers. 6128 In that case we use UCKeyTranslate (ns_get_shifted_character) 6129 to look up the correct character. */ 6130 6131 /* EV_MODIFIERS2 uses parse_solitary_modifier on all known 6132 modifier keys, which returns 0 for shift-like modifiers. 6133 Therefore its return value is the set of control-like 6134 modifiers. */ 6135 Lisp_Object kind = fnKeysym ? QCfunction : QCordinary; 6136 emacs_event->modifiers = EV_MODIFIERS2 (flags, kind); 6137 6138#ifndef NS_IMPL_GNUSTEP 6139 if (NS_KEYLOG) 6140 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n", 6141 code, fnKeysym, flags, emacs_event->modifiers); 6142#endif 6143 6144 /* If it was a function key or had control-like modifiers, pass 6145 it directly to Emacs. */ 6146 if (fnKeysym || (emacs_event->modifiers 6147 && (emacs_event->modifiers != shift_modifier) 6148 && [[theEvent charactersIgnoringModifiers] length] > 0)) 6149 { 6150 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT; 6151 /* FIXME: What are the next four lines supposed to do? */ 6152 if (code < 0x20) 6153 code |= (1<<28)|(3<<16); 6154 else if (code == 0x7f) 6155 code |= (1<<28)|(3<<16); 6156 else if (!fnKeysym) 6157 { 6158#ifdef NS_IMPL_COCOA 6159 /* We potentially have both shift- and control-like 6160 modifiers in use, so find the correct character 6161 ignoring any control-like ones. */ 6162 code = ns_get_shifted_character (theEvent); 6163#endif 6164 6165 /* FIXME: This seems wrong, characters in the range 6166 [0x80, 0xFF] are not ASCII characters. Can’t we just 6167 use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds 6168 of characters? */ 6169 emacs_event->kind = code > 0xFF 6170 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT; 6171 } 6172 6173 emacs_event->code = code; 6174 EV_TRAILER (theEvent); 6175 processingCompose = NO; 6176 return; 6177 } 6178 } 6179 6180 /* If we get here, a non-function key without control-like modifiers 6181 was hit. Use interpretKeyEvents, which in turn will call 6182 insertText; see 6183 https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/HandlingKeyEvents/HandlingKeyEvents.html. */ 6184 6185 if (NS_KEYLOG && !processingCompose) 6186 fputs ("keyDown: Begin compose sequence.\n", stderr); 6187 6188 /* FIXME: interpretKeyEvents doesn’t seem to send insertText if ⌘ is 6189 used as shift-like modifier, at least on El Capitan. Mask it 6190 out. This shouldn’t be needed though; we should figure out what 6191 the correct way of handling ⌘ is. */ 6192 if ([theEvent modifierFlags] & NSEventModifierFlagCommand) 6193 theEvent = [NSEvent keyEventWithType:[theEvent type] 6194 location:[theEvent locationInWindow] 6195 modifierFlags:[theEvent modifierFlags] & ~NSEventModifierFlagCommand 6196 timestamp:[theEvent timestamp] 6197 windowNumber:[theEvent windowNumber] 6198 context:nil 6199 characters:[theEvent characters] 6200 charactersIgnoringModifiers:[theEvent charactersIgnoringModifiers] 6201 isARepeat:[theEvent isARepeat] 6202 keyCode:[theEvent keyCode]]; 6203 6204 processingCompose = YES; 6205 /* FIXME: Use [NSArray arrayWithObject:theEvent]? */ 6206 [nsEvArray addObject: theEvent]; 6207 [self interpretKeyEvents: nsEvArray]; 6208 [nsEvArray removeObject: theEvent]; 6209} 6210 6211 6212/* <NSTextInput> implementation (called through [super interpretKeyEvents:]). */ 6213 6214 6215/* <NSTextInput>: called when done composing; 6216 NOTE: also called when we delete over working text, followed 6217 immediately by doCommandBySelector: deleteBackward: */ 6218- (void)insertText: (id)aString 6219{ 6220 NSString *s; 6221 NSUInteger len; 6222 6223 NSTRACE ("[EmacsView insertText:]"); 6224 6225 if ([aString isKindOfClass:[NSAttributedString class]]) 6226 s = [aString string]; 6227 else 6228 s = aString; 6229 6230 len = [s length]; 6231 6232 if (NS_KEYLOG) 6233 NSLog (@"insertText '%@'\tlen = %lu", aString, (unsigned long) len); 6234 processingCompose = NO; 6235 6236 if (!emacs_event) 6237 return; 6238 6239 /* First, clear any working text. */ 6240 if (workingText != nil) 6241 [self deleteWorkingText]; 6242 6243 /* It might be preferable to use getCharacters:range: below, 6244 cf. https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CocoaPerformance/Articles/StringDrawing.html#//apple_ref/doc/uid/TP40001445-112378. 6245 However, we probably can't use SAFE_NALLOCA here because it might 6246 exit nonlocally. */ 6247 6248 /* Now insert the string as keystrokes. */ 6249 for (NSUInteger i = 0; i < len; i++) 6250 { 6251 NSUInteger code = [s characterAtIndex:i]; 6252 if (UTF_16_HIGH_SURROGATE_P (code) && i < len - 1) 6253 { 6254 unichar low = [s characterAtIndex:i + 1]; 6255 if (UTF_16_LOW_SURROGATE_P (low)) 6256 { 6257 code = surrogates_to_codepoint (low, code); 6258 ++i; 6259 } 6260 } 6261 /* TODO: still need this? */ 6262 if (code == 0x2DC) 6263 code = '~'; /* 0x7E */ 6264 if (code != 32) /* Space */ 6265 emacs_event->modifiers = 0; 6266 emacs_event->kind 6267 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT; 6268 emacs_event->code = code; 6269 EV_TRAILER ((id)nil); 6270 } 6271} 6272 6273 6274/* <NSTextInput>: inserts display of composing characters. */ 6275- (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange 6276{ 6277 NSString *str = [aString respondsToSelector: @selector (string)] ? 6278 [aString string] : aString; 6279 6280 NSTRACE ("[EmacsView setMarkedText:selectedRange:]"); 6281 6282 if (NS_KEYLOG) 6283 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu", 6284 str, (unsigned long)[str length], 6285 (unsigned long)selRange.length, 6286 (unsigned long)selRange.location); 6287 6288 if ([str length] == 0) 6289 { 6290 [self deleteWorkingText]; 6291 return; 6292 } 6293 6294 if (!emacs_event) 6295 return; 6296 6297 processingCompose = YES; 6298 [workingText release]; 6299 workingText = [str copy]; 6300 ns_working_text = [workingText lispString]; 6301 6302 emacs_event->kind = NS_TEXT_EVENT; 6303 emacs_event->code = KEY_NS_PUT_WORKING_TEXT; 6304 EV_TRAILER ((id)nil); 6305} 6306 6307 6308/* Delete display of composing characters [not in <NSTextInput>]. */ 6309- (void)deleteWorkingText 6310{ 6311 NSTRACE ("[EmacsView deleteWorkingText]"); 6312 6313 if (workingText == nil) 6314 return; 6315 if (NS_KEYLOG) 6316 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]); 6317 [workingText release]; 6318 workingText = nil; 6319 processingCompose = NO; 6320 6321 if (!emacs_event) 6322 return; 6323 6324 emacs_event->kind = NS_TEXT_EVENT; 6325 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT; 6326 EV_TRAILER ((id)nil); 6327} 6328 6329 6330- (BOOL)hasMarkedText 6331{ 6332 NSTRACE ("[EmacsView hasMarkedText]"); 6333 6334 return workingText != nil; 6335} 6336 6337 6338- (NSRange)markedRange 6339{ 6340 NSTRACE ("[EmacsView markedRange]"); 6341 6342 NSRange rng = workingText != nil 6343 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0); 6344 if (NS_KEYLOG) 6345 NSLog (@"markedRange request"); 6346 return rng; 6347} 6348 6349 6350- (void)unmarkText 6351{ 6352 NSTRACE ("[EmacsView unmarkText]"); 6353 6354 if (NS_KEYLOG) 6355 NSLog (@"unmark (accept) text"); 6356 [self deleteWorkingText]; 6357 processingCompose = NO; 6358} 6359 6360 6361/* Used to position char selection windows, etc. */ 6362- (NSRect)firstRectForCharacterRange: (NSRange)theRange 6363{ 6364 NSRect rect; 6365 NSPoint pt; 6366 struct window *win; 6367 6368 NSTRACE ("[EmacsView firstRectForCharacterRange:]"); 6369 6370 if (NS_KEYLOG) 6371 NSLog (@"firstRectForCharRange request"); 6372 6373 if (WINDOWP (echo_area_window) && ! NILP (call0 (intern ("ns-in-echo-area")))) 6374 win = XWINDOW (echo_area_window); 6375 else 6376 win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe)); 6377 6378 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe); 6379 rect.size.height = FRAME_LINE_HEIGHT (emacsframe); 6380 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x); 6381 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y 6382 +FRAME_LINE_HEIGHT (emacsframe)); 6383 6384 pt = [self convertPoint: pt toView: nil]; 6385 6386#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 6387#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 6388 if ([[self window] respondsToSelector: @selector(convertRectToScreen:)]) 6389 { 6390#endif 6391 rect.origin = pt; 6392 rect = [(EmacsWindow *) [self window] convertRectToScreen: rect]; 6393#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 6394 } 6395 else 6396#endif 6397#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */ 6398#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \ 6399 || defined (NS_IMPL_GNUSTEP) 6400 { 6401 pt = [[self window] convertBaseToScreen: pt]; 6402 rect.origin = pt; 6403 } 6404#endif 6405 6406 return rect; 6407} 6408 6409 6410- (NSInteger)conversationIdentifier 6411{ 6412 return (NSInteger)self; 6413} 6414 6415 6416- (void)doCommandBySelector: (SEL)aSelector 6417{ 6418 NSTRACE ("[EmacsView doCommandBySelector:]"); 6419 6420 if (NS_KEYLOG) 6421 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector)); 6422 6423 processingCompose = NO; 6424 if (aSelector == @selector (deleteBackward:)) 6425 { 6426 /* Happens when user backspaces over an ongoing composition: 6427 throw a 'delete' into the event queue. */ 6428 if (!emacs_event) 6429 return; 6430 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT; 6431 emacs_event->code = 0xFF08; 6432 EV_TRAILER ((id)nil); 6433 } 6434} 6435 6436- (NSArray *)validAttributesForMarkedText 6437{ 6438 static NSArray *arr = nil; 6439 if (arr == nil) arr = [NSArray new]; 6440 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */ 6441 return arr; 6442} 6443 6444- (NSRange)selectedRange 6445{ 6446 if (NS_KEYLOG) 6447 NSLog (@"selectedRange request"); 6448 return NSMakeRange (NSNotFound, 0); 6449} 6450 6451#if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \ 6452 GNUSTEP_GUI_MINOR_VERSION > 22 6453- (NSUInteger)characterIndexForPoint: (NSPoint)thePoint 6454#else 6455- (unsigned int)characterIndexForPoint: (NSPoint)thePoint 6456#endif 6457{ 6458 if (NS_KEYLOG) 6459 NSLog (@"characterIndexForPoint request"); 6460 return 0; 6461} 6462 6463- (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange 6464{ 6465 static NSAttributedString *str = nil; 6466 if (str == nil) str = [NSAttributedString new]; 6467 if (NS_KEYLOG) 6468 NSLog (@"attributedSubstringFromRange request"); 6469 return str; 6470} 6471 6472/* End <NSTextInput> implementation. */ 6473/*****************************************************************************/ 6474 6475 6476/* This is what happens when the user presses a mouse button. */ 6477- (void)mouseDown: (NSEvent *)theEvent 6478{ 6479 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); 6480 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil]; 6481 6482 NSTRACE ("[EmacsView mouseDown:]"); 6483 6484 if (!emacs_event) 6485 return; 6486 6487 dpyinfo->last_mouse_frame = emacsframe; 6488 /* Appears to be needed to prevent spurious movement events generated on 6489 button clicks. */ 6490 emacsframe->mouse_moved = 0; 6491 6492 if ([theEvent type] == NSEventTypeScrollWheel) 6493 { 6494#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 6495#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 6496 if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)]) 6497 { 6498#endif 6499 /* If the input device is a touchpad or similar, use precise 6500 * scrolling deltas. These are measured in pixels, so we 6501 * have to add them up until they exceed one line height, 6502 * then we can send a scroll wheel event. 6503 * 6504 * If the device only has coarse scrolling deltas, like a 6505 * real mousewheel, the deltas represent a ratio of whole 6506 * lines, so round up the number of lines. This means we 6507 * always send one scroll event per click, but can still 6508 * scroll more than one line if the OS tells us to. 6509 */ 6510 bool horizontal; 6511 int lines = 0; 6512 int x = 0, y = 0; 6513 int scrollUp = NO; 6514 6515 /* FIXME: At the top or bottom of the buffer we should 6516 * ignore momentum-phase events. */ 6517 if (! ns_use_mwheel_momentum 6518 && [theEvent momentumPhase] != NSEventPhaseNone) 6519 return; 6520 6521 if ([theEvent hasPreciseScrollingDeltas]) 6522 { 6523 static int totalDeltaX, totalDeltaY; 6524 int lineHeight; 6525 6526 if (FIXNUMP (ns_mwheel_line_height)) 6527 lineHeight = XFIXNUM (ns_mwheel_line_height); 6528 else 6529 { 6530 /* FIXME: Use actual line height instead of the default. */ 6531 lineHeight = default_line_pixel_height 6532 (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe))); 6533 } 6534 6535 if ([theEvent phase] == NSEventPhaseBegan) 6536 { 6537 totalDeltaX = 0; 6538 totalDeltaY = 0; 6539 } 6540 6541 totalDeltaX += [theEvent scrollingDeltaX]; 6542 totalDeltaY += [theEvent scrollingDeltaY]; 6543 6544 /* Calculate the number of lines, if any, to scroll, and 6545 * reset the total delta for the direction we're NOT 6546 * scrolling so that small movements don't add up. */ 6547 if (abs (totalDeltaX) > abs (totalDeltaY) 6548 && (!mwheel_coalesce_scroll_events 6549 || abs (totalDeltaX) > lineHeight)) 6550 { 6551 horizontal = YES; 6552 scrollUp = totalDeltaX > 0; 6553 6554 lines = abs (totalDeltaX / lineHeight); 6555 x = totalDeltaX; 6556 if (!mwheel_coalesce_scroll_events) 6557 totalDeltaX = 0; 6558 else 6559 totalDeltaX = totalDeltaX % lineHeight; 6560 totalDeltaY = 0; 6561 } 6562 else if (abs (totalDeltaY) >= abs (totalDeltaX) 6563 && (!mwheel_coalesce_scroll_events 6564 || abs (totalDeltaY) > lineHeight)) 6565 { 6566 horizontal = NO; 6567 scrollUp = totalDeltaY > 0; 6568 6569 lines = abs (totalDeltaY / lineHeight); 6570 y = totalDeltaY; 6571 if (!mwheel_coalesce_scroll_events) 6572 totalDeltaY = 0; 6573 else 6574 totalDeltaY = totalDeltaY % lineHeight; 6575 totalDeltaX = 0; 6576 } 6577 6578 if (lines > 1 && ! ns_use_mwheel_acceleration) 6579 lines = 1; 6580 } 6581 else 6582 { 6583 CGFloat delta; 6584 6585 if ([theEvent scrollingDeltaY] == 0) 6586 { 6587 horizontal = YES; 6588 delta = [theEvent scrollingDeltaX]; 6589 } 6590 else 6591 { 6592 horizontal = NO; 6593 delta = [theEvent scrollingDeltaY]; 6594 } 6595 6596 lines = (ns_use_mwheel_acceleration) 6597 ? ceil (fabs (delta)) : 1; 6598 6599 scrollUp = delta > 0; 6600 x = ([theEvent scrollingDeltaX] 6601 * FRAME_COLUMN_WIDTH (emacsframe)); 6602 y = ([theEvent scrollingDeltaY] 6603 * FRAME_LINE_HEIGHT (emacsframe)); 6604 } 6605 6606 if (lines == 0 && mwheel_coalesce_scroll_events) 6607 return; 6608 6609 if (NUMBERP (Vns_scroll_event_delta_factor)) 6610 { 6611 x *= XFLOATINT (Vns_scroll_event_delta_factor); 6612 y *= XFLOATINT (Vns_scroll_event_delta_factor); 6613 } 6614 6615 emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT; 6616 emacs_event->arg = list3 (make_fixnum (lines), 6617 make_float (x), 6618 make_float (y)); 6619 6620 emacs_event->code = 0; 6621 emacs_event->modifiers = EV_MODIFIERS (theEvent) | 6622 (scrollUp ? up_modifier : down_modifier); 6623#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 6624 } 6625 else 6626#endif 6627#endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */ 6628#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070 6629 { 6630 CGFloat delta = [theEvent deltaY]; 6631 /* Mac notebooks send wheel events with delta equal to 0 6632 when trackpad scrolling. */ 6633 if (delta == 0) 6634 { 6635 delta = [theEvent deltaX]; 6636 if (delta == 0) 6637 { 6638 NSTRACE_MSG ("deltaIsZero"); 6639 return; 6640 } 6641 emacs_event->kind = HORIZ_WHEEL_EVENT; 6642 } 6643 else 6644 emacs_event->kind = WHEEL_EVENT; 6645 6646 emacs_event->code = 0; 6647 emacs_event->modifiers = EV_MODIFIERS (theEvent) | 6648 ((delta > 0) ? up_modifier : down_modifier); 6649 } 6650#endif 6651 } 6652 else 6653 { 6654 Lisp_Object tab_bar_arg = Qnil; 6655 bool tab_bar_p = false; 6656 6657 if (WINDOWP (emacsframe->tab_bar_window) 6658 && WINDOW_TOTAL_LINES (XWINDOW (emacsframe->tab_bar_window))) 6659 { 6660 Lisp_Object window; 6661 int x = lrint (p.x); 6662 int y = lrint (p.y); 6663 6664 window = window_from_coordinates (emacsframe, x, y, 0, true, true); 6665 tab_bar_p = EQ (window, emacsframe->tab_bar_window); 6666 6667 if (tab_bar_p) 6668 tab_bar_arg = handle_tab_bar_click (emacsframe, x, y, EV_UDMODIFIERS (theEvent) & down_modifier, 6669 EV_MODIFIERS (theEvent) | EV_UDMODIFIERS (theEvent)); 6670 } 6671 6672 if (!(tab_bar_p && NILP (tab_bar_arg))) 6673 emacs_event->kind = MOUSE_CLICK_EVENT; 6674 emacs_event->arg = tab_bar_arg; 6675 emacs_event->code = EV_BUTTON (theEvent); 6676 emacs_event->modifiers = EV_MODIFIERS (theEvent) 6677 | EV_UDMODIFIERS (theEvent); 6678 6679 if (emacs_event->modifiers & down_modifier) 6680 FRAME_DISPLAY_INFO (emacsframe)->grabbed |= 1 << EV_BUTTON (theEvent); 6681 else 6682 FRAME_DISPLAY_INFO (emacsframe)->grabbed &= ~(1 << EV_BUTTON (theEvent)); 6683 } 6684 6685 XSETINT (emacs_event->x, lrint (p.x)); 6686 XSETINT (emacs_event->y, lrint (p.y)); 6687 EV_TRAILER (theEvent); 6688 return; 6689} 6690 6691 6692- (void)rightMouseDown: (NSEvent *)theEvent 6693{ 6694 NSTRACE ("[EmacsView rightMouseDown:]"); 6695 [self mouseDown: theEvent]; 6696} 6697 6698 6699- (void)otherMouseDown: (NSEvent *)theEvent 6700{ 6701 NSTRACE ("[EmacsView otherMouseDown:]"); 6702 [self mouseDown: theEvent]; 6703} 6704 6705 6706- (void)mouseUp: (NSEvent *)theEvent 6707{ 6708 NSTRACE ("[EmacsView mouseUp:]"); 6709 [self mouseDown: theEvent]; 6710} 6711 6712 6713- (void)rightMouseUp: (NSEvent *)theEvent 6714{ 6715 NSTRACE ("[EmacsView rightMouseUp:]"); 6716 [self mouseDown: theEvent]; 6717} 6718 6719 6720- (void)otherMouseUp: (NSEvent *)theEvent 6721{ 6722 NSTRACE ("[EmacsView otherMouseUp:]"); 6723 [self mouseDown: theEvent]; 6724} 6725 6726 6727- (void) scrollWheel: (NSEvent *)theEvent 6728{ 6729 NSTRACE ("[EmacsView scrollWheel:]"); 6730 [self mouseDown: theEvent]; 6731} 6732 6733 6734/* Tell emacs the mouse has moved. */ 6735- (void)mouseMoved: (NSEvent *)e 6736{ 6737 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe); 6738 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); 6739 Lisp_Object frame; 6740 NSPoint pt; 6741 BOOL dragging; 6742 6743 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]"); 6744 6745 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e); 6746 pt = [self convertPoint: [e locationInWindow] fromView: nil]; 6747 dpyinfo->last_mouse_motion_x = pt.x; 6748 dpyinfo->last_mouse_motion_y = pt.y; 6749 6750 /* Update any mouse face. */ 6751 if (hlinfo->mouse_face_hidden) 6752 { 6753 hlinfo->mouse_face_hidden = 0; 6754 clear_mouse_face (hlinfo); 6755 } 6756 6757 /* Tooltip handling. */ 6758 previous_help_echo_string = help_echo_string; 6759 help_echo_string = Qnil; 6760 6761 if (!NILP (Vmouse_autoselect_window)) 6762 { 6763 NSTRACE_MSG ("mouse_autoselect_window"); 6764 static Lisp_Object last_mouse_window; 6765 Lisp_Object window 6766 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0, 0); 6767 6768 if (WINDOWP (window) 6769 && !EQ (window, last_mouse_window) 6770 && !EQ (window, selected_window) 6771 && (!NILP (focus_follows_mouse) 6772 || (EQ (XWINDOW (window)->frame, 6773 XWINDOW (selected_window)->frame)))) 6774 { 6775 NSTRACE_MSG ("in_window"); 6776 emacs_event->kind = SELECT_WINDOW_EVENT; 6777 emacs_event->frame_or_window = window; 6778 EV_TRAILER2 (e); 6779 } 6780 /* Remember the last window where we saw the mouse. */ 6781 last_mouse_window = window; 6782 } 6783 6784 dragging = (e.type == NSEventTypeLeftMouseDragged); 6785 if (!ns_note_mouse_movement (emacsframe, pt.x, pt.y, dragging)) 6786 help_echo_string = previous_help_echo_string; 6787 6788 XSETFRAME (frame, emacsframe); 6789 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string)) 6790 { 6791 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c 6792 (note_mouse_highlight), which is called through the 6793 ns_note_mouse_movement () call above. */ 6794 any_help_event_p = YES; 6795 gen_help_event (help_echo_string, frame, help_echo_window, 6796 help_echo_object, help_echo_pos); 6797 } 6798 6799 if (emacsframe->mouse_moved && send_appdefined) 6800 ns_send_appdefined (-1); 6801} 6802 6803 6804- (void)mouseDragged: (NSEvent *)e 6805{ 6806 NSTRACE ("[EmacsView mouseDragged:]"); 6807 [self mouseMoved: e]; 6808} 6809 6810 6811- (void)rightMouseDragged: (NSEvent *)e 6812{ 6813 NSTRACE ("[EmacsView rightMouseDragged:]"); 6814 [self mouseMoved: e]; 6815} 6816 6817 6818- (void)otherMouseDragged: (NSEvent *)e 6819{ 6820 NSTRACE ("[EmacsView otherMouseDragged:]"); 6821 [self mouseMoved: e]; 6822} 6823 6824#ifdef NS_IMPL_COCOA 6825- (void) magnifyWithEvent: (NSEvent *) event 6826{ 6827 NSPoint pt = [self convertPoint: [event locationInWindow] fromView: nil]; 6828 static CGFloat last_scale; 6829 6830 NSTRACE ("[EmacsView magnifyWithEvent]"); 6831 if (emacs_event) 6832 { 6833 emacs_event->kind = PINCH_EVENT; 6834 emacs_event->modifiers = EV_MODIFIERS (event); 6835 XSETINT (emacs_event->x, lrint (pt.x)); 6836 XSETINT (emacs_event->y, lrint (pt.y)); 6837 XSETFRAME (emacs_event->frame_or_window, emacsframe); 6838 6839 if ([event phase] == NSEventPhaseBegan) 6840 { 6841 last_scale = 1.0 + [event magnification]; 6842 emacs_event->arg = list4 (make_float (0.0), 6843 make_float (0.0), 6844 make_float (last_scale), 6845 make_float (0.0)); 6846 } 6847 else 6848 /* Report a tiny change so that Lisp code doesn't think this 6849 is the beginning of an event sequence. This is the best we 6850 can do because NS doesn't report pinch events in as much 6851 detail as XInput 2 or GTK+ do. */ 6852 emacs_event->arg = list4 (make_float (0.01), 6853 make_float (0.0), 6854 make_float (last_scale += [event magnification]), 6855 make_float (0.0)); 6856 EV_TRAILER (event); 6857 } 6858} 6859#endif 6860 6861- (BOOL)windowShouldClose: (id)sender 6862{ 6863 NSEvent *e =[[self window] currentEvent]; 6864 6865 NSTRACE ("[EmacsView windowShouldClose:]"); 6866 windowClosing = YES; 6867 if (!emacs_event) 6868 return NO; 6869 emacs_event->kind = DELETE_WINDOW_EVENT; 6870 emacs_event->modifiers = 0; 6871 emacs_event->code = 0; 6872 EV_TRAILER (e); 6873 /* Don't close this window, let this be done from lisp code. */ 6874 return NO; 6875} 6876 6877 6878- (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize 6879/* Normalize frame to gridded text size. */ 6880{ 6881 int extra = 0; 6882 int cols, rows; 6883 6884 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]", 6885 NSTRACE_ARG_SIZE (frameSize)); 6886 NSTRACE_RECT ("[sender frame]", [sender frame]); 6887 NSTRACE_FSTYPE ("fs_state", fs_state); 6888 6889 if (!FRAME_LIVE_P (emacsframe)) 6890 return frameSize; 6891 6892 if (fs_state == FULLSCREEN_MAXIMIZED 6893 && (maximized_width != (int)frameSize.width 6894 || maximized_height != (int)frameSize.height)) 6895 [self setFSValue: FULLSCREEN_NONE]; 6896 else if (fs_state == FULLSCREEN_WIDTH 6897 && maximized_width != (int)frameSize.width) 6898 [self setFSValue: FULLSCREEN_NONE]; 6899 else if (fs_state == FULLSCREEN_HEIGHT 6900 && maximized_height != (int)frameSize.height) 6901 [self setFSValue: FULLSCREEN_NONE]; 6902 6903 if (fs_state == FULLSCREEN_NONE) 6904 maximized_width = maximized_height = -1; 6905 6906 if (! [self isFullscreen]) 6907 { 6908 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe) 6909 + FRAME_TOOLBAR_HEIGHT (emacsframe); 6910 } 6911 6912 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width); 6913 if (cols < MINWIDTH) 6914 cols = MINWIDTH; 6915 6916 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, 6917 frameSize.height - extra); 6918 if (rows < MINHEIGHT) 6919 rows = MINHEIGHT; 6920#ifdef NS_IMPL_COCOA 6921 { 6922 /* This sets window title to have size in it; the wm does this under GS. */ 6923 NSRect r = [[self window] frame]; 6924 if (r.size.height == frameSize.height && r.size.width == frameSize.width) 6925 { 6926 if (old_title != 0) 6927 { 6928 xfree (old_title); 6929 old_title = 0; 6930 } 6931 } 6932 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize 6933 && [[self window] title] != NULL) 6934 { 6935 char *size_title; 6936 NSWindow *window = [self window]; 6937 if (old_title == 0) 6938 { 6939 char *t = strdup ([[[self window] title] UTF8String]); 6940 char *pos = strstr (t, " — "); 6941 if (pos) 6942 *pos = '\0'; 6943 old_title = t; 6944 } 6945 size_title = xmalloc (strlen (old_title) + 40); 6946 esprintf (size_title, "%s — (%d × %d)", old_title, cols, rows); 6947 [window setTitle: [NSString stringWithUTF8String: size_title]]; 6948 [window display]; 6949 xfree (size_title); 6950 } 6951 } 6952#endif /* NS_IMPL_COCOA */ 6953 6954 NSTRACE_MSG ("cols: %d rows: %d", cols, rows); 6955 6956 /* Restrict the new size to the text grid. 6957 6958 Don't restrict the width if the user only adjusted the height, and 6959 vice versa. (Without this, the frame would shrink, and move 6960 slightly, if the window was resized by dragging one of its 6961 borders.) */ 6962 if (!frame_resize_pixelwise) 6963 { 6964 NSRect r = [[self window] frame]; 6965 6966 if (r.size.width != frameSize.width) 6967 { 6968 frameSize.width = 6969 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols); 6970 } 6971 6972 if (r.size.height != frameSize.height) 6973 { 6974 frameSize.height = 6975 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra; 6976 } 6977 } 6978 6979 NSTRACE_RETURN_SIZE (frameSize); 6980 6981 return frameSize; 6982} 6983 6984 6985#ifdef NS_IMPL_COCOA 6986- (void)viewDidEndLiveResize 6987{ 6988 NSTRACE ("[EmacsView viewDidEndLiveResize]"); 6989 6990 [super viewDidEndLiveResize]; 6991 if (old_title != 0) 6992 { 6993 [[self window] setTitle: [NSString stringWithUTF8String: old_title]]; 6994 xfree (old_title); 6995 old_title = 0; 6996 } 6997 maximizing_resize = NO; 6998} 6999#endif /* NS_IMPL_COCOA */ 7000 7001 7002- (void)resizeWithOldSuperviewSize: (NSSize)oldSize 7003{ 7004 NSRect frame; 7005 int width, height; 7006 7007 NSTRACE ("[EmacsView resizeWithOldSuperviewSize:]"); 7008 7009 [super resizeWithOldSuperviewSize:oldSize]; 7010 7011 if (! FRAME_LIVE_P (emacsframe)) 7012 return; 7013 7014 frame = [[self superview] bounds]; 7015 width = (int)NSWidth (frame); 7016 height = (int)NSHeight (frame); 7017 7018 NSTRACE_SIZE ("New size", NSMakeSize (width, height)); 7019 7020 /* Reset the frame size to match the bounds of the superview (the 7021 NSWindow's contentView). We need to do this as sometimes the 7022 view's frame isn't resized correctly, or can end up with the 7023 wrong origin. */ 7024 [self setFrame:frame]; 7025 change_frame_size (emacsframe, width, height, false, YES, false); 7026 7027 SET_FRAME_GARBAGED (emacsframe); 7028 cancel_mouse_face (emacsframe); 7029 ns_send_appdefined (-1); 7030} 7031 7032 7033- (void)windowDidBecomeKey: (NSNotification *)notification 7034/* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */ 7035{ 7036 [self windowDidBecomeKey]; 7037} 7038 7039 7040- (void)windowDidBecomeKey /* for direct calls */ 7041{ 7042 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); 7043 struct frame *old_focus = dpyinfo->ns_focus_frame; 7044 7045 NSTRACE ("[EmacsView windowDidBecomeKey]"); 7046 7047 if (emacsframe != old_focus) 7048 dpyinfo->ns_focus_frame = emacsframe; 7049 7050 ns_frame_rehighlight (emacsframe); 7051 7052 if (emacs_event) 7053 { 7054 emacs_event->kind = FOCUS_IN_EVENT; 7055 EV_TRAILER ((id)nil); 7056 } 7057} 7058 7059 7060- (void)windowDidResignKey: (NSNotification *)notification 7061/* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */ 7062{ 7063 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); 7064 BOOL is_focus_frame = dpyinfo->ns_focus_frame == emacsframe; 7065 NSTRACE ("[EmacsView windowDidResignKey:]"); 7066 7067 if (is_focus_frame) 7068 dpyinfo->ns_focus_frame = 0; 7069 7070 emacsframe->mouse_moved = 0; 7071 ns_frame_rehighlight (emacsframe); 7072 7073 /* FIXME: for some reason needed on second and subsequent clicks away 7074 from sole-frame Emacs to get hollow box to show. */ 7075 if (!windowClosing && [[self window] isVisible] == YES) 7076 { 7077 gui_update_cursor (emacsframe, 1); 7078 ns_set_frame_alpha (emacsframe); 7079 } 7080 7081 if (any_help_event_p) 7082 { 7083 Lisp_Object frame; 7084 XSETFRAME (frame, emacsframe); 7085 help_echo_string = Qnil; 7086 gen_help_event (Qnil, frame, Qnil, Qnil, 0); 7087 any_help_event_p = NO; 7088 } 7089 7090 if (emacs_event && is_focus_frame) 7091 { 7092 emacs_event->kind = FOCUS_OUT_EVENT; 7093 EV_TRAILER ((id)nil); 7094 } 7095} 7096 7097 7098- (void)windowWillMiniaturize: sender 7099{ 7100 NSTRACE ("[EmacsView windowWillMiniaturize:]"); 7101} 7102 7103 7104- (void)setFrame:(NSRect)frameRect 7105{ 7106 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]", 7107 NSTRACE_ARG_RECT (frameRect)); 7108 7109 [super setFrame:(NSRect)frameRect]; 7110} 7111 7112 7113- (BOOL)isFlipped 7114{ 7115 return YES; 7116} 7117 7118 7119- (BOOL)isOpaque 7120{ 7121 return NO; 7122} 7123 7124 7125- (instancetype) initFrameFromEmacs: (struct frame *)f 7126{ 7127 NSTRACE ("[EmacsView initFrameFromEmacs:]"); 7128 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines); 7129 7130 windowClosing = NO; 7131 processingCompose = NO; 7132 scrollbarsNeedingUpdate = 0; 7133 fs_state = FULLSCREEN_NONE; 7134 fs_before_fs = next_maximized = -1; 7135 7136 fs_is_native = NO; 7137#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 7138#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 7139 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7) 7140#endif 7141 fs_is_native = ns_use_native_fullscreen; 7142#endif 7143 7144 maximized_width = maximized_height = -1; 7145 nonfs_window = nil; 7146 7147 ns_userRect = NSMakeRect (0, 0, 0, 0); 7148 [self initWithFrame: 7149 NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols), 7150 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines))]; 7151 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; 7152 7153 FRAME_NS_VIEW (f) = self; 7154 emacsframe = f; 7155#ifdef NS_IMPL_COCOA 7156 old_title = 0; 7157 maximizing_resize = NO; 7158#endif 7159 7160 [[EmacsWindow alloc] initWithEmacsFrame:f]; 7161 7162#ifdef NS_IMPL_COCOA 7163 /* These settings mean AppKit will retain the contents of the frame 7164 on resize. Unfortunately it also means the frame will not be 7165 automatically marked for display, but we can do that ourselves in 7166 resizeWithOldSuperviewSize. */ 7167 [self setWantsLayer:YES]; 7168 [self setLayerContentsRedrawPolicy: 7169 NSViewLayerContentsRedrawOnSetNeedsDisplay]; 7170 [self setLayerContentsPlacement:NSViewLayerContentsPlacementTopLeft]; 7171#endif 7172 7173 if (ns_drag_types) 7174 [self registerForDraggedTypes: ns_drag_types]; 7175 7176#if !defined (NS_IMPL_COCOA) \ 7177 || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 7178#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090 7179 if ([self respondsToSelector: @selector(allocateGState)]) 7180#endif 7181 [self allocateGState]; 7182#endif 7183 [NSApp registerServicesMenuSendTypes: ns_send_types 7184 returnTypes: [NSArray array]]; 7185 7186 ns_window_num++; 7187 return self; 7188} 7189 7190 7191- (void)windowDidMove: sender 7192{ 7193 NSWindow *win = [self window]; 7194 NSRect r = [win frame]; 7195 NSArray *screens = [NSScreen screens]; 7196 NSScreen *screen = [screens objectAtIndex: 0]; 7197 7198 NSTRACE ("[EmacsView windowDidMove:]"); 7199 7200 if (!emacsframe->output_data.ns) 7201 return; 7202 if (screen != nil) 7203 { 7204 emacsframe->left_pos = NSMinX (r) - NS_PARENT_WINDOW_LEFT_POS (emacsframe); 7205 emacsframe->top_pos = NS_PARENT_WINDOW_TOP_POS (emacsframe) - NSMaxY (r); 7206 7207 // FIXME: after event part below didExitFullScreen is not received 7208 // if (emacs_event) 7209 // { 7210 // emacs_event->kind = MOVE_FRAME_EVENT; 7211 // EV_TRAILER ((id)nil); 7212 // } 7213 } 7214} 7215 7216 7217/* Called AFTER method below, but before our windowWillResize call there leads 7218 to windowDidResize -> ns_set_window_size. Update emacs' notion of frame 7219 location so set_window_size moves the frame. */ 7220- (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame 7221{ 7222 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]" 7223 NSTRACE_FMT_RETURN "YES"), 7224 NSTRACE_ARG_RECT (newFrame)); 7225 7226 emacsframe->output_data.ns->zooming = 1; 7227 return YES; 7228} 7229 7230 7231/* Override to do something slightly nonstandard, but nice. First click on 7232 zoom button will zoom vertically. Second will zoom completely. Third 7233 returns to original. */ 7234- (NSRect)windowWillUseStandardFrame:(NSWindow *)sender 7235 defaultFrame:(NSRect)defaultFrame 7236{ 7237 // TODO: Rename to "currentFrame" and assign "result" properly in 7238 // all paths. 7239 NSRect result = [sender frame]; 7240 7241 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:" 7242 NSTRACE_FMT_RECT "]"), 7243 NSTRACE_ARG_RECT (defaultFrame)); 7244 NSTRACE_FSTYPE ("fs_state", fs_state); 7245 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs); 7246 NSTRACE_FSTYPE ("next_maximized", next_maximized); 7247 NSTRACE_RECT ("ns_userRect", ns_userRect); 7248 NSTRACE_RECT ("[sender frame]", [sender frame]); 7249 7250 if (fs_before_fs != -1) /* Entering fullscreen */ 7251 { 7252 NSTRACE_MSG ("Entering fullscreen"); 7253 result = defaultFrame; 7254 } 7255 else 7256 { 7257 // Save the window size and position (frame) before the resize. 7258 if (fs_state != FULLSCREEN_MAXIMIZED 7259 && fs_state != FULLSCREEN_WIDTH) 7260 { 7261 ns_userRect.size.width = result.size.width; 7262 ns_userRect.origin.x = result.origin.x; 7263 } 7264 7265 if (fs_state != FULLSCREEN_MAXIMIZED 7266 && fs_state != FULLSCREEN_HEIGHT) 7267 { 7268 ns_userRect.size.height = result.size.height; 7269 ns_userRect.origin.y = result.origin.y; 7270 } 7271 7272 NSTRACE_RECT ("ns_userRect (2)", ns_userRect); 7273 7274 if (next_maximized == FULLSCREEN_HEIGHT 7275 || (next_maximized == -1 7276 && abs ((int)(defaultFrame.size.height - result.size.height)) 7277 > FRAME_LINE_HEIGHT (emacsframe))) 7278 { 7279 /* first click */ 7280 NSTRACE_MSG ("FULLSCREEN_HEIGHT"); 7281 maximized_height = result.size.height = defaultFrame.size.height; 7282 maximized_width = -1; 7283 result.origin.y = defaultFrame.origin.y; 7284 if (ns_userRect.size.height != 0) 7285 { 7286 result.origin.x = ns_userRect.origin.x; 7287 result.size.width = ns_userRect.size.width; 7288 } 7289 [self setFSValue: FULLSCREEN_HEIGHT]; 7290#ifdef NS_IMPL_COCOA 7291 maximizing_resize = YES; 7292#endif 7293 } 7294 else if (next_maximized == FULLSCREEN_WIDTH) 7295 { 7296 NSTRACE_MSG ("FULLSCREEN_WIDTH"); 7297 maximized_width = result.size.width = defaultFrame.size.width; 7298 maximized_height = -1; 7299 result.origin.x = defaultFrame.origin.x; 7300 if (ns_userRect.size.width != 0) 7301 { 7302 result.origin.y = ns_userRect.origin.y; 7303 result.size.height = ns_userRect.size.height; 7304 } 7305 [self setFSValue: FULLSCREEN_WIDTH]; 7306 } 7307 else if (next_maximized == FULLSCREEN_MAXIMIZED 7308 || (next_maximized == -1 7309 && abs ((int)(defaultFrame.size.width - result.size.width)) 7310 > FRAME_COLUMN_WIDTH (emacsframe))) 7311 { 7312 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED"); 7313 7314 result = defaultFrame; /* second click */ 7315 maximized_width = result.size.width; 7316 maximized_height = result.size.height; 7317 [self setFSValue: FULLSCREEN_MAXIMIZED]; 7318#ifdef NS_IMPL_COCOA 7319 maximizing_resize = YES; 7320#endif 7321 } 7322 else 7323 { 7324 /* restore */ 7325 NSTRACE_MSG ("Restore"); 7326 result = ns_userRect.size.height ? ns_userRect : result; 7327 NSTRACE_RECT ("restore (2)", result); 7328 ns_userRect = NSMakeRect (0, 0, 0, 0); 7329#ifdef NS_IMPL_COCOA 7330 maximizing_resize = fs_state != FULLSCREEN_NONE; 7331#endif 7332 [self setFSValue: FULLSCREEN_NONE]; 7333 maximized_width = maximized_height = -1; 7334 } 7335 } 7336 7337 if (fs_before_fs == -1) next_maximized = -1; 7338 7339 NSTRACE_RECT ("Final ns_userRect", ns_userRect); 7340 NSTRACE_MSG ("Final maximized_width: %d", maximized_width); 7341 NSTRACE_MSG ("Final maximized_height: %d", maximized_height); 7342 NSTRACE_FSTYPE ("Final next_maximized", next_maximized); 7343 7344 [self windowWillResize: sender toSize: result.size]; 7345 7346 NSTRACE_RETURN_RECT (result); 7347 7348 return result; 7349} 7350 7351 7352- (void)windowDidDeminiaturize: sender 7353{ 7354 NSTRACE ("[EmacsView windowDidDeminiaturize:]"); 7355 if (!emacsframe->output_data.ns) 7356 return; 7357 7358 SET_FRAME_ICONIFIED (emacsframe, 0); 7359 SET_FRAME_VISIBLE (emacsframe, 1); 7360 windows_or_buffers_changed = 63; 7361 7362 if (emacs_event) 7363 { 7364 emacs_event->kind = DEICONIFY_EVENT; 7365 EV_TRAILER ((id)nil); 7366 } 7367} 7368 7369 7370- (void)windowDidExpose: sender 7371{ 7372 NSTRACE ("[EmacsView windowDidExpose:]"); 7373 if (!emacsframe->output_data.ns) 7374 return; 7375 7376 SET_FRAME_VISIBLE (emacsframe, 1); 7377 SET_FRAME_GARBAGED (emacsframe); 7378 7379 if (send_appdefined) 7380 ns_send_appdefined (-1); 7381} 7382 7383 7384- (void)windowDidMiniaturize: sender 7385{ 7386 NSTRACE ("[EmacsView windowDidMiniaturize:]"); 7387 if (!emacsframe->output_data.ns) 7388 return; 7389 7390 SET_FRAME_ICONIFIED (emacsframe, 1); 7391 SET_FRAME_VISIBLE (emacsframe, 0); 7392 7393 if (emacs_event) 7394 { 7395 emacs_event->kind = ICONIFY_EVENT; 7396 EV_TRAILER ((id)nil); 7397 } 7398} 7399 7400#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 7401- (NSApplicationPresentationOptions)window:(NSWindow *)window 7402 willUseFullScreenPresentationOptions: 7403 (NSApplicationPresentationOptions)proposedOptions 7404{ 7405 return proposedOptions|NSApplicationPresentationAutoHideToolbar; 7406} 7407#endif 7408 7409- (void)windowWillEnterFullScreen:(NSNotification *)notification 7410{ 7411 NSTRACE ("[EmacsView windowWillEnterFullScreen:]"); 7412 [self windowWillEnterFullScreen]; 7413} 7414- (void)windowWillEnterFullScreen /* provided for direct calls */ 7415{ 7416 NSTRACE ("[EmacsView windowWillEnterFullScreen]"); 7417 fs_before_fs = fs_state; 7418} 7419 7420- (void)windowDidEnterFullScreen:(NSNotification *)notification 7421{ 7422 NSTRACE ("[EmacsView windowDidEnterFullScreen:]"); 7423 [self windowDidEnterFullScreen]; 7424} 7425 7426- (void)windowDidEnterFullScreen /* provided for direct calls */ 7427{ 7428 NSTRACE ("[EmacsView windowDidEnterFullScreen]"); 7429 [self setFSValue: FULLSCREEN_BOTH]; 7430 if (! [self fsIsNative]) 7431 { 7432 [self windowDidBecomeKey]; 7433 [nonfs_window orderOut:self]; 7434 } 7435 else 7436 { 7437#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \ 7438 && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 7439 unsigned val = (unsigned)[NSApp presentationOptions]; 7440 7441 // Mac OS X 10.7 bug fix, the menu won't appear without this. 7442 // val is non-zero on other macOS versions. 7443 if (val == 0) 7444 { 7445 NSApplicationPresentationOptions options 7446 = NSApplicationPresentationAutoHideDock 7447 | NSApplicationPresentationAutoHideMenuBar 7448 | NSApplicationPresentationFullScreen 7449 | NSApplicationPresentationAutoHideToolbar; 7450 7451 [NSApp setPresentationOptions: options]; 7452 } 7453#endif 7454 } 7455} 7456 7457- (void)windowWillExitFullScreen:(NSNotification *)notification 7458{ 7459 NSTRACE ("[EmacsView windowWillExitFullScreen:]"); 7460 [self windowWillExitFullScreen]; 7461} 7462 7463- (void)windowWillExitFullScreen /* provided for direct calls */ 7464{ 7465 NSTRACE ("[EmacsView windowWillExitFullScreen]"); 7466 if (!FRAME_LIVE_P (emacsframe)) 7467 { 7468 NSTRACE_MSG ("Ignored (frame dead)"); 7469 return; 7470 } 7471 if (next_maximized != -1) 7472 fs_before_fs = next_maximized; 7473} 7474 7475- (void)windowDidExitFullScreen:(NSNotification *)notification 7476{ 7477 NSTRACE ("[EmacsView windowDidExitFullScreen:]"); 7478 [self windowDidExitFullScreen]; 7479} 7480 7481- (void)windowDidExitFullScreen /* provided for direct calls */ 7482{ 7483 NSTRACE ("[EmacsView windowDidExitFullScreen]"); 7484 if (!FRAME_LIVE_P (emacsframe)) 7485 { 7486 NSTRACE_MSG ("Ignored (frame dead)"); 7487 return; 7488 } 7489 [self setFSValue: fs_before_fs]; 7490 fs_before_fs = -1; 7491#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 7492 [self updateCollectionBehavior]; 7493#endif 7494 7495 if (next_maximized != -1) 7496 [[self window] performZoom:self]; 7497} 7498 7499- (BOOL)fsIsNative 7500{ 7501 return fs_is_native; 7502} 7503 7504- (BOOL)isFullscreen 7505{ 7506 BOOL res; 7507 7508 if (! fs_is_native) 7509 { 7510 res = (nonfs_window != nil); 7511 } 7512 else 7513 { 7514#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 7515 res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0); 7516#else 7517 res = NO; 7518#endif 7519 } 7520 7521 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d", 7522 (int) res); 7523 7524 return res; 7525} 7526 7527#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 7528- (void)updateCollectionBehavior 7529{ 7530 NSTRACE ("[EmacsView updateCollectionBehavior]"); 7531 7532 if (! [self isFullscreen]) 7533 { 7534 NSWindow *win = [self window]; 7535 NSWindowCollectionBehavior b = [win collectionBehavior]; 7536 if (ns_use_native_fullscreen) 7537 { 7538 if (FRAME_PARENT_FRAME (emacsframe)) 7539 { 7540 b &= ~NSWindowCollectionBehaviorFullScreenPrimary; 7541 b |= NSWindowCollectionBehaviorFullScreenAuxiliary; 7542 } 7543 else 7544 { 7545 b |= NSWindowCollectionBehaviorFullScreenPrimary; 7546 b &= ~NSWindowCollectionBehaviorFullScreenAuxiliary; 7547 } 7548 } 7549 else 7550 { 7551 b &= ~NSWindowCollectionBehaviorFullScreenPrimary; 7552 } 7553 7554 [win setCollectionBehavior: b]; 7555#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 7556 if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7) 7557#endif 7558 fs_is_native = ns_use_native_fullscreen; 7559 } 7560} 7561#endif 7562 7563- (void)toggleFullScreen: (id)sender 7564{ 7565 EmacsWindow *w, *fw; 7566 BOOL onFirstScreen; 7567 struct frame *f; 7568 NSRect r, wr; 7569 NSColor *col; 7570 7571 NSTRACE ("[EmacsView toggleFullScreen:]"); 7572 7573 if (fs_is_native) 7574 { 7575#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 7576#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 7577 if ([[self window] respondsToSelector: @selector(toggleFullScreen:)]) 7578#endif 7579 [[self window] toggleFullScreen:sender]; 7580#endif 7581 return; 7582 } 7583 7584 w = (EmacsWindow *)[self window]; 7585 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]]; 7586 f = emacsframe; 7587 wr = [w frame]; 7588 col = [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND 7589 (FACE_FROM_ID (f, DEFAULT_FACE_ID))]; 7590 7591 if (fs_state != FULLSCREEN_BOTH) 7592 { 7593 NSScreen *screen = [w screen]; 7594 7595#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 7596 /* Hide ghost menu bar on secondary monitor? */ 7597 if (! onFirstScreen 7598#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 7599 && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] 7600#endif 7601 ) 7602 onFirstScreen = [NSScreen screensHaveSeparateSpaces]; 7603#endif 7604 /* Hide dock and menubar if we are on the primary screen. */ 7605 if (onFirstScreen) 7606 { 7607#ifdef NS_IMPL_COCOA 7608 NSApplicationPresentationOptions options 7609 = NSApplicationPresentationAutoHideDock 7610 | NSApplicationPresentationAutoHideMenuBar; 7611 7612 [NSApp setPresentationOptions: options]; 7613#else 7614 [NSMenu setMenuBarVisible:NO]; 7615#endif 7616 } 7617 7618 fw = [[EmacsWindow alloc] initWithEmacsFrame:emacsframe 7619 fullscreen:YES 7620 screen:screen]; 7621 7622 f->border_width = 0; 7623 7624 nonfs_window = w; 7625 7626 [self windowWillEnterFullScreen]; 7627 [fw makeKeyAndOrderFront:NSApp]; 7628 [w orderOut:self]; 7629 r = [fw frameRectForContentRect:[screen frame]]; 7630 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation]; 7631 [self windowDidEnterFullScreen]; 7632 [fw display]; 7633 } 7634 else 7635 { 7636 fw = w; 7637 w = nonfs_window; 7638 nonfs_window = nil; 7639 7640 if (onFirstScreen) 7641 { 7642#ifdef NS_IMPL_COCOA 7643 [NSApp setPresentationOptions: NSApplicationPresentationDefault]; 7644#else 7645 [NSMenu setMenuBarVisible:YES]; 7646#endif 7647 } 7648 7649 [w setContentView:[fw contentView]]; 7650 [w setBackgroundColor: col]; 7651 if ([col alphaComponent] != (EmacsCGFloat) 1.0) 7652 [w setOpaque: NO]; 7653 7654 f->border_width = [w borderWidth]; 7655 7656 // To do: consider using [NSNotificationCenter postNotificationName:] to 7657 // send notifications. 7658 7659 [self windowWillExitFullScreen]; 7660 [fw setFrame:[[w contentView] frame] 7661 display:YES animate:ns_use_fullscreen_animation]; 7662 [fw close]; 7663 [w makeKeyAndOrderFront:NSApp]; 7664 [self windowDidExitFullScreen]; 7665 } 7666} 7667 7668- (void)handleFS 7669{ 7670 NSTRACE ("[EmacsView handleFS]"); 7671 7672 if (fs_state != emacsframe->want_fullscreen) 7673 { 7674 if (fs_state == FULLSCREEN_BOTH) 7675 { 7676 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH"); 7677 [self toggleFullScreen:self]; 7678 } 7679 7680 switch (emacsframe->want_fullscreen) 7681 { 7682 case FULLSCREEN_BOTH: 7683 NSTRACE_MSG ("FULLSCREEN_BOTH"); 7684 [self toggleFullScreen:self]; 7685 break; 7686 case FULLSCREEN_WIDTH: 7687 NSTRACE_MSG ("FULLSCREEN_WIDTH"); 7688 next_maximized = FULLSCREEN_WIDTH; 7689 if (fs_state != FULLSCREEN_BOTH) 7690 [[self window] performZoom:self]; 7691 break; 7692 case FULLSCREEN_HEIGHT: 7693 NSTRACE_MSG ("FULLSCREEN_HEIGHT"); 7694 next_maximized = FULLSCREEN_HEIGHT; 7695 if (fs_state != FULLSCREEN_BOTH) 7696 [[self window] performZoom:self]; 7697 break; 7698 case FULLSCREEN_MAXIMIZED: 7699 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED"); 7700 next_maximized = FULLSCREEN_MAXIMIZED; 7701 if (fs_state != FULLSCREEN_BOTH) 7702 [[self window] performZoom:self]; 7703 break; 7704 case FULLSCREEN_NONE: 7705 NSTRACE_MSG ("FULLSCREEN_NONE"); 7706 if (fs_state != FULLSCREEN_BOTH) 7707 { 7708 next_maximized = FULLSCREEN_NONE; 7709 [[self window] performZoom:self]; 7710 } 7711 break; 7712 } 7713 7714 emacsframe->want_fullscreen = FULLSCREEN_NONE; 7715 } 7716 7717} 7718 7719- (void) setFSValue: (int)value 7720{ 7721 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]", 7722 NSTRACE_ARG_FSTYPE(value)); 7723 7724 Lisp_Object lval = Qnil; 7725 switch (value) 7726 { 7727 case FULLSCREEN_BOTH: 7728 lval = Qfullboth; 7729 break; 7730 case FULLSCREEN_WIDTH: 7731 lval = Qfullwidth; 7732 break; 7733 case FULLSCREEN_HEIGHT: 7734 lval = Qfullheight; 7735 break; 7736 case FULLSCREEN_MAXIMIZED: 7737 lval = Qmaximized; 7738 break; 7739 } 7740 store_frame_param (emacsframe, Qfullscreen, lval); 7741 fs_state = value; 7742} 7743 7744- (void)mouseEntered: (NSEvent *)theEvent 7745{ 7746 NSTRACE ("[EmacsView mouseEntered:]"); 7747 if (emacsframe) 7748 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time 7749 = EV_TIMESTAMP (theEvent); 7750} 7751 7752 7753- (void)mouseExited: (NSEvent *)theEvent 7754{ 7755 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL; 7756 7757 NSTRACE ("[EmacsView mouseExited:]"); 7758 7759 if (!hlinfo) 7760 return; 7761 7762 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time 7763 = EV_TIMESTAMP (theEvent); 7764 7765 if (emacsframe == hlinfo->mouse_face_mouse_frame) 7766 { 7767 clear_mouse_face (hlinfo); 7768 hlinfo->mouse_face_mouse_frame = 0; 7769 } 7770} 7771 7772 7773- (instancetype)menuDown: sender 7774{ 7775 NSTRACE ("[EmacsView menuDown:]"); 7776 if (context_menu_value == -1) 7777 context_menu_value = [sender tag]; 7778 else 7779 { 7780 NSInteger tag = [sender tag]; 7781 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used, 7782 emacsframe->menu_bar_vector, 7783 (void *)tag); 7784 } 7785 7786 ns_send_appdefined (-1); 7787 return self; 7788} 7789 7790 7791/* This gets called on toolbar button click. */ 7792- (instancetype)toolbarClicked: (id)item 7793{ 7794 NSEvent *theEvent; 7795 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS; 7796 7797 NSTRACE ("[EmacsView toolbarClicked:]"); 7798 7799 if (!emacs_event) 7800 return self; 7801 7802 theEvent = [[self window] currentEvent]; 7803 emacs_event->kind = TOOL_BAR_EVENT; 7804 /* XSETINT (emacs_event->code, 0); */ 7805 emacs_event->arg = AREF (emacsframe->tool_bar_items, 7806 idx + TOOL_BAR_ITEM_KEY); 7807 emacs_event->modifiers = EV_MODIFIERS (theEvent); 7808 EV_TRAILER (theEvent); 7809 return self; 7810} 7811 7812 7813- (instancetype)toggleToolbar: (id)sender 7814{ 7815 NSTRACE ("[EmacsView toggleToolbar:]"); 7816 7817 if (!emacs_event) 7818 return self; 7819 7820 emacs_event->kind = NS_NONKEY_EVENT; 7821 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR; 7822 EV_TRAILER ((id)nil); 7823 return self; 7824} 7825 7826 7827#ifdef NS_IMPL_COCOA 7828- (CALayer *)makeBackingLayer; 7829{ 7830 EmacsLayer *l = [[EmacsLayer alloc] 7831 initWithColorSpace:[[[self window] colorSpace] CGColorSpace]]; 7832 [l setDelegate:(id)self]; 7833 [l setContentsScale:[[self window] backingScaleFactor]]; 7834 7835 return l; 7836} 7837 7838 7839- (void)lockFocus 7840{ 7841 NSTRACE ("[EmacsView lockFocus]"); 7842 7843 if ([self wantsLayer]) 7844 { 7845 CGContextRef context = [(EmacsLayer*)[self layer] getContext]; 7846 7847 [NSGraphicsContext 7848 setCurrentContext:[NSGraphicsContext 7849 graphicsContextWithCGContext:context 7850 flipped:YES]]; 7851 } 7852#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 7853 else 7854 [super lockFocus]; 7855#endif 7856} 7857 7858 7859- (void)unlockFocus 7860{ 7861 NSTRACE ("[EmacsView unlockFocus]"); 7862 7863 if ([self wantsLayer]) 7864 { 7865 [NSGraphicsContext setCurrentContext:nil]; 7866 [self setNeedsDisplay:YES]; 7867 } 7868#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 7869 else 7870 { 7871 [super unlockFocus]; 7872 [super flushWindow]; 7873 } 7874#endif 7875} 7876 7877 7878- (void)windowDidChangeBackingProperties:(NSNotification *)notification 7879 /* Update the drawing buffer when the backing properties change. */ 7880{ 7881 NSTRACE ("EmacsView windowDidChangeBackingProperties:]"); 7882 7883 if ([self wantsLayer]) 7884 { 7885 NSRect frame = [self frame]; 7886 EmacsLayer *layer = (EmacsLayer *)[self layer]; 7887 7888 [layer setContentsScale:[[notification object] backingScaleFactor]]; 7889 [layer setColorSpace:[[[notification object] colorSpace] CGColorSpace]]; 7890 7891 ns_clear_frame (emacsframe); 7892 expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame)); 7893 } 7894} 7895#endif /* NS_IMPL_COCOA */ 7896 7897 7898- (void)copyRect:(NSRect)srcRect to:(NSPoint)dest 7899{ 7900 NSTRACE ("[EmacsView copyRect:To:]"); 7901 NSTRACE_RECT ("Source", srcRect); 7902 NSTRACE_POINT ("Destination", dest); 7903 7904 NSRect dstRect = NSMakeRect (dest.x, dest.y, NSWidth (srcRect), 7905 NSHeight (srcRect)); 7906 NSRect frame = [self frame]; 7907 7908 /* TODO: This check is an attempt to debug a rare graphical glitch 7909 on macOS and should be removed before the Emacs 28 release. */ 7910 if (!NSContainsRect (frame, srcRect) 7911 || !NSContainsRect (frame, dstRect)) 7912 { 7913 NSLog (@"[EmacsView copyRect:to:] Attempting to copy to or " 7914 "from an area outside the graphics buffer."); 7915 NSLog (@" Frame: (%f, %f) %f×%f", 7916 NSMinX (frame), NSMinY (frame), 7917 NSWidth (frame), NSHeight (frame)); 7918 NSLog (@" Source: (%f, %f) %f×%f", 7919 NSMinX (srcRect), NSMinY (srcRect), 7920 NSWidth (srcRect), NSHeight (srcRect)); 7921 NSLog (@" Destination: (%f, %f) %f×%f", 7922 NSMinX (dstRect), NSMinY (dstRect), 7923 NSWidth (dstRect), NSHeight (dstRect)); 7924 } 7925 7926#ifdef NS_IMPL_COCOA 7927 if ([self wantsLayer]) 7928 { 7929 double scale = [[self window] backingScaleFactor]; 7930 CGContextRef context = [(EmacsLayer *)[self layer] getContext]; 7931 int bpp = CGBitmapContextGetBitsPerPixel (context) / 8; 7932 void *pixels = CGBitmapContextGetData (context); 7933 int rowSize = CGBitmapContextGetBytesPerRow (context); 7934 int srcRowSize = NSWidth (srcRect) * scale * bpp; 7935 void *srcPixels = (char *) pixels 7936 + (int) (NSMinY (srcRect) * scale * rowSize 7937 + NSMinX (srcRect) * scale * bpp); 7938 void *dstPixels = (char *) pixels 7939 + (int) (dest.y * scale * rowSize 7940 + dest.x * scale * bpp); 7941 7942 if (NSIntersectsRect (srcRect, dstRect) 7943 && NSMinY (srcRect) < NSMinY (dstRect)) 7944 for (int y = NSHeight (srcRect) * scale - 1 ; y >= 0 ; y--) 7945 memmove ((char *) dstPixels + y * rowSize, 7946 (char *) srcPixels + y * rowSize, 7947 srcRowSize); 7948 else 7949 for (int y = 0 ; y < NSHeight (srcRect) * scale ; y++) 7950 memmove ((char *) dstPixels + y * rowSize, 7951 (char *) srcPixels + y * rowSize, 7952 srcRowSize); 7953 7954 } 7955#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 7956 else 7957 { 7958#endif 7959#endif /* NS_IMPL_COCOA */ 7960 7961#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 7962 hide_bell(); // Ensure the bell image isn't scrolled. 7963 7964 ns_focus (emacsframe, &dstRect, 1); 7965 [self scrollRect: srcRect 7966 by: NSMakeSize (dstRect.origin.x - srcRect.origin.x, 7967 dstRect.origin.y - srcRect.origin.y)]; 7968 ns_unfocus (emacsframe); 7969#endif 7970#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400 7971 } 7972#endif 7973} 7974 7975 7976#ifdef NS_IMPL_COCOA 7977/* If the frame has been garbaged but the toolkit wants to draw, for 7978 example when resizing the frame, we end up with a blank screen. 7979 Sometimes this results in an unpleasant flicker, so try to 7980 redisplay before drawing. 7981 7982 This used to be done in viewWillDraw, but with the custom layer 7983 that method is not called. We cannot call redisplay directly from 7984 [NSView layout], because it may trigger another round of layout by 7985 changing the frame size and recursive layout calls are banned. It 7986 appears to be safe to call redisplay here. */ 7987- (void)layoutSublayersOfLayer:(CALayer *)layer 7988{ 7989 if (!redisplaying_p && FRAME_GARBAGED_P (emacsframe)) 7990 { 7991 /* If there is IO going on when redisplay is run here Emacs 7992 crashes. I think it's because this code will always be run 7993 within the run loop and for whatever reason processing input 7994 is dangerous. This technique was stolen wholesale from 7995 nsmenu.m and seems to work. */ 7996 bool owfi = waiting_for_input; 7997 waiting_for_input = 0; 7998 block_input (); 7999 8000 redisplay (); 8001 8002 unblock_input (); 8003 waiting_for_input = owfi; 8004 } 8005} 8006#endif 8007 8008- (void)drawRect: (NSRect)rect 8009{ 8010 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]", 8011 NSTRACE_ARG_RECT(rect)); 8012 8013 if (!emacsframe || !emacsframe->output_data.ns) 8014 return; 8015 8016 int x = NSMinX (rect), y = NSMinY (rect); 8017 int width = NSWidth (rect), height = NSHeight (rect); 8018 8019 ns_clear_frame_area (emacsframe, x, y, width, height); 8020 block_input (); 8021 expose_frame (emacsframe, x, y, width, height); 8022 unblock_input (); 8023} 8024 8025 8026/* NSDraggingDestination protocol methods. Actually this is not really a 8027 protocol, but a category of Object. O well... */ 8028 8029-(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender 8030{ 8031 NSTRACE ("[EmacsView draggingEntered:]"); 8032 return NSDragOperationGeneric; 8033} 8034 8035 8036-(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender 8037{ 8038 return YES; 8039} 8040 8041 8042-(BOOL)performDragOperation: (id <NSDraggingInfo>) sender 8043{ 8044 id pb; 8045 int x, y; 8046 NSString *type; 8047 NSEvent *theEvent = [[self window] currentEvent]; 8048 NSPoint position; 8049 NSDragOperation op = [sender draggingSourceOperationMask]; 8050 Lisp_Object operations = Qnil; 8051 Lisp_Object strings = Qnil; 8052 Lisp_Object type_sym; 8053 8054 NSTRACE ("[EmacsView performDragOperation:]"); 8055 8056 if (!emacs_event) 8057 return NO; 8058 8059 position = [self convertPoint: [sender draggingLocation] fromView: nil]; 8060 x = lrint (position.x); y = lrint (position.y); 8061 8062 pb = [sender draggingPasteboard]; 8063 type = [pb availableTypeFromArray: ns_drag_types]; 8064 8065 /* We used to convert these drag operations to keyboard modifiers, 8066 but because they can be set by the sending program as well as the 8067 keyboard modifiers it was difficult to work out a sensible key 8068 mapping for drag and drop. */ 8069 if (op & NSDragOperationLink) 8070 operations = Fcons (Qns_drag_operation_link, operations); 8071 if (op & NSDragOperationCopy) 8072 operations = Fcons (Qns_drag_operation_copy, operations); 8073 if (op & NSDragOperationGeneric || NILP (operations)) 8074 operations = Fcons (Qns_drag_operation_generic, operations); 8075 8076 if (type == 0) 8077 { 8078 return NO; 8079 } 8080#if NS_USE_NSPasteboardTypeFileURL != 0 8081 else if ([type isEqualToString: NSPasteboardTypeFileURL]) 8082 { 8083 type_sym = Qfile; 8084 8085 NSArray *urls = [pb readObjectsForClasses: @[[NSURL self]] 8086 options: nil]; 8087 NSEnumerator *uenum = [urls objectEnumerator]; 8088 NSURL *url; 8089 while ((url = [uenum nextObject])) 8090 strings = Fcons ([[url path] lispString], strings); 8091 } 8092#else // !NS_USE_NSPasteboardTypeFileURL 8093 else if ([type isEqualToString: NSFilenamesPboardType]) 8094 { 8095 NSArray *files; 8096 NSEnumerator *fenum; 8097 NSString *file; 8098 8099 if (!(files = [pb propertyListForType: type])) 8100 return NO; 8101 8102 type_sym = Qfile; 8103 8104 fenum = [files objectEnumerator]; 8105 while ( (file = [fenum nextObject]) ) 8106 strings = Fcons ([file lispString], strings); 8107 } 8108#endif // !NS_USE_NSPasteboardTypeFileURL 8109 else if ([type isEqualToString: NSPasteboardTypeURL]) 8110 { 8111 NSURL *url = [NSURL URLFromPasteboard: pb]; 8112 if (url == nil) return NO; 8113 8114 type_sym = Qurl; 8115 8116 strings = list1 ([[url absoluteString] lispString]); 8117 } 8118 else if ([type isEqualToString: NSPasteboardTypeString] 8119 || [type isEqualToString: NSPasteboardTypeTabularText]) 8120 { 8121 NSString *data; 8122 8123 if (! (data = [pb stringForType: type])) 8124 return NO; 8125 8126 type_sym = Qnil; 8127 8128 strings = list1 ([data lispString]); 8129 } 8130 else 8131 { 8132 fputs ("Invalid data type in dragging pasteboard\n", stderr); 8133 return NO; 8134 } 8135 8136 emacs_event->kind = DRAG_N_DROP_EVENT; 8137 XSETINT (emacs_event->x, x); 8138 XSETINT (emacs_event->y, y); 8139 emacs_event->modifiers = 0; 8140 8141 emacs_event->arg = Fcons (type_sym, 8142 Fcons (operations, 8143 strings)); 8144 EV_TRAILER (theEvent); 8145 8146 return YES; 8147} 8148 8149 8150- (id) validRequestorForSendType: (NSString *)typeSent 8151 returnType: (NSString *)typeReturned 8152{ 8153 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]"); 8154 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound 8155 && typeReturned == nil) 8156 { 8157 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING))) 8158 return self; 8159 } 8160 8161 return [super validRequestorForSendType: typeSent 8162 returnType: typeReturned]; 8163} 8164 8165 8166/* The next two methods are part of NSServicesRequests informal protocol, 8167 supposedly called when a services menu item is chosen from this app. 8168 But this should not happen because we override the services menu with our 8169 own entries which call ns-perform-service. 8170 Nonetheless, it appeared to happen (under strange circumstances): bug#1435. 8171 So let's at least stub them out until further investigation can be done. */ 8172 8173- (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb 8174{ 8175 /* We could call ns_string_from_pasteboard(pboard) here but then it should 8176 be written into the buffer in place of the existing selection. 8177 Ordinary service calls go through functions defined in ns-win.el. */ 8178 return NO; 8179} 8180 8181- (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types 8182{ 8183 NSArray *typesDeclared; 8184 Lisp_Object val; 8185 8186 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]"); 8187 8188 /* We only support NSPasteboardTypeString. */ 8189 if ([types containsObject:NSPasteboardTypeString] == NO) { 8190 return NO; 8191 } 8192 8193 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING); 8194 if (CONSP (val) && SYMBOLP (XCAR (val))) 8195 { 8196 val = XCDR (val); 8197 if (CONSP (val) && NILP (XCDR (val))) 8198 val = XCAR (val); 8199 } 8200 if (! STRINGP (val)) 8201 return NO; 8202 8203 typesDeclared = [NSArray arrayWithObject:NSPasteboardTypeString]; 8204 [pb declareTypes:typesDeclared owner:nil]; 8205 ns_string_to_pasteboard (pb, val); 8206 return YES; 8207} 8208 8209 8210/* setMini = YES means set from internal (gives a finder icon), NO means set nil 8211 (gives a miniaturized version of the window); currently we use the latter for 8212 frames whose active buffer doesn't correspond to any file 8213 (e.g., '*scratch*'). */ 8214- (instancetype)setMiniwindowImage: (BOOL) setMini 8215{ 8216 id image = [[self window] miniwindowImage]; 8217 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini); 8218 8219 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation 8220 about "AppleDockIconEnabled" notwithstanding, however the set message 8221 below has its effect nonetheless. */ 8222 if (image != emacsframe->output_data.ns->miniimage) 8223 { 8224 if (image && [image isKindOfClass: [EmacsImage class]]) 8225 [image release]; 8226 [[self window] setMiniwindowImage: 8227 setMini ? emacsframe->output_data.ns->miniimage : nil]; 8228 } 8229 8230 return self; 8231} 8232 8233 8234- (int) fullscreenState 8235{ 8236 return fs_state; 8237} 8238 8239@end /* EmacsView */ 8240 8241 8242 8243/* ========================================================================== 8244 8245 EmacsWindow implementation 8246 8247 ========================================================================== */ 8248 8249@implementation EmacsWindow 8250 8251 8252- (instancetype) initWithEmacsFrame:(struct frame *)f 8253{ 8254 return [self initWithEmacsFrame:f fullscreen:NO screen:nil]; 8255} 8256 8257 8258- (instancetype) initWithEmacsFrame:(struct frame *)f 8259 fullscreen:(BOOL)fullscreen 8260 screen:(NSScreen *)screen 8261{ 8262 NSWindowStyleMask styleMask; 8263 8264 NSTRACE ("[EmacsWindow initWithEmacsFrame:fullscreen:screen:]"); 8265 8266 if (fullscreen) 8267 styleMask = NSWindowStyleMaskBorderless; 8268 else if (FRAME_UNDECORATED (f)) 8269 { 8270 styleMask = NSWindowStyleMaskBorderless; 8271#ifdef NS_IMPL_COCOA 8272 styleMask |= NSWindowStyleMaskResizable; 8273#endif 8274 } 8275 else 8276 styleMask = NSWindowStyleMaskTitled 8277 | NSWindowStyleMaskResizable 8278 | NSWindowStyleMaskMiniaturizable 8279 | NSWindowStyleMaskClosable; 8280 8281 self = [super initWithContentRect: 8282 NSMakeRect (0, 0, 8283 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols), 8284 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines)) 8285 styleMask:styleMask 8286 backing:NSBackingStoreBuffered 8287 defer:YES 8288 screen:screen]; 8289 if (self) 8290 { 8291 NSString *name; 8292 NSColor *col; 8293 NSScreen *screen = [self screen]; 8294 EmacsView *view = FRAME_NS_VIEW (f); 8295 8296 [self setDelegate:view]; 8297 [[self contentView] addSubview:view]; 8298 [self makeFirstResponder:view]; 8299 8300#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090 8301#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090 8302 if ([self respondsToSelector: @selector(useOptimizedDrawing:)]) 8303#endif 8304 [self useOptimizedDrawing:YES]; 8305#endif 8306 8307 [self setAcceptsMouseMovedEvents:YES]; 8308 8309 name = NILP (f->name) ? @"Emacs" : [NSString stringWithLispString:f->name]; 8310 [self setTitle:name]; 8311 8312 if (!NILP (f->icon_name)) 8313 [self setMiniwindowTitle: 8314 [NSString stringWithLispString:f->icon_name]]; 8315 8316 [self setAppearance]; 8317 8318#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 8319 if ([self respondsToSelector:@selector(titlebarAppearsTransparent)]) 8320 [self setTitlebarAppearsTransparent:FRAME_NS_TRANSPARENT_TITLEBAR (f)]; 8321#endif 8322 8323 [self setParentChildRelationships]; 8324 8325 if (FRAME_Z_GROUP (f) != z_group_none) 8326 [self setLevel:NSNormalWindowLevel + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1)]; 8327 8328 if (screen != 0) 8329 { 8330 NSPoint pt = NSMakePoint 8331 (IN_BOUND (-SCREENMAX, f->left_pos 8332 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX), 8333 IN_BOUND (-SCREENMAX, 8334 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos, 8335 SCREENMAX)); 8336 8337 [self setFrameTopLeftPoint:pt]; 8338 8339 NSTRACE_RECT ("new frame", [self frame]); 8340 } 8341 8342 f->border_width = [self borderWidth]; 8343 8344 col = [NSColor colorWithUnsignedLong:NS_FACE_BACKGROUND 8345 (FACE_FROM_ID (f, DEFAULT_FACE_ID))]; 8346 [self setBackgroundColor:col]; 8347 if ([col alphaComponent] != (EmacsCGFloat) 1.0) 8348 [self setOpaque:NO]; 8349 8350 /* toolbar support */ 8351 [self createToolbar:f]; 8352 8353 /* macOS Sierra automatically enables tabbed windows. We can't 8354 allow this to be enabled until it's available on a Free system. 8355 Currently it only happens by accident and is buggy anyway. */ 8356#ifdef NS_IMPL_COCOA 8357 if ([self respondsToSelector:@selector(setTabbingMode:)]) 8358 [self setTabbingMode:NSWindowTabbingModeDisallowed]; 8359#endif 8360 } 8361 8362 return self; 8363} 8364 8365 8366- (void)createToolbar: (struct frame *)f 8367{ 8368 if (FRAME_UNDECORATED (f) || !FRAME_EXTERNAL_TOOL_BAR (f)) 8369 return; 8370 8371 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f); 8372 8373 EmacsToolbar *toolbar = [[EmacsToolbar alloc] 8374 initForView:view 8375 withIdentifier:[NSString stringWithLispString:f->name]]; 8376 8377 [self setToolbar:toolbar]; 8378 update_frame_tool_bar_1 (f, toolbar); 8379 8380#ifdef NS_IMPL_COCOA 8381 { 8382 NSButton *toggleButton; 8383 toggleButton = [self standardWindowButton:NSWindowToolbarButton]; 8384 [toggleButton setTarget:view]; 8385 [toggleButton setAction:@selector (toggleToolbar:)]; 8386 } 8387#endif 8388} 8389 8390- (void)dealloc 8391{ 8392 NSTRACE ("[EmacsWindow dealloc]"); 8393 8394 /* We need to release the toolbar ourselves. */ 8395 [[self toolbar] release]; 8396 [super dealloc]; 8397} 8398 8399- (NSInteger) borderWidth 8400{ 8401 return NSWidth ([self frame]) - NSWidth ([[self contentView] frame]); 8402} 8403 8404 8405- (void)setParentChildRelationships 8406 /* After certain operations, for example making a frame visible or 8407 resetting the NSWindow through modifying the undecorated status, 8408 the parent/child relationship may be broken. We can also use 8409 this method to set them, as long as the frame struct already has 8410 the correct relationship set. */ 8411{ 8412 NSTRACE ("[EmacsWindow setParentChildRelationships]"); 8413 8414 Lisp_Object frame, tail; 8415 EmacsView *ourView = (EmacsView *)[self delegate]; 8416 struct frame *ourFrame = ourView->emacsframe; 8417 struct frame *parentFrame = FRAME_PARENT_FRAME (ourFrame); 8418 EmacsWindow *oldParentWindow = (EmacsWindow *)[self parentWindow]; 8419 8420 8421#ifdef NS_IMPL_COCOA 8422 /* We have to set the accessibility subroles and/or the collection 8423 behaviors early otherwise child windows may not go fullscreen as 8424 expected later. */ 8425 8426#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000 8427 if ([child respondsToSelector:@selector(setAccessibilitySubrole:)]) 8428#endif 8429 /* Set the accessibility subroles. */ 8430 if (parentFrame) 8431 [self setAccessibilitySubrole:NSAccessibilityFloatingWindowSubrole]; 8432 else 8433 [self setAccessibilitySubrole:NSAccessibilityStandardWindowSubrole]; 8434 8435#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 8436 [ourView updateCollectionBehavior]; 8437#endif 8438#endif 8439 8440 8441 /* Check if we have an incorrectly set parent. */ 8442 if ((! parentFrame && oldParentWindow) 8443 || (parentFrame && oldParentWindow 8444 && ((EmacsView *)[oldParentWindow delegate])->emacsframe != parentFrame)) 8445 { 8446 [[self parentWindow] removeChildWindow:self]; 8447 8448#ifdef NS_IMPL_COCOA 8449#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 8450 if ([ourView respondsToSelector:@selector (toggleFullScreen)] 8451#endif 8452 /* If we are the descendent of a fullscreen window and we 8453 have no new parent, go fullscreen. */ 8454 { 8455 NSWindow *parent = (NSWindow *)oldParentWindow; 8456 while (parent) 8457 { 8458 if (([parent styleMask] & NSWindowStyleMaskFullScreen) != 0) 8459 { 8460 [ourView toggleFullScreen:self]; 8461 break; 8462 } 8463 parent = [parent parentWindow]; 8464 } 8465 } 8466#endif 8467 } 8468 8469 if (parentFrame) 8470 { 8471 NSWindow *parentWindow = [FRAME_NS_VIEW (parentFrame) window]; 8472 8473#ifdef NS_IMPL_COCOA 8474#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 8475 if ([ourView respondsToSelector:@selector (toggleFullScreen)] 8476#endif 8477 /* Child frames must not be fullscreen. */ 8478 if ([ourView fsIsNative] && [ourView isFullscreen]) 8479 [ourView toggleFullScreen:self]; 8480#endif 8481 8482 [parentWindow addChildWindow:self 8483 ordered:NSWindowAbove]; 8484 } 8485 8486 /* Check our child windows are configured correctly. */ 8487 FOR_EACH_FRAME (tail, frame) 8488 { 8489 if (FRAME_PARENT_FRAME (XFRAME (frame)) == ourFrame) 8490 [(EmacsWindow *)[FRAME_NS_VIEW (XFRAME (frame)) window] setParentChildRelationships]; 8491 } 8492} 8493 8494 8495/* It seems the only way to reorder child frames is by removing them 8496 from the parent and then reattaching them in the correct order. */ 8497 8498- (void)orderFront:(id)sender 8499{ 8500 NSTRACE ("[EmacsWindow orderFront:]"); 8501 8502 NSWindow *parent = [self parentWindow]; 8503 if (parent) 8504 { 8505 [parent removeChildWindow:self]; 8506 [parent addChildWindow:self ordered:NSWindowAbove]; 8507 } 8508 else 8509 [super orderFront:sender]; 8510} 8511 8512- (void)makeKeyAndOrderFront:(id)sender 8513{ 8514 NSTRACE ("[EmacsWindow makeKeyAndOrderFront:]"); 8515 8516 if ([self parentWindow]) 8517 { 8518 [self orderFront:sender]; 8519 [self makeKeyWindow]; 8520 } 8521 else 8522 [super makeKeyAndOrderFront:sender]; 8523} 8524 8525 8526#ifdef NS_IMPL_GNUSTEP 8527/* orderedIndex isn't yet available in GNUstep, but it seems pretty 8528 easy to implement. */ 8529- (NSInteger) orderedIndex 8530{ 8531 return [[NSApp orderedWindows] indexOfObjectIdenticalTo:self]; 8532} 8533#endif 8534 8535 8536/* The array returned by [NSWindow parentWindow] may already be 8537 sorted, but the documentation doesn't tell us whether or not it is, 8538 so to be safe we'll sort it. */ 8539static NSInteger 8540nswindow_orderedIndex_sort (id w1, id w2, void *c) 8541{ 8542 NSInteger i1 = [w1 orderedIndex]; 8543 NSInteger i2 = [w2 orderedIndex]; 8544 8545 if (i1 > i2) 8546 return NSOrderedAscending; 8547 if (i1 < i2) 8548 return NSOrderedDescending; 8549 8550 return NSOrderedSame; 8551} 8552 8553- (void)orderBack:(id)sender 8554{ 8555 NSTRACE ("[EmacsWindow orderBack:]"); 8556 8557 NSWindow *parent = [self parentWindow]; 8558 if (parent) 8559 { 8560 NSArray *children = [[parent childWindows] 8561 sortedArrayUsingFunction:nswindow_orderedIndex_sort 8562 context:nil]; 8563 [parent removeChildWindow:self]; 8564 [parent addChildWindow:self ordered:NSWindowAbove]; 8565 8566 for (NSWindow *win in children) 8567 { 8568 if (win != self) 8569 { 8570 [parent removeChildWindow:win]; 8571 [parent addChildWindow:win ordered:NSWindowAbove]; 8572 } 8573 } 8574 } 8575 else 8576 [super orderBack:sender]; 8577} 8578 8579- (BOOL)restackWindow:(NSWindow *)win above:(BOOL)above 8580{ 8581 NSTRACE ("[EmacsWindow restackWindow:above:]"); 8582 8583 /* If parent windows don't match we can't restack these frames 8584 without changing the parents. */ 8585 if ([self parentWindow] != [win parentWindow]) 8586 return NO; 8587 else if (![self parentWindow]) 8588 [self orderWindow:(above ? NSWindowAbove : NSWindowBelow) 8589 relativeTo:[win windowNumber]]; 8590 else 8591 { 8592 NSInteger index; 8593 NSWindow *parent = [self parentWindow]; 8594 NSMutableArray *children = [[[parent childWindows] 8595 sortedArrayUsingFunction:nswindow_orderedIndex_sort 8596 context:nil] 8597 mutableCopy]; 8598 [children removeObject:self]; 8599 index = [children indexOfObject:win]; 8600 [children insertObject:self atIndex:(above ? index+1 : index)]; 8601 8602 for (NSWindow *w in children) 8603 { 8604 [parent removeChildWindow:w]; 8605 [parent addChildWindow:w ordered:NSWindowAbove]; 8606 } 8607 } 8608 8609 return YES; 8610} 8611 8612#ifdef NS_IMPL_COCOA 8613- (id)accessibilityAttributeValue:(NSString *)attribute 8614{ 8615 Lisp_Object str = Qnil; 8616 struct frame *f = SELECTED_FRAME (); 8617 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents); 8618 8619 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]"); 8620 8621 if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) 8622 return NSAccessibilityTextFieldRole; 8623 8624 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute] 8625 && curbuf && ! NILP (BVAR (curbuf, mark_active))) 8626 { 8627 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING); 8628 } 8629 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute]) 8630 { 8631 if (! NILP (BVAR (curbuf, mark_active))) 8632 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING); 8633 8634 if (NILP (str)) 8635 { 8636 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf); 8637 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte; 8638 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf); 8639 8640 if (! NILP (BVAR (curbuf, enable_multibyte_characters))) 8641 str = make_uninit_multibyte_string (range, byte_range); 8642 else 8643 str = make_uninit_string (range); 8644 /* To check: This returns emacs-utf-8, which is a superset of utf-8. 8645 Is this a problem? */ 8646 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range); 8647 } 8648 } 8649 8650 8651 if (! NILP (str)) 8652 { 8653 if (CONSP (str) && SYMBOLP (XCAR (str))) 8654 { 8655 str = XCDR (str); 8656 if (CONSP (str) && NILP (XCDR (str))) 8657 str = XCAR (str); 8658 } 8659 if (STRINGP (str)) 8660 { 8661 return [NSString stringWithLispString:str]; 8662 } 8663 } 8664 8665 return [super accessibilityAttributeValue:attribute]; 8666} 8667#endif /* NS_IMPL_COCOA */ 8668 8669/* Constrain size and placement of a frame. 8670 8671 By returning the original "frameRect", the frame is not 8672 constrained. This can lead to unwanted situations where, for 8673 example, the menu bar covers the frame. 8674 8675 The default implementation (accessed using "super") constrains the 8676 frame to the visible area of SCREEN, minus the menu bar (if 8677 present) and the Dock. Note that default implementation also calls 8678 windowWillResize, with the frame it thinks should have. (This can 8679 make the frame exit maximized mode.) 8680 8681 Note that this should work in situations where multiple monitors 8682 are present. Common configurations are side-by-side monitors and a 8683 monitor on top of another (e.g. when a laptop is placed under a 8684 large screen). */ 8685- (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen 8686{ 8687 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]", 8688 NSTRACE_ARG_RECT (frameRect)); 8689 8690#ifdef NS_IMPL_COCOA 8691#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 8692 // If separate spaces is on, it is like each screen is independent. There is 8693 // no spanning of frames across screens. 8694 if ( 8695#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 8696 [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] && 8697#endif 8698 [NSScreen screensHaveSeparateSpaces]) 8699 { 8700 NSTRACE_MSG ("Screens have separate spaces"); 8701 frameRect = [super constrainFrameRect:frameRect toScreen:screen]; 8702 NSTRACE_RETURN_RECT (frameRect); 8703 return frameRect; 8704 } 8705 else 8706#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */ 8707 8708 // Check that the proposed frameRect is visible in at least one 8709 // screen. If it is not, ask the system to reposition it (only 8710 // for non-child windows). 8711 8712 if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe)) 8713 { 8714 NSArray *screens = [NSScreen screens]; 8715 NSUInteger nr_screens = [screens count]; 8716 8717 int i; 8718 BOOL frame_on_screen = NO; 8719 8720 for (i = 0; i < nr_screens; ++i) 8721 { 8722 NSScreen *s = [screens objectAtIndex: i]; 8723 NSRect scrRect = [s frame]; 8724 8725 if (NSIntersectsRect(frameRect, scrRect)) 8726 { 8727 frame_on_screen = YES; 8728 break; 8729 } 8730 } 8731 8732 if (!frame_on_screen) 8733 { 8734 NSTRACE_MSG ("Frame outside screens; constraining"); 8735 frameRect = [super constrainFrameRect:frameRect toScreen:screen]; 8736 NSTRACE_RETURN_RECT (frameRect); 8737 return frameRect; 8738 } 8739 } 8740#endif 8741 8742 return constrain_frame_rect(frameRect, 8743 [(EmacsView *)[self delegate] isFullscreen]); 8744} 8745 8746 8747- (void)performZoom:(id)sender 8748{ 8749 NSTRACE ("[EmacsWindow performZoom:]"); 8750 8751 return [super performZoom:sender]; 8752} 8753 8754- (void)zoom:(id)sender 8755{ 8756 NSTRACE ("[EmacsWindow zoom:]"); 8757 8758 ns_update_auto_hide_menu_bar(); 8759 8760 // Below are three zoom implementations. In the final commit, the 8761 // idea is that the last should be included. 8762 8763#if 0 8764 // Native zoom done using the standard zoom animation. Size of the 8765 // resulting frame reduced to accommodate the Dock and, if present, 8766 // the menu-bar. 8767 [super zoom:sender]; 8768 8769#elif 0 8770 // Native zoom done using the standard zoom animation, plus an 8771 // explicit resize to cover the full screen, except the menu-bar and 8772 // dock, if present. 8773 [super zoom:sender]; 8774 8775 // After the native zoom, resize the resulting frame to fill the 8776 // entire screen, except the menu-bar. 8777 // 8778 // This works for all practical purposes. (The only minor oddity is 8779 // when transiting from full-height frame to a maximized, the 8780 // animation reduces the height of the frame slightly (to the 4 8781 // pixels needed to accommodate the Doc) before it snaps back into 8782 // full height. The user would need a very trained eye to spot 8783 // this.) 8784 NSScreen * screen = [self screen]; 8785 if (screen != nil) 8786 { 8787 int fs_state = [(EmacsView *)[self delegate] fullscreenState]; 8788 8789 NSTRACE_FSTYPE ("fullscreenState", fs_state); 8790 8791 NSRect sr = [screen frame]; 8792 struct EmacsMargins margins 8793 = ns_screen_margins_ignoring_hidden_dock(screen); 8794 8795 NSRect wr = [self frame]; 8796 NSTRACE_RECT ("Rect after zoom", wr); 8797 8798 NSRect newWr = wr; 8799 8800 if (fs_state == FULLSCREEN_MAXIMIZED 8801 || fs_state == FULLSCREEN_HEIGHT) 8802 { 8803 newWr.origin.y = sr.origin.y + margins.bottom; 8804 newWr.size.height = sr.size.height - margins.top - margins.bottom; 8805 } 8806 8807 if (fs_state == FULLSCREEN_MAXIMIZED 8808 || fs_state == FULLSCREEN_WIDTH) 8809 { 8810 newWr.origin.x = sr.origin.x + margins.left; 8811 newWr.size.width = sr.size.width - margins.right - margins.left; 8812 } 8813 8814 if (newWr.size.width != wr.size.width 8815 || newWr.size.height != wr.size.height 8816 || newWr.origin.x != wr.origin.x 8817 || newWr.origin.y != wr.origin.y) 8818 { 8819 NSTRACE_MSG ("New frame different"); 8820 [self setFrame: newWr display: NO]; 8821 } 8822 } 8823#else 8824 // Non-native zoom which is done instantaneously. The resulting 8825 // frame covers the entire screen, except the menu-bar and dock, if 8826 // present. 8827 NSScreen * screen = [self screen]; 8828 if (screen != nil) 8829 { 8830 NSRect sr = [screen frame]; 8831 struct EmacsMargins margins 8832 = ns_screen_margins_ignoring_hidden_dock(screen); 8833 8834 sr.size.height -= (margins.top + margins.bottom); 8835 sr.size.width -= (margins.left + margins.right); 8836 sr.origin.x += margins.left; 8837 sr.origin.y += margins.bottom; 8838 8839 sr = [[self delegate] windowWillUseStandardFrame:self 8840 defaultFrame:sr]; 8841 [self setFrame: sr display: NO]; 8842 } 8843#endif 8844} 8845 8846- (void)setAppearance 8847{ 8848#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 8849 struct frame *f = ((EmacsView *)[self delegate])->emacsframe; 8850 NSAppearance *appearance = nil; 8851 8852 NSTRACE ("[EmacsWindow setAppearance]"); 8853 8854#ifndef NSAppKitVersionNumber10_10 8855#define NSAppKitVersionNumber10_10 1343 8856#endif 8857 8858 if (NSAppKitVersionNumber < NSAppKitVersionNumber10_10) 8859 return; 8860 8861 if (FRAME_NS_APPEARANCE (f) == ns_appearance_vibrant_dark) 8862 appearance = 8863 [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark]; 8864 else if (FRAME_NS_APPEARANCE (f) == ns_appearance_aqua) 8865 appearance = 8866 [NSAppearance appearanceNamed:NSAppearanceNameAqua]; 8867 8868 [self setAppearance:appearance]; 8869#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */ 8870} 8871 8872- (void)setFrame:(NSRect)windowFrame 8873 display:(BOOL)displayViews 8874{ 8875 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]", 8876 NSTRACE_ARG_RECT (windowFrame), displayViews); 8877 8878 [super setFrame:windowFrame display:displayViews]; 8879} 8880 8881- (void)setFrame:(NSRect)windowFrame 8882 display:(BOOL)displayViews 8883 animate:(BOOL)performAnimation 8884{ 8885 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT 8886 " display:%d performAnimation:%d]", 8887 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation); 8888 8889 [super setFrame:windowFrame display:displayViews animate:performAnimation]; 8890} 8891 8892- (void)setFrameTopLeftPoint:(NSPoint)point 8893{ 8894 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]", 8895 NSTRACE_ARG_POINT (point)); 8896 8897 [super setFrameTopLeftPoint:point]; 8898} 8899 8900- (BOOL)canBecomeKeyWindow 8901{ 8902 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe); 8903} 8904 8905- (BOOL)canBecomeMainWindow 8906 /* Required for fullscreen and undecorated windows. */ 8907{ 8908 return YES; 8909} 8910 8911@end /* EmacsWindow */ 8912 8913 8914/* ========================================================================== 8915 8916 EmacsScroller implementation 8917 8918 ========================================================================== */ 8919 8920 8921@implementation EmacsScroller 8922 8923/* for repeat button push */ 8924#define SCROLL_BAR_FIRST_DELAY 0.5 8925#define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15) 8926 8927+ (CGFloat) scrollerWidth 8928{ 8929 /* TODO: if we want to allow variable widths, this is the place to do it, 8930 however neither GNUstep nor Cocoa support it very well. */ 8931 CGFloat r; 8932#if defined (NS_IMPL_COCOA) \ 8933 && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 8934#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 8935 if ([NSScroller respondsToSelector: 8936 @selector(scrollerWidthForControlSize:scrollerStyle:)]) 8937#endif 8938 r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular 8939 scrollerStyle: NSScrollerStyleLegacy]; 8940#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 8941 else 8942#endif 8943#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */ 8944#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \ 8945 || defined (NS_IMPL_GNUSTEP) 8946 r = [NSScroller scrollerWidth]; 8947#endif 8948 return r; 8949} 8950 8951- (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin 8952{ 8953 NSTRACE ("[EmacsScroller initFrame: window:]"); 8954 8955 if (r.size.width > r.size.height) 8956 horizontal = YES; 8957 else 8958 horizontal = NO; 8959 8960 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/]; 8961 [self setContinuous: YES]; 8962 [self setEnabled: YES]; 8963 8964 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view 8965 locked against the top and bottom edges, and right edge on macOS, where 8966 scrollers are on right. */ 8967#ifdef NS_IMPL_GNUSTEP 8968 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable]; 8969#else 8970 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable]; 8971#endif 8972 8973 window = XWINDOW (nwin); 8974 condemned = NO; 8975 if (horizontal) 8976 pixel_length = NSWidth (r); 8977 else 8978 pixel_length = NSHeight (r); 8979 if (pixel_length == 0) pixel_length = 1; 8980 min_portion = 20 / pixel_length; 8981 8982 frame = XFRAME (window->frame); 8983 if (FRAME_LIVE_P (frame)) 8984 { 8985 int i; 8986 EmacsView *view = FRAME_NS_VIEW (frame); 8987 NSView *sview = [[view window] contentView]; 8988 NSArray *subs = [sview subviews]; 8989 8990 /* Disable optimization stopping redraw of other scrollbars. */ 8991 view->scrollbarsNeedingUpdate = 0; 8992 for (i =[subs count]-1; i >= 0; i--) 8993 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]]) 8994 view->scrollbarsNeedingUpdate++; 8995 [sview addSubview: self]; 8996 } 8997 8998 /* [self setFrame: r]; */ 8999 9000 return self; 9001} 9002 9003 9004- (void)setFrame: (NSRect)newRect 9005{ 9006 NSTRACE ("[EmacsScroller setFrame:]"); 9007 9008 /* block_input (); */ 9009 if (horizontal) 9010 pixel_length = NSWidth (newRect); 9011 else 9012 pixel_length = NSHeight (newRect); 9013 if (pixel_length == 0) pixel_length = 1; 9014 min_portion = 20 / pixel_length; 9015 [super setFrame: newRect]; 9016 /* unblock_input (); */ 9017} 9018 9019 9020- (void)dealloc 9021{ 9022 NSTRACE ("[EmacsScroller dealloc]"); 9023 if (window) 9024 { 9025 if (horizontal) 9026 wset_horizontal_scroll_bar (window, Qnil); 9027 else 9028 wset_vertical_scroll_bar (window, Qnil); 9029 } 9030 window = 0; 9031 [super dealloc]; 9032} 9033 9034 9035- (instancetype)condemn 9036{ 9037 NSTRACE ("[EmacsScroller condemn]"); 9038 condemned =YES; 9039 return self; 9040} 9041 9042 9043- (instancetype)reprieve 9044{ 9045 NSTRACE ("[EmacsScroller reprieve]"); 9046 condemned =NO; 9047 return self; 9048} 9049 9050 9051-(bool)judge 9052{ 9053 NSTRACE ("[EmacsScroller judge]"); 9054 bool ret = condemned; 9055 if (condemned) 9056 { 9057 EmacsView *view; 9058 block_input (); 9059 /* Ensure other scrollbar updates after deletion. */ 9060 view = (EmacsView *)FRAME_NS_VIEW (frame); 9061 if (view != nil) 9062 view->scrollbarsNeedingUpdate++; 9063 if (window) 9064 { 9065 if (horizontal) 9066 wset_horizontal_scroll_bar (window, Qnil); 9067 else 9068 wset_vertical_scroll_bar (window, Qnil); 9069 } 9070 window = 0; 9071 [self removeFromSuperview]; 9072 [self release]; 9073 unblock_input (); 9074 } 9075 return ret; 9076} 9077 9078 9079- (void)resetCursorRects 9080{ 9081 NSRect visible = [self visibleRect]; 9082 NSTRACE ("[EmacsScroller resetCursorRects]"); 9083 9084 if (!NSIsEmptyRect (visible)) 9085 [self addCursorRect: visible cursor: [NSCursor arrowCursor]]; 9086 9087#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300 9088#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300 9089 if ([[NSCursor arrowCursor] respondsToSelector: 9090 @selector(setOnMouseEntered)]) 9091#endif 9092 [[NSCursor arrowCursor] setOnMouseEntered: YES]; 9093#endif 9094} 9095 9096 9097- (int) checkSamePosition: (int) position portion: (int) portion 9098 whole: (int) whole 9099{ 9100 return em_position ==position && em_portion ==portion && em_whole ==whole 9101 && portion != whole; /* Needed for resizing empty buffer. */ 9102} 9103 9104 9105- (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole 9106{ 9107 NSTRACE ("[EmacsScroller setPosition:portion:whole:]"); 9108 9109 em_position = position; 9110 em_portion = portion; 9111 em_whole = whole; 9112 9113 if (portion >= whole) 9114 { 9115#ifdef NS_IMPL_COCOA 9116 [self setKnobProportion: 1.0]; 9117 [self setDoubleValue: 1.0]; 9118#else 9119 [self setFloatValue: 0.0 knobProportion: 1.0]; 9120#endif 9121 } 9122 else 9123 { 9124 float pos; 9125 CGFloat por; 9126 portion = max ((float)whole*min_portion/pixel_length, portion); 9127 pos = (float)position / (whole - portion); 9128 por = (CGFloat)portion/whole; 9129#ifdef NS_IMPL_COCOA 9130 [self setKnobProportion: por]; 9131 [self setDoubleValue: pos]; 9132#else 9133 [self setFloatValue: pos knobProportion: por]; 9134#endif 9135 } 9136 9137 return self; 9138} 9139 9140/* Set up emacs_event. */ 9141- (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e 9142{ 9143 Lisp_Object win; 9144 9145 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]"); 9146 9147 if (!emacs_event) 9148 return; 9149 9150 emacs_event->part = last_hit_part; 9151 emacs_event->code = 0; 9152 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier; 9153 XSETWINDOW (win, window); 9154 emacs_event->frame_or_window = win; 9155 emacs_event->timestamp = EV_TIMESTAMP (e); 9156 emacs_event->arg = Qnil; 9157 9158 if (horizontal) 9159 { 9160 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT; 9161 XSETINT (emacs_event->x, em_whole * loc / pixel_length); 9162 XSETINT (emacs_event->y, em_whole); 9163 } 9164 else 9165 { 9166 emacs_event->kind = SCROLL_BAR_CLICK_EVENT; 9167 XSETINT (emacs_event->x, loc); 9168 XSETINT (emacs_event->y, pixel_length-20); 9169 } 9170 9171 if (q_event_ptr) 9172 { 9173 n_emacs_events_pending++; 9174 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); 9175 } 9176 else 9177 hold_event (emacs_event); 9178 EVENT_INIT (*emacs_event); 9179 ns_send_appdefined (-1); 9180} 9181 9182 9183/* Called manually through timer to implement repeated button action 9184 with hold-down. */ 9185- (instancetype)repeatScroll: (NSTimer *)scrollEntry 9186{ 9187 NSEvent *e = [[self window] currentEvent]; 9188 NSPoint p = [[self window] mouseLocationOutsideOfEventStream]; 9189 BOOL inKnob = [self testPart: p] == NSScrollerKnob; 9190 9191 NSTRACE ("[EmacsScroller repeatScroll:]"); 9192 9193 /* Clear timer if need be. */ 9194 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY) 9195 { 9196 [scroll_repeat_entry invalidate]; 9197 [scroll_repeat_entry release]; 9198 scroll_repeat_entry = nil; 9199 9200 if (inKnob) 9201 return self; 9202 9203 scroll_repeat_entry 9204 = [[NSTimer scheduledTimerWithTimeInterval: 9205 SCROLL_BAR_CONTINUOUS_DELAY 9206 target: self 9207 selector: @selector (repeatScroll:) 9208 userInfo: 0 9209 repeats: YES] 9210 retain]; 9211 } 9212 9213 [self sendScrollEventAtLoc: 0 fromEvent: e]; 9214 return self; 9215} 9216 9217 9218/* Asynchronous mouse tracking for scroller. This allows us to dispatch 9219 mouseDragged events without going into a modal loop. */ 9220- (void)mouseDown: (NSEvent *)e 9221{ 9222 NSRect sr, kr; 9223 /* hitPart is only updated AFTER event is passed on. */ 9224 NSScrollerPart part = [self testPart: [e locationInWindow]]; 9225 CGFloat loc, kloc, pos UNINIT; 9226 int edge = 0; 9227 9228 NSTRACE ("[EmacsScroller mouseDown:]"); 9229 9230 switch (part) 9231 { 9232 case NSScrollerDecrementPage: 9233 last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break; 9234 case NSScrollerIncrementPage: 9235 last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break; 9236#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070 9237 case NSScrollerDecrementLine: 9238 last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break; 9239 case NSScrollerIncrementLine: 9240 last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break; 9241#endif 9242 case NSScrollerKnob: 9243 last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break; 9244 case NSScrollerKnobSlot: /* GNUstep-only */ 9245 last_hit_part = scroll_bar_move_ratio; break; 9246 default: /* NSScrollerNoPart? */ 9247 fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n", 9248 (long) part); 9249 return; 9250 } 9251 9252 if (part == NSScrollerKnob || part == NSScrollerKnobSlot) 9253 { 9254 /* handle, or on GNUstep possibly slot */ 9255 NSEvent *fake_event; 9256 int length; 9257 9258 /* compute float loc in slot and mouse offset on knob */ 9259 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot] 9260 toView: nil]; 9261 if (horizontal) 9262 { 9263 length = NSWidth (sr); 9264 loc = ([e locationInWindow].x - NSMinX (sr)); 9265 } 9266 else 9267 { 9268 length = NSHeight (sr); 9269 loc = length - ([e locationInWindow].y - NSMinY (sr)); 9270 } 9271 9272 if (loc <= 0.0) 9273 { 9274 loc = 0.0; 9275 edge = -1; 9276 } 9277 else if (loc >= length) 9278 { 9279 loc = length; 9280 edge = 1; 9281 } 9282 9283 if (edge) 9284 kloc = 0.5 * edge; 9285 else 9286 { 9287 kr = [self convertRect: [self rectForPart: NSScrollerKnob] 9288 toView: nil]; 9289 if (horizontal) 9290 kloc = ([e locationInWindow].x - NSMinX (kr)); 9291 else 9292 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr)); 9293 } 9294 last_mouse_offset = kloc; 9295 9296 /* if knob, tell emacs a location offset by knob pos 9297 (to indicate top of handle) */ 9298 if (part == NSScrollerKnob) 9299 pos = (loc - last_mouse_offset); 9300 else 9301 /* else this is a slot click on GNUstep: go straight there */ 9302 pos = loc; 9303 9304 /* If there are buttons in the scroller area, we need to 9305 recalculate pos as emacs expects the scroller slot to take up 9306 the entire available length. */ 9307 if (length != pixel_length) 9308 pos = pos * pixel_length / length; 9309 9310 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */ 9311 fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp 9312 location: [e locationInWindow] 9313 modifierFlags: [e modifierFlags] 9314 timestamp: [e timestamp] 9315 windowNumber: [e windowNumber] 9316 context: nil 9317 eventNumber: [e eventNumber] 9318 clickCount: [e clickCount] 9319 pressure: [e pressure]]; 9320 [super mouseUp: fake_event]; 9321 } 9322 else 9323 { 9324 pos = 0; /* ignored */ 9325 9326 /* Set a timer to repeat, as we can't let superclass do this modally. */ 9327 scroll_repeat_entry 9328 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY 9329 target: self 9330 selector: @selector (repeatScroll:) 9331 userInfo: 0 9332 repeats: YES] 9333 retain]; 9334 } 9335 9336 if (part != NSScrollerKnob) 9337 [self sendScrollEventAtLoc: pos fromEvent: e]; 9338} 9339 9340 9341/* Called as we manually track scroller drags, rather than superclass. */ 9342- (void)mouseDragged: (NSEvent *)e 9343{ 9344 NSRect sr; 9345 double loc, pos; 9346 int length; 9347 9348 NSTRACE ("[EmacsScroller mouseDragged:]"); 9349 9350 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot] 9351 toView: nil]; 9352 9353 if (horizontal) 9354 { 9355 length = NSWidth (sr); 9356 loc = ([e locationInWindow].x - NSMinX (sr)); 9357 } 9358 else 9359 { 9360 length = NSHeight (sr); 9361 loc = length - ([e locationInWindow].y - NSMinY (sr)); 9362 } 9363 9364 if (loc <= 0.0) 9365 { 9366 loc = 0.0; 9367 } 9368 else if (loc >= length + last_mouse_offset) 9369 { 9370 loc = length + last_mouse_offset; 9371 } 9372 9373 pos = (loc - last_mouse_offset); 9374 9375 /* If there are buttons in the scroller area, we need to 9376 recalculate pos as emacs expects the scroller slot to take up 9377 the entire available length. */ 9378 if (length != pixel_length) 9379 pos = pos * pixel_length / length; 9380 9381 [self sendScrollEventAtLoc: pos fromEvent: e]; 9382} 9383 9384 9385- (void)mouseUp: (NSEvent *)e 9386{ 9387 NSTRACE ("[EmacsScroller mouseUp:]"); 9388 9389 if (scroll_repeat_entry) 9390 { 9391 [scroll_repeat_entry invalidate]; 9392 [scroll_repeat_entry release]; 9393 scroll_repeat_entry = nil; 9394 } 9395 last_hit_part = scroll_bar_above_handle; 9396} 9397 9398 9399/* Treat scrollwheel events in the bar as though they were in the main window. */ 9400- (void) scrollWheel: (NSEvent *)theEvent 9401{ 9402 NSTRACE ("[EmacsScroller scrollWheel:]"); 9403 9404 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame); 9405 [view mouseDown: theEvent]; 9406} 9407 9408@end /* EmacsScroller */ 9409 9410 9411#ifdef NS_IMPL_COCOA 9412 9413/* ========================================================================== 9414 9415 A class to handle the screen buffer. 9416 9417 ========================================================================== */ 9418 9419@implementation EmacsLayer 9420 9421 9422/* An IOSurface is a pixel buffer that is efficiently copied to VRAM 9423 for display. In order to use an IOSurface we must first lock it, 9424 write to it, then unlock it. At this point it is transferred to 9425 VRAM and if we modify it during this transfer we may see corruption 9426 of the output. To avoid this problem we can check if the surface 9427 is "in use", and if it is then avoid using it. Unfortunately to 9428 avoid writing to a surface that's in use, but still maintain the 9429 ability to draw to the screen at any time, we need to keep a cache 9430 of multiple surfaces that we can use at will. 9431 9432 The EmacsLayer class maintains this cache of surfaces, and 9433 handles the conversion to a CGGraphicsContext that AppKit can use 9434 to draw on. 9435 9436 The cache is simple: if a free surface is found it is removed from 9437 the cache and set as the "current" surface. Emacs draws to the 9438 surface and when the layer wants to update the screen we set it's 9439 contents to the surface and then add it back on to the end of the 9440 cache. If no free surfaces are found in the cache then a new one 9441 is created. */ 9442 9443#define CACHE_MAX_SIZE 2 9444 9445- (id) initWithColorSpace: (CGColorSpaceRef)cs 9446{ 9447 NSTRACE ("[EmacsLayer initWithColorSpace:]"); 9448 9449 self = [super init]; 9450 if (self) 9451 { 9452 cache = [[NSMutableArray arrayWithCapacity:CACHE_MAX_SIZE] retain]; 9453 [self setColorSpace:cs]; 9454 } 9455 else 9456 { 9457 return nil; 9458 } 9459 9460 return self; 9461} 9462 9463 9464- (void) setColorSpace: (CGColorSpaceRef)cs 9465{ 9466 /* We don't need to clear the cache because the new colorspace will 9467 be used next time we create a new context. */ 9468 if (cs) 9469 colorSpace = cs; 9470 else 9471 colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 9472} 9473 9474 9475- (void) dealloc 9476{ 9477 [self releaseSurfaces]; 9478 [cache release]; 9479 9480 [super dealloc]; 9481} 9482 9483 9484- (void) releaseSurfaces 9485{ 9486 [self setContents:nil]; 9487 [self releaseContext]; 9488 9489 if (currentSurface) 9490 { 9491 CFRelease (currentSurface); 9492 currentSurface = nil; 9493 } 9494 9495 if (cache) 9496 { 9497 for (id object in cache) 9498 CFRelease ((IOSurfaceRef)object); 9499 9500 [cache removeAllObjects]; 9501 } 9502} 9503 9504 9505/* Check whether the current bounds match the IOSurfaces we are using. 9506 If they do return YES, otherwise NO. */ 9507- (BOOL) checkDimensions 9508{ 9509 int width = NSWidth ([self bounds]) * [self contentsScale]; 9510 int height = NSHeight ([self bounds]) * [self contentsScale]; 9511 IOSurfaceRef s = currentSurface ? currentSurface 9512 : (IOSurfaceRef)[cache firstObject]; 9513 9514 return !s || (IOSurfaceGetWidth (s) == width 9515 && IOSurfaceGetHeight (s) == height); 9516} 9517 9518 9519/* Return a CGContextRef that can be used for drawing to the screen. */ 9520- (CGContextRef) getContext 9521{ 9522 CGFloat scale = [self contentsScale]; 9523 9524 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer getContext]"); 9525 NSTRACE_MSG ("IOSurface count: %lu", [cache count] + (currentSurface ? 1 : 0)); 9526 9527 if (![self checkDimensions]) 9528 [self releaseSurfaces]; 9529 9530 if (!context) 9531 { 9532 IOSurfaceRef surface = NULL; 9533 int width = NSWidth ([self bounds]) * scale; 9534 int height = NSHeight ([self bounds]) * scale; 9535 9536 for (id object in cache) 9537 { 9538 if (!IOSurfaceIsInUse ((IOSurfaceRef)object)) 9539 { 9540 surface = (IOSurfaceRef)object; 9541 [cache removeObject:object]; 9542 break; 9543 } 9544 } 9545 9546 if (!surface && [cache count] >= CACHE_MAX_SIZE) 9547 { 9548 /* Just grab the first one off the cache. This may result 9549 in tearing effects. The alternative is to wait for one 9550 of the surfaces to become free. */ 9551 surface = (IOSurfaceRef)[cache firstObject]; 9552 [cache removeObject:(id)surface]; 9553 } 9554 else if (!surface) 9555 { 9556 int bytesPerRow = IOSurfaceAlignProperty (kIOSurfaceBytesPerRow, 9557 width * 4); 9558 9559 surface = IOSurfaceCreate 9560 ((CFDictionaryRef)@{(id)kIOSurfaceWidth:[NSNumber numberWithInt:width], 9561 (id)kIOSurfaceHeight:[NSNumber numberWithInt:height], 9562 (id)kIOSurfaceBytesPerRow:[NSNumber numberWithInt:bytesPerRow], 9563 (id)kIOSurfaceBytesPerElement:[NSNumber numberWithInt:4], 9564 (id)kIOSurfacePixelFormat:[NSNumber numberWithUnsignedInt:'BGRA']}); 9565 } 9566 9567 if (!surface) 9568 { 9569 NSLog (@"Failed to create IOSurface for frame %@", [self delegate]); 9570 return nil; 9571 } 9572 9573 IOReturn lockStatus = IOSurfaceLock (surface, 0, nil); 9574 if (lockStatus != kIOReturnSuccess) 9575 NSLog (@"Failed to lock surface: %x", lockStatus); 9576 9577 [self copyContentsTo:surface]; 9578 9579 currentSurface = surface; 9580 9581 context = CGBitmapContextCreate (IOSurfaceGetBaseAddress (currentSurface), 9582 IOSurfaceGetWidth (currentSurface), 9583 IOSurfaceGetHeight (currentSurface), 9584 8, 9585 IOSurfaceGetBytesPerRow (currentSurface), 9586 colorSpace, 9587 (kCGImageAlphaPremultipliedFirst 9588 | kCGBitmapByteOrder32Host)); 9589 9590 if (!context) 9591 { 9592 NSLog (@"Failed to create context for frame %@", [self delegate]); 9593 IOSurfaceUnlock (currentSurface, 0, nil); 9594 CFRelease (currentSurface); 9595 currentSurface = nil; 9596 return nil; 9597 } 9598 9599 CGContextTranslateCTM(context, 0, IOSurfaceGetHeight (currentSurface)); 9600 CGContextScaleCTM(context, scale, -scale); 9601 } 9602 9603 return context; 9604} 9605 9606 9607/* Releases the CGGraphicsContext and unlocks the associated 9608 IOSurface, so it will be sent to VRAM. */ 9609- (void) releaseContext 9610{ 9611 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer releaseContext]"); 9612 9613 if (!context) 9614 return; 9615 9616 CGContextRelease (context); 9617 context = NULL; 9618 9619 IOReturn lockStatus = IOSurfaceUnlock (currentSurface, 0, nil); 9620 if (lockStatus != kIOReturnSuccess) 9621 NSLog (@"Failed to unlock surface: %x", lockStatus); 9622} 9623 9624 9625- (void) display 9626{ 9627 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer display]"); 9628 9629 if (context) 9630 { 9631 [self releaseContext]; 9632 9633#if CACHE_MAX_SIZE == 1 9634 /* This forces the layer to see the surface as updated. */ 9635 [self setContents:nil]; 9636#endif 9637 9638 [self setContents:(id)currentSurface]; 9639 9640 /* Put currentSurface back on the end of the cache. */ 9641 [cache addObject:(id)currentSurface]; 9642 currentSurface = NULL; 9643 9644 /* Schedule a run of getContext so that if Emacs is idle it will 9645 perform the buffer copy, etc. */ 9646 [self performSelectorOnMainThread:@selector (getContext) 9647 withObject:nil 9648 waitUntilDone:NO]; 9649 } 9650} 9651 9652 9653/* Copy the contents of lastSurface to DESTINATION. This is required 9654 every time we want to use an IOSurface as its contents are probably 9655 blanks (if it's new), or stale. */ 9656- (void) copyContentsTo: (IOSurfaceRef) destination 9657{ 9658 IOReturn lockStatus; 9659 IOSurfaceRef source = (IOSurfaceRef)[self contents]; 9660 void *sourceData, *destinationData; 9661 int numBytes = IOSurfaceGetAllocSize (destination); 9662 9663 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "[EmacsLayer copyContentsTo:]"); 9664 9665 if (!source || source == destination) 9666 return; 9667 9668 lockStatus = IOSurfaceLock (source, kIOSurfaceLockReadOnly, nil); 9669 if (lockStatus != kIOReturnSuccess) 9670 NSLog (@"Failed to lock source surface: %x", lockStatus); 9671 9672 sourceData = IOSurfaceGetBaseAddress (source); 9673 destinationData = IOSurfaceGetBaseAddress (destination); 9674 9675 /* Since every IOSurface should have the exact same settings, a 9676 memcpy seems like the fastest way to copy the data from one to 9677 the other. */ 9678 memcpy (destinationData, sourceData, numBytes); 9679 9680 lockStatus = IOSurfaceUnlock (source, kIOSurfaceLockReadOnly, nil); 9681 if (lockStatus != kIOReturnSuccess) 9682 NSLog (@"Failed to unlock source surface: %x", lockStatus); 9683} 9684 9685#undef CACHE_MAX_SIZE 9686 9687@end /* EmacsLayer */ 9688 9689 9690#endif /* NS_IMPL_COCOA */ 9691 9692 9693#ifdef NS_IMPL_GNUSTEP 9694/* Dummy class to get rid of startup warnings. */ 9695@implementation EmacsDocument 9696 9697@end 9698#endif 9699 9700 9701/* ========================================================================== 9702 9703 Font-related functions; these used to be in nsfaces.m 9704 9705 ========================================================================== */ 9706 9707 9708static Lisp_Object 9709ns_new_font (struct frame *f, Lisp_Object font_object, int fontset) 9710{ 9711 /* -------------------------------------------------------------------------- 9712 External (hook) 9713 -------------------------------------------------------------------------- */ 9714 struct font *font = XFONT_OBJECT (font_object); 9715 EmacsView *view = FRAME_NS_VIEW (f); 9716 int font_ascent, font_descent; 9717 9718 if (fontset < 0) 9719 fontset = fontset_from_font (font_object); 9720 FRAME_FONTSET (f) = fontset; 9721 9722 if (FRAME_FONT (f) == font) 9723 /* This font is already set in frame F. There's nothing more to 9724 do. */ 9725 return font_object; 9726 9727 FRAME_FONT (f) = font; 9728 9729 FRAME_BASELINE_OFFSET (f) = font->baseline_offset; 9730 FRAME_COLUMN_WIDTH (f) = font->average_width; 9731 get_font_ascent_descent (font, &font_ascent, &font_descent); 9732 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent; 9733 9734 /* Compute the scroll bar width in character columns. */ 9735 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0) 9736 { 9737 int wid = FRAME_COLUMN_WIDTH (f); 9738 FRAME_CONFIG_SCROLL_BAR_COLS (f) 9739 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid; 9740 } 9741 else 9742 { 9743 int wid = FRAME_COLUMN_WIDTH (f); 9744 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid; 9745 } 9746 9747 /* Compute the scroll bar height in character lines. */ 9748 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0) 9749 { 9750 int height = FRAME_LINE_HEIGHT (f); 9751 FRAME_CONFIG_SCROLL_BAR_LINES (f) 9752 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height; 9753 } 9754 else 9755 { 9756 int height = FRAME_LINE_HEIGHT (f); 9757 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height; 9758 } 9759 9760 /* Now make the frame display the given font. */ 9761 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen]) 9762 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), 9763 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, 9764 false, Qfont); 9765 9766 return font_object; 9767} 9768 9769 9770/* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */ 9771/* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed 9772 in 1.43. */ 9773 9774const char * 9775ns_xlfd_to_fontname (const char *xlfd) 9776/* -------------------------------------------------------------------------- 9777 Convert an X font name (XLFD) to an NS font name. 9778 Only family is used. 9779 The string returned is temporarily allocated. 9780 -------------------------------------------------------------------------- */ 9781{ 9782 char *name = xmalloc (180); 9783 int i, len; 9784 const char *ret; 9785 9786 if (!strncmp (xlfd, "--", 2)) 9787 sscanf (xlfd, "--%*[^-]-%179[^-]-", name); 9788 else 9789 sscanf (xlfd, "-%*[^-]-%179[^-]-", name); 9790 9791 /* stopgap for malformed XLFD input */ 9792 if (!*name) 9793 strcpy (name, "Monaco"); 9794 9795 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' ' 9796 also uppercase after '-' or ' ' */ 9797 name[0] = c_toupper (name[0]); 9798 for (len =strlen (name), i =0; i<len; i++) 9799 { 9800 if (name[i] == '$') 9801 { 9802 name[i] = '-'; 9803 if (i+1<len) 9804 name[i+1] = c_toupper (name[i+1]); 9805 } 9806 else if (name[i] == '_') 9807 { 9808 name[i] = ' '; 9809 if (i+1<len) 9810 name[i+1] = c_toupper (name[i+1]); 9811 } 9812 } 9813 /* fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */ 9814 ret = [[NSString stringWithUTF8String: name] UTF8String]; 9815 xfree (name); 9816 return ret; 9817} 9818 9819 9820void 9821syms_of_nsterm (void) 9822{ 9823 NSTRACE ("syms_of_nsterm"); 9824 9825 ns_antialias_threshold = 10.0; 9826 PDUMPER_REMEMBER_SCALAR (ns_antialias_threshold); 9827 9828 /* From 23+ we need to tell emacs what modifiers there are. */ 9829 DEFSYM (Qmodifier_value, "modifier-value"); 9830 DEFSYM (Qalt, "alt"); 9831 DEFSYM (Qhyper, "hyper"); 9832 DEFSYM (Qmeta, "meta"); 9833 DEFSYM (Qsuper, "super"); 9834 DEFSYM (Qcontrol, "control"); 9835 DEFSYM (QUTF8_STRING, "UTF8_STRING"); 9836 9837 DEFSYM (Qfile, "file"); 9838 DEFSYM (Qurl, "url"); 9839 9840 DEFSYM (Qns_drag_operation_copy, "ns-drag-operation-copy"); 9841 DEFSYM (Qns_drag_operation_link, "ns-drag-operation-link"); 9842 DEFSYM (Qns_drag_operation_generic, "ns-drag-operation-generic"); 9843 9844 Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier)); 9845 Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier)); 9846 Fput (Qmeta, Qmodifier_value, make_fixnum (meta_modifier)); 9847 Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier)); 9848 Fput (Qcontrol, Qmodifier_value, make_fixnum (ctrl_modifier)); 9849 9850 DEFVAR_LISP ("ns-input-file", ns_input_file, 9851 "The file specified in the last NS event."); 9852 ns_input_file =Qnil; 9853 9854 DEFVAR_LISP ("ns-working-text", ns_working_text, 9855 "String for visualizing working composition sequence."); 9856 ns_working_text =Qnil; 9857 9858 DEFVAR_LISP ("ns-input-font", ns_input_font, 9859 "The font specified in the last NS event."); 9860 ns_input_font =Qnil; 9861 9862 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize, 9863 "The fontsize specified in the last NS event."); 9864 ns_input_fontsize =Qnil; 9865 9866 DEFVAR_LISP ("ns-input-line", ns_input_line, 9867 "The line specified in the last NS event."); 9868 ns_input_line =Qnil; 9869 9870 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name, 9871 "The service name specified in the last NS event."); 9872 ns_input_spi_name =Qnil; 9873 9874 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg, 9875 "The service argument specified in the last NS event."); 9876 ns_input_spi_arg =Qnil; 9877 9878 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier, 9879 "This variable describes the behavior of the alternate or option key.\n\ 9880Either SYMBOL, describing the behavior for any event,\n\ 9881or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 9882separately for ordinary keys, function keys, and mouse events.\n\ 9883\n\ 9884Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 9885If `none', the key is ignored by Emacs and retains its standard meaning."); 9886 ns_alternate_modifier = Qmeta; 9887 9888 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier, 9889 "This variable describes the behavior of the right alternate or option key.\n\ 9890Either SYMBOL, describing the behavior for any event,\n\ 9891or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 9892separately for ordinary keys, function keys, and mouse events.\n\ 9893It can also be `left' to use the value of `ns-alternate-modifier' instead.\n\ 9894\n\ 9895Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 9896If `none', the key is ignored by Emacs and retains its standard meaning."); 9897 ns_right_alternate_modifier = Qleft; 9898 9899 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier, 9900 "This variable describes the behavior of the command key.\n\ 9901Either SYMBOL, describing the behavior for any event,\n\ 9902or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 9903separately for ordinary keys, function keys, and mouse events.\n\ 9904\n\ 9905Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 9906If `none', the key is ignored by Emacs and retains its standard meaning."); 9907 ns_command_modifier = Qsuper; 9908 9909 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier, 9910 "This variable describes the behavior of the right command key.\n\ 9911Either SYMBOL, describing the behavior for any event,\n\ 9912or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 9913separately for ordinary keys, function keys, and mouse events.\n\ 9914It can also be `left' to use the value of `ns-command-modifier' instead.\n\ 9915\n\ 9916Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 9917If `none', the key is ignored by Emacs and retains its standard meaning."); 9918 ns_right_command_modifier = Qleft; 9919 9920 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier, 9921 "This variable describes the behavior of the control key.\n\ 9922Either SYMBOL, describing the behavior for any event,\n\ 9923or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 9924separately for ordinary keys, function keys, and mouse events.\n\ 9925\n\ 9926Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 9927If `none', the key is ignored by Emacs and retains its standard meaning."); 9928 ns_control_modifier = Qcontrol; 9929 9930 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier, 9931 "This variable describes the behavior of the right control key.\n\ 9932Either SYMBOL, describing the behavior for any event,\n\ 9933or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 9934separately for ordinary keys, function keys, and mouse events.\n\ 9935It can also be `left' to use the value of `ns-control-modifier' instead.\n\ 9936\n\ 9937Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 9938If `none', the key is ignored by Emacs and retains its standard meaning."); 9939 ns_right_control_modifier = Qleft; 9940 9941 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier, 9942 "This variable describes the behavior of the function (fn) key.\n\ 9943Either SYMBOL, describing the behavior for any event,\n\ 9944or (:ordinary SYMBOL :function SYMBOL :mouse SYMBOL), describing behavior\n\ 9945separately for ordinary keys, function keys, and mouse events.\n\ 9946\n\ 9947Each SYMBOL is `control', `meta', `alt', `super', `hyper' or `none'.\n\ 9948If `none', the key is ignored by Emacs and retains its standard meaning."); 9949 ns_function_modifier = Qnone; 9950 9951 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text, 9952 "Non-nil (the default) means to render text antialiased."); 9953 ns_antialias_text = Qt; 9954 9955 DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing, 9956 "Non-nil turns on a font smoothing method that produces thinner strokes."); 9957 ns_use_thin_smoothing = Qnil; 9958 9959 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit, 9960 "Whether to confirm application quit using dialog."); 9961 ns_confirm_quit = Qnil; 9962 9963 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar, 9964 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near. 9965Only works on Mac OS X. */); 9966 ns_auto_hide_menu_bar = Qnil; 9967 9968 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen, 9969 doc: /* Non-nil means to use native fullscreen on Mac OS X 10.7 and later. 9970Nil means use fullscreen the old (< 10.7) way. The old way works better with 9971multiple monitors, but lacks tool bar. This variable is ignored on 9972Mac OS X < 10.7. Default is t. */); 9973 ns_use_native_fullscreen = YES; 9974 ns_last_use_native_fullscreen = ns_use_native_fullscreen; 9975 9976 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation, 9977 doc: /* Non-nil means use animation on non-native fullscreen. 9978For native fullscreen, this does nothing. 9979Default is nil. */); 9980 ns_use_fullscreen_animation = NO; 9981 9982 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace, 9983 doc: /* Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later. 9984Note that this does not apply to images. 9985This variable is ignored on Mac OS X < 10.7 and GNUstep. */); 9986 ns_use_srgb_colorspace = YES; 9987 9988 DEFVAR_BOOL ("ns-use-mwheel-acceleration", 9989 ns_use_mwheel_acceleration, 9990 doc: /* Non-nil means use macOS's standard mouse wheel acceleration. 9991This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */); 9992 ns_use_mwheel_acceleration = YES; 9993 9994 DEFVAR_LISP ("ns-mwheel-line-height", ns_mwheel_line_height, 9995 doc: /* The number of pixels touchpad scrolling considers one line. 9996Nil or a non-number means use the default frame line height. 9997This variable is ignored on macOS < 10.7 and GNUstep. Default is nil. */); 9998 ns_mwheel_line_height = Qnil; 9999 10000 DEFVAR_BOOL ("ns-use-mwheel-momentum", ns_use_mwheel_momentum, 10001 doc: /* Non-nil means mouse wheel scrolling uses momentum. 10002This variable is ignored on macOS < 10.7 and GNUstep. Default is t. */); 10003 ns_use_mwheel_momentum = YES; 10004 10005 /* TODO: Move to common code. */ 10006 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars, 10007 doc: /* SKIP: real doc in xterm.c. */); 10008 Vx_toolkit_scroll_bars = Qt; 10009 10010 DEFVAR_BOOL ("x-use-underline-position-properties", 10011 x_use_underline_position_properties, 10012 doc: /* SKIP: real doc in xterm.c. */); 10013 x_use_underline_position_properties = 0; 10014 DEFSYM (Qx_use_underline_position_properties, 10015 "x-use-underline-position-properties"); 10016 10017 DEFVAR_BOOL ("x-underline-at-descent-line", 10018 x_underline_at_descent_line, 10019 doc: /* SKIP: real doc in xterm.c. */); 10020 x_underline_at_descent_line = 0; 10021 10022 DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line"); 10023 10024 DEFVAR_LISP ("ns-scroll-event-delta-factor", Vns_scroll_event_delta_factor, 10025 doc: /* A factor to apply to pixel deltas reported in scroll events. 10026 This is only effective for pixel deltas generated from touch pads or 10027 mice with smooth scrolling capability. */); 10028 Vns_scroll_event_delta_factor = make_float (1.0); 10029 10030 /* Tell Emacs about this window system. */ 10031 Fprovide (Qns, Qnil); 10032 10033 DEFSYM (Qcocoa, "cocoa"); 10034 DEFSYM (Qgnustep, "gnustep"); 10035 DEFSYM (QCordinary, ":ordinary"); 10036 DEFSYM (QCfunction, ":function"); 10037 DEFSYM (QCmouse, ":mouse"); 10038 10039#ifdef NS_IMPL_COCOA 10040 Fprovide (Qcocoa, Qnil); 10041 syms_of_macfont (); 10042#else 10043 Fprovide (Qgnustep, Qnil); 10044 syms_of_nsfont (); 10045#endif 10046 10047} 10048