1 /* NeXT/Open/GNUstep / macOS communication module. -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2017 Free Software
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30 interpretation of even the system includes. */
36 #include <sys/types.h>
42 #include <c-strcase.h>
46 #include "blockinput.h"
47 #include "sysselect.h"
50 #include "character.h"
52 #include "composite.h"
55 #include "termhooks.h"
63 #ifdef NS_IMPL_GNUSTEP
71 static EmacsMenu *dockMenu;
73 static EmacsMenu *mainMenu;
76 /* ==========================================================================
78 NSTRACE, Trace support.
80 ========================================================================== */
84 /* The following use "volatile" since they can be accessed from
86 volatile int nstrace_num = 0;
87 volatile int nstrace_depth = 0;
89 /* When 0, no trace is emitted. This is used by NSTRACE_WHEN and
90 NSTRACE_UNLESS to silence functions called.
92 TODO: This should really be a thread-local variable, to avoid that
93 a function with disabled trace thread silence trace output in
94 another. However, in practice this seldom is a problem. */
95 volatile int nstrace_enabled_global = 1;
97 /* Called when nstrace_enabled goes out of scope. */
98 void nstrace_leave(int * pointer_to_nstrace_enabled)
100 if (*pointer_to_nstrace_enabled)
107 /* Called when nstrace_saved_enabled_global goes out of scope. */
108 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
110 nstrace_enabled_global = *pointer_to_saved_enabled_global;
114 char const * nstrace_fullscreen_type_name (int fs_type)
118 case -1: return "-1";
119 case FULLSCREEN_NONE: return "FULLSCREEN_NONE";
120 case FULLSCREEN_WIDTH: return "FULLSCREEN_WIDTH";
121 case FULLSCREEN_HEIGHT: return "FULLSCREEN_HEIGHT";
122 case FULLSCREEN_BOTH: return "FULLSCREEN_BOTH";
123 case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
124 default: return "FULLSCREEN_?????";
130 /* ==========================================================================
132 NSColor, EmacsColor category.
134 ========================================================================== */
135 @implementation NSColor (EmacsColor)
136 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
137 blue:(CGFloat)blue alpha:(CGFloat)alpha
140 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
141 if (ns_use_srgb_colorspace)
142 return [NSColor colorWithSRGBRed: red
148 return [NSColor colorWithCalibratedRed: red
154 - (NSColor *)colorUsingDefaultColorSpace
157 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
158 if (ns_use_srgb_colorspace)
159 return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
162 return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
167 /* ==========================================================================
171 ========================================================================== */
173 /* Convert a symbol indexed with an NSxxx value to a value as defined
174 in keyboard.c (lispy_function_key). I hope this is a correct way
175 of doing things... */
176 static unsigned convert_ns_to_X_keysym[] =
178 NSHomeFunctionKey, 0x50,
179 NSLeftArrowFunctionKey, 0x51,
180 NSUpArrowFunctionKey, 0x52,
181 NSRightArrowFunctionKey, 0x53,
182 NSDownArrowFunctionKey, 0x54,
183 NSPageUpFunctionKey, 0x55,
184 NSPageDownFunctionKey, 0x56,
185 NSEndFunctionKey, 0x57,
186 NSBeginFunctionKey, 0x58,
187 NSSelectFunctionKey, 0x60,
188 NSPrintFunctionKey, 0x61,
189 NSClearLineFunctionKey, 0x0B,
190 NSExecuteFunctionKey, 0x62,
191 NSInsertFunctionKey, 0x63,
192 NSUndoFunctionKey, 0x65,
193 NSRedoFunctionKey, 0x66,
194 NSMenuFunctionKey, 0x67,
195 NSFindFunctionKey, 0x68,
196 NSHelpFunctionKey, 0x6A,
197 NSBreakFunctionKey, 0x6B,
199 NSF1FunctionKey, 0xBE,
200 NSF2FunctionKey, 0xBF,
201 NSF3FunctionKey, 0xC0,
202 NSF4FunctionKey, 0xC1,
203 NSF5FunctionKey, 0xC2,
204 NSF6FunctionKey, 0xC3,
205 NSF7FunctionKey, 0xC4,
206 NSF8FunctionKey, 0xC5,
207 NSF9FunctionKey, 0xC6,
208 NSF10FunctionKey, 0xC7,
209 NSF11FunctionKey, 0xC8,
210 NSF12FunctionKey, 0xC9,
211 NSF13FunctionKey, 0xCA,
212 NSF14FunctionKey, 0xCB,
213 NSF15FunctionKey, 0xCC,
214 NSF16FunctionKey, 0xCD,
215 NSF17FunctionKey, 0xCE,
216 NSF18FunctionKey, 0xCF,
217 NSF19FunctionKey, 0xD0,
218 NSF20FunctionKey, 0xD1,
219 NSF21FunctionKey, 0xD2,
220 NSF22FunctionKey, 0xD3,
221 NSF23FunctionKey, 0xD4,
222 NSF24FunctionKey, 0xD5,
224 NSBackspaceCharacter, 0x08, /* 8: Not on some KBs. */
225 NSDeleteCharacter, 0xFF, /* 127: Big 'delete' key upper right. */
226 NSDeleteFunctionKey, 0x9F, /* 63272: Del forw key off main array. */
228 NSTabCharacter, 0x09,
229 0x19, 0x09, /* left tab->regular since pass shift */
230 NSCarriageReturnCharacter, 0x0D,
231 NSNewlineCharacter, 0x0D,
232 NSEnterCharacter, 0x8D,
234 0x41|NSEventModifierFlagNumericPad, 0xAE, /* KP_Decimal */
235 0x43|NSEventModifierFlagNumericPad, 0xAA, /* KP_Multiply */
236 0x45|NSEventModifierFlagNumericPad, 0xAB, /* KP_Add */
237 0x4B|NSEventModifierFlagNumericPad, 0xAF, /* KP_Divide */
238 0x4E|NSEventModifierFlagNumericPad, 0xAD, /* KP_Subtract */
239 0x51|NSEventModifierFlagNumericPad, 0xBD, /* KP_Equal */
240 0x52|NSEventModifierFlagNumericPad, 0xB0, /* KP_0 */
241 0x53|NSEventModifierFlagNumericPad, 0xB1, /* KP_1 */
242 0x54|NSEventModifierFlagNumericPad, 0xB2, /* KP_2 */
243 0x55|NSEventModifierFlagNumericPad, 0xB3, /* KP_3 */
244 0x56|NSEventModifierFlagNumericPad, 0xB4, /* KP_4 */
245 0x57|NSEventModifierFlagNumericPad, 0xB5, /* KP_5 */
246 0x58|NSEventModifierFlagNumericPad, 0xB6, /* KP_6 */
247 0x59|NSEventModifierFlagNumericPad, 0xB7, /* KP_7 */
248 0x5B|NSEventModifierFlagNumericPad, 0xB8, /* KP_8 */
249 0x5C|NSEventModifierFlagNumericPad, 0xB9, /* KP_9 */
251 0x1B, 0x1B /* escape */
254 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
255 the maximum font size to NOT antialias. On GNUstep there is currently
256 no way to control this behavior. */
257 float ns_antialias_threshold;
259 NSArray *ns_send_types = 0, *ns_return_types = 0;
260 static NSArray *ns_drag_types = 0;
261 NSString *ns_app_name = @"Emacs"; /* default changed later */
263 /* Display variables */
264 struct ns_display_info *x_display_list; /* Chain of existing displays */
265 long context_menu_value = 0;
268 static struct frame *ns_updating_frame;
269 static NSView *focus_view = NULL;
270 static int ns_window_num = 0;
271 #ifdef NS_IMPL_GNUSTEP
272 static NSRect uRect; // TODO: This is dead, remove it?
274 static BOOL gsaved = NO;
275 static BOOL ns_fake_keydown = NO;
277 static BOOL ns_menu_bar_is_hidden = NO;
279 /*static int debug_lock = 0; */
282 static BOOL send_appdefined = YES;
283 #define NO_APPDEFINED_DATA (-8)
284 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
285 static NSTimer *timed_entry = 0;
286 static NSTimer *scroll_repeat_entry = nil;
287 static fd_set select_readfds, select_writefds;
288 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
289 static int select_nfds = 0, select_valid = 0;
290 static struct timespec select_timeout = { 0, 0 };
291 static int selfds[2] = { -1, -1 };
292 static pthread_mutex_t select_mutex;
293 static NSAutoreleasePool *outerpool;
294 static struct input_event *emacs_event = NULL;
295 static struct input_event *q_event_ptr = NULL;
296 static int n_emacs_events_pending = 0;
297 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
298 *ns_pending_service_args;
299 static BOOL ns_do_open_file = NO;
300 static BOOL ns_last_use_native_fullscreen;
302 /* Non-zero means that a HELP_EVENT has been generated since Emacs
305 static BOOL any_help_event_p = NO;
308 struct input_event *q;
314 static NSString *represented_filename = nil;
315 static struct frame *represented_frame = 0;
319 * State for pending menu activation:
320 * MENU_NONE Normal state
321 * MENU_PENDING A menu has been clicked on, but has been canceled so we can
322 * run lisp to update the menu.
323 * MENU_OPENING Menu is up to date, and the click event is redone so the menu
327 #define MENU_PENDING 1
328 #define MENU_OPENING 2
329 static int menu_will_open_state = MENU_NONE;
331 /* Saved position for menu click. */
332 static CGPoint menu_mouse_point;
335 /* Convert modifiers in a NeXTstep event to emacs style modifiers. */
336 #define NS_FUNCTION_KEY_MASK 0x800000
337 #define NSLeftControlKeyMask (0x000001 | NSEventModifierFlagControl)
338 #define NSRightControlKeyMask (0x002000 | NSEventModifierFlagControl)
339 #define NSLeftCommandKeyMask (0x000008 | NSEventModifierFlagCommand)
340 #define NSRightCommandKeyMask (0x000010 | NSEventModifierFlagCommand)
341 #define NSLeftAlternateKeyMask (0x000020 | NSEventModifierFlagOption)
342 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
343 #define EV_MODIFIERS2(flags) \
344 (((flags & NSEventModifierFlagHelp) ? \
345 hyper_modifier : 0) \
346 | (!EQ (ns_right_alternate_modifier, Qleft) && \
347 ((flags & NSRightAlternateKeyMask) \
348 == NSRightAlternateKeyMask) ? \
349 parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
350 | ((flags & NSEventModifierFlagOption) ? \
351 parse_solitary_modifier (ns_alternate_modifier) : 0) \
352 | ((flags & NSEventModifierFlagShift) ? \
353 shift_modifier : 0) \
354 | (!EQ (ns_right_control_modifier, Qleft) && \
355 ((flags & NSRightControlKeyMask) \
356 == NSRightControlKeyMask) ? \
357 parse_solitary_modifier (ns_right_control_modifier) : 0) \
358 | ((flags & NSEventModifierFlagControl) ? \
359 parse_solitary_modifier (ns_control_modifier) : 0) \
360 | ((flags & NS_FUNCTION_KEY_MASK) ? \
361 parse_solitary_modifier (ns_function_modifier) : 0) \
362 | (!EQ (ns_right_command_modifier, Qleft) && \
363 ((flags & NSRightCommandKeyMask) \
364 == NSRightCommandKeyMask) ? \
365 parse_solitary_modifier (ns_right_command_modifier) : 0) \
366 | ((flags & NSEventModifierFlagCommand) ? \
367 parse_solitary_modifier (ns_command_modifier):0))
368 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
370 #define EV_UDMODIFIERS(e) \
371 ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0) \
372 | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0) \
373 | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0) \
374 | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0) \
375 | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
376 | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
377 | (([e type] == NSEventTypeLeftMouseUp) ? up_modifier : 0) \
378 | (([e type] == NSEventTypeRightMouseUp) ? up_modifier : 0) \
379 | (([e type] == NSEventTypeOtherMouseUp) ? up_modifier : 0))
381 #define EV_BUTTON(e) \
382 ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 : \
383 (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
384 [e buttonNumber] - 1)
386 /* Convert the time field to a timestamp in milliseconds. */
387 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
389 /* This is a piece of code which is common to all the event handling
390 methods. Maybe it should even be a function. */
391 #define EV_TRAILER(e) \
393 XSETFRAME (emacs_event->frame_or_window, emacsframe); \
397 #define EV_TRAILER2(e) \
399 if (e) emacs_event->timestamp = EV_TIMESTAMP (e); \
402 Lisp_Object tem = Vinhibit_quit; \
403 Vinhibit_quit = Qt; \
404 n_emacs_events_pending++; \
405 kbd_buffer_store_event_hold (emacs_event, q_event_ptr); \
406 Vinhibit_quit = tem; \
409 hold_event (emacs_event); \
410 EVENT_INIT (*emacs_event); \
411 ns_send_appdefined (-1); \
415 /* GNUstep always shows decorations if the window is resizable,
416 miniaturizable or closable, but Cocoa does strange things in native
417 fullscreen mode if you don't have at least resizable enabled.
419 These flags will be OR'd or XOR'd with the NSWindow's styleMask
420 property depending on what we're doing. */
422 #define FRAME_DECORATED_FLAGS NSWindowStyleMaskTitled
424 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled \
425 | NSWindowStyleMaskResizable \
426 | NSWindowStyleMaskMiniaturizable \
427 | NSWindowStyleMaskClosable)
429 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
431 /* TODO: get rid of need for these forward declarations */
432 static void ns_condemn_scroll_bars (struct frame *f);
433 static void ns_judge_scroll_bars (struct frame *f);
436 /* ==========================================================================
440 ========================================================================== */
443 ns_set_represented_filename (NSString *fstr, struct frame *f)
445 represented_filename = [fstr retain];
446 represented_frame = f;
450 ns_init_events (struct input_event *ev)
457 ns_finish_events (void)
463 hold_event (struct input_event *event)
465 if (hold_event_q.nr == hold_event_q.cap)
467 if (hold_event_q.cap == 0) hold_event_q.cap = 10;
468 else hold_event_q.cap *= 2;
470 xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
473 hold_event_q.q[hold_event_q.nr++] = *event;
474 /* Make sure ns_read_socket is called, i.e. we have input. */
476 send_appdefined = YES;
480 append2 (Lisp_Object list, Lisp_Object item)
481 /* --------------------------------------------------------------------------
482 Utility to append to a list
483 -------------------------------------------------------------------------- */
485 return CALLN (Fnconc, list, list1 (item));
490 ns_etc_directory (void)
491 /* If running as a self-contained app bundle, return as a string the
492 filename of the etc directory, if present; else nil. */
494 NSBundle *bundle = [NSBundle mainBundle];
495 NSString *resourceDir = [bundle resourcePath];
496 NSString *resourcePath;
497 NSFileManager *fileManager = [NSFileManager defaultManager];
500 resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
501 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
503 if (isDir) return [resourcePath UTF8String];
511 /* If running as a self-contained app bundle, return as a path string
512 the filenames of the libexec and bin directories, ie libexec:bin.
513 Otherwise, return nil.
514 Normally, Emacs does not add its own bin/ directory to the PATH.
515 However, a self-contained NS build has a different layout, with
516 bin/ and libexec/ subdirectories in the directory that contains
518 We put libexec first, because init_callproc_1 uses the first
519 element to initialize exec-directory. An alternative would be
520 for init_callproc to check for invocation-directory/libexec.
523 NSBundle *bundle = [NSBundle mainBundle];
524 NSString *resourceDir = [bundle resourcePath];
525 NSString *binDir = [bundle bundlePath];
526 NSString *resourcePath, *resourcePaths;
528 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
529 NSFileManager *fileManager = [NSFileManager defaultManager];
531 NSEnumerator *pathEnum;
534 range = [resourceDir rangeOfString: @"Contents"];
535 if (range.location != NSNotFound)
537 binDir = [binDir stringByAppendingPathComponent: @"Contents"];
539 binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
543 paths = [binDir stringsByAppendingPaths:
544 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
545 pathEnum = [paths objectEnumerator];
548 while ((resourcePath = [pathEnum nextObject]))
550 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
553 if ([resourcePaths length] > 0)
555 = [resourcePaths stringByAppendingString: pathSeparator];
557 = [resourcePaths stringByAppendingString: resourcePath];
560 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
568 /* If running as a self-contained app bundle, return as a path string
569 the filenames of the site-lisp and lisp directories.
570 Ie, site-lisp:lisp. Otherwise, return nil. */
572 NSBundle *bundle = [NSBundle mainBundle];
573 NSString *resourceDir = [bundle resourcePath];
574 NSString *resourcePath, *resourcePaths;
575 NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
576 NSFileManager *fileManager = [NSFileManager defaultManager];
578 NSArray *paths = [resourceDir stringsByAppendingPaths:
579 [NSArray arrayWithObjects:
580 @"site-lisp", @"lisp", nil]];
581 NSEnumerator *pathEnum = [paths objectEnumerator];
584 /* Hack to skip site-lisp. */
585 if (no_site_lisp) resourcePath = [pathEnum nextObject];
587 while ((resourcePath = [pathEnum nextObject]))
589 if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
592 if ([resourcePaths length] > 0)
594 = [resourcePaths stringByAppendingString: pathSeparator];
596 = [resourcePaths stringByAppendingString: resourcePath];
599 if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
606 ns_init_locale (void)
607 /* macOS doesn't set any environment variables for the locale when run
608 from the GUI. Get the locale from the OS and set LANG. */
610 NSLocale *locale = [NSLocale currentLocale];
612 NSTRACE ("ns_init_locale");
616 /* It seems macOS should probably use UTF-8 everywhere.
617 'localeIdentifier' does not specify the encoding, and I can't
618 find any way to get the OS to tell us which encoding to use,
619 so hard-code '.UTF-8'. */
620 NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
621 [locale localeIdentifier]];
623 /* Set LANG to locale, but not if LANG is already set. */
624 setenv("LANG", [localeID UTF8String], 0);
626 @catch (NSException *e)
628 NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
634 ns_release_object (void *obj)
635 /* --------------------------------------------------------------------------
636 Release an object (callable from C)
637 -------------------------------------------------------------------------- */
644 ns_retain_object (void *obj)
645 /* --------------------------------------------------------------------------
646 Retain an object (callable from C)
647 -------------------------------------------------------------------------- */
654 ns_alloc_autorelease_pool (void)
655 /* --------------------------------------------------------------------------
656 Allocate a pool for temporary objects (callable from C)
657 -------------------------------------------------------------------------- */
659 return [[NSAutoreleasePool alloc] init];
664 ns_release_autorelease_pool (void *pool)
665 /* --------------------------------------------------------------------------
666 Free a pool and temporary objects it refers to (callable from C)
667 -------------------------------------------------------------------------- */
669 ns_release_object (pool);
674 ns_menu_bar_should_be_hidden (void)
675 /* True, if the menu bar should be hidden. */
677 return !NILP (ns_auto_hide_menu_bar)
678 && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
691 static struct EmacsMargins
692 ns_screen_margins (NSScreen *screen)
693 /* The parts of SCREEN used by the operating system. */
695 NSTRACE ("ns_screen_margins");
697 struct EmacsMargins margins;
699 NSRect screenFrame = [screen frame];
700 NSRect screenVisibleFrame = [screen visibleFrame];
702 /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
703 menu bar, check this explicitly. */
704 if (ns_menu_bar_should_be_hidden())
710 CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
711 CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
712 + screenVisibleFrame.size.height);
714 margins.top = frameTop - visibleFrameTop;
718 CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
719 CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
720 + screenVisibleFrame.size.width);
721 margins.right = frameRight - visibleFrameRight;
724 margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
725 margins.left = screenVisibleFrame.origin.x - screenFrame.origin.x;
727 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
737 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
738 assumed to contain a hidden dock. macOS currently use 4 pixels for
739 this, however, to be future compatible, a larger value is used. */
740 #define DOCK_IGNORE_LIMIT 6
742 static struct EmacsMargins
743 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
744 /* The parts of SCREEN used by the operating system, excluding the parts
745 reserved for an hidden dock. */
747 NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
749 struct EmacsMargins margins = ns_screen_margins(screen);
751 /* macOS (currently) reserved 4 pixels along the edge where a hidden
752 dock is located. Unfortunately, it's not possible to find the
753 location and information about if the dock is hidden. Instead,
754 it is assumed that if the margin of an edge is less than
755 DOCK_IGNORE_LIMIT, it contains a hidden dock. */
756 if (margins.left <= DOCK_IGNORE_LIMIT)
760 if (margins.right <= DOCK_IGNORE_LIMIT)
764 if (margins.top <= DOCK_IGNORE_LIMIT)
768 /* Note: This doesn't occur in current versions of macOS, but
769 included for completeness and future compatibility. */
770 if (margins.bottom <= DOCK_IGNORE_LIMIT)
775 NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
786 ns_menu_bar_height (NSScreen *screen)
787 /* The height of the menu bar, if visible.
789 Note: Don't use this when fullscreen is enabled -- the screen
790 sometimes includes, sometimes excludes the menu bar area. */
792 struct EmacsMargins margins = ns_screen_margins(screen);
794 CGFloat res = margins.top;
796 NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
802 /* ==========================================================================
804 Focus (clipping) and screen update
806 ========================================================================== */
809 // Window constraining
810 // -------------------
812 // To ensure that the windows are not placed under the menu bar, they
813 // are typically moved by the call-back constrainFrameRect. However,
814 // by overriding it, it's possible to inhibit this, leaving the window
815 // in it's original position.
817 // It's possible to hide the menu bar. However, technically, it's only
818 // possible to hide it when the application is active. To ensure that
819 // this work properly, the menu bar and window constraining are
820 // deferred until the application becomes active.
822 // Even though it's not possible to manually move a window above the
823 // top of the screen, it is allowed if it's done programmatically,
824 // when the menu is hidden. This allows the editable area to cover the
825 // full screen height.
830 // Use the following extra files:
833 // ;; Hide menu and place frame slightly above the top of the screen.
834 // (setq ns-auto-hide-menu-bar t)
835 // (set-frame-position (selected-frame) 0 -20)
839 // emacs -Q -l init.el
841 // Result: No menu bar, and the title bar should be above the screen.
847 // Result: Menu bar visible, frame placed immediately below the menu.
850 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
852 NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
853 NSTRACE_ARG_RECT (frameRect));
855 // --------------------
856 // Collect information about the screen the frame is covering.
859 NSArray *screens = [NSScreen screens];
860 NSUInteger nr_screens = [screens count];
864 // The height of the menu bar, if present in any screen the frame is
866 int menu_bar_height = 0;
868 // A rectangle covering all the screen the frame is displayed in.
869 NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
870 for (i = 0; i < nr_screens; ++i )
872 NSScreen *s = [screens objectAtIndex: i];
873 NSRect scrRect = [s frame];
875 NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
876 i, NSTRACE_ARG_RECT (scrRect));
878 if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
880 multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
884 CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
885 menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
890 NSTRACE_RECT ("multiscreenRect", multiscreenRect);
892 NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
894 if (multiscreenRect.size.width == 0
895 || multiscreenRect.size.height == 0)
897 // Failed to find any monitor, give up.
898 NSTRACE_MSG ("multiscreenRect empty");
899 NSTRACE_RETURN_RECT (frameRect);
904 // --------------------
905 // Find a suitable placement.
908 if (ns_menu_bar_should_be_hidden())
910 // When the menu bar is hidden, the user may place part of the
911 // frame above the top of the screen, for example to hide the
914 // Hence, keep the original position.
918 // Ensure that the frame is below the menu bar, or below the top
921 // This assume that the menu bar is placed at the top in the
922 // rectangle that covers the monitors. (It doesn't have to be,
923 // but if it's not it's hard to do anything useful.)
924 CGFloat topOfWorkArea = (multiscreenRect.origin.y
925 + multiscreenRect.size.height
928 CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
929 if (topOfFrame > topOfWorkArea)
931 frameRect.origin.y -= topOfFrame - topOfWorkArea;
932 NSTRACE_RECT ("After placement adjust", frameRect);
936 // Include the following section to restrict frame to the screens.
937 // (If so, update it to allow the frame to stretch down below the
940 // --------------------
941 // Ensure frame doesn't stretch below the screens.
944 CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
948 frameRect.origin.y = multiscreenRect.origin.y;
949 frameRect.size.height -= diff;
953 NSTRACE_RETURN_RECT (frameRect);
959 ns_constrain_all_frames (void)
960 /* --------------------------------------------------------------------------
961 Ensure that the menu bar doesn't cover any frames.
962 -------------------------------------------------------------------------- */
964 Lisp_Object tail, frame;
966 NSTRACE ("ns_constrain_all_frames");
970 FOR_EACH_FRAME (tail, frame)
972 struct frame *f = XFRAME (frame);
975 EmacsView *view = FRAME_NS_VIEW (f);
977 if (![view isFullscreen])
980 setFrame:constrain_frame_rect([[view window] frame], false)
991 ns_update_auto_hide_menu_bar (void)
992 /* --------------------------------------------------------------------------
993 Show or hide the menu bar, based on user setting.
994 -------------------------------------------------------------------------- */
997 NSTRACE ("ns_update_auto_hide_menu_bar");
1001 if (NSApp != nil && [NSApp isActive])
1003 // Note, "setPresentationOptions" triggers an error unless the
1004 // application is active.
1005 BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1007 if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1009 NSApplicationPresentationOptions options
1010 = NSApplicationPresentationDefault;
1012 if (menu_bar_should_be_hidden)
1013 options |= NSApplicationPresentationAutoHideMenuBar
1014 | NSApplicationPresentationAutoHideDock;
1016 [NSApp setPresentationOptions: options];
1018 ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1020 if (!ns_menu_bar_is_hidden)
1022 ns_constrain_all_frames ();
1033 ns_update_begin (struct frame *f)
1034 /* --------------------------------------------------------------------------
1035 Prepare for a grouped sequence of drawing calls
1036 external (RIF) call; whole frame, called before update_window_begin
1037 -------------------------------------------------------------------------- */
1039 EmacsView *view = FRAME_NS_VIEW (f);
1040 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1042 ns_update_auto_hide_menu_bar ();
1044 #ifdef NS_IMPL_COCOA
1045 if ([view isFullscreen] && [view fsIsNative])
1047 // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1048 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1049 NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1050 if (! tbar_visible != ! [toolbar isVisible])
1051 [toolbar setVisible: tbar_visible];
1055 ns_updating_frame = f;
1058 /* drawRect may have been called for say the minibuffer, and then clip path
1059 is for the minibuffer. But the display engine may draw more because
1060 we have set the frame as garbaged. So reset clip path to the whole
1062 #ifdef NS_IMPL_COCOA
1065 NSRect r = [view frame];
1066 NSRect cr = [[view window] frame];
1067 /* If a large frame size is set, r may be larger than the window frame
1068 before constrained. In that case don't change the clip path, as we
1069 will clear in to the tool bar and title bar. */
1071 + FRAME_NS_TITLEBAR_HEIGHT (f)
1072 + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1074 bp = [[NSBezierPath bezierPathWithRect: r] retain];
1081 #ifdef NS_IMPL_GNUSTEP
1082 uRect = NSMakeRect (0, 0, 0, 0);
1088 ns_update_window_begin (struct window *w)
1089 /* --------------------------------------------------------------------------
1090 Prepare for a grouped sequence of drawing calls
1091 external (RIF) call; for one window, called after update_begin
1092 -------------------------------------------------------------------------- */
1094 struct frame *f = XFRAME (WINDOW_FRAME (w));
1095 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1097 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1098 w->output_cursor = w->cursor;
1102 if (f == hlinfo->mouse_face_mouse_frame)
1104 /* Don't do highlighting for mouse motion during the update. */
1105 hlinfo->mouse_face_defer = 1;
1107 /* If the frame needs to be redrawn,
1108 simply forget about any prior mouse highlighting. */
1109 if (FRAME_GARBAGED_P (f))
1110 hlinfo->mouse_face_window = Qnil;
1112 /* (further code for mouse faces ifdef'd out in other terms elided) */
1120 ns_update_window_end (struct window *w, bool cursor_on_p,
1121 bool mouse_face_overwritten_p)
1122 /* --------------------------------------------------------------------------
1123 Finished a grouped sequence of drawing calls
1124 external (RIF) call; for one window called before update_end
1125 -------------------------------------------------------------------------- */
1127 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1129 /* note: this fn is nearly identical in all terms */
1130 if (!w->pseudo_window_p)
1135 display_and_set_cursor (w, 1,
1136 w->output_cursor.hpos, w->output_cursor.vpos,
1137 w->output_cursor.x, w->output_cursor.y);
1139 if (draw_window_fringes (w, 1))
1141 if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1142 x_draw_right_divider (w);
1144 x_draw_vertical_border (w);
1150 /* If a row with mouse-face was overwritten, arrange for
1151 frame_up_to_date to redisplay the mouse highlight. */
1152 if (mouse_face_overwritten_p)
1153 reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1158 ns_update_end (struct frame *f)
1159 /* --------------------------------------------------------------------------
1160 Finished a grouped sequence of drawing calls
1161 external (RIF) call; for whole frame, called after update_window_end
1162 -------------------------------------------------------------------------- */
1164 EmacsView *view = FRAME_NS_VIEW (f);
1166 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1168 /* if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1169 MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1174 [[view window] flushWindow];
1177 ns_updating_frame = NULL;
1181 ns_focus (struct frame *f, NSRect *r, int n)
1182 /* --------------------------------------------------------------------------
1183 Internal: Focus on given frame. During small local updates this is used to
1184 draw, however during large updates, ns_update_begin and ns_update_end are
1185 called to wrap the whole thing, in which case these calls are stubbed out.
1186 Except, on GNUstep, we accumulate the rectangle being drawn into, because
1187 the back end won't do this automatically, and will just end up flushing
1189 -------------------------------------------------------------------------- */
1191 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1194 NSTRACE_RECT ("r", *r);
1197 if (f != ns_updating_frame)
1199 NSView *view = FRAME_NS_VIEW (f);
1200 if (view != focus_view)
1202 if (focus_view != NULL)
1204 [focus_view unlockFocus];
1205 [[focus_view window] flushWindow];
1212 /*if (view) debug_lock++; */
1219 [[NSGraphicsContext currentContext] saveGraphicsState];
1221 NSRectClipList (r, 2);
1230 ns_unfocus (struct frame *f)
1231 /* --------------------------------------------------------------------------
1232 Internal: Remove focus on given frame
1233 -------------------------------------------------------------------------- */
1235 NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1239 [[NSGraphicsContext currentContext] restoreGraphicsState];
1243 if (f != ns_updating_frame)
1245 if (focus_view != NULL)
1247 [focus_view unlockFocus];
1248 [[focus_view window] flushWindow];
1257 ns_clip_to_row (struct window *w, struct glyph_row *row,
1258 enum glyph_row_area area, BOOL gc)
1259 /* --------------------------------------------------------------------------
1260 Internal (but parallels other terms): Focus drawing on given row
1261 -------------------------------------------------------------------------- */
1263 struct frame *f = XFRAME (WINDOW_FRAME (w));
1265 int window_x, window_y, window_width;
1267 window_box (w, area, &window_x, &window_y, &window_width, 0);
1269 clip_rect.origin.x = window_x;
1270 clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1271 clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1272 clip_rect.size.width = window_width;
1273 clip_rect.size.height = row->visible_height;
1275 ns_focus (f, &clip_rect, 1);
1279 /* ==========================================================================
1281 Visible bell and beep.
1283 ========================================================================== */
1286 // This bell implementation shows the visual bell image asynchronously
1287 // from the rest of Emacs. This is done by adding a NSView to the
1288 // superview of the Emacs window and removing it using a timer.
1290 // Unfortunately, some Emacs operations, like scrolling, is done using
1291 // low-level primitives that copy the content of the window, including
1292 // the bell image. To some extent, this is handled by removing the
1293 // image prior to scrolling and marking that the window is in need for
1296 // To test this code, make sure that there is no artifacts of the bell
1297 // image in the following situations. Use a non-empty buffer (like the
1298 // tutorial) to ensure that a scroll is performed:
1300 // * Single-window: C-g C-v
1302 // * Side-by-windows: C-x 3 C-g C-v
1304 // * Windows above each other: C-x 2 C-g C-v
1306 @interface EmacsBell : NSImageView
1308 // Number of currently active bell:s.
1309 unsigned int nestCount;
1313 - (void)show:(NSView *)view;
1318 @implementation EmacsBell
1322 NSTRACE ("[EmacsBell init]");
1323 if ((self = [super init]))
1327 #ifdef NS_IMPL_GNUSTEP
1328 // GNUstep doesn't provide named images. This was reported in
1329 // 2011, see https://savannah.gnu.org/bugs/?33396
1331 // As a drop in replacement, a semitransparent gray square is used.
1332 self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1333 [self.image lockFocus];
1334 [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1335 NSRectFill(NSMakeRect(0, 0, 32, 32));
1336 [self.image unlockFocus];
1338 self.image = [NSImage imageNamed:NSImageNameCaution];
1339 [self.image setSize:NSMakeSize(self.image.size.width * 5,
1340 self.image.size.height * 5)];
1346 - (void)show:(NSView *)view
1348 NSTRACE ("[EmacsBell show:]");
1349 NSTRACE_MSG ("nestCount: %u", nestCount);
1351 // Show the image, unless it's already shown.
1354 NSRect rect = [view bounds];
1356 pos.x = rect.origin.x + (rect.size.width - self.image.size.width )/2;
1357 pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1359 [self setFrameOrigin:pos];
1360 [self setFrameSize:self.image.size];
1364 [[[view window] contentView] addSubview:self
1365 positioned:NSWindowAbove
1371 [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1377 // Note: Trace output from this method isn't shown, reason unknown.
1378 // NSTRACE ("[EmacsBell hide]");
1383 // Remove the image once the last bell became inactive.
1393 NSTRACE ("[EmacsBell remove]");
1396 NSTRACE_MSG ("removeFromSuperview");
1397 [self removeFromSuperview];
1398 mView.needsDisplay = YES;
1406 static EmacsBell * bell_view = nil;
1409 ns_ring_bell (struct frame *f)
1410 /* --------------------------------------------------------------------------
1412 -------------------------------------------------------------------------- */
1414 NSTRACE ("ns_ring_bell");
1417 struct frame *frame = SELECTED_FRAME ();
1420 if (bell_view == nil)
1422 bell_view = [[EmacsBell alloc] init];
1428 view = FRAME_NS_VIEW (frame);
1431 [bell_view show:view];
1445 /* --------------------------------------------------------------------------
1446 Ensure the bell is hidden.
1447 -------------------------------------------------------------------------- */
1449 NSTRACE ("hide_bell");
1451 if (bell_view != nil)
1458 /* ==========================================================================
1460 Frame / window manager related functions
1462 ========================================================================== */
1466 ns_raise_frame (struct frame *f, BOOL make_key)
1467 /* --------------------------------------------------------------------------
1468 Bring window to foreground and if make_key is YES, give it focus.
1469 -------------------------------------------------------------------------- */
1473 check_window_system (f);
1474 view = FRAME_NS_VIEW (f);
1476 if (FRAME_VISIBLE_P (f))
1479 [[view window] makeKeyAndOrderFront: NSApp];
1481 [[view window] orderFront: NSApp];
1488 ns_lower_frame (struct frame *f)
1489 /* --------------------------------------------------------------------------
1491 -------------------------------------------------------------------------- */
1495 check_window_system (f);
1496 view = FRAME_NS_VIEW (f);
1498 [[view window] orderBack: NSApp];
1504 ns_frame_raise_lower (struct frame *f, bool raise)
1505 /* --------------------------------------------------------------------------
1507 -------------------------------------------------------------------------- */
1509 NSTRACE ("ns_frame_raise_lower");
1512 ns_raise_frame (f, YES);
1519 ns_frame_rehighlight (struct frame *frame)
1520 /* --------------------------------------------------------------------------
1521 External (hook): called on things like window switching within frame
1522 -------------------------------------------------------------------------- */
1524 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1525 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1527 NSTRACE ("ns_frame_rehighlight");
1528 if (dpyinfo->x_focus_frame)
1530 dpyinfo->x_highlight_frame
1531 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1532 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1533 : dpyinfo->x_focus_frame);
1534 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1536 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1537 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1541 dpyinfo->x_highlight_frame = 0;
1543 if (dpyinfo->x_highlight_frame &&
1544 dpyinfo->x_highlight_frame != old_highlight)
1548 x_update_cursor (old_highlight, 1);
1549 x_set_frame_alpha (old_highlight);
1551 if (dpyinfo->x_highlight_frame)
1553 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1554 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1561 x_make_frame_visible (struct frame *f)
1562 /* --------------------------------------------------------------------------
1563 External: Show the window (X11 semantics)
1564 -------------------------------------------------------------------------- */
1566 NSTRACE ("x_make_frame_visible");
1567 /* XXX: at some points in past this was not needed, as the only place that
1568 called this (frame.c:Fraise_frame ()) also called raise_lower;
1569 if this ends up the case again, comment this out again. */
1570 if (!FRAME_VISIBLE_P (f))
1572 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1573 NSWindow *window = [view window];
1575 SET_FRAME_VISIBLE (f, 1);
1576 ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1578 /* Making a new frame from a fullscreen frame will make the new frame
1579 fullscreen also. So skip handleFS as this will print an error. */
1580 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1581 && [view isFullscreen])
1584 if (f->want_fullscreen != FULLSCREEN_NONE)
1591 /* Making a frame invisible seems to break the parent->child
1592 relationship, so reinstate it. */
1593 if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1595 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1598 [parent addChildWindow: window
1599 ordered: NSWindowAbove];
1602 /* If the parent frame moved while the child frame was
1603 invisible, the child frame's position won't have been
1604 updated. Make sure it's in the right place now. */
1605 x_set_offset(f, f->left_pos, f->top_pos, 0);
1612 x_make_frame_invisible (struct frame *f)
1613 /* --------------------------------------------------------------------------
1614 External: Hide the window (X11 semantics)
1615 -------------------------------------------------------------------------- */
1618 NSTRACE ("x_make_frame_invisible");
1619 check_window_system (f);
1620 view = FRAME_NS_VIEW (f);
1621 [[view window] orderOut: NSApp];
1622 SET_FRAME_VISIBLE (f, 0);
1623 SET_FRAME_ICONIFIED (f, 0);
1628 x_iconify_frame (struct frame *f)
1629 /* --------------------------------------------------------------------------
1630 External: Iconify window
1631 -------------------------------------------------------------------------- */
1634 struct ns_display_info *dpyinfo;
1636 NSTRACE ("x_iconify_frame");
1637 check_window_system (f);
1638 view = FRAME_NS_VIEW (f);
1639 dpyinfo = FRAME_DISPLAY_INFO (f);
1641 if (dpyinfo->x_highlight_frame == f)
1642 dpyinfo->x_highlight_frame = 0;
1644 if ([[view window] windowNumber] <= 0)
1646 /* the window is still deferred. Make it very small, bring it
1647 on screen and order it out. */
1648 NSRect s = { { 100, 100}, {0, 0} };
1650 t = [[view window] frame];
1651 [[view window] setFrame: s display: NO];
1652 [[view window] orderBack: NSApp];
1653 [[view window] orderOut: NSApp];
1654 [[view window] setFrame: t display: NO];
1657 /* Processing input while Emacs is being minimized can cause a
1658 crash, so block it for the duration. */
1660 [[view window] miniaturize: NSApp];
1664 /* Free X resources of frame F. */
1667 x_free_frame_resources (struct frame *f)
1670 struct ns_display_info *dpyinfo;
1671 Mouse_HLInfo *hlinfo;
1673 NSTRACE ("x_free_frame_resources");
1674 check_window_system (f);
1675 view = FRAME_NS_VIEW (f);
1676 dpyinfo = FRAME_DISPLAY_INFO (f);
1677 hlinfo = MOUSE_HL_INFO (f);
1679 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1683 free_frame_menubar (f);
1684 free_frame_faces (f);
1686 if (f == dpyinfo->x_focus_frame)
1687 dpyinfo->x_focus_frame = 0;
1688 if (f == dpyinfo->x_highlight_frame)
1689 dpyinfo->x_highlight_frame = 0;
1690 if (f == hlinfo->mouse_face_mouse_frame)
1691 reset_mouse_highlight (hlinfo);
1693 if (f->output_data.ns->miniimage != nil)
1694 [f->output_data.ns->miniimage release];
1696 [[view window] close];
1699 xfree (f->output_data.ns);
1705 x_destroy_window (struct frame *f)
1706 /* --------------------------------------------------------------------------
1707 External: Delete the window
1708 -------------------------------------------------------------------------- */
1710 NSTRACE ("x_destroy_window");
1712 /* If this frame has a parent window, detach it as not doing so can
1713 cause a crash in GNUStep. */
1714 if (FRAME_PARENT_FRAME (f) != NULL)
1716 NSWindow *child = [FRAME_NS_VIEW (f) window];
1717 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1719 [parent removeChildWindow: child];
1722 check_window_system (f);
1723 x_free_frame_resources (f);
1729 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1730 /* --------------------------------------------------------------------------
1731 External: Position the window
1732 -------------------------------------------------------------------------- */
1734 NSView *view = FRAME_NS_VIEW (f);
1735 NSArray *screens = [NSScreen screens];
1736 NSScreen *fscreen = [screens objectAtIndex: 0];
1737 NSScreen *screen = [[view window] screen];
1739 NSTRACE ("x_set_offset");
1746 if (view != nil && screen && fscreen)
1748 f->left_pos = f->size_hint_flags & XNegative
1749 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1751 /* We use visibleFrame here to take menu bar into account.
1752 Ideally we should also adjust left/top with visibleFrame.origin. */
1754 f->top_pos = f->size_hint_flags & YNegative
1755 ? ([screen visibleFrame].size.height + f->top_pos
1756 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1757 - FRAME_TOOLBAR_HEIGHT (f))
1759 #ifdef NS_IMPL_GNUSTEP
1760 if (FRAME_PARENT_FRAME (f) == NULL)
1762 if (f->left_pos < 100)
1763 f->left_pos = 100; /* don't overlap menu */
1766 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1768 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1769 + NS_PARENT_WINDOW_LEFT_POS (f)),
1770 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1772 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1773 [[view window] setFrameTopLeftPoint: pt];
1774 f->size_hint_flags &= ~(XNegative|YNegative);
1782 x_set_window_size (struct frame *f,
1783 bool change_gravity,
1787 /* --------------------------------------------------------------------------
1788 Adjust window pixel size based on given character grid size
1789 Impl is a bit more complex than other terms, need to do some
1791 -------------------------------------------------------------------------- */
1793 EmacsView *view = FRAME_NS_VIEW (f);
1794 NSWindow *window = [view window];
1795 NSRect wr = [window frame];
1796 int pixelwidth, pixelheight;
1797 int orig_height = wr.size.height;
1799 NSTRACE ("x_set_window_size");
1804 NSTRACE_RECT ("current", wr);
1805 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1806 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1812 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1813 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1817 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1818 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1821 wr.size.width = pixelwidth + f->border_width;
1822 wr.size.height = pixelheight;
1823 if (! [view isFullscreen])
1824 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1825 + FRAME_TOOLBAR_HEIGHT (f);
1827 /* Do not try to constrain to this screen. We may have multiple
1828 screens, and want Emacs to span those. Constraining to screen
1829 prevents that, and that is not nice to the user. */
1830 if (f->output_data.ns->zooming)
1831 f->output_data.ns->zooming = 0;
1833 wr.origin.y += orig_height - wr.size.height;
1835 frame_size_history_add
1836 (f, Qx_set_window_size_1, width, height,
1837 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1838 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1839 make_number (f->border_width),
1840 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1841 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1843 [window setFrame: wr display: YES];
1845 [view updateFrameSize: NO];
1849 #ifdef NS_IMPL_COCOA
1851 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1852 /* --------------------------------------------------------------------------
1853 Set frame F's `undecorated' parameter. If non-nil, F's window-system
1854 window is drawn without decorations, title, minimize/maximize boxes
1855 and external borders. This usually means that the window cannot be
1856 dragged, resized, iconified, maximized or deleted with the mouse. If
1857 nil, draw the frame with all the elements listed above unless these
1858 have been suspended via window manager settings.
1860 GNUStep cannot change an existing window's style.
1861 -------------------------------------------------------------------------- */
1863 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1864 NSWindow *window = [view window];
1866 NSTRACE ("x_set_undecorated");
1868 if (!EQ (new_value, old_value))
1872 if (NILP (new_value))
1874 FRAME_UNDECORATED (f) = false;
1875 [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1876 ^ FRAME_UNDECORATED_FLAGS)];
1878 [view createToolbar: f];
1882 [window setToolbar: nil];
1883 /* Do I need to release the toolbar here? */
1885 FRAME_UNDECORATED (f) = true;
1886 [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1887 ^ FRAME_DECORATED_FLAGS)];
1890 /* At this point it seems we don't have an active NSResponder,
1891 so some key presses (TAB) are swallowed by the system. */
1892 [window makeFirstResponder: view];
1894 [view updateFrameSize: NO];
1898 #endif /* NS_IMPL_COCOA */
1901 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1902 /* --------------------------------------------------------------------------
1903 Set frame F's `parent-frame' parameter. If non-nil, make F a child
1904 frame of the frame specified by that parameter. Technically, this
1905 makes F's window-system window a child window of the parent frame's
1906 window-system window. If nil, make F's window-system window a
1907 top-level window--a child of its display's root window.
1909 A child frame's `left' and `top' parameters specify positions
1910 relative to the top-left corner of its parent frame's native
1911 rectangle. On macOS moving a parent frame moves all its child
1912 frames too, keeping their position relative to the parent
1913 unaltered. When a parent frame is iconified or made invisible, its
1914 child frames are made invisible. When a parent frame is deleted,
1915 its child frames are deleted too.
1917 Whether a child frame has a tool bar may be window-system or window
1918 manager dependent. It's advisable to disable it via the frame
1921 Some window managers may not honor this parameter.
1922 -------------------------------------------------------------------------- */
1924 struct frame *p = NULL;
1925 NSWindow *parent, *child;
1927 NSTRACE ("x_set_parent_frame");
1929 if (!NILP (new_value)
1930 && (!FRAMEP (new_value)
1931 || !FRAME_LIVE_P (p = XFRAME (new_value))
1934 store_frame_param (f, Qparent_frame, old_value);
1935 error ("Invalid specification of `parent-frame'");
1938 if (p != FRAME_PARENT_FRAME (f))
1940 parent = [FRAME_NS_VIEW (p) window];
1941 child = [FRAME_NS_VIEW (f) window];
1944 [parent addChildWindow: child
1945 ordered: NSWindowAbove];
1948 fset_parent_frame (f, new_value);
1953 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1954 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
1955 * that F's window-system window does not want to receive input focus
1956 * when it is mapped. (A frame's window is mapped when the frame is
1957 * displayed for the first time and when the frame changes its state
1958 * from `iconified' or `invisible' to `visible'.)
1960 * Some window managers may not honor this parameter. */
1962 NSTRACE ("x_set_no_focus_on_map");
1964 if (!EQ (new_value, old_value))
1966 FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1971 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1972 /* Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1973 * that F's window-system window does not want to receive input focus
1974 * via mouse clicks or by moving the mouse into it.
1976 * If non-nil, this may have the unwanted side-effect that a user cannot
1977 * scroll a non-selected frame with the mouse.
1979 * Some window managers may not honor this parameter. */
1981 NSTRACE ("x_set_no_accept_focus");
1983 if (!EQ (new_value, old_value))
1984 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1988 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1989 /* Set frame F's `z-group' parameter. If `above', F's window-system
1990 window is displayed above all windows that do not have the `above'
1991 property set. If nil, F's window is shown below all windows that
1992 have the `above' property set and above all windows that have the
1993 `below' property set. If `below', F's window is displayed below
1994 all windows that do.
1996 Some window managers may not honor this parameter. */
1998 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1999 NSWindow *window = [view window];
2001 NSTRACE ("x_set_z_group");
2003 if (NILP (new_value))
2005 window.level = NSNormalWindowLevel;
2006 FRAME_Z_GROUP (f) = z_group_none;
2008 else if (EQ (new_value, Qabove))
2010 window.level = NSNormalWindowLevel + 1;
2011 FRAME_Z_GROUP (f) = z_group_above;
2013 else if (EQ (new_value, Qabove_suspended))
2015 /* Not sure what level this should be. */
2016 window.level = NSNormalWindowLevel + 1;
2017 FRAME_Z_GROUP (f) = z_group_above_suspended;
2019 else if (EQ (new_value, Qbelow))
2021 window.level = NSNormalWindowLevel - 1;
2022 FRAME_Z_GROUP (f) = z_group_below;
2025 error ("Invalid z-group specification");
2029 ns_fullscreen_hook (struct frame *f)
2031 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2033 NSTRACE ("ns_fullscreen_hook");
2035 if (!FRAME_VISIBLE_P (f))
2038 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2040 /* Old style fs don't initiate correctly if created from
2041 init/default-frame alist, so use a timer (not nice...).
2043 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2044 selector: @selector (handleFS)
2045 userInfo: nil repeats: NO];
2054 /* ==========================================================================
2058 ========================================================================== */
2062 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2064 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2065 if (idx < 1 || idx >= color_table->avail)
2067 return color_table->colors[idx];
2072 ns_index_color (NSColor *color, struct frame *f)
2074 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2078 if (!color_table->colors)
2080 color_table->size = NS_COLOR_CAPACITY;
2081 color_table->avail = 1; /* skip idx=0 as marker */
2082 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2083 color_table->colors[0] = nil;
2084 color_table->empty_indices = [[NSMutableSet alloc] init];
2087 /* Do we already have this color? */
2088 for (i = 1; i < color_table->avail; i++)
2089 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2092 if ([color_table->empty_indices count] > 0)
2094 NSNumber *index = [color_table->empty_indices anyObject];
2095 [color_table->empty_indices removeObject: index];
2096 idx = [index unsignedLongValue];
2100 if (color_table->avail == color_table->size)
2101 color_table->colors =
2102 xpalloc (color_table->colors, &color_table->size, 1,
2103 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2104 idx = color_table->avail++;
2107 color_table->colors[idx] = color;
2109 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2115 ns_get_color (const char *name, NSColor **col)
2116 /* --------------------------------------------------------------------------
2118 -------------------------------------------------------------------------- */
2119 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2120 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2121 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2124 static char hex[20];
2126 float r = -1.0, g, b;
2127 NSString *nsname = [NSString stringWithUTF8String: name];
2129 NSTRACE ("ns_get_color(%s, **)", name);
2133 if ([nsname isEqualToString: @"ns_selection_bg_color"])
2135 #ifdef NS_IMPL_COCOA
2136 NSString *defname = [[NSUserDefaults standardUserDefaults]
2137 stringForKey: @"AppleHighlightColor"];
2142 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2144 *col = [new colorUsingDefaultColorSpace];
2149 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2151 name = [nsname UTF8String];
2153 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2155 /* NOTE: macOS applications normally don't set foreground
2156 selection, but text may be unreadable if we don't.
2158 if ((new = [NSColor selectedTextColor]) != nil)
2160 *col = [new colorUsingDefaultColorSpace];
2165 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2166 name = [nsname UTF8String];
2169 /* First, check for some sort of numeric specification. */
2172 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2174 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2175 [scanner scanFloat: &r];
2176 [scanner scanFloat: &g];
2177 [scanner scanFloat: &b];
2179 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2180 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2181 else if (name[0] == '#') /* An old X11 format; convert to newer */
2183 int len = (strlen(name) - 1);
2184 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2186 scaling = strlen(name+start) / 3;
2187 for (i = 0; i < 3; i++)
2188 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2189 name + start + i * scaling);
2190 hex[3 * (scaling + 1) - 1] = '\0';
2195 unsigned int rr, gg, bb;
2196 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2197 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2207 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2212 /* Otherwise, color is expected to be from a list */
2214 NSEnumerator *lenum, *cenum;
2218 #ifdef NS_IMPL_GNUSTEP
2219 /* XXX: who is wrong, the requestor or the implementation? */
2220 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2222 nsname = @"highlightColor";
2225 lenum = [[NSColorList availableColorLists] objectEnumerator];
2226 while ( (clist = [lenum nextObject]) && new == nil)
2228 cenum = [[clist allKeys] objectEnumerator];
2229 while ( (name = [cenum nextObject]) && new == nil )
2231 if ([name compare: nsname
2232 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2233 new = [clist colorWithKey: name];
2239 *col = [new colorUsingDefaultColorSpace];
2246 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2247 /* --------------------------------------------------------------------------
2248 Convert a Lisp string object to a NS color
2249 -------------------------------------------------------------------------- */
2251 NSTRACE ("ns_lisp_to_color");
2252 if (STRINGP (color))
2253 return ns_get_color (SSDATA (color), col);
2254 else if (SYMBOLP (color))
2255 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2261 ns_query_color(void *col, XColor *color_def, int setPixel)
2262 /* --------------------------------------------------------------------------
2263 Get ARGB values out of NSColor col and put them into color_def.
2264 If setPixel, set the pixel to a concatenated version.
2265 and set color_def pixel to the resulting index.
2266 -------------------------------------------------------------------------- */
2268 EmacsCGFloat r, g, b, a;
2270 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2271 color_def->red = r * 65535;
2272 color_def->green = g * 65535;
2273 color_def->blue = b * 65535;
2275 if (setPixel == YES)
2277 = ARGB_TO_ULONG((int)(a*255),
2278 (int)(r*255), (int)(g*255), (int)(b*255));
2283 ns_defined_color (struct frame *f,
2288 /* --------------------------------------------------------------------------
2289 Return true if named color found, and set color_def rgb accordingly.
2290 If makeIndex and alloc are nonzero put the color in the color_table,
2291 and set color_def pixel to the resulting index.
2292 If makeIndex is zero, set color_def pixel to ARGB.
2293 Return false if not found
2294 -------------------------------------------------------------------------- */
2297 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2300 if (ns_get_color (name, &col) != 0) /* Color not found */
2305 if (makeIndex && alloc)
2306 color_def->pixel = ns_index_color (col, f);
2307 ns_query_color (col, color_def, !makeIndex);
2314 x_set_frame_alpha (struct frame *f)
2315 /* --------------------------------------------------------------------------
2316 change the entire-frame transparency
2317 -------------------------------------------------------------------------- */
2319 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2321 double alpha_min = 1.0;
2323 NSTRACE ("x_set_frame_alpha");
2325 if (dpyinfo->x_highlight_frame == f)
2326 alpha = f->alpha[0];
2328 alpha = f->alpha[1];
2330 if (FLOATP (Vframe_alpha_lower_limit))
2331 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2332 else if (INTEGERP (Vframe_alpha_lower_limit))
2333 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2337 else if (1.0 < alpha)
2339 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2342 #ifdef NS_IMPL_COCOA
2344 EmacsView *view = FRAME_NS_VIEW (f);
2345 [[view window] setAlphaValue: alpha];
2351 /* ==========================================================================
2355 ========================================================================== */
2359 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2360 /* --------------------------------------------------------------------------
2361 Programmatically reposition mouse pointer in pixel coordinates
2362 -------------------------------------------------------------------------- */
2364 NSTRACE ("frame_set_mouse_pixel_position");
2366 /* FIXME: what about GNUstep? */
2367 #ifdef NS_IMPL_COCOA
2369 CGPointMake(f->left_pos + pix_x,
2370 f->top_pos + pix_y +
2371 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2372 CGWarpMouseCursorPosition (mouse_pos);
2377 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2378 /* ------------------------------------------------------------------------
2379 Called by EmacsView on mouseMovement events. Passes on
2380 to emacs mainstream code if we moved off of a rect of interest
2381 known as last_mouse_glyph.
2382 ------------------------------------------------------------------------ */
2384 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2387 // NSTRACE ("note_mouse_movement");
2389 dpyinfo->last_mouse_motion_frame = frame;
2390 r = &dpyinfo->last_mouse_glyph;
2392 /* Note, this doesn't get called for enter/leave, since we don't have a
2393 position. Those are taken care of in the corresponding NSView methods. */
2395 /* has movement gone beyond last rect we were tracking? */
2396 if (x < r->origin.x || x >= r->origin.x + r->size.width
2397 || y < r->origin.y || y >= r->origin.y + r->size.height)
2399 ns_update_begin (frame);
2400 frame->mouse_moved = 1;
2401 note_mouse_highlight (frame, x, y);
2402 remember_mouse_glyph (frame, x, y, r);
2403 ns_update_end (frame);
2412 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2413 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2415 /* --------------------------------------------------------------------------
2416 External (hook): inform emacs about mouse position and hit parts.
2417 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2418 x & y should be position in the scrollbar (the whole bar, not the handle)
2419 and length of scrollbar respectively
2420 -------------------------------------------------------------------------- */
2424 Lisp_Object frame, tail;
2426 struct ns_display_info *dpyinfo;
2428 NSTRACE ("ns_mouse_position");
2432 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2436 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2440 /* Clear the mouse-moved flag for every frame on this display. */
2441 FOR_EACH_FRAME (tail, frame)
2442 if (FRAME_NS_P (XFRAME (frame))
2443 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2444 XFRAME (frame)->mouse_moved = 0;
2446 dpyinfo->last_mouse_scroll_bar = nil;
2447 if (dpyinfo->last_mouse_frame
2448 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2449 f = dpyinfo->last_mouse_frame;
2451 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2453 if (f && FRAME_NS_P (f))
2455 view = FRAME_NS_VIEW (*fp);
2457 position = [[view window] mouseLocationOutsideOfEventStream];
2458 position = [view convertPoint: position fromView: nil];
2459 remember_mouse_glyph (f, position.x, position.y,
2460 &dpyinfo->last_mouse_glyph);
2461 NSTRACE_POINT ("position", position);
2463 if (bar_window) *bar_window = Qnil;
2464 if (part) *part = scroll_bar_above_handle;
2466 if (x) XSETINT (*x, lrint (position.x));
2467 if (y) XSETINT (*y, lrint (position.y));
2469 *time = dpyinfo->last_mouse_movement_time;
2478 ns_frame_up_to_date (struct frame *f)
2479 /* --------------------------------------------------------------------------
2480 External (hook): Fix up mouse highlighting right after a full update.
2481 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2482 -------------------------------------------------------------------------- */
2484 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2488 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2489 if (f == hlinfo->mouse_face_mouse_frame)
2493 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2494 hlinfo->mouse_face_mouse_x,
2495 hlinfo->mouse_face_mouse_y);
2504 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2505 /* --------------------------------------------------------------------------
2506 External (RIF): set frame mouse pointer type.
2507 -------------------------------------------------------------------------- */
2509 NSTRACE ("ns_define_frame_cursor");
2510 if (FRAME_POINTER_TYPE (f) != cursor)
2512 EmacsView *view = FRAME_NS_VIEW (f);
2513 FRAME_POINTER_TYPE (f) = cursor;
2514 [[view window] invalidateCursorRectsForView: view];
2515 /* Redisplay assumes this function also draws the changed frame
2516 cursor, but this function doesn't, so do it explicitly. */
2517 x_update_cursor (f, 1);
2523 /* ==========================================================================
2527 ========================================================================== */
2531 ns_convert_key (unsigned code)
2532 /* --------------------------------------------------------------------------
2533 Internal call used by NSView-keyDown.
2534 -------------------------------------------------------------------------- */
2536 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2538 /* An array would be faster, but less easy to read. */
2539 for (keysym = 0; keysym < last_keysym; keysym += 2)
2540 if (code == convert_ns_to_X_keysym[keysym])
2541 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2543 /* if decide to use keyCode and Carbon table, use this line:
2544 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2549 x_get_keysym_name (int keysym)
2550 /* --------------------------------------------------------------------------
2551 Called by keyboard.c. Not sure if the return val is important, except
2553 -------------------------------------------------------------------------- */
2555 static char value[16];
2556 NSTRACE ("x_get_keysym_name");
2557 sprintf (value, "%d", keysym);
2563 /* ==========================================================================
2565 Block drawing operations
2567 ========================================================================== */
2571 ns_redraw_scroll_bars (struct frame *f)
2575 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2576 NSTRACE ("ns_redraw_scroll_bars");
2577 for (i =[subviews count]-1; i >= 0; i--)
2579 view = [subviews objectAtIndex: i];
2580 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2587 ns_clear_frame (struct frame *f)
2588 /* --------------------------------------------------------------------------
2589 External (hook): Erase the entire frame
2590 -------------------------------------------------------------------------- */
2592 NSView *view = FRAME_NS_VIEW (f);
2595 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2597 /* comes on initial frame because we have
2598 after-make-frame-functions = select-frame */
2599 if (!FRAME_DEFAULT_FACE (f))
2602 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2607 ns_focus (f, &r, 1);
2608 [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2609 (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2613 /* as of 2006/11 or so this is now needed */
2614 ns_redraw_scroll_bars (f);
2620 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2621 /* --------------------------------------------------------------------------
2622 External (RIF): Clear section of frame
2623 -------------------------------------------------------------------------- */
2625 NSRect r = NSMakeRect (x, y, width, height);
2626 NSView *view = FRAME_NS_VIEW (f);
2627 struct face *face = FRAME_DEFAULT_FACE (f);
2632 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2634 r = NSIntersectionRect (r, [view frame]);
2635 ns_focus (f, &r, 1);
2636 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2645 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2647 NSTRACE ("ns_copy_bits");
2649 if (FRAME_NS_VIEW (f))
2651 hide_bell(); // Ensure the bell image isn't scrolled.
2653 ns_focus (f, &dest, 1);
2654 [FRAME_NS_VIEW (f) scrollRect: src
2655 by: NSMakeSize (dest.origin.x - src.origin.x,
2656 dest.origin.y - src.origin.y)];
2662 ns_scroll_run (struct window *w, struct run *run)
2663 /* --------------------------------------------------------------------------
2664 External (RIF): Insert or delete n lines at line vpos
2665 -------------------------------------------------------------------------- */
2667 struct frame *f = XFRAME (w->frame);
2668 int x, y, width, height, from_y, to_y, bottom_y;
2670 NSTRACE ("ns_scroll_run");
2672 /* begin copy from other terms */
2673 /* Get frame-relative bounding box of the text display area of W,
2674 without mode lines. Include in this box the left and right
2676 window_box (w, ANY_AREA, &x, &y, &width, &height);
2678 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2679 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2680 bottom_y = y + height;
2684 /* Scrolling up. Make sure we don't copy part of the mode
2685 line at the bottom. */
2686 if (from_y + run->height > bottom_y)
2687 height = bottom_y - from_y;
2689 height = run->height;
2693 /* Scrolling down. Make sure we don't copy over the mode line.
2695 if (to_y + run->height > bottom_y)
2696 height = bottom_y - to_y;
2698 height = run->height;
2700 /* end copy from other terms */
2710 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2711 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2713 ns_copy_bits (f, srcRect , dstRect);
2721 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2722 /* --------------------------------------------------------------------------
2723 External (RIF): preparatory to fringe update after text was updated
2724 -------------------------------------------------------------------------- */
2729 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2731 /* begin copy from other terms */
2734 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2735 desired_row->redraw_fringe_bitmaps_p = 1;
2737 /* When a window has disappeared, make sure that no rest of
2738 full-width rows stays visible in the internal border. */
2739 if (windows_or_buffers_changed
2740 && desired_row->full_width_p
2741 && (f = XFRAME (w->frame),
2742 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2744 && (height = desired_row->visible_height,
2747 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2750 ns_clear_frame_area (f, 0, y, width, height);
2751 ns_clear_frame_area (f,
2752 FRAME_PIXEL_WIDTH (f) - width,
2760 ns_shift_glyphs_for_insert (struct frame *f,
2761 int x, int y, int width, int height,
2763 /* --------------------------------------------------------------------------
2764 External (RIF): copy an area horizontally, don't worry about clearing src
2765 -------------------------------------------------------------------------- */
2767 NSRect srcRect = NSMakeRect (x, y, width, height);
2768 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2770 NSTRACE ("ns_shift_glyphs_for_insert");
2772 ns_copy_bits (f, srcRect, dstRect);
2777 /* ==========================================================================
2779 Character encoding and metrics
2781 ========================================================================== */
2785 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2786 /* --------------------------------------------------------------------------
2787 External (RIF); compute left/right overhang of whole string and set in s
2788 -------------------------------------------------------------------------- */
2790 struct font *font = s->font;
2794 struct font_metrics metrics;
2795 unsigned int codes[2];
2796 codes[0] = *(s->char2b);
2797 codes[1] = *(s->char2b + s->nchars - 1);
2799 font->driver->text_extents (font, codes, 2, &metrics);
2800 s->left_overhang = -metrics.lbearing;
2802 = metrics.rbearing > metrics.width
2803 ? metrics.rbearing - metrics.width : 0;
2807 s->left_overhang = 0;
2808 if (EQ (font->driver->type, Qns))
2809 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2810 FONT_HEIGHT (font) * 0.2 : 0;
2812 s->right_overhang = 0;
2818 /* ==========================================================================
2820 Fringe and cursor drawing
2822 ========================================================================== */
2825 extern int max_used_fringe_bitmap;
2827 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2828 struct draw_fringe_bitmap_params *p)
2829 /* --------------------------------------------------------------------------
2830 External (RIF); fringe-related
2831 -------------------------------------------------------------------------- */
2833 /* Fringe bitmaps comes in two variants, normal and periodic. A
2834 periodic bitmap is used to create a continuous pattern. Since a
2835 bitmap is rendered one text line at a time, the start offset (dh)
2836 of the bitmap varies. Concretely, this is used for the empty
2839 For a bitmap, "h + dh" is the full height and is always
2840 invariant. For a normal bitmap "dh" is zero.
2842 For example, when the period is three and the full height is 72
2843 the following combinations exists:
2849 struct frame *f = XFRAME (WINDOW_FRAME (w));
2850 struct face *face = p->face;
2851 static EmacsImage **bimgs = NULL;
2852 static int nBimgs = 0;
2854 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2855 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2856 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2858 /* grow bimgs if needed */
2859 if (nBimgs < max_used_fringe_bitmap)
2861 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2862 memset (bimgs + nBimgs, 0,
2863 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2864 nBimgs = max_used_fringe_bitmap;
2867 /* Must clip because of partially visible lines. */
2868 ns_clip_to_row (w, row, ANY_AREA, YES);
2872 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2874 if (bx >= 0 && nx > 0)
2876 NSRect r = NSMakeRect (bx, by, nx, ny);
2878 [ns_lookup_indexed_color (face->background, f) set];
2885 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2886 EmacsImage *img = bimgs[p->which - 1];
2890 // Note: For "periodic" images, allocate one EmacsImage for
2891 // the base image, and use it for all dh:s.
2892 unsigned short *bits = p->bits;
2893 int full_height = p->h + p->dh;
2895 unsigned char *cbits = xmalloc (full_height);
2897 for (i = 0; i < full_height; i++)
2899 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2902 bimgs[p->which - 1] = img;
2906 NSTRACE_RECT ("r", r);
2909 /* Since we composite the bitmap instead of just blitting it, we need
2910 to erase the whole background. */
2911 [ns_lookup_indexed_color(face->background, f) set];
2917 bm_color = ns_lookup_indexed_color(face->foreground, f);
2918 else if (p->overlay_p)
2919 bm_color = ns_lookup_indexed_color(face->background, f);
2921 bm_color = f->output_data.ns->cursor_color;
2922 [img setXBMColor: bm_color];
2925 #ifdef NS_IMPL_COCOA
2926 // Note: For periodic images, the full image height is "h + hd".
2927 // By using the height h, a suitable part of the image is used.
2928 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2930 NSTRACE_RECT ("fromRect", fromRect);
2934 operation: NSCompositingOperationSourceOver
2940 NSPoint pt = r.origin;
2942 [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
2951 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2952 int x, int y, enum text_cursor_kinds cursor_type,
2953 int cursor_width, bool on_p, bool active_p)
2954 /* --------------------------------------------------------------------------
2955 External call (RIF): draw cursor.
2956 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2957 -------------------------------------------------------------------------- */
2960 int fx, fy, h, cursor_height;
2961 struct frame *f = WINDOW_XFRAME (w);
2962 struct glyph *phys_cursor_glyph;
2963 struct glyph *cursor_glyph;
2965 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2967 /* If cursor is out of bounds, don't draw garbage. This can happen
2968 in mini-buffer windows when switching between echo area glyphs
2971 NSTRACE ("ns_draw_window_cursor");
2976 w->phys_cursor_type = cursor_type;
2977 w->phys_cursor_on_p = on_p;
2979 if (cursor_type == NO_CURSOR)
2981 w->phys_cursor_width = 0;
2985 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2987 if (glyph_row->exact_window_width_line_p
2988 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2990 glyph_row->cursor_in_fringe_p = 1;
2991 draw_fringe_bitmap (w, glyph_row, 0);
2996 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2997 (other terminals do it the other way round). We must set
2998 w->phys_cursor_width to the cursor width. For bar cursors, that
2999 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
3000 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3002 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3003 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3004 if (cursor_type == BAR_CURSOR)
3006 if (cursor_width < 1)
3007 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3009 /* The bar cursor should never be wider than the glyph. */
3010 if (cursor_width < w->phys_cursor_width)
3011 w->phys_cursor_width = cursor_width;
3013 /* If we have an HBAR, "cursor_width" MAY specify height. */
3014 else if (cursor_type == HBAR_CURSOR)
3016 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3017 if (cursor_height > glyph_row->height)
3018 cursor_height = glyph_row->height;
3019 if (h > cursor_height) // Cursor smaller than line height, move down
3020 fy += h - cursor_height;
3024 r.origin.x = fx, r.origin.y = fy;
3026 r.size.width = w->phys_cursor_width;
3028 /* Prevent the cursor from being drawn outside the text area. */
3029 ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3032 face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3033 if (face && NS_FACE_BACKGROUND (face)
3034 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3036 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3037 hollow_color = FRAME_CURSOR_COLOR (f);
3040 [FRAME_CURSOR_COLOR (f) set];
3042 #ifdef NS_IMPL_COCOA
3043 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3044 atomic. Cleaner ways of doing this should be investigated.
3045 One way would be to set a global variable DRAWING_CURSOR
3046 when making the call to draw_phys..(), don't focus in that
3047 case, then move the ns_unfocus() here after that call. */
3048 NSDisableScreenUpdates ();
3051 switch (cursor_type)
3053 case DEFAULT_CURSOR:
3056 case FILLED_BOX_CURSOR:
3059 case HOLLOW_BOX_CURSOR:
3062 NSRectFill (NSInsetRect (r, 1, 1));
3063 [FRAME_CURSOR_COLOR (f) set];
3070 /* If the character under cursor is R2L, draw the bar cursor
3071 on the right of its glyph, rather than on the left. */
3072 cursor_glyph = get_phys_cursor_glyph (w);
3073 if ((cursor_glyph->resolved_level & 1) != 0)
3074 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3081 /* draw the character under the cursor */
3082 if (cursor_type != NO_CURSOR)
3083 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3085 #ifdef NS_IMPL_COCOA
3086 NSEnableScreenUpdates ();
3093 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3094 /* --------------------------------------------------------------------------
3095 External (RIF): Draw a vertical line.
3096 -------------------------------------------------------------------------- */
3098 struct frame *f = XFRAME (WINDOW_FRAME (w));
3100 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3102 NSTRACE ("ns_draw_vertical_window_border");
3104 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3106 ns_focus (f, &r, 1);
3108 [ns_lookup_indexed_color(face->foreground, f) set];
3116 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3117 /* --------------------------------------------------------------------------
3118 External (RIF): Draw a window divider.
3119 -------------------------------------------------------------------------- */
3121 struct frame *f = XFRAME (WINDOW_FRAME (w));
3123 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
3125 NSTRACE ("ns_draw_window_divider");
3127 face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3129 ns_focus (f, &r, 1);
3131 [ns_lookup_indexed_color(face->foreground, f) set];
3138 ns_show_hourglass (struct frame *f)
3140 /* TODO: add NSProgressIndicator to all frames. */
3144 ns_hide_hourglass (struct frame *f)
3146 /* TODO: remove NSProgressIndicator from all frames. */
3149 /* ==========================================================================
3151 Glyph drawing operations
3153 ========================================================================== */
3156 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3157 /* --------------------------------------------------------------------------
3158 Wrapper utility to account for internal border width on full-width lines,
3159 and allow top full-width rows to hit the frame top. nr should be pointer
3160 to two successive NSRects. Number of rects actually used is returned.
3161 -------------------------------------------------------------------------- */
3163 int n = get_glyph_string_clip_rects (s, nr, 2);
3167 /* --------------------------------------------------------------------
3168 Draw a wavy line under glyph string s. The wave fills wave_height
3175 wave_height = 3 | * * * *
3176 --------------------------------------------------------------------- */
3179 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3181 int wave_height = 3, wave_length = 2;
3182 int y, dx, dy, odd, xmax;
3187 dy = wave_height - 1;
3188 y = s->ybase - wave_height + 3;
3191 /* Find and set clipping rectangle */
3192 waveClip = NSMakeRect (x, y, width, wave_height);
3193 [[NSGraphicsContext currentContext] saveGraphicsState];
3194 NSRectClip (waveClip);
3196 /* Draw the waves */
3197 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3199 odd = (int)(a.x/dx) % 2;
3200 a.y = b.y = y + 0.5;
3209 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3210 a.x = b.x, a.y = b.y;
3211 b.x += dx, b.y = y + 0.5 + odd*dy;
3215 /* Restore previous clipping rectangle(s) */
3216 [[NSGraphicsContext currentContext] restoreGraphicsState];
3222 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3223 NSColor *defaultCol, CGFloat width, CGFloat x)
3224 /* --------------------------------------------------------------------------
3225 Draw underline, overline, and strike-through on glyph string s.
3226 -------------------------------------------------------------------------- */
3228 if (s->for_overlaps)
3232 if (face->underline_p)
3234 if (s->face->underline_type == FACE_UNDER_WAVE)
3236 if (face->underline_defaulted_p)
3239 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3241 ns_draw_underwave (s, width, x);
3243 else if (s->face->underline_type == FACE_UNDER_LINE)
3247 unsigned long thickness, position;
3249 /* If the prev was underlined, match its appearance. */
3250 if (s->prev && s->prev->face->underline_p
3251 && s->prev->face->underline_type == FACE_UNDER_LINE
3252 && s->prev->underline_thickness > 0)
3254 thickness = s->prev->underline_thickness;
3255 position = s->prev->underline_position;
3259 struct font *font = font_for_underline_metrics (s);
3260 unsigned long descent = s->y + s->height - s->ybase;
3262 /* Use underline thickness of font, defaulting to 1. */
3263 thickness = (font && font->underline_thickness > 0)
3264 ? font->underline_thickness : 1;
3266 /* Determine the offset of underlining from the baseline. */
3267 if (x_underline_at_descent_line)
3268 position = descent - thickness;
3269 else if (x_use_underline_position_properties
3270 && font && font->underline_position >= 0)
3271 position = font->underline_position;
3273 position = lround (font->descent / 2);
3275 position = underline_minimum_offset;
3277 position = max (position, underline_minimum_offset);
3279 /* Ensure underlining is not cropped. */
3280 if (descent <= position)
3282 position = descent - 1;
3285 else if (descent < position + thickness)
3289 s->underline_thickness = thickness;
3290 s->underline_position = position;
3292 r = NSMakeRect (x, s->ybase + position, width, thickness);
3294 if (face->underline_defaulted_p)
3297 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3301 /* Do overline. We follow other terms in using a thickness of 1
3302 and ignoring overline_margin. */
3303 if (face->overline_p)
3306 r = NSMakeRect (x, s->y, width, 1);
3308 if (face->overline_color_defaulted_p)
3311 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3315 /* Do strike-through. We follow other terms for thickness and
3316 vertical position.*/
3317 if (face->strike_through_p)
3320 /* Y-coordinate and height of the glyph string's first glyph.
3321 We cannot use s->y and s->height because those could be
3322 larger if there are taller display elements (e.g., characters
3323 displayed with a larger font) in the same glyph row. */
3324 int glyph_y = s->ybase - s->first_glyph->ascent;
3325 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3326 /* Strike-through width and offset from the glyph string's
3328 unsigned long h = 1;
3331 dy = lrint ((glyph_height - h) / 2);
3332 r = NSMakeRect (x, glyph_y + dy, width, 1);
3334 if (face->strike_through_color_defaulted_p)
3337 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3343 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3344 char left_p, char right_p)
3345 /* --------------------------------------------------------------------------
3346 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3347 Note we can't just use an NSDrawRect command, because of the possibility
3348 of some sides not being drawn, and because the rect will be filled.
3349 -------------------------------------------------------------------------- */
3355 s.size.height = thickness;
3357 s.origin.y += r.size.height - thickness;
3360 s.size.height = r.size.height;
3361 s.origin.y = r.origin.y;
3363 /* left, right (optional) */
3364 s.size.width = thickness;
3369 s.origin.x += r.size.width - thickness;
3376 ns_draw_relief (NSRect r, int thickness, char raised_p,
3377 char top_p, char bottom_p, char left_p, char right_p,
3378 struct glyph_string *s)
3379 /* --------------------------------------------------------------------------
3380 Draw a relief rect inside r, optionally leaving some sides open.
3381 Note we can't just use an NSDrawBezel command, because of the possibility
3382 of some sides not being drawn, and because the rect will be filled.
3383 -------------------------------------------------------------------------- */
3385 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3386 NSColor *newBaseCol = nil;
3389 NSTRACE ("ns_draw_relief");
3393 if (s->face->use_box_color_for_shadows_p)
3395 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3397 /* else if (s->first_glyph->type == IMAGE_GLYPH
3399 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3401 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3405 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3408 if (newBaseCol == nil)
3409 newBaseCol = [NSColor grayColor];
3411 if (newBaseCol != baseCol) /* TODO: better check */
3414 baseCol = [newBaseCol retain];
3416 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3418 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3421 [(raised_p ? lightCol : darkCol) set];
3423 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3426 sr.size.height = thickness;
3427 if (top_p) NSRectFill (sr);
3430 sr.size.height = r.size.height;
3431 sr.size.width = thickness;
3432 if (left_p) NSRectFill (sr);
3434 [(raised_p ? darkCol : lightCol) set];
3437 sr.size.width = r.size.width;
3438 sr.size.height = thickness;
3439 sr.origin.y += r.size.height - thickness;
3440 if (bottom_p) NSRectFill (sr);
3443 sr.size.height = r.size.height;
3444 sr.origin.y = r.origin.y;
3445 sr.size.width = thickness;
3446 sr.origin.x += r.size.width - thickness;
3447 if (right_p) NSRectFill (sr);
3452 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3453 /* --------------------------------------------------------------------------
3454 Function modeled after x_draw_glyph_string_box ().
3455 Sets up parameters for drawing.
3456 -------------------------------------------------------------------------- */
3458 int right_x, last_x;
3459 char left_p, right_p;
3460 struct glyph *last_glyph;
3465 if (s->hl == DRAW_MOUSE_FACE)
3467 face = FACE_FROM_ID_OR_NULL (s->f,
3468 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3470 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3475 thickness = face->box_line_width;
3477 NSTRACE ("ns_dumpglyphs_box_or_relief");
3479 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3480 ? WINDOW_RIGHT_EDGE_X (s->w)
3481 : window_box_right (s->w, s->area));
3482 last_glyph = (s->cmp || s->img
3483 ? s->first_glyph : s->first_glyph + s->nchars-1);
3485 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3486 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3488 left_p = (s->first_glyph->left_box_line_p
3489 || (s->hl == DRAW_MOUSE_FACE
3490 && (s->prev == NULL || s->prev->hl != s->hl)));
3491 right_p = (last_glyph->right_box_line_p
3492 || (s->hl == DRAW_MOUSE_FACE
3493 && (s->next == NULL || s->next->hl != s->hl)));
3495 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3497 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3498 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3500 ns_draw_box (r, abs (thickness),
3501 ns_lookup_indexed_color (face->box_color, s->f),
3506 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3507 1, 1, left_p, right_p, s);
3513 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3514 /* --------------------------------------------------------------------------
3515 Modeled after x_draw_glyph_string_background, which draws BG in
3516 certain cases. Others are left to the text rendering routine.
3517 -------------------------------------------------------------------------- */
3519 NSTRACE ("ns_maybe_dumpglyphs_background");
3521 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3523 int box_line_width = max (s->face->box_line_width, 0);
3524 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3525 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3526 dimensions, since the actual glyphs might be much
3527 smaller. So in that case we always clear the rectangle
3528 with background color. */
3529 || FONT_TOO_HIGH (s->font)
3530 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3533 if (s->hl == DRAW_MOUSE_FACE)
3536 = FACE_FROM_ID_OR_NULL (s->f,
3537 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3539 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3542 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3544 [(NS_FACE_BACKGROUND (face) != 0
3545 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3546 : FRAME_BACKGROUND_COLOR (s->f)) set];
3549 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3550 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3553 if (s->hl != DRAW_CURSOR)
3555 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3556 s->background_width,
3557 s->height-2*box_line_width);
3561 s->background_filled_p = 1;
3568 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3569 /* --------------------------------------------------------------------------
3570 Renders an image and associated borders.
3571 -------------------------------------------------------------------------- */
3573 EmacsImage *img = s->img->pixmap;
3574 int box_line_vwidth = max (s->face->box_line_width, 0);
3575 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3576 int bg_x, bg_y, bg_height;
3583 NSTRACE ("ns_dumpglyphs_image");
3585 if (s->face->box != FACE_NO_BOX
3586 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3587 x += abs (s->face->box_line_width);
3590 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3591 bg_height = s->height;
3592 /* other terms have this, but was causing problems w/tabbar mode */
3593 /* - 2 * box_line_vwidth; */
3595 if (s->slice.x == 0) x += s->img->hmargin;
3596 if (s->slice.y == 0) y += s->img->vmargin;
3598 /* Draw BG: if we need larger area than image itself cleared, do that,
3599 otherwise, since we composite the image under NS (instead of mucking
3600 with its background color), we must clear just the image area. */
3601 if (s->hl == DRAW_MOUSE_FACE)
3603 face = FACE_FROM_ID_OR_NULL (s->f,
3604 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3606 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3609 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3611 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3613 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3614 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3616 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3617 s->background_filled_p = 1;
3621 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3626 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3629 #ifdef NS_IMPL_COCOA
3630 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3631 NSRect ir = NSMakeRect (s->slice.x,
3632 s->img->height - s->slice.y - s->slice.height,
3633 s->slice.width, s->slice.height);
3636 operation: NSCompositingOperationSourceOver
3641 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3642 operation: NSCompositingOperationSourceOver];
3646 if (s->hl == DRAW_CURSOR)
3648 [FRAME_CURSOR_COLOR (s->f) set];
3649 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3650 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3652 /* Currently on NS img->mask is always 0. Since
3653 get_window_cursor_type specifies a hollow box cursor when on
3654 a non-masked image we never reach this clause. But we put it
3655 in in anticipation of better support for image masks on
3657 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3661 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3664 /* Draw underline, overline, strike-through. */
3665 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3667 /* Draw relief, if requested */
3668 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3670 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3672 th = tool_bar_button_relief >= 0 ?
3673 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3674 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3678 th = abs (s->img->relief);
3679 raised_p = (s->img->relief > 0);
3682 r.origin.x = x - th;
3683 r.origin.y = y - th;
3684 r.size.width = s->slice.width + 2*th-1;
3685 r.size.height = s->slice.height + 2*th-1;
3686 ns_draw_relief (r, th, raised_p,
3688 s->slice.y + s->slice.height == s->img->height,
3690 s->slice.x + s->slice.width == s->img->width, s);
3693 /* If there is no mask, the background won't be seen,
3694 so draw a rectangle on the image for the cursor.
3695 Do this for all images, getting transparency right is not reliable. */
3696 if (s->hl == DRAW_CURSOR)
3698 int thickness = abs (s->img->relief);
3699 if (thickness == 0) thickness = 1;
3700 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3706 ns_dumpglyphs_stretch (struct glyph_string *s)
3711 NSColor *fgCol, *bgCol;
3713 if (!s->background_filled_p)
3715 n = ns_get_glyph_string_clip_rect (s, r);
3716 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3718 ns_focus (s->f, r, n);
3720 if (s->hl == DRAW_MOUSE_FACE)
3722 face = FACE_FROM_ID_OR_NULL (s->f,
3723 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3725 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3728 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3730 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3731 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3733 for (i = 0; i < n; ++i)
3735 if (!s->row->full_width_p)
3737 int overrun, leftoverrun;
3739 /* truncate to avoid overwriting fringe and/or scrollbar */
3740 overrun = max (0, (s->x + s->background_width)
3741 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3742 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3743 r[i].size.width -= overrun;
3745 /* truncate to avoid overwriting to left of the window box */
3746 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3747 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3749 if (leftoverrun > 0)
3751 r[i].origin.x += leftoverrun;
3752 r[i].size.width -= leftoverrun;
3755 /* XXX: Try to work between problem where a stretch glyph on
3756 a partially-visible bottom row will clear part of the
3757 modeline, and another where list-buffers headers and similar
3758 rows erroneously have visible_height set to 0. Not sure
3759 where this is coming from as other terms seem not to show. */
3760 r[i].size.height = min (s->height, s->row->visible_height);
3765 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3766 overwriting cursor (usually when cursor on a tab) */
3767 if (s->hl == DRAW_CURSOR)
3772 width = s->w->phys_cursor_width;
3773 r[i].size.width -= width;
3774 r[i].origin.x += width;
3778 /* Draw overlining, etc. on the cursor. */
3779 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3780 ns_draw_text_decoration (s, face, bgCol, width, x);
3782 ns_draw_text_decoration (s, face, fgCol, width, x);
3789 /* Draw overlining, etc. on the stretch glyph (or the part
3790 of the stretch glyph after the cursor). */
3791 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3795 s->background_filled_p = 1;
3801 ns_draw_glyph_string_foreground (struct glyph_string *s)
3804 struct font *font = s->font;
3806 /* If first glyph of S has a left box line, start drawing the text
3807 of S to the right of that box line. */
3808 if (s->face && s->face->box != FACE_NO_BOX
3809 && s->first_glyph->left_box_line_p)
3810 x = s->x + eabs (s->face->box_line_width);
3814 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3815 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3816 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3817 NS_DUMPGLYPH_NORMAL));
3820 (s, s->cmp_from, s->nchars, x, s->ybase,
3821 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3822 || flags == NS_DUMPGLYPH_MOUSEFACE);
3827 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3830 struct font *font = s->font;
3832 /* If first glyph of S has a left box line, start drawing the text
3833 of S to the right of that box line. */
3834 if (s->face && s->face->box != FACE_NO_BOX
3835 && s->first_glyph->left_box_line_p)
3836 x = s->x + eabs (s->face->box_line_width);
3840 /* S is a glyph string for a composition. S->cmp_from is the index
3841 of the first character drawn for glyphs of this composition.
3842 S->cmp_from == 0 means we are drawing the very first character of
3843 this composition. */
3845 /* Draw a rectangle for the composition if the font for the very
3846 first character of the composition could not be loaded. */
3847 if (s->font_not_found_p)
3849 if (s->cmp_from == 0)
3851 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3852 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3855 else if (! s->first_glyph->u.cmp.automatic)
3859 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3860 /* TAB in a composition means display glyphs with padding
3861 space on the left or right. */
3862 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3864 int xx = x + s->cmp->offsets[j * 2];
3865 int yy = y - s->cmp->offsets[j * 2 + 1];
3867 font->driver->draw (s, j, j + 1, xx, yy, false);
3868 if (s->face->overstrike)
3869 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3874 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3879 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3881 glyph = LGSTRING_GLYPH (gstring, i);
3882 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3883 width += LGLYPH_WIDTH (glyph);
3886 int xoff, yoff, wadjust;
3890 font->driver->draw (s, j, i, x, y, false);
3891 if (s->face->overstrike)
3892 font->driver->draw (s, j, i, x + 1, y, false);
3895 xoff = LGLYPH_XOFF (glyph);
3896 yoff = LGLYPH_YOFF (glyph);
3897 wadjust = LGLYPH_WADJUST (glyph);
3898 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3899 if (s->face->overstrike)
3900 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3909 font->driver->draw (s, j, i, x, y, false);
3910 if (s->face->overstrike)
3911 font->driver->draw (s, j, i, x + 1, y, false);
3917 ns_draw_glyph_string (struct glyph_string *s)
3918 /* --------------------------------------------------------------------------
3919 External (RIF): Main draw-text call.
3920 -------------------------------------------------------------------------- */
3922 /* TODO (optimize): focus for box and contents draw */
3925 char box_drawn_p = 0;
3926 struct font *font = s->face->font;
3927 if (! font) font = FRAME_FONT (s->f);
3929 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3931 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3934 struct glyph_string *next;
3936 for (width = 0, next = s->next;
3937 next && width < s->right_overhang;
3938 width += next->width, next = next->next)
3939 if (next->first_glyph->type != IMAGE_GLYPH)
3941 if (next->first_glyph->type != STRETCH_GLYPH)
3943 n = ns_get_glyph_string_clip_rect (s->next, r);
3944 ns_focus (s->f, r, n);
3945 ns_maybe_dumpglyphs_background (s->next, 1);
3950 ns_dumpglyphs_stretch (s->next);
3952 next->num_clips = 0;
3956 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3957 && (s->first_glyph->type == CHAR_GLYPH
3958 || s->first_glyph->type == COMPOSITE_GLYPH))
3960 n = ns_get_glyph_string_clip_rect (s, r);
3961 ns_focus (s->f, r, n);
3962 ns_maybe_dumpglyphs_background (s, 1);
3963 ns_dumpglyphs_box_or_relief (s);
3968 switch (s->first_glyph->type)
3972 n = ns_get_glyph_string_clip_rect (s, r);
3973 ns_focus (s->f, r, n);
3974 ns_dumpglyphs_image (s, r[0]);
3979 ns_dumpglyphs_stretch (s);
3983 case COMPOSITE_GLYPH:
3984 n = ns_get_glyph_string_clip_rect (s, r);
3985 ns_focus (s->f, r, n);
3987 if (s->for_overlaps || (s->cmp_from > 0
3988 && ! s->first_glyph->u.cmp.automatic))
3989 s->background_filled_p = 1;
3991 ns_maybe_dumpglyphs_background
3992 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3994 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3996 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3997 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3998 NS_FACE_FOREGROUND (s->face) = tmp;
4002 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4005 ns_draw_composite_glyph_string_foreground (s);
4007 ns_draw_glyph_string_foreground (s);
4011 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4012 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4014 : FRAME_FOREGROUND_COLOR (s->f));
4017 /* Draw underline, overline, strike-through. */
4018 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4021 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4023 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4024 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4025 NS_FACE_FOREGROUND (s->face) = tmp;
4031 case GLYPHLESS_GLYPH:
4032 n = ns_get_glyph_string_clip_rect (s, r);
4033 ns_focus (s->f, r, n);
4035 if (s->for_overlaps || (s->cmp_from > 0
4036 && ! s->first_glyph->u.cmp.automatic))
4037 s->background_filled_p = 1;
4039 ns_maybe_dumpglyphs_background
4040 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4042 /* Not yet implemented. */
4051 /* Draw box if not done already. */
4052 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4054 n = ns_get_glyph_string_clip_rect (s, r);
4055 ns_focus (s->f, r, n);
4056 ns_dumpglyphs_box_or_relief (s);
4065 /* ==========================================================================
4069 ========================================================================== */
4073 ns_send_appdefined (int value)
4074 /* --------------------------------------------------------------------------
4075 Internal: post an appdefined event which EmacsApp-sendEvent will
4076 recognize and take as a command to halt the event loop.
4077 -------------------------------------------------------------------------- */
4079 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4081 // GNUstep needs postEvent to happen on the main thread.
4082 // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4083 if (! [[NSThread currentThread] isMainThread])
4085 EmacsApp *app = (EmacsApp *)NSApp;
4086 app->nextappdefined = value;
4087 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4093 /* Only post this event if we haven't already posted one. This will end
4094 the [NXApp run] main loop after having processed all events queued at
4097 #ifdef NS_IMPL_COCOA
4098 if (! send_appdefined)
4100 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4101 in certain situations (rapid incoming events).
4102 So check if we have one, if not add one. */
4103 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4104 untilDate:[NSDate distantPast]
4105 inMode:NSDefaultRunLoopMode
4107 if (! appev) send_appdefined = YES;
4111 if (send_appdefined)
4115 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
4116 send_appdefined = NO;
4118 /* Don't need wakeup timer any more */
4121 [timed_entry invalidate];
4122 [timed_entry release];
4126 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4127 location: NSMakePoint (0, 0)
4130 windowNumber: [[NSApp mainWindow] windowNumber]
4131 context: [NSApp context]
4136 /* Post an application defined event on the event queue. When this is
4137 received the [NXApp run] will return, thus having processed all
4138 events which are currently queued. */
4139 [NSApp postEvent: nxev atStart: NO];
4143 #ifdef HAVE_NATIVE_FS
4147 Lisp_Object frame, tail;
4149 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4152 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4154 FOR_EACH_FRAME (tail, frame)
4156 struct frame *f = XFRAME (frame);
4159 EmacsView *view = FRAME_NS_VIEW (f);
4160 [view updateCollectionBehavior];
4166 /* GNUstep does not have cancelTracking. */
4167 #ifdef NS_IMPL_COCOA
4168 /* Check if menu open should be canceled or continued as normal. */
4170 ns_check_menu_open (NSMenu *menu)
4172 /* Click in menu bar? */
4173 NSArray *a = [[NSApp mainMenu] itemArray];
4177 if (menu == nil) // Menu tracking ended.
4179 if (menu_will_open_state == MENU_OPENING)
4180 menu_will_open_state = MENU_NONE;
4184 for (i = 0; ! found && i < [a count]; i++)
4185 found = menu == [[a objectAtIndex:i] submenu];
4188 if (menu_will_open_state == MENU_NONE && emacs_event)
4190 NSEvent *theEvent = [NSApp currentEvent];
4191 struct frame *emacsframe = SELECTED_FRAME ();
4193 [menu cancelTracking];
4194 menu_will_open_state = MENU_PENDING;
4195 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4196 EV_TRAILER (theEvent);
4198 CGEventRef ourEvent = CGEventCreate (NULL);
4199 menu_mouse_point = CGEventGetLocation (ourEvent);
4200 CFRelease (ourEvent);
4202 else if (menu_will_open_state == MENU_OPENING)
4204 menu_will_open_state = MENU_NONE;
4209 /* Redo saved menu click if state is MENU_PENDING. */
4211 ns_check_pending_open_menu ()
4213 if (menu_will_open_state == MENU_PENDING)
4215 CGEventSourceRef source
4216 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4218 CGEventRef event = CGEventCreateMouseEvent (source,
4219 kCGEventLeftMouseDown,
4221 kCGMouseButtonLeft);
4222 CGEventSetType (event, kCGEventLeftMouseDown);
4223 CGEventPost (kCGHIDEventTap, event);
4227 menu_will_open_state = MENU_OPENING;
4230 #endif /* NS_IMPL_COCOA */
4233 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4234 /* --------------------------------------------------------------------------
4235 External (hook): Post an event to ourself and keep reading events until
4236 we read it back again. In effect process all events which were waiting.
4237 From 21+ we have to manage the event buffer ourselves.
4238 -------------------------------------------------------------------------- */
4240 struct input_event ev;
4243 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4245 #ifdef HAVE_NATIVE_FS
4249 if ([NSApp modalWindow] != nil)
4252 if (hold_event_q.nr > 0)
4255 for (i = 0; i < hold_event_q.nr; ++i)
4256 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4257 hold_event_q.nr = 0;
4261 if ([NSThread isMainThread])
4264 n_emacs_events_pending = 0;
4265 ns_init_events (&ev);
4266 q_event_ptr = hold_quit;
4268 /* we manage autorelease pools by allocate/reallocate each time around
4269 the loop; strict nesting is occasionally violated but seems not to
4270 matter.. earlier methods using full nesting caused major memory leaks */
4271 [outerpool release];
4272 outerpool = [[NSAutoreleasePool alloc] init];
4274 /* If have pending open-file requests, attend to the next one of those. */
4275 if (ns_pending_files && [ns_pending_files count] != 0
4276 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4278 [ns_pending_files removeObjectAtIndex: 0];
4280 /* Deal with pending service requests. */
4281 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4283 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4284 withArg: [ns_pending_service_args objectAtIndex: 0]])
4286 [ns_pending_service_names removeObjectAtIndex: 0];
4287 [ns_pending_service_args removeObjectAtIndex: 0];
4291 /* Run and wait for events. We must always send one NX_APPDEFINED event
4292 to ourself, otherwise [NXApp run] will never exit. */
4293 send_appdefined = YES;
4294 ns_send_appdefined (-1);
4299 nevents = n_emacs_events_pending;
4300 n_emacs_events_pending = 0;
4301 ns_finish_events ();
4313 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4314 fd_set *exceptfds, struct timespec *timeout,
4316 /* --------------------------------------------------------------------------
4317 Replacement for select, checking for events
4318 -------------------------------------------------------------------------- */
4322 struct input_event event;
4325 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4327 #ifdef HAVE_NATIVE_FS
4331 if (hold_event_q.nr > 0)
4333 /* We already have events pending. */
4339 for (k = 0; k < nfds+1; k++)
4341 if (readfds && FD_ISSET(k, readfds)) ++nr;
4342 if (writefds && FD_ISSET(k, writefds)) ++nr;
4346 || ![NSThread isMainThread]
4347 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4348 return thread_select(pselect, nfds, readfds, writefds,
4349 exceptfds, timeout, sigmask);
4352 struct timespec t = {0, 0};
4353 thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4356 [outerpool release];
4357 outerpool = [[NSAutoreleasePool alloc] init];
4360 send_appdefined = YES;
4363 pthread_mutex_lock (&select_mutex);
4368 select_readfds = *readfds;
4369 select_valid += SELECT_HAVE_READ;
4373 select_writefds = *writefds;
4374 select_valid += SELECT_HAVE_WRITE;
4379 select_timeout = *timeout;
4380 select_valid += SELECT_HAVE_TMO;
4383 pthread_mutex_unlock (&select_mutex);
4385 /* Inform fd_handler that select should be called */
4387 emacs_write_sig (selfds[1], &c, 1);
4389 else if (nr == 0 && timeout)
4391 /* No file descriptor, just a timeout, no need to wake fd_handler */
4392 double time = timespectod (*timeout);
4393 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4396 @selector (timeout_handler:)
4401 else /* No timeout and no file descriptors, can this happen? */
4403 /* Send appdefined so we exit from the loop */
4404 ns_send_appdefined (-1);
4408 ns_init_events (&event);
4412 ns_finish_events ();
4413 if (nr > 0 && readfds)
4416 emacs_write_sig (selfds[1], &c, 1);
4420 t = last_appdefined_event_data;
4422 if (t != NO_APPDEFINED_DATA)
4424 last_appdefined_event_data = NO_APPDEFINED_DATA;
4428 /* The NX_APPDEFINED event we received was a timeout. */
4433 /* The NX_APPDEFINED event we received was the result of
4434 at least one real input event arriving. */
4440 /* Received back from select () in fd_handler; copy the results */
4441 pthread_mutex_lock (&select_mutex);
4442 if (readfds) *readfds = select_readfds;
4443 if (writefds) *writefds = select_writefds;
4444 pthread_mutex_unlock (&select_mutex);
4459 ns_run_loop_break ()
4460 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4462 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4464 /* If we don't have a GUI, don't send the event. */
4466 ns_send_appdefined(-1);
4471 /* ==========================================================================
4475 ========================================================================== */
4479 ns_set_vertical_scroll_bar (struct window *window,
4480 int portion, int whole, int position)
4481 /* --------------------------------------------------------------------------
4482 External (hook): Update or add scrollbar
4483 -------------------------------------------------------------------------- */
4487 struct frame *f = XFRAME (WINDOW_FRAME (window));
4488 EmacsView *view = FRAME_NS_VIEW (f);
4490 int window_y, window_height;
4491 int top, left, height, width;
4492 BOOL update_p = YES;
4494 /* optimization; display engine sends WAY too many of these.. */
4495 if (!NILP (window->vertical_scroll_bar))
4497 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4498 if ([bar checkSamePosition: position portion: portion whole: whole])
4500 if (view->scrollbarsNeedingUpdate == 0)
4502 if (!windows_or_buffers_changed)
4506 view->scrollbarsNeedingUpdate--;
4511 NSTRACE ("ns_set_vertical_scroll_bar");
4513 /* Get dimensions. */
4514 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4516 height = window_height;
4517 width = NS_SCROLL_BAR_WIDTH (f);
4518 left = WINDOW_SCROLL_BAR_AREA_X (window);
4520 r = NSMakeRect (left, top, width, height);
4521 /* the parent view is flipped, so we need to flip y value */
4523 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4525 XSETWINDOW (win, window);
4528 /* we want at least 5 lines to display a scrollbar */
4529 if (WINDOW_TOTAL_LINES (window) < 5)
4531 if (!NILP (window->vertical_scroll_bar))
4533 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4534 [bar removeFromSuperview];
4535 wset_vertical_scroll_bar (window, Qnil);
4538 ns_clear_frame_area (f, left, top, width, height);
4543 if (NILP (window->vertical_scroll_bar))
4545 if (width > 0 && height > 0)
4546 ns_clear_frame_area (f, left, top, width, height);
4548 bar = [[EmacsScroller alloc] initFrame: r window: win];
4549 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4555 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4556 oldRect = [bar frame];
4557 r.size.width = oldRect.size.width;
4558 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4560 if (oldRect.origin.x != r.origin.x)
4561 ns_clear_frame_area (f, left, top, width, height);
4567 [bar setPosition: position portion: portion whole: whole];
4573 ns_set_horizontal_scroll_bar (struct window *window,
4574 int portion, int whole, int position)
4575 /* --------------------------------------------------------------------------
4576 External (hook): Update or add scrollbar
4577 -------------------------------------------------------------------------- */
4581 struct frame *f = XFRAME (WINDOW_FRAME (window));
4582 EmacsView *view = FRAME_NS_VIEW (f);
4584 int top, height, left, width;
4585 int window_x, window_width;
4586 BOOL update_p = YES;
4588 /* optimization; display engine sends WAY too many of these.. */
4589 if (!NILP (window->horizontal_scroll_bar))
4591 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4592 if ([bar checkSamePosition: position portion: portion whole: whole])
4594 if (view->scrollbarsNeedingUpdate == 0)
4596 if (!windows_or_buffers_changed)
4600 view->scrollbarsNeedingUpdate--;
4605 NSTRACE ("ns_set_horizontal_scroll_bar");
4607 /* Get dimensions. */
4608 window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4610 width = window_width;
4611 height = NS_SCROLL_BAR_HEIGHT (f);
4612 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4614 r = NSMakeRect (left, top, width, height);
4615 /* the parent view is flipped, so we need to flip y value */
4617 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4619 XSETWINDOW (win, window);
4622 if (NILP (window->horizontal_scroll_bar))
4624 if (width > 0 && height > 0)
4625 ns_clear_frame_area (f, left, top, width, height);
4627 bar = [[EmacsScroller alloc] initFrame: r window: win];
4628 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4634 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4635 oldRect = [bar frame];
4636 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4638 if (oldRect.origin.y != r.origin.y)
4639 ns_clear_frame_area (f, left, top, width, height);
4645 /* If there are both horizontal and vertical scroll-bars they leave
4646 a square that belongs to neither. We need to clear it otherwise
4647 it fills with junk. */
4648 if (!NILP (window->vertical_scroll_bar))
4649 ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4650 NS_SCROLL_BAR_HEIGHT (f), height);
4653 [bar setPosition: position portion: portion whole: whole];
4659 ns_condemn_scroll_bars (struct frame *f)
4660 /* --------------------------------------------------------------------------
4661 External (hook): arrange for all frame's scrollbars to be removed
4662 at next call to judge_scroll_bars, except for those redeemed.
4663 -------------------------------------------------------------------------- */
4667 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4669 NSTRACE ("ns_condemn_scroll_bars");
4671 for (i =[subviews count]-1; i >= 0; i--)
4673 view = [subviews objectAtIndex: i];
4674 if ([view isKindOfClass: [EmacsScroller class]])
4681 ns_redeem_scroll_bar (struct window *window)
4682 /* --------------------------------------------------------------------------
4683 External (hook): arrange to spare this window's scrollbar
4684 at next call to judge_scroll_bars.
4685 -------------------------------------------------------------------------- */
4688 NSTRACE ("ns_redeem_scroll_bar");
4689 if (!NILP (window->vertical_scroll_bar)
4690 && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4692 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4696 if (!NILP (window->horizontal_scroll_bar)
4697 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4699 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4706 ns_judge_scroll_bars (struct frame *f)
4707 /* --------------------------------------------------------------------------
4708 External (hook): destroy all scrollbars on frame that weren't
4709 redeemed after call to condemn_scroll_bars.
4710 -------------------------------------------------------------------------- */
4714 EmacsView *eview = FRAME_NS_VIEW (f);
4715 NSArray *subviews = [[eview superview] subviews];
4718 NSTRACE ("ns_judge_scroll_bars");
4719 for (i = [subviews count]-1; i >= 0; --i)
4721 view = [subviews objectAtIndex: i];
4722 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4728 [eview updateFrameSize: NO];
4731 /* ==========================================================================
4735 ========================================================================== */
4738 x_display_pixel_height (struct ns_display_info *dpyinfo)
4740 NSArray *screens = [NSScreen screens];
4741 NSEnumerator *enumerator = [screens objectEnumerator];
4746 while ((screen = [enumerator nextObject]) != nil)
4747 frame = NSUnionRect (frame, [screen frame]);
4749 return NSHeight (frame);
4753 x_display_pixel_width (struct ns_display_info *dpyinfo)
4755 NSArray *screens = [NSScreen screens];
4756 NSEnumerator *enumerator = [screens objectEnumerator];
4761 while ((screen = [enumerator nextObject]) != nil)
4762 frame = NSUnionRect (frame, [screen frame]);
4764 return NSWidth (frame);
4768 static Lisp_Object ns_string_to_lispmod (const char *s)
4769 /* --------------------------------------------------------------------------
4770 Convert modifier name to lisp symbol
4771 -------------------------------------------------------------------------- */
4773 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4775 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4777 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4779 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4781 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4783 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4791 ns_default (const char *parameter, Lisp_Object *result,
4792 Lisp_Object yesval, Lisp_Object noval,
4793 BOOL is_float, BOOL is_modstring)
4794 /* --------------------------------------------------------------------------
4795 Check a parameter value in user's preferences
4796 -------------------------------------------------------------------------- */
4798 const char *value = ns_get_defaults_value (parameter);
4804 if (c_strcasecmp (value, "YES") == 0)
4806 else if (c_strcasecmp (value, "NO") == 0)
4808 else if (is_float && (f = strtod (value, &pos), pos != value))
4809 *result = make_float (f);
4810 else if (is_modstring && value)
4811 *result = ns_string_to_lispmod (value);
4812 else fprintf (stderr,
4813 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4819 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4820 /* --------------------------------------------------------------------------
4821 Initialize global info and storage for display.
4822 -------------------------------------------------------------------------- */
4824 NSScreen *screen = [NSScreen mainScreen];
4825 NSWindowDepth depth = [screen depth];
4827 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4828 dpyinfo->resy = 72.27;
4829 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4830 NSColorSpaceFromDepth (depth)]
4831 && ![NSCalibratedWhiteColorSpace isEqualToString:
4832 NSColorSpaceFromDepth (depth)];
4833 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4834 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4835 dpyinfo->color_table->colors = NULL;
4836 dpyinfo->root_window = 42; /* a placeholder.. */
4837 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4838 dpyinfo->n_fonts = 0;
4839 dpyinfo->smallest_font_height = 1;
4840 dpyinfo->smallest_char_width = 1;
4842 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4846 /* This and next define (many of the) public functions in this file. */
4847 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4848 with using despite presence in the "system dependent" redisplay
4849 interface. In addition, many of the ns_ methods have code that is
4850 shared with all terms, indicating need for further refactoring. */
4851 extern frame_parm_handler ns_frame_parm_handlers[];
4852 static struct redisplay_interface ns_redisplay_interface =
4854 ns_frame_parm_handlers,
4858 x_clear_end_of_line,
4860 ns_after_update_window_line,
4861 ns_update_window_begin,
4862 ns_update_window_end,
4863 0, /* flush_display */
4864 x_clear_window_mouse_face,
4865 x_get_glyph_overhangs,
4866 x_fix_overlapping_area,
4867 ns_draw_fringe_bitmap,
4868 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4869 0, /* destroy_fringe_bitmap */
4870 ns_compute_glyph_string_overhangs,
4871 ns_draw_glyph_string,
4872 ns_define_frame_cursor,
4873 ns_clear_frame_area,
4874 ns_draw_window_cursor,
4875 ns_draw_vertical_window_border,
4876 ns_draw_window_divider,
4877 ns_shift_glyphs_for_insert,
4884 ns_delete_display (struct ns_display_info *dpyinfo)
4890 /* This function is called when the last frame on a display is deleted. */
4892 ns_delete_terminal (struct terminal *terminal)
4894 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4896 NSTRACE ("ns_delete_terminal");
4898 /* Protect against recursive calls. delete_frame in
4899 delete_terminal calls us back when it deletes our last frame. */
4900 if (!terminal->name)
4905 x_destroy_all_bitmaps (dpyinfo);
4906 ns_delete_display (dpyinfo);
4911 static struct terminal *
4912 ns_create_terminal (struct ns_display_info *dpyinfo)
4913 /* --------------------------------------------------------------------------
4914 Set up use of NS before we make the first connection.
4915 -------------------------------------------------------------------------- */
4917 struct terminal *terminal;
4919 NSTRACE ("ns_create_terminal");
4921 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4923 terminal->display_info.ns = dpyinfo;
4924 dpyinfo->terminal = terminal;
4926 terminal->clear_frame_hook = ns_clear_frame;
4927 terminal->ring_bell_hook = ns_ring_bell;
4928 terminal->update_begin_hook = ns_update_begin;
4929 terminal->update_end_hook = ns_update_end;
4930 terminal->read_socket_hook = ns_read_socket;
4931 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4932 terminal->mouse_position_hook = ns_mouse_position;
4933 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4934 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4935 terminal->fullscreen_hook = ns_fullscreen_hook;
4936 terminal->menu_show_hook = ns_menu_show;
4937 terminal->popup_dialog_hook = ns_popup_dialog;
4938 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4939 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4940 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4941 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4942 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4943 terminal->delete_frame_hook = x_destroy_window;
4944 terminal->delete_terminal_hook = ns_delete_terminal;
4945 /* Other hooks are NULL by default. */
4951 struct ns_display_info *
4952 ns_term_init (Lisp_Object display_name)
4953 /* --------------------------------------------------------------------------
4954 Start the Application and get things rolling.
4955 -------------------------------------------------------------------------- */
4957 struct terminal *terminal;
4958 struct ns_display_info *dpyinfo;
4959 static int ns_initialized = 0;
4962 if (ns_initialized) return x_display_list;
4967 NSTRACE ("ns_term_init");
4969 [outerpool release];
4970 outerpool = [[NSAutoreleasePool alloc] init];
4972 /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
4973 /*GSDebugAllocationActive (YES); */
4977 Fset_input_interrupt_mode (Qnil);
4979 if (selfds[0] == -1)
4981 if (emacs_pipe (selfds) != 0)
4983 fprintf (stderr, "Failed to create pipe: %s\n",
4984 emacs_strerror (errno));
4988 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4989 FD_ZERO (&select_readfds);
4990 FD_ZERO (&select_writefds);
4991 pthread_mutex_init (&select_mutex, NULL);
4994 ns_pending_files = [[NSMutableArray alloc] init];
4995 ns_pending_service_names = [[NSMutableArray alloc] init];
4996 ns_pending_service_args = [[NSMutableArray alloc] init];
4998 /* Start app and create the main menu, window, view.
4999 Needs to be here because ns_initialize_display_info () uses AppKit classes.
5000 The view will then ask the NSApp to stop and return to Emacs. */
5001 [EmacsApp sharedApplication];
5004 [NSApp setDelegate: NSApp];
5006 /* Start the select thread. */
5007 [NSThread detachNewThreadSelector:@selector (fd_handler:)
5011 /* debugging: log all notifications */
5012 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
5013 selector: @selector (logNotification:)
5014 name: nil object: nil]; */
5016 dpyinfo = xzalloc (sizeof *dpyinfo);
5018 ns_initialize_display_info (dpyinfo);
5019 terminal = ns_create_terminal (dpyinfo);
5021 terminal->kboard = allocate_kboard (Qns);
5022 /* Don't let the initial kboard remain current longer than necessary.
5023 That would cause problems if a file loaded on startup tries to
5024 prompt in the mini-buffer. */
5025 if (current_kboard == initial_kboard)
5026 current_kboard = terminal->kboard;
5027 terminal->kboard->reference_count++;
5029 dpyinfo->next = x_display_list;
5030 x_display_list = dpyinfo;
5032 dpyinfo->name_list_element = Fcons (display_name, Qnil);
5034 terminal->name = xlispstrdup (display_name);
5038 if (!inhibit_x_resources)
5040 ns_default ("GSFontAntiAlias", &ns_antialias_text,
5043 /* this is a standard variable */
5044 ns_default ("AppleAntiAliasingThreshold", &tmp,
5045 make_float (10.0), make_float (6.0), YES, NO);
5046 ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5049 NSTRACE_MSG ("Colors");
5052 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5056 Lisp_Object color_file, color_map, color;
5060 color_file = Fexpand_file_name (build_string ("rgb.txt"),
5061 Fsymbol_value (intern ("data-directory")));
5063 color_map = Fx_load_color_file (color_file);
5064 if (NILP (color_map))
5065 fatal ("Could not read %s.\n", SDATA (color_file));
5067 cl = [[NSColorList alloc] initWithName: @"Emacs"];
5068 for ( ; CONSP (color_map); color_map = XCDR (color_map))
5070 color = XCAR (color_map);
5071 name = SSDATA (XCAR (color));
5072 c = XINT (XCDR (color));
5074 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5075 green: GREEN_FROM_ULONG (c) / 255.0
5076 blue: BLUE_FROM_ULONG (c) / 255.0
5078 forKey: [NSString stringWithUTF8String: name]];
5080 [cl writeToFile: nil];
5084 NSTRACE_MSG ("Versions");
5087 #ifdef NS_IMPL_GNUSTEP
5088 Vwindow_system_version = build_string (gnustep_base_version);
5090 /*PSnextrelease (128, c); */
5091 char c[DBL_BUFSIZE_BOUND];
5092 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5093 Vwindow_system_version = make_unibyte_string (c, len);
5097 delete_keyboard_wait_descriptor (0);
5099 ns_app_name = [[NSProcessInfo processInfo] processName];
5101 /* Set up macOS app menu */
5103 NSTRACE_MSG ("Menu init");
5105 #ifdef NS_IMPL_COCOA
5109 /* set up the application menu */
5110 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5111 [svcsMenu setAutoenablesItems: NO];
5112 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5113 [appMenu setAutoenablesItems: NO];
5114 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5115 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5117 [appMenu insertItemWithTitle: @"About Emacs"
5118 action: @selector (orderFrontStandardAboutPanel:)
5121 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5122 [appMenu insertItemWithTitle: @"Preferences..."
5123 action: @selector (showPreferencesWindow:)
5126 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5127 item = [appMenu insertItemWithTitle: @"Services"
5128 action: @selector (menuDown:)
5131 [appMenu setSubmenu: svcsMenu forItem: item];
5132 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5133 [appMenu insertItemWithTitle: @"Hide Emacs"
5134 action: @selector (hide:)
5137 item = [appMenu insertItemWithTitle: @"Hide Others"
5138 action: @selector (hideOtherApplications:)
5141 [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5142 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5143 [appMenu insertItemWithTitle: @"Quit Emacs"
5144 action: @selector (terminate:)
5148 item = [mainMenu insertItemWithTitle: ns_app_name
5149 action: @selector (menuDown:)
5152 [mainMenu setSubmenu: appMenu forItem: item];
5153 [dockMenu insertItemWithTitle: @"New Frame"
5154 action: @selector (newFrame:)
5158 [NSApp setMainMenu: mainMenu];
5159 [NSApp setAppleMenu: appMenu];
5160 [NSApp setServicesMenu: svcsMenu];
5161 /* Needed at least on Cocoa, to get dock menu to show windows */
5162 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5164 [[NSNotificationCenter defaultCenter]
5165 addObserver: mainMenu
5166 selector: @selector (trackingNotification:)
5167 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5168 [[NSNotificationCenter defaultCenter]
5169 addObserver: mainMenu
5170 selector: @selector (trackingNotification:)
5171 name: NSMenuDidEndTrackingNotification object: mainMenu];
5173 #endif /* macOS menu setup */
5175 /* Register our external input/output types, used for determining
5176 applicable services and also drag/drop eligibility. */
5178 NSTRACE_MSG ("Input/output types");
5180 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5181 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5183 ns_drag_types = [[NSArray arrayWithObjects:
5185 NSTabularTextPboardType,
5186 NSFilenamesPboardType,
5187 NSURLPboardType, nil] retain];
5189 /* If fullscreen is in init/default-frame-alist, focus isn't set
5190 right for fullscreen windows, so set this. */
5191 [NSApp activateIgnoringOtherApps:YES];
5193 NSTRACE_MSG ("Call NSApp run");
5196 ns_do_open_file = YES;
5198 #ifdef NS_IMPL_GNUSTEP
5199 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5200 We must re-catch it so subprocess works. */
5201 catch_child_signal ();
5204 NSTRACE_MSG ("ns_term_init done");
5213 ns_term_shutdown (int sig)
5215 [[NSUserDefaults standardUserDefaults] synchronize];
5217 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5218 if (STRINGP (Vauto_save_list_file_name))
5219 unlink (SSDATA (Vauto_save_list_file_name));
5221 if (sig == 0 || sig == SIGTERM)
5223 [NSApp terminate: NSApp];
5225 else // force a stack trace to happen
5232 /* ==========================================================================
5234 EmacsApp implementation
5236 ========================================================================== */
5239 @implementation EmacsApp
5243 NSTRACE ("[EmacsApp init]");
5245 if ((self = [super init]))
5247 #ifdef NS_IMPL_COCOA
5248 self->isFirst = YES;
5250 #ifdef NS_IMPL_GNUSTEP
5251 self->applicationDidFinishLaunchingCalled = NO;
5258 #ifdef NS_IMPL_COCOA
5261 NSTRACE ("[EmacsApp run]");
5263 #ifndef NSAppKitVersionNumber10_9
5264 #define NSAppKitVersionNumber10_9 1265
5267 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5273 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5275 if (isFirst) [self finishLaunching];
5278 shouldKeepRunning = YES;
5282 pool = [[NSAutoreleasePool alloc] init];
5285 [self nextEventMatchingMask:NSEventMaskAny
5286 untilDate:[NSDate distantFuture]
5287 inMode:NSDefaultRunLoopMode
5290 [self sendEvent:event];
5291 [self updateWindows];
5292 } while (shouldKeepRunning);
5297 - (void)stop: (id)sender
5299 NSTRACE ("[EmacsApp stop:]");
5301 shouldKeepRunning = NO;
5302 // Stop possible dialog also. Noop if no dialog present.
5303 // The file dialog still leaks 7k - 10k on 10.9 though.
5304 [super stop:sender];
5306 #endif /* NS_IMPL_COCOA */
5308 - (void)logNotification: (NSNotification *)notification
5310 NSTRACE ("[EmacsApp logNotification:]");
5312 const char *name = [[notification name] UTF8String];
5313 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5314 && !strstr (name, "WindowNumber"))
5315 NSLog (@"notification: '%@'", [notification name]);
5319 - (void)sendEvent: (NSEvent *)theEvent
5320 /* --------------------------------------------------------------------------
5321 Called when NSApp is running for each event received. Used to stop
5322 the loop when we choose, since there's no way to just run one iteration.
5323 -------------------------------------------------------------------------- */
5325 int type = [theEvent type];
5326 NSWindow *window = [theEvent window];
5328 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5329 NSTRACE_MSG ("Type: %d", type);
5331 #ifdef NS_IMPL_GNUSTEP
5332 // Keyboard events aren't propagated to file dialogs for some reason.
5333 if ([NSApp modalWindow] != nil &&
5334 (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5336 [[NSApp modalWindow] sendEvent: theEvent];
5341 if (represented_filename != nil && represented_frame)
5343 NSString *fstr = represented_filename;
5344 NSView *view = FRAME_NS_VIEW (represented_frame);
5345 #ifdef NS_IMPL_COCOA
5346 /* work around a bug observed on 10.3 and later where
5347 setTitleWithRepresentedFilename does not clear out previous state
5348 if given filename does not exist */
5349 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5350 [[view window] setRepresentedFilename: @""];
5352 [[view window] setRepresentedFilename: fstr];
5353 [represented_filename release];
5354 represented_filename = nil;
5355 represented_frame = NULL;
5358 if (type == NSEventTypeApplicationDefined)
5360 switch ([theEvent data2])
5362 #ifdef NS_IMPL_COCOA
5363 case NSAPP_DATA2_RUNASSCRIPT:
5368 case NSAPP_DATA2_RUNFILEDIALOG:
5369 ns_run_file_dialog ();
5375 if (type == NSEventTypeCursorUpdate && window == nil)
5377 fprintf (stderr, "Dropping external cursor update event.\n");
5381 if (type == NSEventTypeApplicationDefined)
5383 /* Events posted by ns_send_appdefined interrupt the run loop here.
5384 But, if a modal window is up, an appdefined can still come through,
5385 (e.g., from a makeKeyWindow event) but stopping self also stops the
5386 modal loop. Just defer it until later. */
5387 if ([NSApp modalWindow] == nil)
5389 last_appdefined_event_data = [theEvent data1];
5394 send_appdefined = YES;
5399 #ifdef NS_IMPL_COCOA
5400 /* If no dialog and none of our frames have focus and it is a move, skip it.
5401 It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5402 such as Wifi, sound, date or similar.
5403 This prevents "spooky" highlighting in the frame under the menu. */
5404 if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5406 struct ns_display_info *di;
5407 BOOL has_focus = NO;
5408 for (di = x_display_list; ! has_focus && di; di = di->next)
5409 has_focus = di->x_focus_frame != 0;
5415 NSTRACE_UNSILENCE();
5417 [super sendEvent: theEvent];
5421 - (void)showPreferencesWindow: (id)sender
5423 struct frame *emacsframe = SELECTED_FRAME ();
5424 NSEvent *theEvent = [NSApp currentEvent];
5428 emacs_event->kind = NS_NONKEY_EVENT;
5429 emacs_event->code = KEY_NS_SHOW_PREFS;
5430 emacs_event->modifiers = 0;
5431 EV_TRAILER (theEvent);
5435 - (void)newFrame: (id)sender
5437 NSTRACE ("[EmacsApp newFrame:]");
5439 struct frame *emacsframe = SELECTED_FRAME ();
5440 NSEvent *theEvent = [NSApp currentEvent];
5444 emacs_event->kind = NS_NONKEY_EVENT;
5445 emacs_event->code = KEY_NS_NEW_FRAME;
5446 emacs_event->modifiers = 0;
5447 EV_TRAILER (theEvent);
5451 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5452 - (BOOL) openFile: (NSString *)fileName
5454 NSTRACE ("[EmacsApp openFile:]");
5456 struct frame *emacsframe = SELECTED_FRAME ();
5457 NSEvent *theEvent = [NSApp currentEvent];
5462 emacs_event->kind = NS_NONKEY_EVENT;
5463 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5464 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5465 ns_input_line = Qnil; /* can be start or cons start,end */
5466 emacs_event->modifiers =0;
5467 EV_TRAILER (theEvent);
5473 /* **************************************************************************
5475 EmacsApp delegate implementation
5477 ************************************************************************** */
5479 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5480 /* --------------------------------------------------------------------------
5481 When application is loaded, terminate event loop in ns_term_init
5482 -------------------------------------------------------------------------- */
5484 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5486 #ifdef NS_IMPL_GNUSTEP
5487 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5489 [NSApp setServicesProvider: NSApp];
5491 [self antialiasThresholdDidChange:nil];
5492 #ifdef NS_IMPL_COCOA
5493 [[NSNotificationCenter defaultCenter]
5495 selector:@selector(antialiasThresholdDidChange:)
5496 name:NSAntialiasThresholdChangedNotification
5500 ns_send_appdefined (-2);
5503 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5505 #ifdef NS_IMPL_COCOA
5506 macfont_update_antialias_threshold ();
5511 /* Termination sequences:
5514 MenuBar | File | Exit:
5515 Select Quit from App menubar:
5517 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5520 Select Quit from Dock menu:
5523 Cancel -> Nothing else
5527 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5532 - (void) terminate: (id)sender
5534 NSTRACE ("[EmacsApp terminate:]");
5536 struct frame *emacsframe = SELECTED_FRAME ();
5541 emacs_event->kind = NS_NONKEY_EVENT;
5542 emacs_event->code = KEY_NS_POWER_OFF;
5543 emacs_event->arg = Qt; /* mark as non-key event */
5544 EV_TRAILER ((id)nil);
5548 runAlertPanel(NSString *title,
5549 NSString *msgFormat,
5550 NSString *defaultButton,
5551 NSString *alternateButton)
5553 #if !defined (NS_IMPL_COCOA) || \
5554 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5555 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5556 == NSAlertDefaultReturn;
5558 NSAlert *alert = [[NSAlert alloc] init];
5559 [alert setAlertStyle: NSAlertStyleCritical];
5560 [alert setMessageText: msgFormat];
5561 [alert addButtonWithTitle: defaultButton];
5562 [alert addButtonWithTitle: alternateButton];
5563 NSInteger ret = [alert runModal];
5565 return ret == NSAlertFirstButtonReturn;
5570 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5572 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5576 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5577 return NSTerminateNow;
5579 ret = runAlertPanel(ns_app_name,
5580 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5581 @"Save Buffers and Exit", @"Cancel");
5583 return ret ? NSTerminateNow : NSTerminateCancel;
5587 not_in_argv (NSString *arg)
5590 const char *a = [arg UTF8String];
5591 for (k = 1; k < initial_argc; ++k)
5592 if (strcmp (a, initial_argv[k]) == 0) return 0;
5596 /* Notification from the Workspace to open a file */
5597 - (BOOL)application: sender openFile: (NSString *)file
5599 if (ns_do_open_file || not_in_argv (file))
5600 [ns_pending_files addObject: file];
5605 /* Open a file as a temporary file */
5606 - (BOOL)application: sender openTempFile: (NSString *)file
5608 if (ns_do_open_file || not_in_argv (file))
5609 [ns_pending_files addObject: file];
5614 /* Notification from the Workspace to open a file noninteractively (?) */
5615 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5617 if (ns_do_open_file || not_in_argv (file))
5618 [ns_pending_files addObject: file];
5622 /* Notification from the Workspace to open multiple files */
5623 - (void)application: sender openFiles: (NSArray *)fileList
5625 NSEnumerator *files = [fileList objectEnumerator];
5627 /* Don't open files from the command line unconditionally,
5628 Cocoa parses the command line wrong, --option value tries to open value
5629 if --option is the last option. */
5630 while ((file = [files nextObject]) != nil)
5631 if (ns_do_open_file || not_in_argv (file))
5632 [ns_pending_files addObject: file];
5634 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5639 /* Handle dock menu requests. */
5640 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5646 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5647 - (void)applicationWillBecomeActive: (NSNotification *)notification
5649 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5650 //ns_app_active=YES;
5653 - (void)applicationDidBecomeActive: (NSNotification *)notification
5655 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5657 #ifdef NS_IMPL_GNUSTEP
5658 if (! applicationDidFinishLaunchingCalled)
5659 [self applicationDidFinishLaunching:notification];
5661 //ns_app_active=YES;
5663 ns_update_auto_hide_menu_bar ();
5664 // No constraining takes place when the application is not active.
5665 ns_constrain_all_frames ();
5667 - (void)applicationDidResignActive: (NSNotification *)notification
5669 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5672 ns_send_appdefined (-1);
5677 /* ==========================================================================
5679 EmacsApp aux handlers for managing event loop
5681 ========================================================================== */
5684 - (void)timeout_handler: (NSTimer *)timedEntry
5685 /* --------------------------------------------------------------------------
5686 The timeout specified to ns_select has passed.
5687 -------------------------------------------------------------------------- */
5689 /*NSTRACE ("timeout_handler"); */
5690 ns_send_appdefined (-2);
5693 - (void)sendFromMainThread:(id)unused
5695 ns_send_appdefined (nextappdefined);
5698 - (void)fd_handler:(id)unused
5699 /* --------------------------------------------------------------------------
5700 Check data waiting on file descriptors and terminate if so
5701 -------------------------------------------------------------------------- */
5704 int waiting = 1, nfds;
5707 fd_set readfds, writefds, *wfds;
5708 struct timespec timeout, *tmo;
5709 NSAutoreleasePool *pool = nil;
5711 /* NSTRACE ("fd_handler"); */
5716 pool = [[NSAutoreleasePool alloc] init];
5722 FD_SET (selfds[0], &fds);
5723 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5724 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5729 pthread_mutex_lock (&select_mutex);
5732 if (select_valid & SELECT_HAVE_READ)
5733 readfds = select_readfds;
5737 if (select_valid & SELECT_HAVE_WRITE)
5739 writefds = select_writefds;
5744 if (select_valid & SELECT_HAVE_TMO)
5746 timeout = select_timeout;
5752 pthread_mutex_unlock (&select_mutex);
5754 FD_SET (selfds[0], &readfds);
5755 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5757 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5760 ns_send_appdefined (-2);
5761 else if (result > 0)
5763 if (FD_ISSET (selfds[0], &readfds))
5765 if (read (selfds[0], &c, 1) == 1 && c == 's')
5770 pthread_mutex_lock (&select_mutex);
5771 if (select_valid & SELECT_HAVE_READ)
5772 select_readfds = readfds;
5773 if (select_valid & SELECT_HAVE_WRITE)
5774 select_writefds = writefds;
5775 if (select_valid & SELECT_HAVE_TMO)
5776 select_timeout = timeout;
5777 pthread_mutex_unlock (&select_mutex);
5779 ns_send_appdefined (result);
5789 /* ==========================================================================
5793 ========================================================================== */
5795 /* called from system: queue for next pass through event loop */
5796 - (void)requestService: (NSPasteboard *)pboard
5797 userData: (NSString *)userData
5798 error: (NSString **)error
5800 [ns_pending_service_names addObject: userData];
5801 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5802 SSDATA (ns_string_from_pasteboard (pboard))]];
5806 /* called from ns_read_socket to clear queue */
5807 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5809 struct frame *emacsframe = SELECTED_FRAME ();
5810 NSEvent *theEvent = [NSApp currentEvent];
5812 NSTRACE ("[EmacsApp fulfillService:withArg:]");
5817 emacs_event->kind = NS_NONKEY_EVENT;
5818 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5819 ns_input_spi_name = build_string ([name UTF8String]);
5820 ns_input_spi_arg = build_string ([arg UTF8String]);
5821 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5822 EV_TRAILER (theEvent);
5832 /* ==========================================================================
5834 EmacsView implementation
5836 ========================================================================== */
5839 @implementation EmacsView
5841 /* needed to inform when window closed from LISP */
5842 - (void) setWindowClosing: (BOOL)closing
5844 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5846 windowClosing = closing;
5852 NSTRACE ("[EmacsView dealloc]");
5854 if (fs_state == FULLSCREEN_BOTH)
5855 [nonfs_window release];
5860 /* called on font panel selection */
5861 - (void)changeFont: (id)sender
5863 NSEvent *e = [[self window] currentEvent];
5864 struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5865 struct font *font = face->font;
5870 NSTRACE ("[EmacsView changeFont:]");
5875 #ifdef NS_IMPL_GNUSTEP
5876 nsfont = ((struct nsfont_info *)font)->nsfont;
5878 #ifdef NS_IMPL_COCOA
5879 nsfont = (NSFont *) macfont_get_nsctfont (font);
5882 if ((newFont = [sender convertFont: nsfont]))
5884 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5886 emacs_event->kind = NS_NONKEY_EVENT;
5887 emacs_event->modifiers = 0;
5888 emacs_event->code = KEY_NS_CHANGE_FONT;
5890 size = [newFont pointSize];
5891 ns_input_fontsize = make_number (lrint (size));
5892 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5898 - (BOOL)acceptsFirstResponder
5900 NSTRACE ("[EmacsView acceptsFirstResponder]");
5905 - (void)resetCursorRects
5907 NSRect visible = [self visibleRect];
5908 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5909 NSTRACE ("[EmacsView resetCursorRects]");
5911 if (currentCursor == nil)
5912 currentCursor = [NSCursor arrowCursor];
5914 if (!NSIsEmptyRect (visible))
5915 [self addCursorRect: visible cursor: currentCursor];
5916 [currentCursor setOnMouseEntered: YES];
5921 /*****************************************************************************/
5922 /* Keyboard handling. */
5925 - (void)keyDown: (NSEvent *)theEvent
5927 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5929 unsigned fnKeysym = 0;
5930 static NSMutableArray *nsEvArray;
5932 unsigned int flags = [theEvent modifierFlags];
5934 NSTRACE ("[EmacsView keyDown:]");
5936 /* Rhapsody and macOS give up and down events for the arrow keys */
5937 if (ns_fake_keydown == YES)
5938 ns_fake_keydown = NO;
5939 else if ([theEvent type] != NSEventTypeKeyDown)
5945 if (![[self window] isKeyWindow]
5946 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5947 /* we must avoid an infinite loop here. */
5948 && (EmacsView *)[[theEvent window] delegate] != self)
5950 /* XXX: There is an occasional condition in which, when Emacs display
5951 updates a different frame from the current one, and temporarily
5952 selects it, then processes some interrupt-driven input
5953 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5954 for some reason that window has its first responder set to the NSView
5955 most recently updated (I guess), which is not the correct one. */
5956 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5960 if (nsEvArray == nil)
5961 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5963 [NSCursor setHiddenUntilMouseMoves: YES];
5965 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5967 clear_mouse_face (hlinfo);
5968 hlinfo->mouse_face_hidden = 1;
5971 if (!processingCompose)
5973 /* When using screen sharing, no left or right information is sent,
5974 so use Left key in those cases. */
5975 int is_left_key, is_right_key;
5977 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5978 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5980 /* (Carbon way: [theEvent keyCode]) */
5982 /* is it a "function key"? */
5983 /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
5984 flag set (this is probably a bug in the OS).
5986 if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
5988 fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
5992 fnKeysym = ns_convert_key (code);
5997 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5998 because Emacs treats Delete and KP-Delete same (in simple.el). */
5999 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6000 #ifdef NS_IMPL_GNUSTEP
6001 /* GNUstep uses incompatible keycodes, even for those that are
6002 supposed to be hardware independent. Just check for delete.
6003 Keypad delete does not have keysym 0xFFFF.
6004 See http://savannah.gnu.org/bugs/?25395
6006 || (fnKeysym == 0xFFFF && code == 127)
6009 code = 0xFF08; /* backspace */
6014 /* are there modifiers? */
6015 emacs_event->modifiers = 0;
6017 if (flags & NSEventModifierFlagHelp)
6018 emacs_event->modifiers |= hyper_modifier;
6020 if (flags & NSEventModifierFlagShift)
6021 emacs_event->modifiers |= shift_modifier;
6023 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
6024 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
6025 || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
6028 emacs_event->modifiers |= parse_solitary_modifier
6029 (EQ (ns_right_command_modifier, Qleft)
6030 ? ns_command_modifier
6031 : ns_right_command_modifier);
6035 emacs_event->modifiers |= parse_solitary_modifier
6036 (ns_command_modifier);
6038 /* if super (default), take input manager's word so things like
6039 dvorak / qwerty layout work */
6040 if (EQ (ns_command_modifier, Qsuper)
6042 && [[theEvent characters] length] != 0)
6044 /* XXX: the code we get will be unshifted, so if we have
6045 a shift modifier, must convert ourselves */
6046 if (!(flags & NSEventModifierFlagShift))
6047 code = [[theEvent characters] characterAtIndex: 0];
6049 /* this is ugly and also requires linking w/Carbon framework
6050 (for LMGetKbdType) so for now leave this rare (?) case
6051 undealt with.. in future look into CGEvent methods */
6054 long smv = GetScriptManagerVariable (smKeyScript);
6055 Handle uchrHandle = GetResource
6056 ('uchr', GetScriptVariable (smv, smScriptKeys));
6058 UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6059 [[theEvent characters] characterAtIndex: 0],
6060 kUCKeyActionDisplay,
6061 (flags & ~NSEventModifierFlagCommand) >> 8,
6062 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6063 &dummy, 1, &dummy, &code);
6070 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6071 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6072 || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6075 emacs_event->modifiers |= parse_solitary_modifier
6076 (EQ (ns_right_control_modifier, Qleft)
6077 ? ns_control_modifier
6078 : ns_right_control_modifier);
6081 emacs_event->modifiers |= parse_solitary_modifier
6082 (ns_control_modifier);
6084 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6085 emacs_event->modifiers |=
6086 parse_solitary_modifier (ns_function_modifier);
6088 left_is_none = NILP (ns_alternate_modifier)
6089 || EQ (ns_alternate_modifier, Qnone);
6091 is_right_key = (flags & NSRightAlternateKeyMask)
6092 == NSRightAlternateKeyMask;
6093 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6095 && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6099 if ((NILP (ns_right_alternate_modifier)
6100 || EQ (ns_right_alternate_modifier, Qnone)
6101 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6103 { /* accept pre-interp alt comb */
6104 if ([[theEvent characters] length] > 0)
6105 code = [[theEvent characters] characterAtIndex: 0];
6106 /*HACK: clear lone shift modifier to stop next if from firing */
6107 if (emacs_event->modifiers == shift_modifier)
6108 emacs_event->modifiers = 0;
6111 emacs_event->modifiers |= parse_solitary_modifier
6112 (EQ (ns_right_alternate_modifier, Qleft)
6113 ? ns_alternate_modifier
6114 : ns_right_alternate_modifier);
6117 if (is_left_key) /* default = meta */
6119 if (left_is_none && !fnKeysym)
6120 { /* accept pre-interp alt comb */
6121 if ([[theEvent characters] length] > 0)
6122 code = [[theEvent characters] characterAtIndex: 0];
6123 /*HACK: clear lone shift modifier to stop next if from firing */
6124 if (emacs_event->modifiers == shift_modifier)
6125 emacs_event->modifiers = 0;
6128 emacs_event->modifiers |=
6129 parse_solitary_modifier (ns_alternate_modifier);
6133 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6134 (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6136 /* if it was a function key or had modifiers, pass it directly to emacs */
6137 if (fnKeysym || (emacs_event->modifiers
6138 && (emacs_event->modifiers != shift_modifier)
6139 && [[theEvent charactersIgnoringModifiers] length] > 0))
6140 /*[[theEvent characters] length] */
6142 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6144 code |= (1<<28)|(3<<16);
6145 else if (code == 0x7f)
6146 code |= (1<<28)|(3<<16);
6148 emacs_event->kind = code > 0xFF
6149 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6151 emacs_event->code = code;
6152 EV_TRAILER (theEvent);
6153 processingCompose = NO;
6159 if (NS_KEYLOG && !processingCompose)
6160 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6162 processingCompose = YES;
6163 [nsEvArray addObject: theEvent];
6164 [self interpretKeyEvents: nsEvArray];
6165 [nsEvArray removeObject: theEvent];
6169 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6172 /* <NSTextInput>: called when done composing;
6173 NOTE: also called when we delete over working text, followed immed.
6174 by doCommandBySelector: deleteBackward: */
6175 - (void)insertText: (id)aString
6178 int len = [(NSString *)aString length];
6181 NSTRACE ("[EmacsView insertText:]");
6184 NSLog (@"insertText '%@'\tlen = %d", aString, len);
6185 processingCompose = NO;
6190 /* first, clear any working text */
6191 if (workingText != nil)
6192 [self deleteWorkingText];
6194 /* now insert the string as keystrokes */
6195 for (i =0; i<len; i++)
6197 code = [aString characterAtIndex: i];
6198 /* TODO: still need this? */
6200 code = '~'; /* 0x7E */
6201 if (code != 32) /* Space */
6202 emacs_event->modifiers = 0;
6204 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6205 emacs_event->code = code;
6206 EV_TRAILER ((id)nil);
6211 /* <NSTextInput>: inserts display of composing characters */
6212 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6214 NSString *str = [aString respondsToSelector: @selector (string)] ?
6215 [aString string] : aString;
6217 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6220 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6221 str, (unsigned long)[str length],
6222 (unsigned long)selRange.length,
6223 (unsigned long)selRange.location);
6225 if (workingText != nil)
6226 [self deleteWorkingText];
6227 if ([str length] == 0)
6233 processingCompose = YES;
6234 workingText = [str copy];
6235 ns_working_text = build_string ([workingText UTF8String]);
6237 emacs_event->kind = NS_TEXT_EVENT;
6238 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6239 EV_TRAILER ((id)nil);
6243 /* delete display of composing characters [not in <NSTextInput>] */
6244 - (void)deleteWorkingText
6246 NSTRACE ("[EmacsView deleteWorkingText]");
6248 if (workingText == nil)
6251 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6252 [workingText release];
6254 processingCompose = NO;
6259 emacs_event->kind = NS_TEXT_EVENT;
6260 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6261 EV_TRAILER ((id)nil);
6265 - (BOOL)hasMarkedText
6267 NSTRACE ("[EmacsView hasMarkedText]");
6269 return workingText != nil;
6273 - (NSRange)markedRange
6275 NSTRACE ("[EmacsView markedRange]");
6277 NSRange rng = workingText != nil
6278 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6280 NSLog (@"markedRange request");
6287 NSTRACE ("[EmacsView unmarkText]");
6290 NSLog (@"unmark (accept) text");
6291 [self deleteWorkingText];
6292 processingCompose = NO;
6296 /* used to position char selection windows, etc. */
6297 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6301 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6303 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6306 NSLog (@"firstRectForCharRange request");
6308 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6309 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6310 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6311 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6312 +FRAME_LINE_HEIGHT (emacsframe));
6314 pt = [self convertPoint: pt toView: nil];
6315 #if !defined (NS_IMPL_COCOA) || \
6316 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
6317 pt = [[self window] convertBaseToScreen: pt];
6321 rect = [[self window] convertRectToScreen: rect];
6327 - (NSInteger)conversationIdentifier
6329 return (NSInteger)self;
6333 - (void)doCommandBySelector: (SEL)aSelector
6335 NSTRACE ("[EmacsView doCommandBySelector:]");
6338 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6340 processingCompose = NO;
6341 if (aSelector == @selector (deleteBackward:))
6343 /* happens when user backspaces over an ongoing composition:
6344 throw a 'delete' into the event queue */
6347 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6348 emacs_event->code = 0xFF08;
6349 EV_TRAILER ((id)nil);
6353 - (NSArray *)validAttributesForMarkedText
6355 static NSArray *arr = nil;
6356 if (arr == nil) arr = [NSArray new];
6357 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6361 - (NSRange)selectedRange
6364 NSLog (@"selectedRange request");
6365 return NSMakeRange (NSNotFound, 0);
6368 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6369 GNUSTEP_GUI_MINOR_VERSION > 22
6370 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6372 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6376 NSLog (@"characterIndexForPoint request");
6380 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6382 static NSAttributedString *str = nil;
6383 if (str == nil) str = [NSAttributedString new];
6385 NSLog (@"attributedSubstringFromRange request");
6389 /* End <NSTextInput> impl. */
6390 /*****************************************************************************/
6393 /* This is what happens when the user presses a mouse button. */
6394 - (void)mouseDown: (NSEvent *)theEvent
6396 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6397 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6399 NSTRACE ("[EmacsView mouseDown:]");
6401 [self deleteWorkingText];
6406 dpyinfo->last_mouse_frame = emacsframe;
6407 /* appears to be needed to prevent spurious movement events generated on
6409 emacsframe->mouse_moved = 0;
6411 if ([theEvent type] == NSEventTypeScrollWheel)
6413 CGFloat delta = [theEvent deltaY];
6414 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6417 delta = [theEvent deltaX];
6420 NSTRACE_MSG ("deltaIsZero");
6423 emacs_event->kind = HORIZ_WHEEL_EVENT;
6426 emacs_event->kind = WHEEL_EVENT;
6428 emacs_event->code = 0;
6429 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6430 ((delta > 0) ? up_modifier : down_modifier);
6434 emacs_event->kind = MOUSE_CLICK_EVENT;
6435 emacs_event->code = EV_BUTTON (theEvent);
6436 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6437 | EV_UDMODIFIERS (theEvent);
6439 XSETINT (emacs_event->x, lrint (p.x));
6440 XSETINT (emacs_event->y, lrint (p.y));
6441 EV_TRAILER (theEvent);
6445 - (void)rightMouseDown: (NSEvent *)theEvent
6447 NSTRACE ("[EmacsView rightMouseDown:]");
6448 [self mouseDown: theEvent];
6452 - (void)otherMouseDown: (NSEvent *)theEvent
6454 NSTRACE ("[EmacsView otherMouseDown:]");
6455 [self mouseDown: theEvent];
6459 - (void)mouseUp: (NSEvent *)theEvent
6461 NSTRACE ("[EmacsView mouseUp:]");
6462 [self mouseDown: theEvent];
6466 - (void)rightMouseUp: (NSEvent *)theEvent
6468 NSTRACE ("[EmacsView rightMouseUp:]");
6469 [self mouseDown: theEvent];
6473 - (void)otherMouseUp: (NSEvent *)theEvent
6475 NSTRACE ("[EmacsView otherMouseUp:]");
6476 [self mouseDown: theEvent];
6480 - (void) scrollWheel: (NSEvent *)theEvent
6482 NSTRACE ("[EmacsView scrollWheel:]");
6483 [self mouseDown: theEvent];
6487 /* Tell emacs the mouse has moved. */
6488 - (void)mouseMoved: (NSEvent *)e
6490 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6491 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6495 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6497 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6498 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6499 dpyinfo->last_mouse_motion_x = pt.x;
6500 dpyinfo->last_mouse_motion_y = pt.y;
6502 /* update any mouse face */
6503 if (hlinfo->mouse_face_hidden)
6505 hlinfo->mouse_face_hidden = 0;
6506 clear_mouse_face (hlinfo);
6509 /* tooltip handling */
6510 previous_help_echo_string = help_echo_string;
6511 help_echo_string = Qnil;
6513 if (!NILP (Vmouse_autoselect_window))
6515 NSTRACE_MSG ("mouse_autoselect_window");
6516 static Lisp_Object last_mouse_window;
6518 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6520 if (WINDOWP (window)
6521 && !EQ (window, last_mouse_window)
6522 && !EQ (window, selected_window)
6523 && (!NILP (focus_follows_mouse)
6524 || (EQ (XWINDOW (window)->frame,
6525 XWINDOW (selected_window)->frame))))
6527 NSTRACE_MSG ("in_window");
6528 emacs_event->kind = SELECT_WINDOW_EVENT;
6529 emacs_event->frame_or_window = window;
6532 /* Remember the last window where we saw the mouse. */
6533 last_mouse_window = window;
6536 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6537 help_echo_string = previous_help_echo_string;
6539 XSETFRAME (frame, emacsframe);
6540 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6542 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6543 (note_mouse_highlight), which is called through the
6544 note_mouse_movement () call above */
6545 any_help_event_p = YES;
6546 gen_help_event (help_echo_string, frame, help_echo_window,
6547 help_echo_object, help_echo_pos);
6550 if (emacsframe->mouse_moved && send_appdefined)
6551 ns_send_appdefined (-1);
6555 - (void)mouseDragged: (NSEvent *)e
6557 NSTRACE ("[EmacsView mouseDragged:]");
6558 [self mouseMoved: e];
6562 - (void)rightMouseDragged: (NSEvent *)e
6564 NSTRACE ("[EmacsView rightMouseDragged:]");
6565 [self mouseMoved: e];
6569 - (void)otherMouseDragged: (NSEvent *)e
6571 NSTRACE ("[EmacsView otherMouseDragged:]");
6572 [self mouseMoved: e];
6576 - (BOOL)windowShouldClose: (id)sender
6578 NSEvent *e =[[self window] currentEvent];
6580 NSTRACE ("[EmacsView windowShouldClose:]");
6581 windowClosing = YES;
6584 emacs_event->kind = DELETE_WINDOW_EVENT;
6585 emacs_event->modifiers = 0;
6586 emacs_event->code = 0;
6588 /* Don't close this window, let this be done from lisp code. */
6592 - (void) updateFrameSize: (BOOL) delay
6594 NSWindow *window = [self window];
6595 NSRect wr = [window frame];
6597 int oldc = cols, oldr = rows;
6598 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6599 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6602 NSTRACE ("[EmacsView updateFrameSize:]");
6603 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6604 NSTRACE_RECT ("Original frame", wr);
6605 NSTRACE_MSG ("Original columns: %d", cols);
6606 NSTRACE_MSG ("Original rows: %d", rows);
6608 if (! [self isFullscreen])
6610 #ifdef NS_IMPL_GNUSTEP
6611 // GNUstep does not always update the tool bar height. Force it.
6612 if (toolbar && [toolbar isVisible])
6613 update_frame_tool_bar (emacsframe);
6616 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6617 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6620 if (wait_for_tool_bar)
6622 /* The toolbar height is always 0 in fullscreen, so don't wait
6623 for it to become available. */
6624 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6625 && ! [self isFullscreen])
6627 NSTRACE_MSG ("Waiting for toolbar");
6630 wait_for_tool_bar = NO;
6633 neww = (int)wr.size.width - emacsframe->border_width;
6634 newh = (int)wr.size.height - extra;
6636 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6637 NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6638 NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6640 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6641 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6643 if (cols < MINWIDTH)
6646 if (rows < MINHEIGHT)
6649 NSTRACE_MSG ("New columns: %d", cols);
6650 NSTRACE_MSG ("New rows: %d", rows);
6652 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6654 NSView *view = FRAME_NS_VIEW (emacsframe);
6656 change_frame_size (emacsframe,
6657 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6658 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6660 SET_FRAME_GARBAGED (emacsframe);
6661 cancel_mouse_face (emacsframe);
6663 /* The next two lines appear to be setting the frame to the same
6664 size as it already is. Why are they there? */
6665 // wr = NSMakeRect (0, 0, neww, newh);
6667 // [view setFrame: wr];
6669 // to do: consider using [NSNotificationCenter postNotificationName:].
6670 [self windowDidMove: // Update top/left.
6671 [NSNotification notificationWithName:NSWindowDidMoveNotification
6672 object:[view window]]];
6676 NSTRACE_MSG ("No change");
6680 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6681 /* normalize frame to gridded text size */
6685 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6686 NSTRACE_ARG_SIZE (frameSize));
6687 NSTRACE_RECT ("[sender frame]", [sender frame]);
6688 NSTRACE_FSTYPE ("fs_state", fs_state);
6690 if (fs_state == FULLSCREEN_MAXIMIZED
6691 && (maximized_width != (int)frameSize.width
6692 || maximized_height != (int)frameSize.height))
6693 [self setFSValue: FULLSCREEN_NONE];
6694 else if (fs_state == FULLSCREEN_WIDTH
6695 && maximized_width != (int)frameSize.width)
6696 [self setFSValue: FULLSCREEN_NONE];
6697 else if (fs_state == FULLSCREEN_HEIGHT
6698 && maximized_height != (int)frameSize.height)
6699 [self setFSValue: FULLSCREEN_NONE];
6701 if (fs_state == FULLSCREEN_NONE)
6702 maximized_width = maximized_height = -1;
6704 if (! [self isFullscreen])
6706 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6707 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6710 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6711 if (cols < MINWIDTH)
6714 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6715 frameSize.height - extra);
6716 if (rows < MINHEIGHT)
6718 #ifdef NS_IMPL_COCOA
6720 /* this sets window title to have size in it; the wm does this under GS */
6721 NSRect r = [[self window] frame];
6722 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6730 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6731 && [[self window] title] != NULL)
6734 NSWindow *window = [self window];
6737 char *t = strdup ([[[self window] title] UTF8String]);
6738 char *pos = strstr (t, " — ");
6743 size_title = xmalloc (strlen (old_title) + 40);
6744 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6745 [window setTitle: [NSString stringWithUTF8String: size_title]];
6750 #endif /* NS_IMPL_COCOA */
6752 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
6754 /* Restrict the new size to the text gird.
6756 Don't restrict the width if the user only adjusted the height, and
6757 vice versa. (Without this, the frame would shrink, and move
6758 slightly, if the window was resized by dragging one of its
6760 if (!frame_resize_pixelwise)
6762 NSRect r = [[self window] frame];
6764 if (r.size.width != frameSize.width)
6767 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
6770 if (r.size.height != frameSize.height)
6773 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6777 NSTRACE_RETURN_SIZE (frameSize);
6783 - (void)windowDidResize: (NSNotification *)notification
6785 NSTRACE ("[EmacsView windowDidResize:]");
6786 if (!FRAME_LIVE_P (emacsframe))
6788 NSTRACE_MSG ("Ignored (frame dead)");
6791 if (emacsframe->output_data.ns->in_animation)
6793 NSTRACE_MSG ("Ignored (in animation)");
6797 if (! [self fsIsNative])
6799 NSWindow *theWindow = [notification object];
6800 /* We can get notification on the non-FS window when in
6802 if ([self window] != theWindow) return;
6805 NSTRACE_RECT ("frame", [[notification object] frame]);
6807 #ifdef NS_IMPL_GNUSTEP
6808 NSWindow *theWindow = [notification object];
6810 /* In GNUstep, at least currently, it's possible to get a didResize
6811 without getting a willResize.. therefore we need to act as if we got
6812 the willResize now */
6813 NSSize sz = [theWindow frame].size;
6814 sz = [self windowWillResize: theWindow toSize: sz];
6815 #endif /* NS_IMPL_GNUSTEP */
6817 if (cols > 0 && rows > 0)
6819 [self updateFrameSize: YES];
6822 ns_send_appdefined (-1);
6825 #ifdef NS_IMPL_COCOA
6826 - (void)viewDidEndLiveResize
6828 NSTRACE ("[EmacsView viewDidEndLiveResize]");
6830 [super viewDidEndLiveResize];
6833 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6837 maximizing_resize = NO;
6839 #endif /* NS_IMPL_COCOA */
6842 - (void)windowDidBecomeKey: (NSNotification *)notification
6843 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6845 [self windowDidBecomeKey];
6849 - (void)windowDidBecomeKey /* for direct calls */
6851 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6852 struct frame *old_focus = dpyinfo->x_focus_frame;
6854 NSTRACE ("[EmacsView windowDidBecomeKey]");
6856 if (emacsframe != old_focus)
6857 dpyinfo->x_focus_frame = emacsframe;
6859 ns_frame_rehighlight (emacsframe);
6863 emacs_event->kind = FOCUS_IN_EVENT;
6864 EV_TRAILER ((id)nil);
6869 - (void)windowDidResignKey: (NSNotification *)notification
6870 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6872 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6873 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6874 NSTRACE ("[EmacsView windowDidResignKey:]");
6877 dpyinfo->x_focus_frame = 0;
6879 emacsframe->mouse_moved = 0;
6880 ns_frame_rehighlight (emacsframe);
6882 /* FIXME: for some reason needed on second and subsequent clicks away
6883 from sole-frame Emacs to get hollow box to show */
6884 if (!windowClosing && [[self window] isVisible] == YES)
6886 x_update_cursor (emacsframe, 1);
6887 x_set_frame_alpha (emacsframe);
6890 if (any_help_event_p)
6893 XSETFRAME (frame, emacsframe);
6894 help_echo_string = Qnil;
6895 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6898 if (emacs_event && is_focus_frame)
6900 [self deleteWorkingText];
6901 emacs_event->kind = FOCUS_OUT_EVENT;
6902 EV_TRAILER ((id)nil);
6907 - (void)windowWillMiniaturize: sender
6909 NSTRACE ("[EmacsView windowWillMiniaturize:]");
6913 - (void)setFrame:(NSRect)frameRect
6915 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6916 NSTRACE_ARG_RECT (frameRect));
6918 [super setFrame:(NSRect)frameRect];
6934 - (void)createToolbar: (struct frame *)f
6936 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
6937 NSWindow *window = [view window];
6939 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6940 [NSString stringWithFormat: @"Emacs Frame %d",
6942 [toolbar setVisible: NO];
6943 [window setToolbar: toolbar];
6945 /* Don't set frame garbaged until tool bar is up to date?
6946 This avoids an extra clear and redraw (flicker) at frame creation. */
6947 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6948 else wait_for_tool_bar = NO;
6951 #ifdef NS_IMPL_COCOA
6953 NSButton *toggleButton;
6954 toggleButton = [window standardWindowButton: NSWindowToolbarButton];
6955 [toggleButton setTarget: self];
6956 [toggleButton setAction: @selector (toggleToolbar: )];
6962 - (instancetype) initFrameFromEmacs: (struct frame *)f
6970 NSTRACE ("[EmacsView initFrameFromEmacs:]");
6971 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6974 processingCompose = NO;
6975 scrollbarsNeedingUpdate = 0;
6976 fs_state = FULLSCREEN_NONE;
6977 fs_before_fs = next_maximized = -1;
6978 #ifdef HAVE_NATIVE_FS
6979 fs_is_native = ns_use_native_fullscreen;
6983 maximized_width = maximized_height = -1;
6986 ns_userRect = NSMakeRect (0, 0, 0, 0);
6987 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6988 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6989 [self initWithFrame: r];
6990 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6992 FRAME_NS_VIEW (f) = self;
6994 #ifdef NS_IMPL_COCOA
6996 maximizing_resize = NO;
6999 win = [[EmacsWindow alloc]
7000 initWithContentRect: r
7001 styleMask: (FRAME_UNDECORATED (f)
7002 ? FRAME_UNDECORATED_FLAGS
7003 : FRAME_DECORATED_FLAGS
7004 #ifdef NS_IMPL_COCOA
7005 | NSWindowStyleMaskResizable
7006 | NSWindowStyleMaskMiniaturizable
7007 | NSWindowStyleMaskClosable
7010 backing: NSBackingStoreBuffered
7013 #ifdef HAVE_NATIVE_FS
7014 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7018 bwidth = f->border_width = wr.size.width - r.size.width;
7020 [win setAcceptsMouseMovedEvents: YES];
7021 [win setDelegate: self];
7022 #if !defined (NS_IMPL_COCOA) || \
7023 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7024 [win useOptimizedDrawing: YES];
7027 [[win contentView] addSubview: self];
7030 [self registerForDraggedTypes: ns_drag_types];
7033 name = [NSString stringWithUTF8String:
7034 NILP (tem) ? "Emacs" : SSDATA (tem)];
7035 [win setTitle: name];
7037 /* toolbar support */
7038 if (! FRAME_UNDECORATED (f))
7039 [self createToolbar: f];
7043 [win setMiniwindowTitle:
7044 [NSString stringWithUTF8String: SSDATA (tem)]];
7046 if (FRAME_PARENT_FRAME (f) != NULL)
7048 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7049 [parent addChildWindow: win
7050 ordered: NSWindowAbove];
7053 if (FRAME_Z_GROUP (f) != z_group_none)
7054 win.level = NSNormalWindowLevel
7055 + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7058 NSScreen *screen = [win screen];
7062 NSPoint pt = NSMakePoint
7063 (IN_BOUND (-SCREENMAX, f->left_pos
7064 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7065 IN_BOUND (-SCREENMAX,
7066 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7069 [win setFrameTopLeftPoint: pt];
7071 NSTRACE_RECT ("new frame", [win frame]);
7075 [win makeFirstResponder: self];
7077 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7078 (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7080 [win setBackgroundColor: col];
7081 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7082 [win setOpaque: NO];
7084 #if !defined (NS_IMPL_COCOA) || \
7085 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7086 [self allocateGState];
7088 [NSApp registerServicesMenuSendTypes: ns_send_types
7089 returnTypes: [NSArray array]];
7091 /* macOS Sierra automatically enables tabbed windows. We can't
7092 allow this to be enabled until it's available on a Free system.
7093 Currently it only happens by accident and is buggy anyway. */
7094 #if defined (NS_IMPL_COCOA) && \
7095 MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
7096 [win setTabbingMode: NSWindowTabbingModeDisallowed];
7104 - (void)windowDidMove: sender
7106 NSWindow *win = [self window];
7107 NSRect r = [win frame];
7108 NSArray *screens = [NSScreen screens];
7109 NSScreen *screen = [screens objectAtIndex: 0];
7111 NSTRACE ("[EmacsView windowDidMove:]");
7113 if (!emacsframe->output_data.ns)
7117 emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7118 emacsframe->top_pos =
7119 NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7123 emacs_event->kind = MOVE_FRAME_EVENT;
7124 EV_TRAILER ((id)nil);
7130 /* Called AFTER method below, but before our windowWillResize call there leads
7131 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
7132 location so set_window_size moves the frame. */
7133 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7135 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7136 NSTRACE_FMT_RETURN "YES"),
7137 NSTRACE_ARG_RECT (newFrame));
7139 emacsframe->output_data.ns->zooming = 1;
7144 /* Override to do something slightly nonstandard, but nice. First click on
7145 zoom button will zoom vertically. Second will zoom completely. Third
7146 returns to original. */
7147 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7148 defaultFrame:(NSRect)defaultFrame
7150 // TODO: Rename to "currentFrame" and assign "result" properly in
7152 NSRect result = [sender frame];
7154 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7155 NSTRACE_FMT_RECT "]"),
7156 NSTRACE_ARG_RECT (defaultFrame));
7157 NSTRACE_FSTYPE ("fs_state", fs_state);
7158 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7159 NSTRACE_FSTYPE ("next_maximized", next_maximized);
7160 NSTRACE_RECT ("ns_userRect", ns_userRect);
7161 NSTRACE_RECT ("[sender frame]", [sender frame]);
7163 if (fs_before_fs != -1) /* Entering fullscreen */
7165 NSTRACE_MSG ("Entering fullscreen");
7166 result = defaultFrame;
7170 // Save the window size and position (frame) before the resize.
7171 if (fs_state != FULLSCREEN_MAXIMIZED
7172 && fs_state != FULLSCREEN_WIDTH)
7174 ns_userRect.size.width = result.size.width;
7175 ns_userRect.origin.x = result.origin.x;
7178 if (fs_state != FULLSCREEN_MAXIMIZED
7179 && fs_state != FULLSCREEN_HEIGHT)
7181 ns_userRect.size.height = result.size.height;
7182 ns_userRect.origin.y = result.origin.y;
7185 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7187 if (next_maximized == FULLSCREEN_HEIGHT
7188 || (next_maximized == -1
7189 && abs ((int)(defaultFrame.size.height - result.size.height))
7190 > FRAME_LINE_HEIGHT (emacsframe)))
7193 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7194 maximized_height = result.size.height = defaultFrame.size.height;
7195 maximized_width = -1;
7196 result.origin.y = defaultFrame.origin.y;
7197 if (ns_userRect.size.height != 0)
7199 result.origin.x = ns_userRect.origin.x;
7200 result.size.width = ns_userRect.size.width;
7202 [self setFSValue: FULLSCREEN_HEIGHT];
7203 #ifdef NS_IMPL_COCOA
7204 maximizing_resize = YES;
7207 else if (next_maximized == FULLSCREEN_WIDTH)
7209 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7210 maximized_width = result.size.width = defaultFrame.size.width;
7211 maximized_height = -1;
7212 result.origin.x = defaultFrame.origin.x;
7213 if (ns_userRect.size.width != 0)
7215 result.origin.y = ns_userRect.origin.y;
7216 result.size.height = ns_userRect.size.height;
7218 [self setFSValue: FULLSCREEN_WIDTH];
7220 else if (next_maximized == FULLSCREEN_MAXIMIZED
7221 || (next_maximized == -1
7222 && abs ((int)(defaultFrame.size.width - result.size.width))
7223 > FRAME_COLUMN_WIDTH (emacsframe)))
7225 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7227 result = defaultFrame; /* second click */
7228 maximized_width = result.size.width;
7229 maximized_height = result.size.height;
7230 [self setFSValue: FULLSCREEN_MAXIMIZED];
7231 #ifdef NS_IMPL_COCOA
7232 maximizing_resize = YES;
7238 NSTRACE_MSG ("Restore");
7239 result = ns_userRect.size.height ? ns_userRect : result;
7240 NSTRACE_RECT ("restore (2)", result);
7241 ns_userRect = NSMakeRect (0, 0, 0, 0);
7242 #ifdef NS_IMPL_COCOA
7243 maximizing_resize = fs_state != FULLSCREEN_NONE;
7245 [self setFSValue: FULLSCREEN_NONE];
7246 maximized_width = maximized_height = -1;
7250 if (fs_before_fs == -1) next_maximized = -1;
7252 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7253 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7254 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7255 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7257 [self windowWillResize: sender toSize: result.size];
7259 NSTRACE_RETURN_RECT (result);
7265 - (void)windowDidDeminiaturize: sender
7267 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7268 if (!emacsframe->output_data.ns)
7271 SET_FRAME_ICONIFIED (emacsframe, 0);
7272 SET_FRAME_VISIBLE (emacsframe, 1);
7273 windows_or_buffers_changed = 63;
7277 emacs_event->kind = DEICONIFY_EVENT;
7278 EV_TRAILER ((id)nil);
7283 - (void)windowDidExpose: sender
7285 NSTRACE ("[EmacsView windowDidExpose:]");
7286 if (!emacsframe->output_data.ns)
7289 SET_FRAME_VISIBLE (emacsframe, 1);
7290 SET_FRAME_GARBAGED (emacsframe);
7292 if (send_appdefined)
7293 ns_send_appdefined (-1);
7297 - (void)windowDidMiniaturize: sender
7299 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7300 if (!emacsframe->output_data.ns)
7303 SET_FRAME_ICONIFIED (emacsframe, 1);
7304 SET_FRAME_VISIBLE (emacsframe, 0);
7308 emacs_event->kind = ICONIFY_EVENT;
7309 EV_TRAILER ((id)nil);
7313 #ifdef HAVE_NATIVE_FS
7314 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7315 willUseFullScreenPresentationOptions:
7316 (NSApplicationPresentationOptions)proposedOptions
7318 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7322 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7324 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7325 [self windowWillEnterFullScreen];
7327 - (void)windowWillEnterFullScreen /* provided for direct calls */
7329 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7330 fs_before_fs = fs_state;
7333 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7335 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7336 [self windowDidEnterFullScreen];
7339 - (void)windowDidEnterFullScreen /* provided for direct calls */
7341 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7342 [self setFSValue: FULLSCREEN_BOTH];
7343 if (! [self fsIsNative])
7345 [self windowDidBecomeKey];
7346 [nonfs_window orderOut:self];
7350 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7351 #ifdef NS_IMPL_COCOA
7352 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7353 unsigned val = (unsigned)[NSApp presentationOptions];
7355 // Mac OS X 10.7 bug fix, the menu won't appear without this.
7356 // val is non-zero on other macOS versions.
7359 NSApplicationPresentationOptions options
7360 = NSApplicationPresentationAutoHideDock
7361 | NSApplicationPresentationAutoHideMenuBar
7362 | NSApplicationPresentationFullScreen
7363 | NSApplicationPresentationAutoHideToolbar;
7365 [NSApp setPresentationOptions: options];
7369 [toolbar setVisible:tbar_visible];
7373 - (void)windowWillExitFullScreen:(NSNotification *)notification
7375 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7376 [self windowWillExitFullScreen];
7379 - (void)windowWillExitFullScreen /* provided for direct calls */
7381 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7382 if (!FRAME_LIVE_P (emacsframe))
7384 NSTRACE_MSG ("Ignored (frame dead)");
7387 if (next_maximized != -1)
7388 fs_before_fs = next_maximized;
7391 - (void)windowDidExitFullScreen:(NSNotification *)notification
7393 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7394 [self windowDidExitFullScreen];
7397 - (void)windowDidExitFullScreen /* provided for direct calls */
7399 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7400 if (!FRAME_LIVE_P (emacsframe))
7402 NSTRACE_MSG ("Ignored (frame dead)");
7405 [self setFSValue: fs_before_fs];
7407 #ifdef HAVE_NATIVE_FS
7408 [self updateCollectionBehavior];
7410 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7412 [toolbar setVisible:YES];
7413 update_frame_tool_bar (emacsframe);
7414 [self updateFrameSize:YES];
7415 [[self window] display];
7418 [toolbar setVisible:NO];
7420 if (next_maximized != -1)
7421 [[self window] performZoom:self];
7426 return fs_is_native;
7429 - (BOOL)isFullscreen
7435 res = (nonfs_window != nil);
7439 #ifdef HAVE_NATIVE_FS
7440 res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7446 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7452 #ifdef HAVE_NATIVE_FS
7453 - (void)updateCollectionBehavior
7455 NSTRACE ("[EmacsView updateCollectionBehavior]");
7457 if (! [self isFullscreen])
7459 NSWindow *win = [self window];
7460 NSWindowCollectionBehavior b = [win collectionBehavior];
7461 if (ns_use_native_fullscreen)
7462 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7464 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7466 [win setCollectionBehavior: b];
7467 fs_is_native = ns_use_native_fullscreen;
7472 - (void)toggleFullScreen: (id)sender
7480 NSTRACE ("[EmacsView toggleFullScreen:]");
7484 #ifdef HAVE_NATIVE_FS
7485 [[self window] toggleFullScreen:sender];
7491 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7494 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7495 (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7498 if (fs_state != FULLSCREEN_BOTH)
7500 NSScreen *screen = [w screen];
7502 #if defined (NS_IMPL_COCOA) && \
7503 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7504 /* Hide ghost menu bar on secondary monitor? */
7505 if (! onFirstScreen)
7506 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7508 /* Hide dock and menubar if we are on the primary screen. */
7511 #ifdef NS_IMPL_COCOA
7512 NSApplicationPresentationOptions options
7513 = NSApplicationPresentationAutoHideDock
7514 | NSApplicationPresentationAutoHideMenuBar;
7516 [NSApp setPresentationOptions: options];
7518 [NSMenu setMenuBarVisible:NO];
7522 fw = [[EmacsFSWindow alloc]
7523 initWithContentRect:[w contentRectForFrameRect:wr]
7524 styleMask:NSWindowStyleMaskBorderless
7525 backing:NSBackingStoreBuffered
7529 [fw setContentView:[w contentView]];
7530 [fw setTitle:[w title]];
7531 [fw setDelegate:self];
7532 [fw setAcceptsMouseMovedEvents: YES];
7533 #if !defined (NS_IMPL_COCOA) || \
7534 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7535 [fw useOptimizedDrawing: YES];
7537 [fw setBackgroundColor: col];
7538 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7541 f->border_width = 0;
7545 [self windowWillEnterFullScreen];
7546 [fw makeKeyAndOrderFront:NSApp];
7547 [fw makeFirstResponder:self];
7549 r = [fw frameRectForContentRect:[screen frame]];
7550 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7551 [self windowDidEnterFullScreen];
7562 #ifdef NS_IMPL_COCOA
7563 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7565 [NSMenu setMenuBarVisible:YES];
7569 [w setContentView:[fw contentView]];
7570 [w setBackgroundColor: col];
7571 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7574 f->border_width = bwidth;
7576 // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7578 [self windowWillExitFullScreen];
7579 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7581 [w makeKeyAndOrderFront:NSApp];
7582 [self windowDidExitFullScreen];
7583 [self updateFrameSize:YES];
7589 NSTRACE ("[EmacsView handleFS]");
7591 if (fs_state != emacsframe->want_fullscreen)
7593 if (fs_state == FULLSCREEN_BOTH)
7595 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7596 [self toggleFullScreen:self];
7599 switch (emacsframe->want_fullscreen)
7601 case FULLSCREEN_BOTH:
7602 NSTRACE_MSG ("FULLSCREEN_BOTH");
7603 [self toggleFullScreen:self];
7605 case FULLSCREEN_WIDTH:
7606 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7607 next_maximized = FULLSCREEN_WIDTH;
7608 if (fs_state != FULLSCREEN_BOTH)
7609 [[self window] performZoom:self];
7611 case FULLSCREEN_HEIGHT:
7612 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7613 next_maximized = FULLSCREEN_HEIGHT;
7614 if (fs_state != FULLSCREEN_BOTH)
7615 [[self window] performZoom:self];
7617 case FULLSCREEN_MAXIMIZED:
7618 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7619 next_maximized = FULLSCREEN_MAXIMIZED;
7620 if (fs_state != FULLSCREEN_BOTH)
7621 [[self window] performZoom:self];
7623 case FULLSCREEN_NONE:
7624 NSTRACE_MSG ("FULLSCREEN_NONE");
7625 if (fs_state != FULLSCREEN_BOTH)
7627 next_maximized = FULLSCREEN_NONE;
7628 [[self window] performZoom:self];
7633 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7638 - (void) setFSValue: (int)value
7640 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7641 NSTRACE_ARG_FSTYPE(value));
7643 Lisp_Object lval = Qnil;
7646 case FULLSCREEN_BOTH:
7649 case FULLSCREEN_WIDTH:
7652 case FULLSCREEN_HEIGHT:
7655 case FULLSCREEN_MAXIMIZED:
7659 store_frame_param (emacsframe, Qfullscreen, lval);
7663 - (void)mouseEntered: (NSEvent *)theEvent
7665 NSTRACE ("[EmacsView mouseEntered:]");
7667 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7668 = EV_TIMESTAMP (theEvent);
7672 - (void)mouseExited: (NSEvent *)theEvent
7674 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7676 NSTRACE ("[EmacsView mouseExited:]");
7681 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7682 = EV_TIMESTAMP (theEvent);
7684 if (emacsframe == hlinfo->mouse_face_mouse_frame)
7686 clear_mouse_face (hlinfo);
7687 hlinfo->mouse_face_mouse_frame = 0;
7692 - (instancetype)menuDown: sender
7694 NSTRACE ("[EmacsView menuDown:]");
7695 if (context_menu_value == -1)
7696 context_menu_value = [sender tag];
7699 NSInteger tag = [sender tag];
7700 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7701 emacsframe->menu_bar_vector,
7705 ns_send_appdefined (-1);
7710 - (EmacsToolbar *)toolbar
7716 /* this gets called on toolbar button click */
7717 - (instancetype)toolbarClicked: (id)item
7720 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7722 NSTRACE ("[EmacsView toolbarClicked:]");
7727 /* send first event (for some reason two needed) */
7728 theEvent = [[self window] currentEvent];
7729 emacs_event->kind = TOOL_BAR_EVENT;
7730 XSETFRAME (emacs_event->arg, emacsframe);
7731 EV_TRAILER (theEvent);
7733 emacs_event->kind = TOOL_BAR_EVENT;
7734 /* XSETINT (emacs_event->code, 0); */
7735 emacs_event->arg = AREF (emacsframe->tool_bar_items,
7736 idx + TOOL_BAR_ITEM_KEY);
7737 emacs_event->modifiers = EV_MODIFIERS (theEvent);
7738 EV_TRAILER (theEvent);
7743 - (instancetype)toggleToolbar: (id)sender
7745 NSTRACE ("[EmacsView toggleToolbar:]");
7750 emacs_event->kind = NS_NONKEY_EVENT;
7751 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7752 EV_TRAILER ((id)nil);
7757 - (void)drawRect: (NSRect)rect
7759 int x = NSMinX (rect), y = NSMinY (rect);
7760 int width = NSWidth (rect), height = NSHeight (rect);
7762 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7763 NSTRACE_ARG_RECT(rect));
7765 if (!emacsframe || !emacsframe->output_data.ns)
7768 ns_clear_frame_area (emacsframe, x, y, width, height);
7770 expose_frame (emacsframe, x, y, width, height);
7774 drawRect: may be called (at least in Mac OS X 10.5) for invisible
7775 views as well for some reason. Thus, do not infer visibility
7778 emacsframe->async_visible = 1;
7779 emacsframe->async_iconified = 0;
7784 /* NSDraggingDestination protocol methods. Actually this is not really a
7785 protocol, but a category of Object. O well... */
7787 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7789 NSTRACE ("[EmacsView draggingEntered:]");
7790 return NSDragOperationGeneric;
7794 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7800 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7805 NSEvent *theEvent = [[self window] currentEvent];
7807 NSDragOperation op = [sender draggingSourceOperationMask];
7810 NSTRACE ("[EmacsView performDragOperation:]");
7815 position = [self convertPoint: [sender draggingLocation] fromView: nil];
7816 x = lrint (position.x); y = lrint (position.y);
7818 pb = [sender draggingPasteboard];
7819 type = [pb availableTypeFromArray: ns_drag_types];
7821 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7822 // URL drags contain all operations (0xf), don't allow all to be set.
7825 if (op & NSDragOperationLink)
7826 modifiers |= NSEventModifierFlagControl;
7827 if (op & NSDragOperationCopy)
7828 modifiers |= NSEventModifierFlagOption;
7829 if (op & NSDragOperationGeneric)
7830 modifiers |= NSEventModifierFlagCommand;
7833 modifiers = EV_MODIFIERS2 (modifiers);
7838 else if ([type isEqualToString: NSFilenamesPboardType])
7841 NSEnumerator *fenum;
7844 if (!(files = [pb propertyListForType: type]))
7847 fenum = [files objectEnumerator];
7848 while ( (file = [fenum nextObject]) )
7850 emacs_event->kind = DRAG_N_DROP_EVENT;
7851 XSETINT (emacs_event->x, x);
7852 XSETINT (emacs_event->y, y);
7853 ns_input_file = append2 (ns_input_file,
7854 build_string ([file UTF8String]));
7855 emacs_event->modifiers = modifiers;
7856 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
7857 EV_TRAILER (theEvent);
7861 else if ([type isEqualToString: NSURLPboardType])
7863 NSURL *url = [NSURL URLFromPasteboard: pb];
7864 if (url == nil) return NO;
7866 emacs_event->kind = DRAG_N_DROP_EVENT;
7867 XSETINT (emacs_event->x, x);
7868 XSETINT (emacs_event->y, y);
7869 emacs_event->modifiers = modifiers;
7870 emacs_event->arg = list2 (Qurl,
7871 build_string ([[url absoluteString]
7873 EV_TRAILER (theEvent);
7875 if ([url isFileURL] != NO)
7877 NSString *file = [url path];
7878 ns_input_file = append2 (ns_input_file,
7879 build_string ([file UTF8String]));
7883 else if ([type isEqualToString: NSStringPboardType]
7884 || [type isEqualToString: NSTabularTextPboardType])
7888 if (! (data = [pb stringForType: type]))
7891 emacs_event->kind = DRAG_N_DROP_EVENT;
7892 XSETINT (emacs_event->x, x);
7893 XSETINT (emacs_event->y, y);
7894 emacs_event->modifiers = modifiers;
7895 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
7896 EV_TRAILER (theEvent);
7901 fprintf (stderr, "Invalid data type in dragging pasteboard");
7907 - (id) validRequestorForSendType: (NSString *)typeSent
7908 returnType: (NSString *)typeReturned
7910 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7911 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7912 && typeReturned == nil)
7914 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7918 return [super validRequestorForSendType: typeSent
7919 returnType: typeReturned];
7923 /* The next two methods are part of NSServicesRequests informal protocol,
7924 supposedly called when a services menu item is chosen from this app.
7925 But this should not happen because we override the services menu with our
7926 own entries which call ns-perform-service.
7927 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7928 So let's at least stub them out until further investigation can be done. */
7930 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7932 /* we could call ns_string_from_pasteboard(pboard) here but then it should
7933 be written into the buffer in place of the existing selection..
7934 ordinary service calls go through functions defined in ns-win.el */
7938 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7940 NSArray *typesDeclared;
7943 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7945 /* We only support NSStringPboardType */
7946 if ([types containsObject:NSStringPboardType] == NO) {
7950 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7951 if (CONSP (val) && SYMBOLP (XCAR (val)))
7954 if (CONSP (val) && NILP (XCDR (val)))
7957 if (! STRINGP (val))
7960 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7961 [pb declareTypes:typesDeclared owner:nil];
7962 ns_string_to_pasteboard (pb, val);
7967 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7968 (gives a miniaturized version of the window); currently we use the latter for
7969 frames whose active buffer doesn't correspond to any file
7970 (e.g., '*scratch*') */
7971 - (instancetype)setMiniwindowImage: (BOOL) setMini
7973 id image = [[self window] miniwindowImage];
7974 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7976 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7977 about "AppleDockIconEnabled" notwithstanding, however the set message
7978 below has its effect nonetheless. */
7979 if (image != emacsframe->output_data.ns->miniimage)
7981 if (image && [image isKindOfClass: [EmacsImage class]])
7983 [[self window] setMiniwindowImage:
7984 setMini ? emacsframe->output_data.ns->miniimage : nil];
7991 - (void) setRows: (int) r andColumns: (int) c
7993 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7998 - (int) fullscreenState
8003 @end /* EmacsView */
8007 /* ==========================================================================
8009 EmacsWindow implementation
8011 ========================================================================== */
8013 @implementation EmacsWindow
8015 #ifdef NS_IMPL_COCOA
8016 - (id)accessibilityAttributeValue:(NSString *)attribute
8018 Lisp_Object str = Qnil;
8019 struct frame *f = SELECTED_FRAME ();
8020 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8022 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8024 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8025 return NSAccessibilityTextFieldRole;
8027 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8028 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8030 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8032 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8034 if (! NILP (BVAR (curbuf, mark_active)))
8035 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8039 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8040 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8041 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8043 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8044 str = make_uninit_multibyte_string (range, byte_range);
8046 str = make_uninit_string (range);
8047 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8048 Is this a problem? */
8049 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8056 if (CONSP (str) && SYMBOLP (XCAR (str)))
8059 if (CONSP (str) && NILP (XCDR (str)))
8064 const char *utfStr = SSDATA (str);
8065 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8070 return [super accessibilityAttributeValue:attribute];
8072 #endif /* NS_IMPL_COCOA */
8074 /* Constrain size and placement of a frame.
8076 By returning the original "frameRect", the frame is not
8077 constrained. This can lead to unwanted situations where, for
8078 example, the menu bar covers the frame.
8080 The default implementation (accessed using "super") constrains the
8081 frame to the visible area of SCREEN, minus the menu bar (if
8082 present) and the Dock. Note that default implementation also calls
8083 windowWillResize, with the frame it thinks should have. (This can
8084 make the frame exit maximized mode.)
8086 Note that this should work in situations where multiple monitors
8087 are present. Common configurations are side-by-side monitors and a
8088 monitor on top of another (e.g. when a laptop is placed under a
8090 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8092 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8093 NSTRACE_ARG_RECT (frameRect));
8095 #ifdef NS_IMPL_COCOA
8096 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
8097 // If separate spaces is on, it is like each screen is independent. There is
8098 // no spanning of frames across screens.
8099 if ([NSScreen screensHaveSeparateSpaces])
8101 NSTRACE_MSG ("Screens have separate spaces");
8102 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8103 NSTRACE_RETURN_RECT (frameRect);
8107 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 */
8108 // Check that the proposed frameRect is visible in at least one
8109 // screen. If it is not, ask the system to reposition it (only
8110 // for non-child windows).
8112 if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8114 NSArray *screens = [NSScreen screens];
8115 NSUInteger nr_screens = [screens count];
8118 BOOL frame_on_screen = NO;
8120 for (i = 0; i < nr_screens; ++i)
8122 NSScreen *s = [screens objectAtIndex: i];
8123 NSRect scrRect = [s frame];
8125 if (NSIntersectsRect(frameRect, scrRect))
8127 frame_on_screen = YES;
8132 if (!frame_on_screen)
8134 NSTRACE_MSG ("Frame outside screens; constraining");
8135 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8136 NSTRACE_RETURN_RECT (frameRect);
8142 return constrain_frame_rect(frameRect,
8143 [(EmacsView *)[self delegate] isFullscreen]);
8147 - (void)performZoom:(id)sender
8149 NSTRACE ("[EmacsWindow performZoom:]");
8151 return [super performZoom:sender];
8154 - (void)zoom:(id)sender
8156 NSTRACE ("[EmacsWindow zoom:]");
8158 ns_update_auto_hide_menu_bar();
8160 // Below are three zoom implementations. In the final commit, the
8161 // idea is that the last should be included.
8164 // Native zoom done using the standard zoom animation. Size of the
8165 // resulting frame reduced to accommodate the Dock and, if present,
8167 [super zoom:sender];
8170 // Native zoom done using the standard zoom animation, plus an
8171 // explicit resize to cover the full screen, except the menu-bar and
8172 // dock, if present.
8173 [super zoom:sender];
8175 // After the native zoom, resize the resulting frame to fill the
8176 // entire screen, except the menu-bar.
8178 // This works for all practical purposes. (The only minor oddity is
8179 // when transiting from full-height frame to a maximized, the
8180 // animation reduces the height of the frame slightly (to the 4
8181 // pixels needed to accommodate the Doc) before it snaps back into
8182 // full height. The user would need a very trained eye to spot
8184 NSScreen * screen = [self screen];
8187 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8189 NSTRACE_FSTYPE ("fullscreenState", fs_state);
8191 NSRect sr = [screen frame];
8192 struct EmacsMargins margins
8193 = ns_screen_margins_ignoring_hidden_dock(screen);
8195 NSRect wr = [self frame];
8196 NSTRACE_RECT ("Rect after zoom", wr);
8200 if (fs_state == FULLSCREEN_MAXIMIZED
8201 || fs_state == FULLSCREEN_HEIGHT)
8203 newWr.origin.y = sr.origin.y + margins.bottom;
8204 newWr.size.height = sr.size.height - margins.top - margins.bottom;
8207 if (fs_state == FULLSCREEN_MAXIMIZED
8208 || fs_state == FULLSCREEN_WIDTH)
8210 newWr.origin.x = sr.origin.x + margins.left;
8211 newWr.size.width = sr.size.width - margins.right - margins.left;
8214 if (newWr.size.width != wr.size.width
8215 || newWr.size.height != wr.size.height
8216 || newWr.origin.x != wr.origin.x
8217 || newWr.origin.y != wr.origin.y)
8219 NSTRACE_MSG ("New frame different");
8220 [self setFrame: newWr display: NO];
8224 // Non-native zoom which is done instantaneously. The resulting
8225 // frame covers the entire screen, except the menu-bar and dock, if
8227 NSScreen * screen = [self screen];
8230 NSRect sr = [screen frame];
8231 struct EmacsMargins margins
8232 = ns_screen_margins_ignoring_hidden_dock(screen);
8234 sr.size.height -= (margins.top + margins.bottom);
8235 sr.size.width -= (margins.left + margins.right);
8236 sr.origin.x += margins.left;
8237 sr.origin.y += margins.bottom;
8239 sr = [[self delegate] windowWillUseStandardFrame:self
8241 [self setFrame: sr display: NO];
8246 - (void)setFrame:(NSRect)windowFrame
8247 display:(BOOL)displayViews
8249 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8250 NSTRACE_ARG_RECT (windowFrame), displayViews);
8252 [super setFrame:windowFrame display:displayViews];
8255 - (void)setFrame:(NSRect)windowFrame
8256 display:(BOOL)displayViews
8257 animate:(BOOL)performAnimation
8259 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8260 " display:%d performAnimation:%d]",
8261 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8263 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8266 - (void)setFrameTopLeftPoint:(NSPoint)point
8268 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8269 NSTRACE_ARG_POINT (point));
8271 [super setFrameTopLeftPoint:point];
8274 - (BOOL)canBecomeKeyWindow
8276 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8278 @end /* EmacsWindow */
8281 @implementation EmacsFSWindow
8283 - (BOOL)canBecomeKeyWindow
8288 - (BOOL)canBecomeMainWindow
8295 /* ==========================================================================
8297 EmacsScroller implementation
8299 ========================================================================== */
8302 @implementation EmacsScroller
8304 /* for repeat button push */
8305 #define SCROLL_BAR_FIRST_DELAY 0.5
8306 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8308 + (CGFloat) scrollerWidth
8310 /* TODO: if we want to allow variable widths, this is the place to do it,
8311 however neither GNUstep nor Cocoa support it very well */
8313 #if !defined (NS_IMPL_COCOA) || \
8314 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
8315 r = [NSScroller scrollerWidth];
8317 r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8318 scrollerStyle: NSScrollerStyleLegacy];
8323 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8325 NSTRACE ("[EmacsScroller initFrame: window:]");
8327 if (r.size.width > r.size.height)
8332 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8333 [self setContinuous: YES];
8334 [self setEnabled: YES];
8336 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8337 locked against the top and bottom edges, and right edge on macOS, where
8338 scrollers are on right. */
8339 #ifdef NS_IMPL_GNUSTEP
8340 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8342 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8345 window = XWINDOW (nwin);
8348 pixel_length = NSWidth (r);
8350 pixel_length = NSHeight (r);
8351 if (pixel_length == 0) pixel_length = 1;
8352 min_portion = 20 / pixel_length;
8354 frame = XFRAME (window->frame);
8355 if (FRAME_LIVE_P (frame))
8358 EmacsView *view = FRAME_NS_VIEW (frame);
8359 NSView *sview = [[view window] contentView];
8360 NSArray *subs = [sview subviews];
8362 /* disable optimization stopping redraw of other scrollbars */
8363 view->scrollbarsNeedingUpdate = 0;
8364 for (i =[subs count]-1; i >= 0; i--)
8365 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8366 view->scrollbarsNeedingUpdate++;
8367 [sview addSubview: self];
8370 /* [self setFrame: r]; */
8376 - (void)setFrame: (NSRect)newRect
8378 NSTRACE ("[EmacsScroller setFrame:]");
8380 /* block_input (); */
8382 pixel_length = NSWidth (newRect);
8384 pixel_length = NSHeight (newRect);
8385 if (pixel_length == 0) pixel_length = 1;
8386 min_portion = 20 / pixel_length;
8387 [super setFrame: newRect];
8388 /* unblock_input (); */
8394 NSTRACE ("[EmacsScroller dealloc]");
8398 wset_horizontal_scroll_bar (window, Qnil);
8400 wset_vertical_scroll_bar (window, Qnil);
8407 - (instancetype)condemn
8409 NSTRACE ("[EmacsScroller condemn]");
8415 - (instancetype)reprieve
8417 NSTRACE ("[EmacsScroller reprieve]");
8425 NSTRACE ("[EmacsScroller judge]");
8426 bool ret = condemned;
8431 /* ensure other scrollbar updates after deletion */
8432 view = (EmacsView *)FRAME_NS_VIEW (frame);
8434 view->scrollbarsNeedingUpdate++;
8438 wset_horizontal_scroll_bar (window, Qnil);
8440 wset_vertical_scroll_bar (window, Qnil);
8443 [self removeFromSuperview];
8451 - (void)resetCursorRects
8453 NSRect visible = [self visibleRect];
8454 NSTRACE ("[EmacsScroller resetCursorRects]");
8456 if (!NSIsEmptyRect (visible))
8457 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8458 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8462 - (int) checkSamePosition: (int) position portion: (int) portion
8465 return em_position ==position && em_portion ==portion && em_whole ==whole
8466 && portion != whole; /* needed for resize empty buf */
8470 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8472 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8474 em_position = position;
8475 em_portion = portion;
8478 if (portion >= whole)
8480 #ifdef NS_IMPL_COCOA
8481 [self setKnobProportion: 1.0];
8482 [self setDoubleValue: 1.0];
8484 [self setFloatValue: 0.0 knobProportion: 1.0];
8491 portion = max ((float)whole*min_portion/pixel_length, portion);
8492 pos = (float)position / (whole - portion);
8493 por = (CGFloat)portion/whole;
8494 #ifdef NS_IMPL_COCOA
8495 [self setKnobProportion: por];
8496 [self setDoubleValue: pos];
8498 [self setFloatValue: pos knobProportion: por];
8505 /* set up emacs_event */
8506 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8510 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8515 emacs_event->part = last_hit_part;
8516 emacs_event->code = 0;
8517 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8518 XSETWINDOW (win, window);
8519 emacs_event->frame_or_window = win;
8520 emacs_event->timestamp = EV_TIMESTAMP (e);
8521 emacs_event->arg = Qnil;
8525 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8526 XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8527 XSETINT (emacs_event->y, em_whole);
8531 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8532 XSETINT (emacs_event->x, loc);
8533 XSETINT (emacs_event->y, pixel_length-20);
8538 n_emacs_events_pending++;
8539 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8542 hold_event (emacs_event);
8543 EVENT_INIT (*emacs_event);
8544 ns_send_appdefined (-1);
8548 /* called manually thru timer to implement repeated button action w/hold-down */
8549 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8551 NSEvent *e = [[self window] currentEvent];
8552 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8553 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8555 NSTRACE ("[EmacsScroller repeatScroll:]");
8557 /* clear timer if need be */
8558 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8560 [scroll_repeat_entry invalidate];
8561 [scroll_repeat_entry release];
8562 scroll_repeat_entry = nil;
8568 = [[NSTimer scheduledTimerWithTimeInterval:
8569 SCROLL_BAR_CONTINUOUS_DELAY
8571 selector: @selector (repeatScroll:)
8577 [self sendScrollEventAtLoc: 0 fromEvent: e];
8582 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8583 mouseDragged events without going into a modal loop. */
8584 - (void)mouseDown: (NSEvent *)e
8587 /* hitPart is only updated AFTER event is passed on */
8588 NSScrollerPart part = [self testPart: [e locationInWindow]];
8589 CGFloat loc, kloc, pos UNINIT;
8592 NSTRACE ("[EmacsScroller mouseDown:]");
8596 case NSScrollerDecrementPage:
8597 last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8598 case NSScrollerIncrementPage:
8599 last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8600 case NSScrollerDecrementLine:
8601 last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8602 case NSScrollerIncrementLine:
8603 last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8604 case NSScrollerKnob:
8605 last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8606 case NSScrollerKnobSlot: /* GNUstep-only */
8607 last_hit_part = scroll_bar_move_ratio; break;
8608 default: /* NSScrollerNoPart? */
8609 fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8614 if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8616 /* handle, or on GNUstep possibly slot */
8617 NSEvent *fake_event;
8620 /* compute float loc in slot and mouse offset on knob */
8621 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8625 length = NSWidth (sr);
8626 loc = ([e locationInWindow].x - NSMinX (sr));
8630 length = NSHeight (sr);
8631 loc = length - ([e locationInWindow].y - NSMinY (sr));
8639 else if (loc >= length)
8649 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8652 kloc = ([e locationInWindow].x - NSMinX (kr));
8654 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8656 last_mouse_offset = kloc;
8658 if (part != NSScrollerKnob)
8659 /* this is a slot click on GNUstep: go straight there */
8662 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8663 fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8664 location: [e locationInWindow]
8665 modifierFlags: [e modifierFlags]
8666 timestamp: [e timestamp]
8667 windowNumber: [e windowNumber]
8669 eventNumber: [e eventNumber]
8670 clickCount: [e clickCount]
8671 pressure: [e pressure]];
8672 [super mouseUp: fake_event];
8676 pos = 0; /* ignored */
8678 /* set a timer to repeat, as we can't let superclass do this modally */
8680 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8682 selector: @selector (repeatScroll:)
8688 if (part != NSScrollerKnob)
8689 [self sendScrollEventAtLoc: pos fromEvent: e];
8693 /* Called as we manually track scroller drags, rather than superclass. */
8694 - (void)mouseDragged: (NSEvent *)e
8700 NSTRACE ("[EmacsScroller mouseDragged:]");
8702 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8707 length = NSWidth (sr);
8708 loc = ([e locationInWindow].x - NSMinX (sr));
8712 length = NSHeight (sr);
8713 loc = length - ([e locationInWindow].y - NSMinY (sr));
8720 else if (loc >= length + last_mouse_offset)
8722 loc = length + last_mouse_offset;
8725 pos = (loc - last_mouse_offset);
8726 [self sendScrollEventAtLoc: pos fromEvent: e];
8730 - (void)mouseUp: (NSEvent *)e
8732 NSTRACE ("[EmacsScroller mouseUp:]");
8734 if (scroll_repeat_entry)
8736 [scroll_repeat_entry invalidate];
8737 [scroll_repeat_entry release];
8738 scroll_repeat_entry = nil;
8740 last_hit_part = scroll_bar_above_handle;
8744 /* treat scrollwheel events in the bar as though they were in the main window */
8745 - (void) scrollWheel: (NSEvent *)theEvent
8747 NSTRACE ("[EmacsScroller scrollWheel:]");
8749 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8750 [view mouseDown: theEvent];
8753 @end /* EmacsScroller */
8756 #ifdef NS_IMPL_GNUSTEP
8757 /* Dummy class to get rid of startup warnings. */
8758 @implementation EmacsDocument
8764 /* ==========================================================================
8766 Font-related functions; these used to be in nsfaces.m
8768 ========================================================================== */
8772 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8774 struct font *font = XFONT_OBJECT (font_object);
8775 EmacsView *view = FRAME_NS_VIEW (f);
8776 int font_ascent, font_descent;
8779 fontset = fontset_from_font (font_object);
8780 FRAME_FONTSET (f) = fontset;
8782 if (FRAME_FONT (f) == font)
8783 /* This font is already set in frame F. There's nothing more to
8787 FRAME_FONT (f) = font;
8789 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8790 FRAME_COLUMN_WIDTH (f) = font->average_width;
8791 get_font_ascent_descent (font, &font_ascent, &font_descent);
8792 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8794 /* Compute the scroll bar width in character columns. */
8795 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8797 int wid = FRAME_COLUMN_WIDTH (f);
8798 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8799 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8803 int wid = FRAME_COLUMN_WIDTH (f);
8804 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8807 /* Compute the scroll bar height in character lines. */
8808 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8810 int height = FRAME_LINE_HEIGHT (f);
8811 FRAME_CONFIG_SCROLL_BAR_LINES (f)
8812 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8816 int height = FRAME_LINE_HEIGHT (f);
8817 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8820 /* Now make the frame display the given font. */
8821 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8822 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8823 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8830 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8831 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8835 ns_xlfd_to_fontname (const char *xlfd)
8836 /* --------------------------------------------------------------------------
8837 Convert an X font name (XLFD) to an NS font name.
8838 Only family is used.
8839 The string returned is temporarily allocated.
8840 -------------------------------------------------------------------------- */
8842 char *name = xmalloc (180);
8846 if (!strncmp (xlfd, "--", 2))
8847 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8849 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8851 /* stopgap for malformed XLFD input */
8852 if (strlen (name) == 0)
8853 strcpy (name, "Monaco");
8855 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8856 also uppercase after '-' or ' ' */
8857 name[0] = c_toupper (name[0]);
8858 for (len =strlen (name), i =0; i<len; i++)
8864 name[i+1] = c_toupper (name[i+1]);
8866 else if (name[i] == '_')
8870 name[i+1] = c_toupper (name[i+1]);
8873 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
8874 ret = [[NSString stringWithUTF8String: name] UTF8String];
8881 syms_of_nsterm (void)
8883 NSTRACE ("syms_of_nsterm");
8885 ns_antialias_threshold = 10.0;
8887 /* from 23+ we need to tell emacs what modifiers there are.. */
8888 DEFSYM (Qmodifier_value, "modifier-value");
8889 DEFSYM (Qalt, "alt");
8890 DEFSYM (Qhyper, "hyper");
8891 DEFSYM (Qmeta, "meta");
8892 DEFSYM (Qsuper, "super");
8893 DEFSYM (Qcontrol, "control");
8894 DEFSYM (QUTF8_STRING, "UTF8_STRING");
8896 DEFSYM (Qfile, "file");
8897 DEFSYM (Qurl, "url");
8899 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8900 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8901 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8902 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8903 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8905 DEFVAR_LISP ("ns-input-file", ns_input_file,
8906 "The file specified in the last NS event.");
8907 ns_input_file =Qnil;
8909 DEFVAR_LISP ("ns-working-text", ns_working_text,
8910 "String for visualizing working composition sequence.");
8911 ns_working_text =Qnil;
8913 DEFVAR_LISP ("ns-input-font", ns_input_font,
8914 "The font specified in the last NS event.");
8915 ns_input_font =Qnil;
8917 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8918 "The fontsize specified in the last NS event.");
8919 ns_input_fontsize =Qnil;
8921 DEFVAR_LISP ("ns-input-line", ns_input_line,
8922 "The line specified in the last NS event.");
8923 ns_input_line =Qnil;
8925 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8926 "The service name specified in the last NS event.");
8927 ns_input_spi_name =Qnil;
8929 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8930 "The service argument specified in the last NS event.");
8931 ns_input_spi_arg =Qnil;
8933 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8934 "This variable describes the behavior of the alternate or option key.\n\
8935 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8937 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8938 at all, allowing it to be used at a lower level for accented character entry.");
8939 ns_alternate_modifier = Qmeta;
8941 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8942 "This variable describes the behavior of the right alternate or option key.\n\
8943 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8945 Set to left means be the same key as `ns-alternate-modifier'.\n\
8946 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8947 at all, allowing it to be used at a lower level for accented character entry.");
8948 ns_right_alternate_modifier = Qleft;
8950 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8951 "This variable describes the behavior of the command key.\n\
8952 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8954 ns_command_modifier = Qsuper;
8956 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8957 "This variable describes the behavior of the right command key.\n\
8958 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8960 Set to left means be the same key as `ns-command-modifier'.\n\
8961 Set to none means that the command / option key is not interpreted by Emacs\n\
8962 at all, allowing it to be used at a lower level for accented character entry.");
8963 ns_right_command_modifier = Qleft;
8965 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8966 "This variable describes the behavior of the control key.\n\
8967 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8969 ns_control_modifier = Qcontrol;
8971 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8972 "This variable describes the behavior of the right control key.\n\
8973 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8975 Set to left means be the same key as `ns-control-modifier'.\n\
8976 Set to none means that the control / option key is not interpreted by Emacs\n\
8977 at all, allowing it to be used at a lower level for accented character entry.");
8978 ns_right_control_modifier = Qleft;
8980 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8981 "This variable describes the behavior of the function key (on laptops).\n\
8982 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8984 Set to none means that the function key is not interpreted by Emacs at all,\n\
8985 allowing it to be used at a lower level for accented character entry.");
8986 ns_function_modifier = Qnone;
8988 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8989 "Non-nil (the default) means to render text antialiased.");
8990 ns_antialias_text = Qt;
8992 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8993 "Whether to confirm application quit using dialog.");
8994 ns_confirm_quit = Qnil;
8996 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8997 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8998 Only works on Mac OS X 10.6 or later. */);
8999 ns_auto_hide_menu_bar = Qnil;
9001 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9002 doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9003 Nil means use fullscreen the old (< 10.7) way. The old way works better with
9004 multiple monitors, but lacks tool bar. This variable is ignored on
9005 Mac OS X < 10.7. Default is t for 10.7 and later, nil otherwise. */);
9006 #ifdef HAVE_NATIVE_FS
9007 ns_use_native_fullscreen = YES;
9009 ns_use_native_fullscreen = NO;
9011 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9013 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9014 doc: /*Non-nil means use animation on non-native fullscreen.
9015 For native fullscreen, this does nothing.
9016 Default is nil. */);
9017 ns_use_fullscreen_animation = NO;
9019 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9020 doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9021 Note that this does not apply to images.
9022 This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
9023 ns_use_srgb_colorspace = YES;
9025 /* TODO: move to common code */
9026 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9027 doc: /* Which toolkit scroll bars Emacs uses, if any.
9028 A value of nil means Emacs doesn't use toolkit scroll bars.
9029 With the X Window system, the value is a symbol describing the
9030 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
9031 With MS Windows or Nextstep, the value is t. */);
9032 Vx_toolkit_scroll_bars = Qt;
9034 DEFVAR_BOOL ("x-use-underline-position-properties",
9035 x_use_underline_position_properties,
9036 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9037 A value of nil means ignore them. If you encounter fonts with bogus
9038 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9039 to 4.1, set this to nil. */);
9040 x_use_underline_position_properties = 0;
9042 DEFVAR_BOOL ("x-underline-at-descent-line",
9043 x_underline_at_descent_line,
9044 doc: /* Non-nil means to draw the underline at the same place as the descent line.
9045 A value of nil means to draw the underline according to the value of the
9046 variable `x-use-underline-position-properties', which is usually at the
9047 baseline level. The default value is nil. */);
9048 x_underline_at_descent_line = 0;
9050 /* Tell Emacs about this window system. */
9051 Fprovide (Qns, Qnil);
9053 DEFSYM (Qcocoa, "cocoa");
9054 DEFSYM (Qgnustep, "gnustep");
9056 #ifdef NS_IMPL_COCOA
9057 Fprovide (Qcocoa, Qnil);
9060 Fprovide (Qgnustep, Qnil);