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)
1467 /* --------------------------------------------------------------------------
1468 Bring window to foreground and make it active
1469 -------------------------------------------------------------------------- */
1473 check_window_system (f);
1474 view = FRAME_NS_VIEW (f);
1476 if (FRAME_VISIBLE_P (f))
1477 [[view window] makeKeyAndOrderFront: NSApp];
1483 ns_lower_frame (struct frame *f)
1484 /* --------------------------------------------------------------------------
1486 -------------------------------------------------------------------------- */
1490 check_window_system (f);
1491 view = FRAME_NS_VIEW (f);
1493 [[view window] orderBack: NSApp];
1499 ns_frame_raise_lower (struct frame *f, bool raise)
1500 /* --------------------------------------------------------------------------
1502 -------------------------------------------------------------------------- */
1504 NSTRACE ("ns_frame_raise_lower");
1514 ns_frame_rehighlight (struct frame *frame)
1515 /* --------------------------------------------------------------------------
1516 External (hook): called on things like window switching within frame
1517 -------------------------------------------------------------------------- */
1519 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1520 struct frame *old_highlight = dpyinfo->x_highlight_frame;
1522 NSTRACE ("ns_frame_rehighlight");
1523 if (dpyinfo->x_focus_frame)
1525 dpyinfo->x_highlight_frame
1526 = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1527 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1528 : dpyinfo->x_focus_frame);
1529 if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1531 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1532 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1536 dpyinfo->x_highlight_frame = 0;
1538 if (dpyinfo->x_highlight_frame &&
1539 dpyinfo->x_highlight_frame != old_highlight)
1543 x_update_cursor (old_highlight, 1);
1544 x_set_frame_alpha (old_highlight);
1546 if (dpyinfo->x_highlight_frame)
1548 x_update_cursor (dpyinfo->x_highlight_frame, 1);
1549 x_set_frame_alpha (dpyinfo->x_highlight_frame);
1556 x_make_frame_visible (struct frame *f)
1557 /* --------------------------------------------------------------------------
1558 External: Show the window (X11 semantics)
1559 -------------------------------------------------------------------------- */
1561 NSTRACE ("x_make_frame_visible");
1562 /* XXX: at some points in past this was not needed, as the only place that
1563 called this (frame.c:Fraise_frame ()) also called raise_lower;
1564 if this ends up the case again, comment this out again. */
1565 if (!FRAME_VISIBLE_P (f))
1567 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1569 SET_FRAME_VISIBLE (f, 1);
1572 /* Making a new frame from a fullscreen frame will make the new frame
1573 fullscreen also. So skip handleFS as this will print an error. */
1574 if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1575 && [view isFullscreen])
1578 if (f->want_fullscreen != FULLSCREEN_NONE)
1589 x_make_frame_invisible (struct frame *f)
1590 /* --------------------------------------------------------------------------
1591 External: Hide the window (X11 semantics)
1592 -------------------------------------------------------------------------- */
1595 NSTRACE ("x_make_frame_invisible");
1596 check_window_system (f);
1597 view = FRAME_NS_VIEW (f);
1598 [[view window] orderOut: NSApp];
1599 SET_FRAME_VISIBLE (f, 0);
1600 SET_FRAME_ICONIFIED (f, 0);
1605 x_iconify_frame (struct frame *f)
1606 /* --------------------------------------------------------------------------
1607 External: Iconify window
1608 -------------------------------------------------------------------------- */
1611 struct ns_display_info *dpyinfo;
1613 NSTRACE ("x_iconify_frame");
1614 check_window_system (f);
1615 view = FRAME_NS_VIEW (f);
1616 dpyinfo = FRAME_DISPLAY_INFO (f);
1618 if (dpyinfo->x_highlight_frame == f)
1619 dpyinfo->x_highlight_frame = 0;
1621 if ([[view window] windowNumber] <= 0)
1623 /* the window is still deferred. Make it very small, bring it
1624 on screen and order it out. */
1625 NSRect s = { { 100, 100}, {0, 0} };
1627 t = [[view window] frame];
1628 [[view window] setFrame: s display: NO];
1629 [[view window] orderBack: NSApp];
1630 [[view window] orderOut: NSApp];
1631 [[view window] setFrame: t display: NO];
1634 /* Processing input while Emacs is being minimized can cause a
1635 crash, so block it for the duration. */
1637 [[view window] miniaturize: NSApp];
1641 /* Free X resources of frame F. */
1644 x_free_frame_resources (struct frame *f)
1647 struct ns_display_info *dpyinfo;
1648 Mouse_HLInfo *hlinfo;
1650 NSTRACE ("x_free_frame_resources");
1651 check_window_system (f);
1652 view = FRAME_NS_VIEW (f);
1653 dpyinfo = FRAME_DISPLAY_INFO (f);
1654 hlinfo = MOUSE_HL_INFO (f);
1656 [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1660 free_frame_menubar (f);
1661 free_frame_faces (f);
1663 if (f == dpyinfo->x_focus_frame)
1664 dpyinfo->x_focus_frame = 0;
1665 if (f == dpyinfo->x_highlight_frame)
1666 dpyinfo->x_highlight_frame = 0;
1667 if (f == hlinfo->mouse_face_mouse_frame)
1668 reset_mouse_highlight (hlinfo);
1670 if (f->output_data.ns->miniimage != nil)
1671 [f->output_data.ns->miniimage release];
1673 [[view window] close];
1676 xfree (f->output_data.ns);
1682 x_destroy_window (struct frame *f)
1683 /* --------------------------------------------------------------------------
1684 External: Delete the window
1685 -------------------------------------------------------------------------- */
1687 NSTRACE ("x_destroy_window");
1689 /* If this frame has a parent window, detach it as not doing so can
1690 cause a crash in GNUStep. */
1691 if (FRAME_PARENT_FRAME (f) != NULL)
1693 NSWindow *child = [FRAME_NS_VIEW (f) window];
1694 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1696 [parent removeChildWindow: child];
1699 check_window_system (f);
1700 x_free_frame_resources (f);
1706 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1707 /* --------------------------------------------------------------------------
1708 External: Position the window
1709 -------------------------------------------------------------------------- */
1711 NSView *view = FRAME_NS_VIEW (f);
1712 NSArray *screens = [NSScreen screens];
1713 NSScreen *fscreen = [screens objectAtIndex: 0];
1714 NSScreen *screen = [[view window] screen];
1716 NSTRACE ("x_set_offset");
1723 if (view != nil && screen && fscreen)
1725 f->left_pos = f->size_hint_flags & XNegative
1726 ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1728 /* We use visibleFrame here to take menu bar into account.
1729 Ideally we should also adjust left/top with visibleFrame.origin. */
1731 f->top_pos = f->size_hint_flags & YNegative
1732 ? ([screen visibleFrame].size.height + f->top_pos
1733 - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1734 - FRAME_TOOLBAR_HEIGHT (f))
1736 #ifdef NS_IMPL_GNUSTEP
1737 if (FRAME_PARENT_FRAME (f) == NULL)
1739 if (f->left_pos < 100)
1740 f->left_pos = 100; /* don't overlap menu */
1743 /* Constrain the setFrameTopLeftPoint so we don't move behind the
1745 NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1746 + NS_PARENT_WINDOW_LEFT_POS (f)),
1747 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1749 NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1750 [[view window] setFrameTopLeftPoint: pt];
1751 f->size_hint_flags &= ~(XNegative|YNegative);
1759 x_set_window_size (struct frame *f,
1760 bool change_gravity,
1764 /* --------------------------------------------------------------------------
1765 Adjust window pixel size based on given character grid size
1766 Impl is a bit more complex than other terms, need to do some
1768 -------------------------------------------------------------------------- */
1770 EmacsView *view = FRAME_NS_VIEW (f);
1771 NSWindow *window = [view window];
1772 NSRect wr = [window frame];
1773 int pixelwidth, pixelheight;
1774 int orig_height = wr.size.height;
1776 NSTRACE ("x_set_window_size");
1781 NSTRACE_RECT ("current", wr);
1782 NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1783 NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1789 pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1790 pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1794 pixelwidth = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, width);
1795 pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1798 wr.size.width = pixelwidth + f->border_width;
1799 wr.size.height = pixelheight;
1800 if (! [view isFullscreen])
1801 wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1802 + FRAME_TOOLBAR_HEIGHT (f);
1804 /* Do not try to constrain to this screen. We may have multiple
1805 screens, and want Emacs to span those. Constraining to screen
1806 prevents that, and that is not nice to the user. */
1807 if (f->output_data.ns->zooming)
1808 f->output_data.ns->zooming = 0;
1810 wr.origin.y += orig_height - wr.size.height;
1812 frame_size_history_add
1813 (f, Qx_set_window_size_1, width, height,
1814 list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1815 Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1816 make_number (f->border_width),
1817 make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1818 make_number (FRAME_TOOLBAR_HEIGHT (f))));
1820 [window setFrame: wr display: YES];
1822 [view updateFrameSize: NO];
1826 #ifdef NS_IMPL_COCOA
1828 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1829 /* --------------------------------------------------------------------------
1830 Set frame F's `undecorated' parameter. If non-nil, F's window-system
1831 window is drawn without decorations, title, minimize/maximize boxes
1832 and external borders. This usually means that the window cannot be
1833 dragged, resized, iconified, maximized or deleted with the mouse. If
1834 nil, draw the frame with all the elements listed above unless these
1835 have been suspended via window manager settings.
1837 GNUStep cannot change an existing window's style.
1838 -------------------------------------------------------------------------- */
1840 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1841 NSWindow *window = [view window];
1843 NSTRACE ("x_set_undecorated");
1845 if (!EQ (new_value, old_value))
1849 if (NILP (new_value))
1851 FRAME_UNDECORATED (f) = false;
1852 [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1853 ^ FRAME_UNDECORATED_FLAGS)];
1855 [view createToolbar: f];
1859 [window setToolbar: nil];
1860 /* Do I need to release the toolbar here? */
1862 FRAME_UNDECORATED (f) = true;
1863 [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1864 ^ FRAME_DECORATED_FLAGS)];
1867 /* At this point it seems we don't have an active NSResponder,
1868 so some key presses (TAB) are swallowed by the system. */
1869 [window makeFirstResponder: view];
1871 [view updateFrameSize: NO];
1875 #endif /* NS_IMPL_COCOA */
1878 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1879 /* --------------------------------------------------------------------------
1880 Set frame F's `parent-frame' parameter. If non-nil, make F a child
1881 frame of the frame specified by that parameter. Technically, this
1882 makes F's window-system window a child window of the parent frame's
1883 window-system window. If nil, make F's window-system window a
1884 top-level window--a child of its display's root window.
1886 A child frame's `left' and `top' parameters specify positions
1887 relative to the top-left corner of its parent frame's native
1888 rectangle. On macOS moving a parent frame moves all its child
1889 frames too, keeping their position relative to the parent
1890 unaltered. When a parent frame is iconified or made invisible, its
1891 child frames are made invisible. When a parent frame is deleted,
1892 its child frames are deleted too.
1894 Whether a child frame has a tool bar may be window-system or window
1895 manager dependent. It's advisable to disable it via the frame
1898 Some window managers may not honor this parameter.
1899 -------------------------------------------------------------------------- */
1901 struct frame *p = NULL;
1902 NSWindow *parent, *child;
1904 NSTRACE ("x_set_parent_frame");
1906 if (!NILP (new_value)
1907 && (!FRAMEP (new_value)
1908 || !FRAME_LIVE_P (p = XFRAME (new_value))
1911 store_frame_param (f, Qparent_frame, old_value);
1912 error ("Invalid specification of `parent-frame'");
1915 if (p != FRAME_PARENT_FRAME (f))
1917 parent = [FRAME_NS_VIEW (p) window];
1918 child = [FRAME_NS_VIEW (f) window];
1921 [parent addChildWindow: child
1922 ordered: NSWindowAbove];
1925 fset_parent_frame (f, new_value);
1930 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1931 /* Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1932 * that F's window-system window does not want to receive input focus
1933 * via mouse clicks or by moving the mouse into it.
1935 * If non-nil, this may have the unwanted side-effect that a user cannot
1936 * scroll a non-selected frame with the mouse.
1938 * Some window managers may not honor this parameter. */
1940 NSTRACE ("x_set_no_accept_focus");
1942 if (!EQ (new_value, old_value))
1943 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1947 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1948 /* Set frame F's `z-group' parameter. If `above', F's window-system
1949 window is displayed above all windows that do not have the `above'
1950 property set. If nil, F's window is shown below all windows that
1951 have the `above' property set and above all windows that have the
1952 `below' property set. If `below', F's window is displayed below
1953 all windows that do.
1955 Some window managers may not honor this parameter. */
1957 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1958 NSWindow *window = [view window];
1960 NSTRACE ("x_set_z_group");
1962 if (NILP (new_value))
1964 window.level = NSNormalWindowLevel;
1965 FRAME_Z_GROUP (f) = z_group_none;
1967 else if (EQ (new_value, Qabove))
1969 window.level = NSNormalWindowLevel + 1;
1970 FRAME_Z_GROUP (f) = z_group_above;
1972 else if (EQ (new_value, Qabove_suspended))
1974 /* Not sure what level this should be. */
1975 window.level = NSNormalWindowLevel + 1;
1976 FRAME_Z_GROUP (f) = z_group_above_suspended;
1978 else if (EQ (new_value, Qbelow))
1980 window.level = NSNormalWindowLevel - 1;
1981 FRAME_Z_GROUP (f) = z_group_below;
1984 error ("Invalid z-group specification");
1988 ns_fullscreen_hook (struct frame *f)
1990 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1992 NSTRACE ("ns_fullscreen_hook");
1994 if (!FRAME_VISIBLE_P (f))
1997 if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1999 /* Old style fs don't initiate correctly if created from
2000 init/default-frame alist, so use a timer (not nice...).
2002 [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2003 selector: @selector (handleFS)
2004 userInfo: nil repeats: NO];
2013 /* ==========================================================================
2017 ========================================================================== */
2021 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2023 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2024 if (idx < 1 || idx >= color_table->avail)
2026 return color_table->colors[idx];
2031 ns_index_color (NSColor *color, struct frame *f)
2033 struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2037 if (!color_table->colors)
2039 color_table->size = NS_COLOR_CAPACITY;
2040 color_table->avail = 1; /* skip idx=0 as marker */
2041 color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2042 color_table->colors[0] = nil;
2043 color_table->empty_indices = [[NSMutableSet alloc] init];
2046 /* Do we already have this color? */
2047 for (i = 1; i < color_table->avail; i++)
2048 if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2051 if ([color_table->empty_indices count] > 0)
2053 NSNumber *index = [color_table->empty_indices anyObject];
2054 [color_table->empty_indices removeObject: index];
2055 idx = [index unsignedLongValue];
2059 if (color_table->avail == color_table->size)
2060 color_table->colors =
2061 xpalloc (color_table->colors, &color_table->size, 1,
2062 min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2063 idx = color_table->avail++;
2066 color_table->colors[idx] = color;
2068 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2074 ns_get_color (const char *name, NSColor **col)
2075 /* --------------------------------------------------------------------------
2077 -------------------------------------------------------------------------- */
2078 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2079 X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2080 See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2083 static char hex[20];
2085 float r = -1.0, g, b;
2086 NSString *nsname = [NSString stringWithUTF8String: name];
2088 NSTRACE ("ns_get_color(%s, **)", name);
2092 if ([nsname isEqualToString: @"ns_selection_bg_color"])
2094 #ifdef NS_IMPL_COCOA
2095 NSString *defname = [[NSUserDefaults standardUserDefaults]
2096 stringForKey: @"AppleHighlightColor"];
2101 if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2103 *col = [new colorUsingDefaultColorSpace];
2108 nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2110 name = [nsname UTF8String];
2112 else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2114 /* NOTE: macOS applications normally don't set foreground
2115 selection, but text may be unreadable if we don't.
2117 if ((new = [NSColor selectedTextColor]) != nil)
2119 *col = [new colorUsingDefaultColorSpace];
2124 nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2125 name = [nsname UTF8String];
2128 /* First, check for some sort of numeric specification. */
2131 if (name[0] == '0' || name[0] == '1' || name[0] == '.') /* RGB decimal */
2133 NSScanner *scanner = [NSScanner scannerWithString: nsname];
2134 [scanner scanFloat: &r];
2135 [scanner scanFloat: &g];
2136 [scanner scanFloat: &b];
2138 else if (!strncmp(name, "rgb:", 4)) /* A newer X11 format -- rgb:r/g/b */
2139 scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2140 else if (name[0] == '#') /* An old X11 format; convert to newer */
2142 int len = (strlen(name) - 1);
2143 int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2145 scaling = strlen(name+start) / 3;
2146 for (i = 0; i < 3; i++)
2147 sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2148 name + start + i * scaling);
2149 hex[3 * (scaling + 1) - 1] = '\0';
2154 unsigned int rr, gg, bb;
2155 float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2156 if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2166 *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2171 /* Otherwise, color is expected to be from a list */
2173 NSEnumerator *lenum, *cenum;
2177 #ifdef NS_IMPL_GNUSTEP
2178 /* XXX: who is wrong, the requestor or the implementation? */
2179 if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2181 nsname = @"highlightColor";
2184 lenum = [[NSColorList availableColorLists] objectEnumerator];
2185 while ( (clist = [lenum nextObject]) && new == nil)
2187 cenum = [[clist allKeys] objectEnumerator];
2188 while ( (name = [cenum nextObject]) && new == nil )
2190 if ([name compare: nsname
2191 options: NSCaseInsensitiveSearch] == NSOrderedSame )
2192 new = [clist colorWithKey: name];
2198 *col = [new colorUsingDefaultColorSpace];
2205 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2206 /* --------------------------------------------------------------------------
2207 Convert a Lisp string object to a NS color
2208 -------------------------------------------------------------------------- */
2210 NSTRACE ("ns_lisp_to_color");
2211 if (STRINGP (color))
2212 return ns_get_color (SSDATA (color), col);
2213 else if (SYMBOLP (color))
2214 return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2220 ns_query_color(void *col, XColor *color_def, int setPixel)
2221 /* --------------------------------------------------------------------------
2222 Get ARGB values out of NSColor col and put them into color_def.
2223 If setPixel, set the pixel to a concatenated version.
2224 and set color_def pixel to the resulting index.
2225 -------------------------------------------------------------------------- */
2227 EmacsCGFloat r, g, b, a;
2229 [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2230 color_def->red = r * 65535;
2231 color_def->green = g * 65535;
2232 color_def->blue = b * 65535;
2234 if (setPixel == YES)
2236 = ARGB_TO_ULONG((int)(a*255),
2237 (int)(r*255), (int)(g*255), (int)(b*255));
2242 ns_defined_color (struct frame *f,
2247 /* --------------------------------------------------------------------------
2248 Return true if named color found, and set color_def rgb accordingly.
2249 If makeIndex and alloc are nonzero put the color in the color_table,
2250 and set color_def pixel to the resulting index.
2251 If makeIndex is zero, set color_def pixel to ARGB.
2252 Return false if not found
2253 -------------------------------------------------------------------------- */
2256 NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2259 if (ns_get_color (name, &col) != 0) /* Color not found */
2264 if (makeIndex && alloc)
2265 color_def->pixel = ns_index_color (col, f);
2266 ns_query_color (col, color_def, !makeIndex);
2273 x_set_frame_alpha (struct frame *f)
2274 /* --------------------------------------------------------------------------
2275 change the entire-frame transparency
2276 -------------------------------------------------------------------------- */
2278 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2280 double alpha_min = 1.0;
2282 NSTRACE ("x_set_frame_alpha");
2284 if (dpyinfo->x_highlight_frame == f)
2285 alpha = f->alpha[0];
2287 alpha = f->alpha[1];
2289 if (FLOATP (Vframe_alpha_lower_limit))
2290 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2291 else if (INTEGERP (Vframe_alpha_lower_limit))
2292 alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2296 else if (1.0 < alpha)
2298 else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2301 #ifdef NS_IMPL_COCOA
2303 EmacsView *view = FRAME_NS_VIEW (f);
2304 [[view window] setAlphaValue: alpha];
2310 /* ==========================================================================
2314 ========================================================================== */
2318 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2319 /* --------------------------------------------------------------------------
2320 Programmatically reposition mouse pointer in pixel coordinates
2321 -------------------------------------------------------------------------- */
2323 NSTRACE ("frame_set_mouse_pixel_position");
2325 /* FIXME: what about GNUstep? */
2326 #ifdef NS_IMPL_COCOA
2328 CGPointMake(f->left_pos + pix_x,
2329 f->top_pos + pix_y +
2330 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2331 CGWarpMouseCursorPosition (mouse_pos);
2336 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2337 /* ------------------------------------------------------------------------
2338 Called by EmacsView on mouseMovement events. Passes on
2339 to emacs mainstream code if we moved off of a rect of interest
2340 known as last_mouse_glyph.
2341 ------------------------------------------------------------------------ */
2343 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2346 // NSTRACE ("note_mouse_movement");
2348 dpyinfo->last_mouse_motion_frame = frame;
2349 r = &dpyinfo->last_mouse_glyph;
2351 /* Note, this doesn't get called for enter/leave, since we don't have a
2352 position. Those are taken care of in the corresponding NSView methods. */
2354 /* has movement gone beyond last rect we were tracking? */
2355 if (x < r->origin.x || x >= r->origin.x + r->size.width
2356 || y < r->origin.y || y >= r->origin.y + r->size.height)
2358 ns_update_begin (frame);
2359 frame->mouse_moved = 1;
2360 note_mouse_highlight (frame, x, y);
2361 remember_mouse_glyph (frame, x, y, r);
2362 ns_update_end (frame);
2371 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2372 enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2374 /* --------------------------------------------------------------------------
2375 External (hook): inform emacs about mouse position and hit parts.
2376 If a scrollbar is being dragged, set bar_window, part, x, y, time.
2377 x & y should be position in the scrollbar (the whole bar, not the handle)
2378 and length of scrollbar respectively
2379 -------------------------------------------------------------------------- */
2383 Lisp_Object frame, tail;
2385 struct ns_display_info *dpyinfo;
2387 NSTRACE ("ns_mouse_position");
2391 fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2395 dpyinfo = FRAME_DISPLAY_INFO (*fp);
2399 /* Clear the mouse-moved flag for every frame on this display. */
2400 FOR_EACH_FRAME (tail, frame)
2401 if (FRAME_NS_P (XFRAME (frame))
2402 && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2403 XFRAME (frame)->mouse_moved = 0;
2405 dpyinfo->last_mouse_scroll_bar = nil;
2406 if (dpyinfo->last_mouse_frame
2407 && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2408 f = dpyinfo->last_mouse_frame;
2410 f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2412 if (f && FRAME_NS_P (f))
2414 view = FRAME_NS_VIEW (*fp);
2416 position = [[view window] mouseLocationOutsideOfEventStream];
2417 position = [view convertPoint: position fromView: nil];
2418 remember_mouse_glyph (f, position.x, position.y,
2419 &dpyinfo->last_mouse_glyph);
2420 NSTRACE_POINT ("position", position);
2422 if (bar_window) *bar_window = Qnil;
2423 if (part) *part = scroll_bar_above_handle;
2425 if (x) XSETINT (*x, lrint (position.x));
2426 if (y) XSETINT (*y, lrint (position.y));
2428 *time = dpyinfo->last_mouse_movement_time;
2437 ns_frame_up_to_date (struct frame *f)
2438 /* --------------------------------------------------------------------------
2439 External (hook): Fix up mouse highlighting right after a full update.
2440 Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2441 -------------------------------------------------------------------------- */
2443 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2447 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2448 if (f == hlinfo->mouse_face_mouse_frame)
2452 note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2453 hlinfo->mouse_face_mouse_x,
2454 hlinfo->mouse_face_mouse_y);
2463 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2464 /* --------------------------------------------------------------------------
2465 External (RIF): set frame mouse pointer type.
2466 -------------------------------------------------------------------------- */
2468 NSTRACE ("ns_define_frame_cursor");
2469 if (FRAME_POINTER_TYPE (f) != cursor)
2471 EmacsView *view = FRAME_NS_VIEW (f);
2472 FRAME_POINTER_TYPE (f) = cursor;
2473 [[view window] invalidateCursorRectsForView: view];
2474 /* Redisplay assumes this function also draws the changed frame
2475 cursor, but this function doesn't, so do it explicitly. */
2476 x_update_cursor (f, 1);
2482 /* ==========================================================================
2486 ========================================================================== */
2490 ns_convert_key (unsigned code)
2491 /* --------------------------------------------------------------------------
2492 Internal call used by NSView-keyDown.
2493 -------------------------------------------------------------------------- */
2495 const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2497 /* An array would be faster, but less easy to read. */
2498 for (keysym = 0; keysym < last_keysym; keysym += 2)
2499 if (code == convert_ns_to_X_keysym[keysym])
2500 return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2502 /* if decide to use keyCode and Carbon table, use this line:
2503 return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2508 x_get_keysym_name (int keysym)
2509 /* --------------------------------------------------------------------------
2510 Called by keyboard.c. Not sure if the return val is important, except
2512 -------------------------------------------------------------------------- */
2514 static char value[16];
2515 NSTRACE ("x_get_keysym_name");
2516 sprintf (value, "%d", keysym);
2522 /* ==========================================================================
2524 Block drawing operations
2526 ========================================================================== */
2530 ns_redraw_scroll_bars (struct frame *f)
2534 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2535 NSTRACE ("ns_redraw_scroll_bars");
2536 for (i =[subviews count]-1; i >= 0; i--)
2538 view = [subviews objectAtIndex: i];
2539 if (![view isKindOfClass: [EmacsScroller class]]) continue;
2546 ns_clear_frame (struct frame *f)
2547 /* --------------------------------------------------------------------------
2548 External (hook): Erase the entire frame
2549 -------------------------------------------------------------------------- */
2551 NSView *view = FRAME_NS_VIEW (f);
2554 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2556 /* comes on initial frame because we have
2557 after-make-frame-functions = select-frame */
2558 if (!FRAME_DEFAULT_FACE (f))
2561 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2566 ns_focus (f, &r, 1);
2567 [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2568 (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2572 /* as of 2006/11 or so this is now needed */
2573 ns_redraw_scroll_bars (f);
2579 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2580 /* --------------------------------------------------------------------------
2581 External (RIF): Clear section of frame
2582 -------------------------------------------------------------------------- */
2584 NSRect r = NSMakeRect (x, y, width, height);
2585 NSView *view = FRAME_NS_VIEW (f);
2586 struct face *face = FRAME_DEFAULT_FACE (f);
2591 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2593 r = NSIntersectionRect (r, [view frame]);
2594 ns_focus (f, &r, 1);
2595 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2604 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2606 NSTRACE ("ns_copy_bits");
2608 if (FRAME_NS_VIEW (f))
2610 hide_bell(); // Ensure the bell image isn't scrolled.
2612 ns_focus (f, &dest, 1);
2613 [FRAME_NS_VIEW (f) scrollRect: src
2614 by: NSMakeSize (dest.origin.x - src.origin.x,
2615 dest.origin.y - src.origin.y)];
2621 ns_scroll_run (struct window *w, struct run *run)
2622 /* --------------------------------------------------------------------------
2623 External (RIF): Insert or delete n lines at line vpos
2624 -------------------------------------------------------------------------- */
2626 struct frame *f = XFRAME (w->frame);
2627 int x, y, width, height, from_y, to_y, bottom_y;
2629 NSTRACE ("ns_scroll_run");
2631 /* begin copy from other terms */
2632 /* Get frame-relative bounding box of the text display area of W,
2633 without mode lines. Include in this box the left and right
2635 window_box (w, ANY_AREA, &x, &y, &width, &height);
2637 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2638 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2639 bottom_y = y + height;
2643 /* Scrolling up. Make sure we don't copy part of the mode
2644 line at the bottom. */
2645 if (from_y + run->height > bottom_y)
2646 height = bottom_y - from_y;
2648 height = run->height;
2652 /* Scrolling down. Make sure we don't copy over the mode line.
2654 if (to_y + run->height > bottom_y)
2655 height = bottom_y - to_y;
2657 height = run->height;
2659 /* end copy from other terms */
2669 NSRect srcRect = NSMakeRect (x, from_y, width, height);
2670 NSRect dstRect = NSMakeRect (x, to_y, width, height);
2672 ns_copy_bits (f, srcRect , dstRect);
2680 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2681 /* --------------------------------------------------------------------------
2682 External (RIF): preparatory to fringe update after text was updated
2683 -------------------------------------------------------------------------- */
2688 NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2690 /* begin copy from other terms */
2693 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2694 desired_row->redraw_fringe_bitmaps_p = 1;
2696 /* When a window has disappeared, make sure that no rest of
2697 full-width rows stays visible in the internal border. */
2698 if (windows_or_buffers_changed
2699 && desired_row->full_width_p
2700 && (f = XFRAME (w->frame),
2701 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2703 && (height = desired_row->visible_height,
2706 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2709 ns_clear_frame_area (f, 0, y, width, height);
2710 ns_clear_frame_area (f,
2711 FRAME_PIXEL_WIDTH (f) - width,
2719 ns_shift_glyphs_for_insert (struct frame *f,
2720 int x, int y, int width, int height,
2722 /* --------------------------------------------------------------------------
2723 External (RIF): copy an area horizontally, don't worry about clearing src
2724 -------------------------------------------------------------------------- */
2726 NSRect srcRect = NSMakeRect (x, y, width, height);
2727 NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2729 NSTRACE ("ns_shift_glyphs_for_insert");
2731 ns_copy_bits (f, srcRect, dstRect);
2736 /* ==========================================================================
2738 Character encoding and metrics
2740 ========================================================================== */
2744 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2745 /* --------------------------------------------------------------------------
2746 External (RIF); compute left/right overhang of whole string and set in s
2747 -------------------------------------------------------------------------- */
2749 struct font *font = s->font;
2753 struct font_metrics metrics;
2754 unsigned int codes[2];
2755 codes[0] = *(s->char2b);
2756 codes[1] = *(s->char2b + s->nchars - 1);
2758 font->driver->text_extents (font, codes, 2, &metrics);
2759 s->left_overhang = -metrics.lbearing;
2761 = metrics.rbearing > metrics.width
2762 ? metrics.rbearing - metrics.width : 0;
2766 s->left_overhang = 0;
2767 if (EQ (font->driver->type, Qns))
2768 s->right_overhang = ((struct nsfont_info *)font)->ital ?
2769 FONT_HEIGHT (font) * 0.2 : 0;
2771 s->right_overhang = 0;
2777 /* ==========================================================================
2779 Fringe and cursor drawing
2781 ========================================================================== */
2784 extern int max_used_fringe_bitmap;
2786 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2787 struct draw_fringe_bitmap_params *p)
2788 /* --------------------------------------------------------------------------
2789 External (RIF); fringe-related
2790 -------------------------------------------------------------------------- */
2792 /* Fringe bitmaps comes in two variants, normal and periodic. A
2793 periodic bitmap is used to create a continuous pattern. Since a
2794 bitmap is rendered one text line at a time, the start offset (dh)
2795 of the bitmap varies. Concretely, this is used for the empty
2798 For a bitmap, "h + dh" is the full height and is always
2799 invariant. For a normal bitmap "dh" is zero.
2801 For example, when the period is three and the full height is 72
2802 the following combinations exists:
2808 struct frame *f = XFRAME (WINDOW_FRAME (w));
2809 struct face *face = p->face;
2810 static EmacsImage **bimgs = NULL;
2811 static int nBimgs = 0;
2813 NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2814 NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2815 p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2817 /* grow bimgs if needed */
2818 if (nBimgs < max_used_fringe_bitmap)
2820 bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2821 memset (bimgs + nBimgs, 0,
2822 (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2823 nBimgs = max_used_fringe_bitmap;
2826 /* Must clip because of partially visible lines. */
2827 ns_clip_to_row (w, row, ANY_AREA, YES);
2831 int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2833 if (bx >= 0 && nx > 0)
2835 NSRect r = NSMakeRect (bx, by, nx, ny);
2837 [ns_lookup_indexed_color (face->background, f) set];
2844 NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2845 EmacsImage *img = bimgs[p->which - 1];
2849 // Note: For "periodic" images, allocate one EmacsImage for
2850 // the base image, and use it for all dh:s.
2851 unsigned short *bits = p->bits;
2852 int full_height = p->h + p->dh;
2854 unsigned char *cbits = xmalloc (full_height);
2856 for (i = 0; i < full_height; i++)
2858 img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2861 bimgs[p->which - 1] = img;
2865 NSTRACE_RECT ("r", r);
2868 /* Since we composite the bitmap instead of just blitting it, we need
2869 to erase the whole background. */
2870 [ns_lookup_indexed_color(face->background, f) set];
2876 bm_color = ns_lookup_indexed_color(face->foreground, f);
2877 else if (p->overlay_p)
2878 bm_color = ns_lookup_indexed_color(face->background, f);
2880 bm_color = f->output_data.ns->cursor_color;
2881 [img setXBMColor: bm_color];
2884 #ifdef NS_IMPL_COCOA
2885 // Note: For periodic images, the full image height is "h + hd".
2886 // By using the height h, a suitable part of the image is used.
2887 NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2889 NSTRACE_RECT ("fromRect", fromRect);
2893 operation: NSCompositingOperationSourceOver
2899 NSPoint pt = r.origin;
2901 [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
2910 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2911 int x, int y, enum text_cursor_kinds cursor_type,
2912 int cursor_width, bool on_p, bool active_p)
2913 /* --------------------------------------------------------------------------
2914 External call (RIF): draw cursor.
2915 Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2916 -------------------------------------------------------------------------- */
2919 int fx, fy, h, cursor_height;
2920 struct frame *f = WINDOW_XFRAME (w);
2921 struct glyph *phys_cursor_glyph;
2922 struct glyph *cursor_glyph;
2924 NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2926 /* If cursor is out of bounds, don't draw garbage. This can happen
2927 in mini-buffer windows when switching between echo area glyphs
2930 NSTRACE ("ns_draw_window_cursor");
2935 w->phys_cursor_type = cursor_type;
2936 w->phys_cursor_on_p = on_p;
2938 if (cursor_type == NO_CURSOR)
2940 w->phys_cursor_width = 0;
2944 if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2946 if (glyph_row->exact_window_width_line_p
2947 && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2949 glyph_row->cursor_in_fringe_p = 1;
2950 draw_fringe_bitmap (w, glyph_row, 0);
2955 /* We draw the cursor (with NSRectFill), then draw the glyph on top
2956 (other terminals do it the other way round). We must set
2957 w->phys_cursor_width to the cursor width. For bar cursors, that
2958 is CURSOR_WIDTH; for box cursors, it is the glyph width. */
2959 get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2961 /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2962 to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2963 if (cursor_type == BAR_CURSOR)
2965 if (cursor_width < 1)
2966 cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2968 /* The bar cursor should never be wider than the glyph. */
2969 if (cursor_width < w->phys_cursor_width)
2970 w->phys_cursor_width = cursor_width;
2972 /* If we have an HBAR, "cursor_width" MAY specify height. */
2973 else if (cursor_type == HBAR_CURSOR)
2975 cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2976 if (cursor_height > glyph_row->height)
2977 cursor_height = glyph_row->height;
2978 if (h > cursor_height) // Cursor smaller than line height, move down
2979 fy += h - cursor_height;
2983 r.origin.x = fx, r.origin.y = fy;
2985 r.size.width = w->phys_cursor_width;
2987 /* Prevent the cursor from being drawn outside the text area. */
2988 ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2991 face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
2992 if (face && NS_FACE_BACKGROUND (face)
2993 == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2995 [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2996 hollow_color = FRAME_CURSOR_COLOR (f);
2999 [FRAME_CURSOR_COLOR (f) set];
3001 #ifdef NS_IMPL_COCOA
3002 /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3003 atomic. Cleaner ways of doing this should be investigated.
3004 One way would be to set a global variable DRAWING_CURSOR
3005 when making the call to draw_phys..(), don't focus in that
3006 case, then move the ns_unfocus() here after that call. */
3007 NSDisableScreenUpdates ();
3010 switch (cursor_type)
3012 case DEFAULT_CURSOR:
3015 case FILLED_BOX_CURSOR:
3018 case HOLLOW_BOX_CURSOR:
3021 NSRectFill (NSInsetRect (r, 1, 1));
3022 [FRAME_CURSOR_COLOR (f) set];
3029 /* If the character under cursor is R2L, draw the bar cursor
3030 on the right of its glyph, rather than on the left. */
3031 cursor_glyph = get_phys_cursor_glyph (w);
3032 if ((cursor_glyph->resolved_level & 1) != 0)
3033 s.origin.x += cursor_glyph->pixel_width - s.size.width;
3040 /* draw the character under the cursor */
3041 if (cursor_type != NO_CURSOR)
3042 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3044 #ifdef NS_IMPL_COCOA
3045 NSEnableScreenUpdates ();
3052 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3053 /* --------------------------------------------------------------------------
3054 External (RIF): Draw a vertical line.
3055 -------------------------------------------------------------------------- */
3057 struct frame *f = XFRAME (WINDOW_FRAME (w));
3059 NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3061 NSTRACE ("ns_draw_vertical_window_border");
3063 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3065 ns_focus (f, &r, 1);
3067 [ns_lookup_indexed_color(face->foreground, f) set];
3075 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3076 /* --------------------------------------------------------------------------
3077 External (RIF): Draw a window divider.
3078 -------------------------------------------------------------------------- */
3080 struct frame *f = XFRAME (WINDOW_FRAME (w));
3082 NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
3084 NSTRACE ("ns_draw_window_divider");
3086 face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3088 ns_focus (f, &r, 1);
3090 [ns_lookup_indexed_color(face->foreground, f) set];
3097 ns_show_hourglass (struct frame *f)
3099 /* TODO: add NSProgressIndicator to all frames. */
3103 ns_hide_hourglass (struct frame *f)
3105 /* TODO: remove NSProgressIndicator from all frames. */
3108 /* ==========================================================================
3110 Glyph drawing operations
3112 ========================================================================== */
3115 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3116 /* --------------------------------------------------------------------------
3117 Wrapper utility to account for internal border width on full-width lines,
3118 and allow top full-width rows to hit the frame top. nr should be pointer
3119 to two successive NSRects. Number of rects actually used is returned.
3120 -------------------------------------------------------------------------- */
3122 int n = get_glyph_string_clip_rects (s, nr, 2);
3126 /* --------------------------------------------------------------------
3127 Draw a wavy line under glyph string s. The wave fills wave_height
3134 wave_height = 3 | * * * *
3135 --------------------------------------------------------------------- */
3138 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3140 int wave_height = 3, wave_length = 2;
3141 int y, dx, dy, odd, xmax;
3146 dy = wave_height - 1;
3147 y = s->ybase - wave_height + 3;
3150 /* Find and set clipping rectangle */
3151 waveClip = NSMakeRect (x, y, width, wave_height);
3152 [[NSGraphicsContext currentContext] saveGraphicsState];
3153 NSRectClip (waveClip);
3155 /* Draw the waves */
3156 a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3158 odd = (int)(a.x/dx) % 2;
3159 a.y = b.y = y + 0.5;
3168 [NSBezierPath strokeLineFromPoint:a toPoint:b];
3169 a.x = b.x, a.y = b.y;
3170 b.x += dx, b.y = y + 0.5 + odd*dy;
3174 /* Restore previous clipping rectangle(s) */
3175 [[NSGraphicsContext currentContext] restoreGraphicsState];
3181 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3182 NSColor *defaultCol, CGFloat width, CGFloat x)
3183 /* --------------------------------------------------------------------------
3184 Draw underline, overline, and strike-through on glyph string s.
3185 -------------------------------------------------------------------------- */
3187 if (s->for_overlaps)
3191 if (face->underline_p)
3193 if (s->face->underline_type == FACE_UNDER_WAVE)
3195 if (face->underline_defaulted_p)
3198 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3200 ns_draw_underwave (s, width, x);
3202 else if (s->face->underline_type == FACE_UNDER_LINE)
3206 unsigned long thickness, position;
3208 /* If the prev was underlined, match its appearance. */
3209 if (s->prev && s->prev->face->underline_p
3210 && s->prev->face->underline_type == FACE_UNDER_LINE
3211 && s->prev->underline_thickness > 0)
3213 thickness = s->prev->underline_thickness;
3214 position = s->prev->underline_position;
3218 struct font *font = font_for_underline_metrics (s);
3219 unsigned long descent = s->y + s->height - s->ybase;
3221 /* Use underline thickness of font, defaulting to 1. */
3222 thickness = (font && font->underline_thickness > 0)
3223 ? font->underline_thickness : 1;
3225 /* Determine the offset of underlining from the baseline. */
3226 if (x_underline_at_descent_line)
3227 position = descent - thickness;
3228 else if (x_use_underline_position_properties
3229 && font && font->underline_position >= 0)
3230 position = font->underline_position;
3232 position = lround (font->descent / 2);
3234 position = underline_minimum_offset;
3236 position = max (position, underline_minimum_offset);
3238 /* Ensure underlining is not cropped. */
3239 if (descent <= position)
3241 position = descent - 1;
3244 else if (descent < position + thickness)
3248 s->underline_thickness = thickness;
3249 s->underline_position = position;
3251 r = NSMakeRect (x, s->ybase + position, width, thickness);
3253 if (face->underline_defaulted_p)
3256 [ns_lookup_indexed_color (face->underline_color, s->f) set];
3260 /* Do overline. We follow other terms in using a thickness of 1
3261 and ignoring overline_margin. */
3262 if (face->overline_p)
3265 r = NSMakeRect (x, s->y, width, 1);
3267 if (face->overline_color_defaulted_p)
3270 [ns_lookup_indexed_color (face->overline_color, s->f) set];
3274 /* Do strike-through. We follow other terms for thickness and
3275 vertical position.*/
3276 if (face->strike_through_p)
3279 /* Y-coordinate and height of the glyph string's first glyph.
3280 We cannot use s->y and s->height because those could be
3281 larger if there are taller display elements (e.g., characters
3282 displayed with a larger font) in the same glyph row. */
3283 int glyph_y = s->ybase - s->first_glyph->ascent;
3284 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3285 /* Strike-through width and offset from the glyph string's
3287 unsigned long h = 1;
3290 dy = lrint ((glyph_height - h) / 2);
3291 r = NSMakeRect (x, glyph_y + dy, width, 1);
3293 if (face->strike_through_color_defaulted_p)
3296 [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3302 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3303 char left_p, char right_p)
3304 /* --------------------------------------------------------------------------
3305 Draw an unfilled rect inside r, optionally leaving left and/or right open.
3306 Note we can't just use an NSDrawRect command, because of the possibility
3307 of some sides not being drawn, and because the rect will be filled.
3308 -------------------------------------------------------------------------- */
3314 s.size.height = thickness;
3316 s.origin.y += r.size.height - thickness;
3319 s.size.height = r.size.height;
3320 s.origin.y = r.origin.y;
3322 /* left, right (optional) */
3323 s.size.width = thickness;
3328 s.origin.x += r.size.width - thickness;
3335 ns_draw_relief (NSRect r, int thickness, char raised_p,
3336 char top_p, char bottom_p, char left_p, char right_p,
3337 struct glyph_string *s)
3338 /* --------------------------------------------------------------------------
3339 Draw a relief rect inside r, optionally leaving some sides open.
3340 Note we can't just use an NSDrawBezel command, because of the possibility
3341 of some sides not being drawn, and because the rect will be filled.
3342 -------------------------------------------------------------------------- */
3344 static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3345 NSColor *newBaseCol = nil;
3348 NSTRACE ("ns_draw_relief");
3352 if (s->face->use_box_color_for_shadows_p)
3354 newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3356 /* else if (s->first_glyph->type == IMAGE_GLYPH
3358 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3360 newBaseCol = IMAGE_BACKGROUND (s->img, s->f, 0);
3364 newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3367 if (newBaseCol == nil)
3368 newBaseCol = [NSColor grayColor];
3370 if (newBaseCol != baseCol) /* TODO: better check */
3373 baseCol = [newBaseCol retain];
3375 lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3377 darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3380 [(raised_p ? lightCol : darkCol) set];
3382 /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3385 sr.size.height = thickness;
3386 if (top_p) NSRectFill (sr);
3389 sr.size.height = r.size.height;
3390 sr.size.width = thickness;
3391 if (left_p) NSRectFill (sr);
3393 [(raised_p ? darkCol : lightCol) set];
3396 sr.size.width = r.size.width;
3397 sr.size.height = thickness;
3398 sr.origin.y += r.size.height - thickness;
3399 if (bottom_p) NSRectFill (sr);
3402 sr.size.height = r.size.height;
3403 sr.origin.y = r.origin.y;
3404 sr.size.width = thickness;
3405 sr.origin.x += r.size.width - thickness;
3406 if (right_p) NSRectFill (sr);
3411 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3412 /* --------------------------------------------------------------------------
3413 Function modeled after x_draw_glyph_string_box ().
3414 Sets up parameters for drawing.
3415 -------------------------------------------------------------------------- */
3417 int right_x, last_x;
3418 char left_p, right_p;
3419 struct glyph *last_glyph;
3424 if (s->hl == DRAW_MOUSE_FACE)
3426 face = FACE_FROM_ID_OR_NULL (s->f,
3427 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3429 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3434 thickness = face->box_line_width;
3436 NSTRACE ("ns_dumpglyphs_box_or_relief");
3438 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3439 ? WINDOW_RIGHT_EDGE_X (s->w)
3440 : window_box_right (s->w, s->area));
3441 last_glyph = (s->cmp || s->img
3442 ? s->first_glyph : s->first_glyph + s->nchars-1);
3444 right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3445 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3447 left_p = (s->first_glyph->left_box_line_p
3448 || (s->hl == DRAW_MOUSE_FACE
3449 && (s->prev == NULL || s->prev->hl != s->hl)));
3450 right_p = (last_glyph->right_box_line_p
3451 || (s->hl == DRAW_MOUSE_FACE
3452 && (s->next == NULL || s->next->hl != s->hl)));
3454 r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3456 /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3457 if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3459 ns_draw_box (r, abs (thickness),
3460 ns_lookup_indexed_color (face->box_color, s->f),
3465 ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3466 1, 1, left_p, right_p, s);
3472 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3473 /* --------------------------------------------------------------------------
3474 Modeled after x_draw_glyph_string_background, which draws BG in
3475 certain cases. Others are left to the text rendering routine.
3476 -------------------------------------------------------------------------- */
3478 NSTRACE ("ns_maybe_dumpglyphs_background");
3480 if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3482 int box_line_width = max (s->face->box_line_width, 0);
3483 if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3484 /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3485 dimensions, since the actual glyphs might be much
3486 smaller. So in that case we always clear the rectangle
3487 with background color. */
3488 || FONT_TOO_HIGH (s->font)
3489 || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3492 if (s->hl == DRAW_MOUSE_FACE)
3495 = FACE_FROM_ID_OR_NULL (s->f,
3496 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3498 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3501 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3503 [(NS_FACE_BACKGROUND (face) != 0
3504 ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3505 : FRAME_BACKGROUND_COLOR (s->f)) set];
3508 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3509 [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3512 if (s->hl != DRAW_CURSOR)
3514 NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3515 s->background_width,
3516 s->height-2*box_line_width);
3520 s->background_filled_p = 1;
3527 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3528 /* --------------------------------------------------------------------------
3529 Renders an image and associated borders.
3530 -------------------------------------------------------------------------- */
3532 EmacsImage *img = s->img->pixmap;
3533 int box_line_vwidth = max (s->face->box_line_width, 0);
3534 int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3535 int bg_x, bg_y, bg_height;
3542 NSTRACE ("ns_dumpglyphs_image");
3544 if (s->face->box != FACE_NO_BOX
3545 && s->first_glyph->left_box_line_p && s->slice.x == 0)
3546 x += abs (s->face->box_line_width);
3549 bg_y = s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3550 bg_height = s->height;
3551 /* other terms have this, but was causing problems w/tabbar mode */
3552 /* - 2 * box_line_vwidth; */
3554 if (s->slice.x == 0) x += s->img->hmargin;
3555 if (s->slice.y == 0) y += s->img->vmargin;
3557 /* Draw BG: if we need larger area than image itself cleared, do that,
3558 otherwise, since we composite the image under NS (instead of mucking
3559 with its background color), we must clear just the image area. */
3560 if (s->hl == DRAW_MOUSE_FACE)
3562 face = FACE_FROM_ID_OR_NULL (s->f,
3563 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3565 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3568 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3570 [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3572 if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3573 || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3575 br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3576 s->background_filled_p = 1;
3580 br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3585 /* Draw the image.. do we need to draw placeholder if img ==nil? */
3588 #ifdef NS_IMPL_COCOA
3589 NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3590 NSRect ir = NSMakeRect (s->slice.x,
3591 s->img->height - s->slice.y - s->slice.height,
3592 s->slice.width, s->slice.height);
3595 operation: NSCompositingOperationSourceOver
3600 [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3601 operation: NSCompositingOperationSourceOver];
3605 if (s->hl == DRAW_CURSOR)
3607 [FRAME_CURSOR_COLOR (s->f) set];
3608 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3609 tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3611 /* Currently on NS img->mask is always 0. Since
3612 get_window_cursor_type specifies a hollow box cursor when on
3613 a non-masked image we never reach this clause. But we put it
3614 in in anticipation of better support for image masks on
3616 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3620 tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3623 /* Draw underline, overline, strike-through. */
3624 ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3626 /* Draw relief, if requested */
3627 if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3629 if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3631 th = tool_bar_button_relief >= 0 ?
3632 tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3633 raised_p = (s->hl == DRAW_IMAGE_RAISED);
3637 th = abs (s->img->relief);
3638 raised_p = (s->img->relief > 0);
3641 r.origin.x = x - th;
3642 r.origin.y = y - th;
3643 r.size.width = s->slice.width + 2*th-1;
3644 r.size.height = s->slice.height + 2*th-1;
3645 ns_draw_relief (r, th, raised_p,
3647 s->slice.y + s->slice.height == s->img->height,
3649 s->slice.x + s->slice.width == s->img->width, s);
3652 /* If there is no mask, the background won't be seen,
3653 so draw a rectangle on the image for the cursor.
3654 Do this for all images, getting transparency right is not reliable. */
3655 if (s->hl == DRAW_CURSOR)
3657 int thickness = abs (s->img->relief);
3658 if (thickness == 0) thickness = 1;
3659 ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3665 ns_dumpglyphs_stretch (struct glyph_string *s)
3670 NSColor *fgCol, *bgCol;
3672 if (!s->background_filled_p)
3674 n = ns_get_glyph_string_clip_rect (s, r);
3675 *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3677 ns_focus (s->f, r, n);
3679 if (s->hl == DRAW_MOUSE_FACE)
3681 face = FACE_FROM_ID_OR_NULL (s->f,
3682 MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3684 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3687 face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3689 bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3690 fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3692 for (i = 0; i < n; ++i)
3694 if (!s->row->full_width_p)
3696 int overrun, leftoverrun;
3698 /* truncate to avoid overwriting fringe and/or scrollbar */
3699 overrun = max (0, (s->x + s->background_width)
3700 - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3701 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3702 r[i].size.width -= overrun;
3704 /* truncate to avoid overwriting to left of the window box */
3705 leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3706 + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3708 if (leftoverrun > 0)
3710 r[i].origin.x += leftoverrun;
3711 r[i].size.width -= leftoverrun;
3714 /* XXX: Try to work between problem where a stretch glyph on
3715 a partially-visible bottom row will clear part of the
3716 modeline, and another where list-buffers headers and similar
3717 rows erroneously have visible_height set to 0. Not sure
3718 where this is coming from as other terms seem not to show. */
3719 r[i].size.height = min (s->height, s->row->visible_height);
3724 /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3725 overwriting cursor (usually when cursor on a tab) */
3726 if (s->hl == DRAW_CURSOR)
3731 width = s->w->phys_cursor_width;
3732 r[i].size.width -= width;
3733 r[i].origin.x += width;
3737 /* Draw overlining, etc. on the cursor. */
3738 if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3739 ns_draw_text_decoration (s, face, bgCol, width, x);
3741 ns_draw_text_decoration (s, face, fgCol, width, x);
3748 /* Draw overlining, etc. on the stretch glyph (or the part
3749 of the stretch glyph after the cursor). */
3750 ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3754 s->background_filled_p = 1;
3760 ns_draw_glyph_string_foreground (struct glyph_string *s)
3763 struct font *font = s->font;
3765 /* If first glyph of S has a left box line, start drawing the text
3766 of S to the right of that box line. */
3767 if (s->face && s->face->box != FACE_NO_BOX
3768 && s->first_glyph->left_box_line_p)
3769 x = s->x + eabs (s->face->box_line_width);
3773 flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3774 (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3775 (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3776 NS_DUMPGLYPH_NORMAL));
3779 (s, s->cmp_from, s->nchars, x, s->ybase,
3780 (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3781 || flags == NS_DUMPGLYPH_MOUSEFACE);
3786 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3789 struct font *font = s->font;
3791 /* If first glyph of S has a left box line, start drawing the text
3792 of S to the right of that box line. */
3793 if (s->face && s->face->box != FACE_NO_BOX
3794 && s->first_glyph->left_box_line_p)
3795 x = s->x + eabs (s->face->box_line_width);
3799 /* S is a glyph string for a composition. S->cmp_from is the index
3800 of the first character drawn for glyphs of this composition.
3801 S->cmp_from == 0 means we are drawing the very first character of
3802 this composition. */
3804 /* Draw a rectangle for the composition if the font for the very
3805 first character of the composition could not be loaded. */
3806 if (s->font_not_found_p)
3808 if (s->cmp_from == 0)
3810 NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3811 ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3814 else if (! s->first_glyph->u.cmp.automatic)
3818 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3819 /* TAB in a composition means display glyphs with padding
3820 space on the left or right. */
3821 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3823 int xx = x + s->cmp->offsets[j * 2];
3824 int yy = y - s->cmp->offsets[j * 2 + 1];
3826 font->driver->draw (s, j, j + 1, xx, yy, false);
3827 if (s->face->overstrike)
3828 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3833 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3838 for (i = j = s->cmp_from; i < s->cmp_to; i++)
3840 glyph = LGSTRING_GLYPH (gstring, i);
3841 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3842 width += LGLYPH_WIDTH (glyph);
3845 int xoff, yoff, wadjust;
3849 font->driver->draw (s, j, i, x, y, false);
3850 if (s->face->overstrike)
3851 font->driver->draw (s, j, i, x + 1, y, false);
3854 xoff = LGLYPH_XOFF (glyph);
3855 yoff = LGLYPH_YOFF (glyph);
3856 wadjust = LGLYPH_WADJUST (glyph);
3857 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3858 if (s->face->overstrike)
3859 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3868 font->driver->draw (s, j, i, x, y, false);
3869 if (s->face->overstrike)
3870 font->driver->draw (s, j, i, x + 1, y, false);
3876 ns_draw_glyph_string (struct glyph_string *s)
3877 /* --------------------------------------------------------------------------
3878 External (RIF): Main draw-text call.
3879 -------------------------------------------------------------------------- */
3881 /* TODO (optimize): focus for box and contents draw */
3884 char box_drawn_p = 0;
3885 struct font *font = s->face->font;
3886 if (! font) font = FRAME_FONT (s->f);
3888 NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3890 if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3893 struct glyph_string *next;
3895 for (width = 0, next = s->next;
3896 next && width < s->right_overhang;
3897 width += next->width, next = next->next)
3898 if (next->first_glyph->type != IMAGE_GLYPH)
3900 if (next->first_glyph->type != STRETCH_GLYPH)
3902 n = ns_get_glyph_string_clip_rect (s->next, r);
3903 ns_focus (s->f, r, n);
3904 ns_maybe_dumpglyphs_background (s->next, 1);
3909 ns_dumpglyphs_stretch (s->next);
3911 next->num_clips = 0;
3915 if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3916 && (s->first_glyph->type == CHAR_GLYPH
3917 || s->first_glyph->type == COMPOSITE_GLYPH))
3919 n = ns_get_glyph_string_clip_rect (s, r);
3920 ns_focus (s->f, r, n);
3921 ns_maybe_dumpglyphs_background (s, 1);
3922 ns_dumpglyphs_box_or_relief (s);
3927 switch (s->first_glyph->type)
3931 n = ns_get_glyph_string_clip_rect (s, r);
3932 ns_focus (s->f, r, n);
3933 ns_dumpglyphs_image (s, r[0]);
3938 ns_dumpglyphs_stretch (s);
3942 case COMPOSITE_GLYPH:
3943 n = ns_get_glyph_string_clip_rect (s, r);
3944 ns_focus (s->f, r, n);
3946 if (s->for_overlaps || (s->cmp_from > 0
3947 && ! s->first_glyph->u.cmp.automatic))
3948 s->background_filled_p = 1;
3950 ns_maybe_dumpglyphs_background
3951 (s, s->first_glyph->type == COMPOSITE_GLYPH);
3953 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3955 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3956 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3957 NS_FACE_FOREGROUND (s->face) = tmp;
3961 BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3964 ns_draw_composite_glyph_string_foreground (s);
3966 ns_draw_glyph_string_foreground (s);
3970 NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3971 ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3973 : FRAME_FOREGROUND_COLOR (s->f));
3976 /* Draw underline, overline, strike-through. */
3977 ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3980 if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3982 unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3983 NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3984 NS_FACE_FOREGROUND (s->face) = tmp;
3990 case GLYPHLESS_GLYPH:
3991 n = ns_get_glyph_string_clip_rect (s, r);
3992 ns_focus (s->f, r, n);
3994 if (s->for_overlaps || (s->cmp_from > 0
3995 && ! s->first_glyph->u.cmp.automatic))
3996 s->background_filled_p = 1;
3998 ns_maybe_dumpglyphs_background
3999 (s, s->first_glyph->type == COMPOSITE_GLYPH);
4001 /* Not yet implemented. */
4010 /* Draw box if not done already. */
4011 if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4013 n = ns_get_glyph_string_clip_rect (s, r);
4014 ns_focus (s->f, r, n);
4015 ns_dumpglyphs_box_or_relief (s);
4024 /* ==========================================================================
4028 ========================================================================== */
4032 ns_send_appdefined (int value)
4033 /* --------------------------------------------------------------------------
4034 Internal: post an appdefined event which EmacsApp-sendEvent will
4035 recognize and take as a command to halt the event loop.
4036 -------------------------------------------------------------------------- */
4038 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4040 // GNUstep needs postEvent to happen on the main thread.
4041 // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4042 if (! [[NSThread currentThread] isMainThread])
4044 EmacsApp *app = (EmacsApp *)NSApp;
4045 app->nextappdefined = value;
4046 [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4052 /* Only post this event if we haven't already posted one. This will end
4053 the [NXApp run] main loop after having processed all events queued at
4056 #ifdef NS_IMPL_COCOA
4057 if (! send_appdefined)
4059 /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4060 in certain situations (rapid incoming events).
4061 So check if we have one, if not add one. */
4062 NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4063 untilDate:[NSDate distantPast]
4064 inMode:NSDefaultRunLoopMode
4066 if (! appev) send_appdefined = YES;
4070 if (send_appdefined)
4074 /* We only need one NX_APPDEFINED event to stop NXApp from running. */
4075 send_appdefined = NO;
4077 /* Don't need wakeup timer any more */
4080 [timed_entry invalidate];
4081 [timed_entry release];
4085 nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4086 location: NSMakePoint (0, 0)
4089 windowNumber: [[NSApp mainWindow] windowNumber]
4090 context: [NSApp context]
4095 /* Post an application defined event on the event queue. When this is
4096 received the [NXApp run] will return, thus having processed all
4097 events which are currently queued. */
4098 [NSApp postEvent: nxev atStart: NO];
4102 #ifdef HAVE_NATIVE_FS
4106 Lisp_Object frame, tail;
4108 if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4111 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4113 FOR_EACH_FRAME (tail, frame)
4115 struct frame *f = XFRAME (frame);
4118 EmacsView *view = FRAME_NS_VIEW (f);
4119 [view updateCollectionBehavior];
4125 /* GNUstep does not have cancelTracking. */
4126 #ifdef NS_IMPL_COCOA
4127 /* Check if menu open should be canceled or continued as normal. */
4129 ns_check_menu_open (NSMenu *menu)
4131 /* Click in menu bar? */
4132 NSArray *a = [[NSApp mainMenu] itemArray];
4136 if (menu == nil) // Menu tracking ended.
4138 if (menu_will_open_state == MENU_OPENING)
4139 menu_will_open_state = MENU_NONE;
4143 for (i = 0; ! found && i < [a count]; i++)
4144 found = menu == [[a objectAtIndex:i] submenu];
4147 if (menu_will_open_state == MENU_NONE && emacs_event)
4149 NSEvent *theEvent = [NSApp currentEvent];
4150 struct frame *emacsframe = SELECTED_FRAME ();
4152 [menu cancelTracking];
4153 menu_will_open_state = MENU_PENDING;
4154 emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4155 EV_TRAILER (theEvent);
4157 CGEventRef ourEvent = CGEventCreate (NULL);
4158 menu_mouse_point = CGEventGetLocation (ourEvent);
4159 CFRelease (ourEvent);
4161 else if (menu_will_open_state == MENU_OPENING)
4163 menu_will_open_state = MENU_NONE;
4168 /* Redo saved menu click if state is MENU_PENDING. */
4170 ns_check_pending_open_menu ()
4172 if (menu_will_open_state == MENU_PENDING)
4174 CGEventSourceRef source
4175 = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4177 CGEventRef event = CGEventCreateMouseEvent (source,
4178 kCGEventLeftMouseDown,
4180 kCGMouseButtonLeft);
4181 CGEventSetType (event, kCGEventLeftMouseDown);
4182 CGEventPost (kCGHIDEventTap, event);
4186 menu_will_open_state = MENU_OPENING;
4189 #endif /* NS_IMPL_COCOA */
4192 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4193 /* --------------------------------------------------------------------------
4194 External (hook): Post an event to ourself and keep reading events until
4195 we read it back again. In effect process all events which were waiting.
4196 From 21+ we have to manage the event buffer ourselves.
4197 -------------------------------------------------------------------------- */
4199 struct input_event ev;
4202 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4204 #ifdef HAVE_NATIVE_FS
4208 if ([NSApp modalWindow] != nil)
4211 if (hold_event_q.nr > 0)
4214 for (i = 0; i < hold_event_q.nr; ++i)
4215 kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4216 hold_event_q.nr = 0;
4220 if ([NSThread isMainThread])
4223 n_emacs_events_pending = 0;
4224 ns_init_events (&ev);
4225 q_event_ptr = hold_quit;
4227 /* we manage autorelease pools by allocate/reallocate each time around
4228 the loop; strict nesting is occasionally violated but seems not to
4229 matter.. earlier methods using full nesting caused major memory leaks */
4230 [outerpool release];
4231 outerpool = [[NSAutoreleasePool alloc] init];
4233 /* If have pending open-file requests, attend to the next one of those. */
4234 if (ns_pending_files && [ns_pending_files count] != 0
4235 && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4237 [ns_pending_files removeObjectAtIndex: 0];
4239 /* Deal with pending service requests. */
4240 else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4242 NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4243 withArg: [ns_pending_service_args objectAtIndex: 0]])
4245 [ns_pending_service_names removeObjectAtIndex: 0];
4246 [ns_pending_service_args removeObjectAtIndex: 0];
4250 /* Run and wait for events. We must always send one NX_APPDEFINED event
4251 to ourself, otherwise [NXApp run] will never exit. */
4252 send_appdefined = YES;
4253 ns_send_appdefined (-1);
4258 nevents = n_emacs_events_pending;
4259 n_emacs_events_pending = 0;
4260 ns_finish_events ();
4272 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4273 fd_set *exceptfds, struct timespec const *timeout,
4274 sigset_t const *sigmask)
4275 /* --------------------------------------------------------------------------
4276 Replacement for select, checking for events
4277 -------------------------------------------------------------------------- */
4281 struct input_event event;
4284 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4286 #ifdef HAVE_NATIVE_FS
4290 if (hold_event_q.nr > 0)
4292 /* We already have events pending. */
4298 for (k = 0; k < nfds+1; k++)
4300 if (readfds && FD_ISSET(k, readfds)) ++nr;
4301 if (writefds && FD_ISSET(k, writefds)) ++nr;
4305 || ![NSThread isMainThread]
4306 || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4307 return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
4309 [outerpool release];
4310 outerpool = [[NSAutoreleasePool alloc] init];
4313 send_appdefined = YES;
4316 pthread_mutex_lock (&select_mutex);
4321 select_readfds = *readfds;
4322 select_valid += SELECT_HAVE_READ;
4326 select_writefds = *writefds;
4327 select_valid += SELECT_HAVE_WRITE;
4332 select_timeout = *timeout;
4333 select_valid += SELECT_HAVE_TMO;
4336 pthread_mutex_unlock (&select_mutex);
4338 /* Inform fd_handler that select should be called */
4340 emacs_write_sig (selfds[1], &c, 1);
4342 else if (nr == 0 && timeout)
4344 /* No file descriptor, just a timeout, no need to wake fd_handler */
4345 double time = timespectod (*timeout);
4346 timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4349 @selector (timeout_handler:)
4354 else /* No timeout and no file descriptors, can this happen? */
4356 /* Send appdefined so we exit from the loop */
4357 ns_send_appdefined (-1);
4361 ns_init_events (&event);
4365 ns_finish_events ();
4366 if (nr > 0 && readfds)
4369 emacs_write_sig (selfds[1], &c, 1);
4373 t = last_appdefined_event_data;
4375 if (t != NO_APPDEFINED_DATA)
4377 last_appdefined_event_data = NO_APPDEFINED_DATA;
4381 /* The NX_APPDEFINED event we received was a timeout. */
4386 /* The NX_APPDEFINED event we received was the result of
4387 at least one real input event arriving. */
4393 /* Received back from select () in fd_handler; copy the results */
4394 pthread_mutex_lock (&select_mutex);
4395 if (readfds) *readfds = select_readfds;
4396 if (writefds) *writefds = select_writefds;
4397 pthread_mutex_unlock (&select_mutex);
4412 /* ==========================================================================
4416 ========================================================================== */
4420 ns_set_vertical_scroll_bar (struct window *window,
4421 int portion, int whole, int position)
4422 /* --------------------------------------------------------------------------
4423 External (hook): Update or add scrollbar
4424 -------------------------------------------------------------------------- */
4428 struct frame *f = XFRAME (WINDOW_FRAME (window));
4429 EmacsView *view = FRAME_NS_VIEW (f);
4431 int window_y, window_height;
4432 int top, left, height, width;
4433 BOOL update_p = YES;
4435 /* optimization; display engine sends WAY too many of these.. */
4436 if (!NILP (window->vertical_scroll_bar))
4438 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4439 if ([bar checkSamePosition: position portion: portion whole: whole])
4441 if (view->scrollbarsNeedingUpdate == 0)
4443 if (!windows_or_buffers_changed)
4447 view->scrollbarsNeedingUpdate--;
4452 NSTRACE ("ns_set_vertical_scroll_bar");
4454 /* Get dimensions. */
4455 window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4457 height = window_height;
4458 width = NS_SCROLL_BAR_WIDTH (f);
4459 left = WINDOW_SCROLL_BAR_AREA_X (window);
4461 r = NSMakeRect (left, top, width, height);
4462 /* the parent view is flipped, so we need to flip y value */
4464 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4466 XSETWINDOW (win, window);
4469 /* we want at least 5 lines to display a scrollbar */
4470 if (WINDOW_TOTAL_LINES (window) < 5)
4472 if (!NILP (window->vertical_scroll_bar))
4474 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4475 [bar removeFromSuperview];
4476 wset_vertical_scroll_bar (window, Qnil);
4479 ns_clear_frame_area (f, left, top, width, height);
4484 if (NILP (window->vertical_scroll_bar))
4486 if (width > 0 && height > 0)
4487 ns_clear_frame_area (f, left, top, width, height);
4489 bar = [[EmacsScroller alloc] initFrame: r window: win];
4490 wset_vertical_scroll_bar (window, make_save_ptr (bar));
4496 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4497 oldRect = [bar frame];
4498 r.size.width = oldRect.size.width;
4499 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4501 if (oldRect.origin.x != r.origin.x)
4502 ns_clear_frame_area (f, left, top, width, height);
4508 [bar setPosition: position portion: portion whole: whole];
4514 ns_set_horizontal_scroll_bar (struct window *window,
4515 int portion, int whole, int position)
4516 /* --------------------------------------------------------------------------
4517 External (hook): Update or add scrollbar
4518 -------------------------------------------------------------------------- */
4522 struct frame *f = XFRAME (WINDOW_FRAME (window));
4523 EmacsView *view = FRAME_NS_VIEW (f);
4525 int top, height, left, width;
4526 int window_x, window_width;
4527 BOOL update_p = YES;
4529 /* optimization; display engine sends WAY too many of these.. */
4530 if (!NILP (window->horizontal_scroll_bar))
4532 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4533 if ([bar checkSamePosition: position portion: portion whole: whole])
4535 if (view->scrollbarsNeedingUpdate == 0)
4537 if (!windows_or_buffers_changed)
4541 view->scrollbarsNeedingUpdate--;
4546 NSTRACE ("ns_set_horizontal_scroll_bar");
4548 /* Get dimensions. */
4549 window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4551 width = window_width;
4552 height = NS_SCROLL_BAR_HEIGHT (f);
4553 top = WINDOW_SCROLL_BAR_AREA_Y (window);
4555 r = NSMakeRect (left, top, width, height);
4556 /* the parent view is flipped, so we need to flip y value */
4558 r.origin.y = (v.size.height - r.size.height - r.origin.y);
4560 XSETWINDOW (win, window);
4563 if (NILP (window->horizontal_scroll_bar))
4565 if (width > 0 && height > 0)
4566 ns_clear_frame_area (f, left, top, width, height);
4568 bar = [[EmacsScroller alloc] initFrame: r window: win];
4569 wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4575 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4576 oldRect = [bar frame];
4577 if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4579 if (oldRect.origin.y != r.origin.y)
4580 ns_clear_frame_area (f, left, top, width, height);
4586 /* If there are both horizontal and vertical scroll-bars they leave
4587 a square that belongs to neither. We need to clear it otherwise
4588 it fills with junk. */
4589 if (!NILP (window->vertical_scroll_bar))
4590 ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4591 NS_SCROLL_BAR_HEIGHT (f), height);
4594 [bar setPosition: position portion: portion whole: whole];
4600 ns_condemn_scroll_bars (struct frame *f)
4601 /* --------------------------------------------------------------------------
4602 External (hook): arrange for all frame's scrollbars to be removed
4603 at next call to judge_scroll_bars, except for those redeemed.
4604 -------------------------------------------------------------------------- */
4608 NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4610 NSTRACE ("ns_condemn_scroll_bars");
4612 for (i =[subviews count]-1; i >= 0; i--)
4614 view = [subviews objectAtIndex: i];
4615 if ([view isKindOfClass: [EmacsScroller class]])
4622 ns_redeem_scroll_bar (struct window *window)
4623 /* --------------------------------------------------------------------------
4624 External (hook): arrange to spare this window's scrollbar
4625 at next call to judge_scroll_bars.
4626 -------------------------------------------------------------------------- */
4629 NSTRACE ("ns_redeem_scroll_bar");
4630 if (!NILP (window->vertical_scroll_bar)
4631 && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4633 bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4637 if (!NILP (window->horizontal_scroll_bar)
4638 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4640 bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4647 ns_judge_scroll_bars (struct frame *f)
4648 /* --------------------------------------------------------------------------
4649 External (hook): destroy all scrollbars on frame that weren't
4650 redeemed after call to condemn_scroll_bars.
4651 -------------------------------------------------------------------------- */
4655 EmacsView *eview = FRAME_NS_VIEW (f);
4656 NSArray *subviews = [[eview superview] subviews];
4659 NSTRACE ("ns_judge_scroll_bars");
4660 for (i = [subviews count]-1; i >= 0; --i)
4662 view = [subviews objectAtIndex: i];
4663 if (![view isKindOfClass: [EmacsScroller class]]) continue;
4669 [eview updateFrameSize: NO];
4672 /* ==========================================================================
4676 ========================================================================== */
4679 x_display_pixel_height (struct ns_display_info *dpyinfo)
4681 NSArray *screens = [NSScreen screens];
4682 NSEnumerator *enumerator = [screens objectEnumerator];
4687 while ((screen = [enumerator nextObject]) != nil)
4688 frame = NSUnionRect (frame, [screen frame]);
4690 return NSHeight (frame);
4694 x_display_pixel_width (struct ns_display_info *dpyinfo)
4696 NSArray *screens = [NSScreen screens];
4697 NSEnumerator *enumerator = [screens objectEnumerator];
4702 while ((screen = [enumerator nextObject]) != nil)
4703 frame = NSUnionRect (frame, [screen frame]);
4705 return NSWidth (frame);
4709 static Lisp_Object ns_string_to_lispmod (const char *s)
4710 /* --------------------------------------------------------------------------
4711 Convert modifier name to lisp symbol
4712 -------------------------------------------------------------------------- */
4714 if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4716 else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4718 else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4720 else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4722 else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4724 else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4732 ns_default (const char *parameter, Lisp_Object *result,
4733 Lisp_Object yesval, Lisp_Object noval,
4734 BOOL is_float, BOOL is_modstring)
4735 /* --------------------------------------------------------------------------
4736 Check a parameter value in user's preferences
4737 -------------------------------------------------------------------------- */
4739 const char *value = ns_get_defaults_value (parameter);
4745 if (c_strcasecmp (value, "YES") == 0)
4747 else if (c_strcasecmp (value, "NO") == 0)
4749 else if (is_float && (f = strtod (value, &pos), pos != value))
4750 *result = make_float (f);
4751 else if (is_modstring && value)
4752 *result = ns_string_to_lispmod (value);
4753 else fprintf (stderr,
4754 "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4760 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4761 /* --------------------------------------------------------------------------
4762 Initialize global info and storage for display.
4763 -------------------------------------------------------------------------- */
4765 NSScreen *screen = [NSScreen mainScreen];
4766 NSWindowDepth depth = [screen depth];
4768 dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4769 dpyinfo->resy = 72.27;
4770 dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4771 NSColorSpaceFromDepth (depth)]
4772 && ![NSCalibratedWhiteColorSpace isEqualToString:
4773 NSColorSpaceFromDepth (depth)];
4774 dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4775 dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4776 dpyinfo->color_table->colors = NULL;
4777 dpyinfo->root_window = 42; /* a placeholder.. */
4778 dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4779 dpyinfo->n_fonts = 0;
4780 dpyinfo->smallest_font_height = 1;
4781 dpyinfo->smallest_char_width = 1;
4783 reset_mouse_highlight (&dpyinfo->mouse_highlight);
4787 /* This and next define (many of the) public functions in this file. */
4788 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4789 with using despite presence in the "system dependent" redisplay
4790 interface. In addition, many of the ns_ methods have code that is
4791 shared with all terms, indicating need for further refactoring. */
4792 extern frame_parm_handler ns_frame_parm_handlers[];
4793 static struct redisplay_interface ns_redisplay_interface =
4795 ns_frame_parm_handlers,
4799 x_clear_end_of_line,
4801 ns_after_update_window_line,
4802 ns_update_window_begin,
4803 ns_update_window_end,
4804 0, /* flush_display */
4805 x_clear_window_mouse_face,
4806 x_get_glyph_overhangs,
4807 x_fix_overlapping_area,
4808 ns_draw_fringe_bitmap,
4809 0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4810 0, /* destroy_fringe_bitmap */
4811 ns_compute_glyph_string_overhangs,
4812 ns_draw_glyph_string,
4813 ns_define_frame_cursor,
4814 ns_clear_frame_area,
4815 ns_draw_window_cursor,
4816 ns_draw_vertical_window_border,
4817 ns_draw_window_divider,
4818 ns_shift_glyphs_for_insert,
4825 ns_delete_display (struct ns_display_info *dpyinfo)
4831 /* This function is called when the last frame on a display is deleted. */
4833 ns_delete_terminal (struct terminal *terminal)
4835 struct ns_display_info *dpyinfo = terminal->display_info.ns;
4837 NSTRACE ("ns_delete_terminal");
4839 /* Protect against recursive calls. delete_frame in
4840 delete_terminal calls us back when it deletes our last frame. */
4841 if (!terminal->name)
4846 x_destroy_all_bitmaps (dpyinfo);
4847 ns_delete_display (dpyinfo);
4852 static struct terminal *
4853 ns_create_terminal (struct ns_display_info *dpyinfo)
4854 /* --------------------------------------------------------------------------
4855 Set up use of NS before we make the first connection.
4856 -------------------------------------------------------------------------- */
4858 struct terminal *terminal;
4860 NSTRACE ("ns_create_terminal");
4862 terminal = create_terminal (output_ns, &ns_redisplay_interface);
4864 terminal->display_info.ns = dpyinfo;
4865 dpyinfo->terminal = terminal;
4867 terminal->clear_frame_hook = ns_clear_frame;
4868 terminal->ring_bell_hook = ns_ring_bell;
4869 terminal->update_begin_hook = ns_update_begin;
4870 terminal->update_end_hook = ns_update_end;
4871 terminal->read_socket_hook = ns_read_socket;
4872 terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4873 terminal->mouse_position_hook = ns_mouse_position;
4874 terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4875 terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4876 terminal->fullscreen_hook = ns_fullscreen_hook;
4877 terminal->menu_show_hook = ns_menu_show;
4878 terminal->popup_dialog_hook = ns_popup_dialog;
4879 terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4880 terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4881 terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4882 terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4883 terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4884 terminal->delete_frame_hook = x_destroy_window;
4885 terminal->delete_terminal_hook = ns_delete_terminal;
4886 /* Other hooks are NULL by default. */
4892 struct ns_display_info *
4893 ns_term_init (Lisp_Object display_name)
4894 /* --------------------------------------------------------------------------
4895 Start the Application and get things rolling.
4896 -------------------------------------------------------------------------- */
4898 struct terminal *terminal;
4899 struct ns_display_info *dpyinfo;
4900 static int ns_initialized = 0;
4903 if (ns_initialized) return x_display_list;
4908 NSTRACE ("ns_term_init");
4910 [outerpool release];
4911 outerpool = [[NSAutoreleasePool alloc] init];
4913 /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
4914 /*GSDebugAllocationActive (YES); */
4918 Fset_input_interrupt_mode (Qnil);
4920 if (selfds[0] == -1)
4922 if (emacs_pipe (selfds) != 0)
4924 fprintf (stderr, "Failed to create pipe: %s\n",
4925 emacs_strerror (errno));
4929 fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4930 FD_ZERO (&select_readfds);
4931 FD_ZERO (&select_writefds);
4932 pthread_mutex_init (&select_mutex, NULL);
4935 ns_pending_files = [[NSMutableArray alloc] init];
4936 ns_pending_service_names = [[NSMutableArray alloc] init];
4937 ns_pending_service_args = [[NSMutableArray alloc] init];
4939 /* Start app and create the main menu, window, view.
4940 Needs to be here because ns_initialize_display_info () uses AppKit classes.
4941 The view will then ask the NSApp to stop and return to Emacs. */
4942 [EmacsApp sharedApplication];
4945 [NSApp setDelegate: NSApp];
4947 /* Start the select thread. */
4948 [NSThread detachNewThreadSelector:@selector (fd_handler:)
4952 /* debugging: log all notifications */
4953 /* [[NSNotificationCenter defaultCenter] addObserver: NSApp
4954 selector: @selector (logNotification:)
4955 name: nil object: nil]; */
4957 dpyinfo = xzalloc (sizeof *dpyinfo);
4959 ns_initialize_display_info (dpyinfo);
4960 terminal = ns_create_terminal (dpyinfo);
4962 terminal->kboard = allocate_kboard (Qns);
4963 /* Don't let the initial kboard remain current longer than necessary.
4964 That would cause problems if a file loaded on startup tries to
4965 prompt in the mini-buffer. */
4966 if (current_kboard == initial_kboard)
4967 current_kboard = terminal->kboard;
4968 terminal->kboard->reference_count++;
4970 dpyinfo->next = x_display_list;
4971 x_display_list = dpyinfo;
4973 dpyinfo->name_list_element = Fcons (display_name, Qnil);
4975 terminal->name = xlispstrdup (display_name);
4979 if (!inhibit_x_resources)
4981 ns_default ("GSFontAntiAlias", &ns_antialias_text,
4984 /* this is a standard variable */
4985 ns_default ("AppleAntiAliasingThreshold", &tmp,
4986 make_float (10.0), make_float (6.0), YES, NO);
4987 ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
4990 NSTRACE_MSG ("Colors");
4993 NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4997 Lisp_Object color_file, color_map, color;
5001 color_file = Fexpand_file_name (build_string ("rgb.txt"),
5002 Fsymbol_value (intern ("data-directory")));
5004 color_map = Fx_load_color_file (color_file);
5005 if (NILP (color_map))
5006 fatal ("Could not read %s.\n", SDATA (color_file));
5008 cl = [[NSColorList alloc] initWithName: @"Emacs"];
5009 for ( ; CONSP (color_map); color_map = XCDR (color_map))
5011 color = XCAR (color_map);
5012 name = SSDATA (XCAR (color));
5013 c = XINT (XCDR (color));
5015 [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5016 green: GREEN_FROM_ULONG (c) / 255.0
5017 blue: BLUE_FROM_ULONG (c) / 255.0
5019 forKey: [NSString stringWithUTF8String: name]];
5021 [cl writeToFile: nil];
5025 NSTRACE_MSG ("Versions");
5028 #ifdef NS_IMPL_GNUSTEP
5029 Vwindow_system_version = build_string (gnustep_base_version);
5031 /*PSnextrelease (128, c); */
5032 char c[DBL_BUFSIZE_BOUND];
5033 int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5034 Vwindow_system_version = make_unibyte_string (c, len);
5038 delete_keyboard_wait_descriptor (0);
5040 ns_app_name = [[NSProcessInfo processInfo] processName];
5042 /* Set up macOS app menu */
5044 NSTRACE_MSG ("Menu init");
5046 #ifdef NS_IMPL_COCOA
5050 /* set up the application menu */
5051 svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5052 [svcsMenu setAutoenablesItems: NO];
5053 appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5054 [appMenu setAutoenablesItems: NO];
5055 mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5056 dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5058 [appMenu insertItemWithTitle: @"About Emacs"
5059 action: @selector (orderFrontStandardAboutPanel:)
5062 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5063 [appMenu insertItemWithTitle: @"Preferences..."
5064 action: @selector (showPreferencesWindow:)
5067 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5068 item = [appMenu insertItemWithTitle: @"Services"
5069 action: @selector (menuDown:)
5072 [appMenu setSubmenu: svcsMenu forItem: item];
5073 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5074 [appMenu insertItemWithTitle: @"Hide Emacs"
5075 action: @selector (hide:)
5078 item = [appMenu insertItemWithTitle: @"Hide Others"
5079 action: @selector (hideOtherApplications:)
5082 [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5083 [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5084 [appMenu insertItemWithTitle: @"Quit Emacs"
5085 action: @selector (terminate:)
5089 item = [mainMenu insertItemWithTitle: ns_app_name
5090 action: @selector (menuDown:)
5093 [mainMenu setSubmenu: appMenu forItem: item];
5094 [dockMenu insertItemWithTitle: @"New Frame"
5095 action: @selector (newFrame:)
5099 [NSApp setMainMenu: mainMenu];
5100 [NSApp setAppleMenu: appMenu];
5101 [NSApp setServicesMenu: svcsMenu];
5102 /* Needed at least on Cocoa, to get dock menu to show windows */
5103 [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5105 [[NSNotificationCenter defaultCenter]
5106 addObserver: mainMenu
5107 selector: @selector (trackingNotification:)
5108 name: NSMenuDidBeginTrackingNotification object: mainMenu];
5109 [[NSNotificationCenter defaultCenter]
5110 addObserver: mainMenu
5111 selector: @selector (trackingNotification:)
5112 name: NSMenuDidEndTrackingNotification object: mainMenu];
5114 #endif /* macOS menu setup */
5116 /* Register our external input/output types, used for determining
5117 applicable services and also drag/drop eligibility. */
5119 NSTRACE_MSG ("Input/output types");
5121 ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5122 ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5124 ns_drag_types = [[NSArray arrayWithObjects:
5126 NSTabularTextPboardType,
5127 NSFilenamesPboardType,
5128 NSURLPboardType, nil] retain];
5130 /* If fullscreen is in init/default-frame-alist, focus isn't set
5131 right for fullscreen windows, so set this. */
5132 [NSApp activateIgnoringOtherApps:YES];
5134 NSTRACE_MSG ("Call NSApp run");
5137 ns_do_open_file = YES;
5139 #ifdef NS_IMPL_GNUSTEP
5140 /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5141 We must re-catch it so subprocess works. */
5142 catch_child_signal ();
5145 NSTRACE_MSG ("ns_term_init done");
5154 ns_term_shutdown (int sig)
5156 [[NSUserDefaults standardUserDefaults] synchronize];
5158 /* code not reached in emacs.c after this is called by shut_down_emacs: */
5159 if (STRINGP (Vauto_save_list_file_name))
5160 unlink (SSDATA (Vauto_save_list_file_name));
5162 if (sig == 0 || sig == SIGTERM)
5164 [NSApp terminate: NSApp];
5166 else // force a stack trace to happen
5173 /* ==========================================================================
5175 EmacsApp implementation
5177 ========================================================================== */
5180 @implementation EmacsApp
5184 NSTRACE ("[EmacsApp init]");
5186 if ((self = [super init]))
5188 #ifdef NS_IMPL_COCOA
5189 self->isFirst = YES;
5191 #ifdef NS_IMPL_GNUSTEP
5192 self->applicationDidFinishLaunchingCalled = NO;
5199 #ifdef NS_IMPL_COCOA
5202 NSTRACE ("[EmacsApp run]");
5204 #ifndef NSAppKitVersionNumber10_9
5205 #define NSAppKitVersionNumber10_9 1265
5208 if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5214 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5216 if (isFirst) [self finishLaunching];
5219 shouldKeepRunning = YES;
5223 pool = [[NSAutoreleasePool alloc] init];
5226 [self nextEventMatchingMask:NSEventMaskAny
5227 untilDate:[NSDate distantFuture]
5228 inMode:NSDefaultRunLoopMode
5231 [self sendEvent:event];
5232 [self updateWindows];
5233 } while (shouldKeepRunning);
5238 - (void)stop: (id)sender
5240 NSTRACE ("[EmacsApp stop:]");
5242 shouldKeepRunning = NO;
5243 // Stop possible dialog also. Noop if no dialog present.
5244 // The file dialog still leaks 7k - 10k on 10.9 though.
5245 [super stop:sender];
5247 #endif /* NS_IMPL_COCOA */
5249 - (void)logNotification: (NSNotification *)notification
5251 NSTRACE ("[EmacsApp logNotification:]");
5253 const char *name = [[notification name] UTF8String];
5254 if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5255 && !strstr (name, "WindowNumber"))
5256 NSLog (@"notification: '%@'", [notification name]);
5260 - (void)sendEvent: (NSEvent *)theEvent
5261 /* --------------------------------------------------------------------------
5262 Called when NSApp is running for each event received. Used to stop
5263 the loop when we choose, since there's no way to just run one iteration.
5264 -------------------------------------------------------------------------- */
5266 int type = [theEvent type];
5267 NSWindow *window = [theEvent window];
5269 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5270 NSTRACE_MSG ("Type: %d", type);
5272 #ifdef NS_IMPL_GNUSTEP
5273 // Keyboard events aren't propagated to file dialogs for some reason.
5274 if ([NSApp modalWindow] != nil &&
5275 (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5277 [[NSApp modalWindow] sendEvent: theEvent];
5282 if (represented_filename != nil && represented_frame)
5284 NSString *fstr = represented_filename;
5285 NSView *view = FRAME_NS_VIEW (represented_frame);
5286 #ifdef NS_IMPL_COCOA
5287 /* work around a bug observed on 10.3 and later where
5288 setTitleWithRepresentedFilename does not clear out previous state
5289 if given filename does not exist */
5290 if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5291 [[view window] setRepresentedFilename: @""];
5293 [[view window] setRepresentedFilename: fstr];
5294 [represented_filename release];
5295 represented_filename = nil;
5296 represented_frame = NULL;
5299 if (type == NSEventTypeApplicationDefined)
5301 switch ([theEvent data2])
5303 #ifdef NS_IMPL_COCOA
5304 case NSAPP_DATA2_RUNASSCRIPT:
5309 case NSAPP_DATA2_RUNFILEDIALOG:
5310 ns_run_file_dialog ();
5316 if (type == NSEventTypeCursorUpdate && window == nil)
5318 fprintf (stderr, "Dropping external cursor update event.\n");
5322 if (type == NSEventTypeApplicationDefined)
5324 /* Events posted by ns_send_appdefined interrupt the run loop here.
5325 But, if a modal window is up, an appdefined can still come through,
5326 (e.g., from a makeKeyWindow event) but stopping self also stops the
5327 modal loop. Just defer it until later. */
5328 if ([NSApp modalWindow] == nil)
5330 last_appdefined_event_data = [theEvent data1];
5335 send_appdefined = YES;
5340 #ifdef NS_IMPL_COCOA
5341 /* If no dialog and none of our frames have focus and it is a move, skip it.
5342 It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5343 such as Wifi, sound, date or similar.
5344 This prevents "spooky" highlighting in the frame under the menu. */
5345 if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5347 struct ns_display_info *di;
5348 BOOL has_focus = NO;
5349 for (di = x_display_list; ! has_focus && di; di = di->next)
5350 has_focus = di->x_focus_frame != 0;
5356 NSTRACE_UNSILENCE();
5358 [super sendEvent: theEvent];
5362 - (void)showPreferencesWindow: (id)sender
5364 struct frame *emacsframe = SELECTED_FRAME ();
5365 NSEvent *theEvent = [NSApp currentEvent];
5369 emacs_event->kind = NS_NONKEY_EVENT;
5370 emacs_event->code = KEY_NS_SHOW_PREFS;
5371 emacs_event->modifiers = 0;
5372 EV_TRAILER (theEvent);
5376 - (void)newFrame: (id)sender
5378 NSTRACE ("[EmacsApp newFrame:]");
5380 struct frame *emacsframe = SELECTED_FRAME ();
5381 NSEvent *theEvent = [NSApp currentEvent];
5385 emacs_event->kind = NS_NONKEY_EVENT;
5386 emacs_event->code = KEY_NS_NEW_FRAME;
5387 emacs_event->modifiers = 0;
5388 EV_TRAILER (theEvent);
5392 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5393 - (BOOL) openFile: (NSString *)fileName
5395 NSTRACE ("[EmacsApp openFile:]");
5397 struct frame *emacsframe = SELECTED_FRAME ();
5398 NSEvent *theEvent = [NSApp currentEvent];
5403 emacs_event->kind = NS_NONKEY_EVENT;
5404 emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5405 ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5406 ns_input_line = Qnil; /* can be start or cons start,end */
5407 emacs_event->modifiers =0;
5408 EV_TRAILER (theEvent);
5414 /* **************************************************************************
5416 EmacsApp delegate implementation
5418 ************************************************************************** */
5420 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5421 /* --------------------------------------------------------------------------
5422 When application is loaded, terminate event loop in ns_term_init
5423 -------------------------------------------------------------------------- */
5425 NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5427 #ifdef NS_IMPL_GNUSTEP
5428 ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5430 [NSApp setServicesProvider: NSApp];
5432 [self antialiasThresholdDidChange:nil];
5433 #ifdef NS_IMPL_COCOA
5434 [[NSNotificationCenter defaultCenter]
5436 selector:@selector(antialiasThresholdDidChange:)
5437 name:NSAntialiasThresholdChangedNotification
5441 ns_send_appdefined (-2);
5444 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5446 #ifdef NS_IMPL_COCOA
5447 macfont_update_antialias_threshold ();
5452 /* Termination sequences:
5455 MenuBar | File | Exit:
5456 Select Quit from App menubar:
5458 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5461 Select Quit from Dock menu:
5464 Cancel -> Nothing else
5468 KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5473 - (void) terminate: (id)sender
5475 NSTRACE ("[EmacsApp terminate:]");
5477 struct frame *emacsframe = SELECTED_FRAME ();
5482 emacs_event->kind = NS_NONKEY_EVENT;
5483 emacs_event->code = KEY_NS_POWER_OFF;
5484 emacs_event->arg = Qt; /* mark as non-key event */
5485 EV_TRAILER ((id)nil);
5489 runAlertPanel(NSString *title,
5490 NSString *msgFormat,
5491 NSString *defaultButton,
5492 NSString *alternateButton)
5494 #if !defined (NS_IMPL_COCOA) || \
5495 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5496 return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5497 == NSAlertDefaultReturn;
5499 NSAlert *alert = [[NSAlert alloc] init];
5500 [alert setAlertStyle: NSAlertStyleCritical];
5501 [alert setMessageText: msgFormat];
5502 [alert addButtonWithTitle: defaultButton];
5503 [alert addButtonWithTitle: alternateButton];
5504 NSInteger ret = [alert runModal];
5506 return ret == NSAlertFirstButtonReturn;
5511 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5513 NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5517 if (NILP (ns_confirm_quit)) // || ns_shutdown_properly --> TO DO
5518 return NSTerminateNow;
5520 ret = runAlertPanel(ns_app_name,
5521 @"Exit requested. Would you like to Save Buffers and Exit, or Cancel the request?",
5522 @"Save Buffers and Exit", @"Cancel");
5524 return ret ? NSTerminateNow : NSTerminateCancel;
5528 not_in_argv (NSString *arg)
5531 const char *a = [arg UTF8String];
5532 for (k = 1; k < initial_argc; ++k)
5533 if (strcmp (a, initial_argv[k]) == 0) return 0;
5537 /* Notification from the Workspace to open a file */
5538 - (BOOL)application: sender openFile: (NSString *)file
5540 if (ns_do_open_file || not_in_argv (file))
5541 [ns_pending_files addObject: file];
5546 /* Open a file as a temporary file */
5547 - (BOOL)application: sender openTempFile: (NSString *)file
5549 if (ns_do_open_file || not_in_argv (file))
5550 [ns_pending_files addObject: file];
5555 /* Notification from the Workspace to open a file noninteractively (?) */
5556 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5558 if (ns_do_open_file || not_in_argv (file))
5559 [ns_pending_files addObject: file];
5563 /* Notification from the Workspace to open multiple files */
5564 - (void)application: sender openFiles: (NSArray *)fileList
5566 NSEnumerator *files = [fileList objectEnumerator];
5568 /* Don't open files from the command line unconditionally,
5569 Cocoa parses the command line wrong, --option value tries to open value
5570 if --option is the last option. */
5571 while ((file = [files nextObject]) != nil)
5572 if (ns_do_open_file || not_in_argv (file))
5573 [ns_pending_files addObject: file];
5575 [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5580 /* Handle dock menu requests. */
5581 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5587 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5588 - (void)applicationWillBecomeActive: (NSNotification *)notification
5590 NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5591 //ns_app_active=YES;
5594 - (void)applicationDidBecomeActive: (NSNotification *)notification
5596 NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5598 #ifdef NS_IMPL_GNUSTEP
5599 if (! applicationDidFinishLaunchingCalled)
5600 [self applicationDidFinishLaunching:notification];
5602 //ns_app_active=YES;
5604 ns_update_auto_hide_menu_bar ();
5605 // No constraining takes place when the application is not active.
5606 ns_constrain_all_frames ();
5608 - (void)applicationDidResignActive: (NSNotification *)notification
5610 NSTRACE ("[EmacsApp applicationDidResignActive:]");
5613 ns_send_appdefined (-1);
5618 /* ==========================================================================
5620 EmacsApp aux handlers for managing event loop
5622 ========================================================================== */
5625 - (void)timeout_handler: (NSTimer *)timedEntry
5626 /* --------------------------------------------------------------------------
5627 The timeout specified to ns_select has passed.
5628 -------------------------------------------------------------------------- */
5630 /*NSTRACE ("timeout_handler"); */
5631 ns_send_appdefined (-2);
5634 - (void)sendFromMainThread:(id)unused
5636 ns_send_appdefined (nextappdefined);
5639 - (void)fd_handler:(id)unused
5640 /* --------------------------------------------------------------------------
5641 Check data waiting on file descriptors and terminate if so
5642 -------------------------------------------------------------------------- */
5645 int waiting = 1, nfds;
5648 fd_set readfds, writefds, *wfds;
5649 struct timespec timeout, *tmo;
5650 NSAutoreleasePool *pool = nil;
5652 /* NSTRACE ("fd_handler"); */
5657 pool = [[NSAutoreleasePool alloc] init];
5663 FD_SET (selfds[0], &fds);
5664 result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5665 if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5670 pthread_mutex_lock (&select_mutex);
5673 if (select_valid & SELECT_HAVE_READ)
5674 readfds = select_readfds;
5678 if (select_valid & SELECT_HAVE_WRITE)
5680 writefds = select_writefds;
5685 if (select_valid & SELECT_HAVE_TMO)
5687 timeout = select_timeout;
5693 pthread_mutex_unlock (&select_mutex);
5695 FD_SET (selfds[0], &readfds);
5696 if (selfds[0] >= nfds) nfds = selfds[0]+1;
5698 result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5701 ns_send_appdefined (-2);
5702 else if (result > 0)
5704 if (FD_ISSET (selfds[0], &readfds))
5706 if (read (selfds[0], &c, 1) == 1 && c == 's')
5711 pthread_mutex_lock (&select_mutex);
5712 if (select_valid & SELECT_HAVE_READ)
5713 select_readfds = readfds;
5714 if (select_valid & SELECT_HAVE_WRITE)
5715 select_writefds = writefds;
5716 if (select_valid & SELECT_HAVE_TMO)
5717 select_timeout = timeout;
5718 pthread_mutex_unlock (&select_mutex);
5720 ns_send_appdefined (result);
5730 /* ==========================================================================
5734 ========================================================================== */
5736 /* called from system: queue for next pass through event loop */
5737 - (void)requestService: (NSPasteboard *)pboard
5738 userData: (NSString *)userData
5739 error: (NSString **)error
5741 [ns_pending_service_names addObject: userData];
5742 [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5743 SSDATA (ns_string_from_pasteboard (pboard))]];
5747 /* called from ns_read_socket to clear queue */
5748 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5750 struct frame *emacsframe = SELECTED_FRAME ();
5751 NSEvent *theEvent = [NSApp currentEvent];
5753 NSTRACE ("[EmacsApp fulfillService:withArg:]");
5758 emacs_event->kind = NS_NONKEY_EVENT;
5759 emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5760 ns_input_spi_name = build_string ([name UTF8String]);
5761 ns_input_spi_arg = build_string ([arg UTF8String]);
5762 emacs_event->modifiers = EV_MODIFIERS (theEvent);
5763 EV_TRAILER (theEvent);
5773 /* ==========================================================================
5775 EmacsView implementation
5777 ========================================================================== */
5780 @implementation EmacsView
5782 /* needed to inform when window closed from LISP */
5783 - (void) setWindowClosing: (BOOL)closing
5785 NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5787 windowClosing = closing;
5793 NSTRACE ("[EmacsView dealloc]");
5795 if (fs_state == FULLSCREEN_BOTH)
5796 [nonfs_window release];
5801 /* called on font panel selection */
5802 - (void)changeFont: (id)sender
5804 NSEvent *e = [[self window] currentEvent];
5805 struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5806 struct font *font = face->font;
5811 NSTRACE ("[EmacsView changeFont:]");
5816 #ifdef NS_IMPL_GNUSTEP
5817 nsfont = ((struct nsfont_info *)font)->nsfont;
5819 #ifdef NS_IMPL_COCOA
5820 nsfont = (NSFont *) macfont_get_nsctfont (font);
5823 if ((newFont = [sender convertFont: nsfont]))
5825 SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5827 emacs_event->kind = NS_NONKEY_EVENT;
5828 emacs_event->modifiers = 0;
5829 emacs_event->code = KEY_NS_CHANGE_FONT;
5831 size = [newFont pointSize];
5832 ns_input_fontsize = make_number (lrint (size));
5833 ns_input_font = build_string ([[newFont familyName] UTF8String]);
5839 - (BOOL)acceptsFirstResponder
5841 NSTRACE ("[EmacsView acceptsFirstResponder]");
5846 - (void)resetCursorRects
5848 NSRect visible = [self visibleRect];
5849 NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5850 NSTRACE ("[EmacsView resetCursorRects]");
5852 if (currentCursor == nil)
5853 currentCursor = [NSCursor arrowCursor];
5855 if (!NSIsEmptyRect (visible))
5856 [self addCursorRect: visible cursor: currentCursor];
5857 [currentCursor setOnMouseEntered: YES];
5862 /*****************************************************************************/
5863 /* Keyboard handling. */
5866 - (void)keyDown: (NSEvent *)theEvent
5868 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5870 unsigned fnKeysym = 0;
5871 static NSMutableArray *nsEvArray;
5873 unsigned int flags = [theEvent modifierFlags];
5875 NSTRACE ("[EmacsView keyDown:]");
5877 /* Rhapsody and macOS give up and down events for the arrow keys */
5878 if (ns_fake_keydown == YES)
5879 ns_fake_keydown = NO;
5880 else if ([theEvent type] != NSEventTypeKeyDown)
5886 if (![[self window] isKeyWindow]
5887 && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5888 /* we must avoid an infinite loop here. */
5889 && (EmacsView *)[[theEvent window] delegate] != self)
5891 /* XXX: There is an occasional condition in which, when Emacs display
5892 updates a different frame from the current one, and temporarily
5893 selects it, then processes some interrupt-driven input
5894 (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5895 for some reason that window has its first responder set to the NSView
5896 most recently updated (I guess), which is not the correct one. */
5897 [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5901 if (nsEvArray == nil)
5902 nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5904 [NSCursor setHiddenUntilMouseMoves: YES];
5906 if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5908 clear_mouse_face (hlinfo);
5909 hlinfo->mouse_face_hidden = 1;
5912 if (!processingCompose)
5914 /* When using screen sharing, no left or right information is sent,
5915 so use Left key in those cases. */
5916 int is_left_key, is_right_key;
5918 code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5919 0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5921 /* (Carbon way: [theEvent keyCode]) */
5923 /* is it a "function key"? */
5924 /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
5925 flag set (this is probably a bug in the OS).
5927 if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
5929 fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
5933 fnKeysym = ns_convert_key (code);
5938 /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5939 because Emacs treats Delete and KP-Delete same (in simple.el). */
5940 if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5941 #ifdef NS_IMPL_GNUSTEP
5942 /* GNUstep uses incompatible keycodes, even for those that are
5943 supposed to be hardware independent. Just check for delete.
5944 Keypad delete does not have keysym 0xFFFF.
5945 See http://savannah.gnu.org/bugs/?25395
5947 || (fnKeysym == 0xFFFF && code == 127)
5950 code = 0xFF08; /* backspace */
5955 /* are there modifiers? */
5956 emacs_event->modifiers = 0;
5958 if (flags & NSEventModifierFlagHelp)
5959 emacs_event->modifiers |= hyper_modifier;
5961 if (flags & NSEventModifierFlagShift)
5962 emacs_event->modifiers |= shift_modifier;
5964 is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5965 is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5966 || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
5969 emacs_event->modifiers |= parse_solitary_modifier
5970 (EQ (ns_right_command_modifier, Qleft)
5971 ? ns_command_modifier
5972 : ns_right_command_modifier);
5976 emacs_event->modifiers |= parse_solitary_modifier
5977 (ns_command_modifier);
5979 /* if super (default), take input manager's word so things like
5980 dvorak / qwerty layout work */
5981 if (EQ (ns_command_modifier, Qsuper)
5983 && [[theEvent characters] length] != 0)
5985 /* XXX: the code we get will be unshifted, so if we have
5986 a shift modifier, must convert ourselves */
5987 if (!(flags & NSEventModifierFlagShift))
5988 code = [[theEvent characters] characterAtIndex: 0];
5990 /* this is ugly and also requires linking w/Carbon framework
5991 (for LMGetKbdType) so for now leave this rare (?) case
5992 undealt with.. in future look into CGEvent methods */
5995 long smv = GetScriptManagerVariable (smKeyScript);
5996 Handle uchrHandle = GetResource
5997 ('uchr', GetScriptVariable (smv, smScriptKeys));
5999 UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6000 [[theEvent characters] characterAtIndex: 0],
6001 kUCKeyActionDisplay,
6002 (flags & ~NSEventModifierFlagCommand) >> 8,
6003 LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6004 &dummy, 1, &dummy, &code);
6011 is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6012 is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6013 || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6016 emacs_event->modifiers |= parse_solitary_modifier
6017 (EQ (ns_right_control_modifier, Qleft)
6018 ? ns_control_modifier
6019 : ns_right_control_modifier);
6022 emacs_event->modifiers |= parse_solitary_modifier
6023 (ns_control_modifier);
6025 if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6026 emacs_event->modifiers |=
6027 parse_solitary_modifier (ns_function_modifier);
6029 left_is_none = NILP (ns_alternate_modifier)
6030 || EQ (ns_alternate_modifier, Qnone);
6032 is_right_key = (flags & NSRightAlternateKeyMask)
6033 == NSRightAlternateKeyMask;
6034 is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6036 && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6040 if ((NILP (ns_right_alternate_modifier)
6041 || EQ (ns_right_alternate_modifier, Qnone)
6042 || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6044 { /* accept pre-interp alt comb */
6045 if ([[theEvent characters] length] > 0)
6046 code = [[theEvent characters] characterAtIndex: 0];
6047 /*HACK: clear lone shift modifier to stop next if from firing */
6048 if (emacs_event->modifiers == shift_modifier)
6049 emacs_event->modifiers = 0;
6052 emacs_event->modifiers |= parse_solitary_modifier
6053 (EQ (ns_right_alternate_modifier, Qleft)
6054 ? ns_alternate_modifier
6055 : ns_right_alternate_modifier);
6058 if (is_left_key) /* default = meta */
6060 if (left_is_none && !fnKeysym)
6061 { /* accept pre-interp alt comb */
6062 if ([[theEvent characters] length] > 0)
6063 code = [[theEvent characters] characterAtIndex: 0];
6064 /*HACK: clear lone shift modifier to stop next if from firing */
6065 if (emacs_event->modifiers == shift_modifier)
6066 emacs_event->modifiers = 0;
6069 emacs_event->modifiers |=
6070 parse_solitary_modifier (ns_alternate_modifier);
6074 fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6075 (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6077 /* if it was a function key or had modifiers, pass it directly to emacs */
6078 if (fnKeysym || (emacs_event->modifiers
6079 && (emacs_event->modifiers != shift_modifier)
6080 && [[theEvent charactersIgnoringModifiers] length] > 0))
6081 /*[[theEvent characters] length] */
6083 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6085 code |= (1<<28)|(3<<16);
6086 else if (code == 0x7f)
6087 code |= (1<<28)|(3<<16);
6089 emacs_event->kind = code > 0xFF
6090 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6092 emacs_event->code = code;
6093 EV_TRAILER (theEvent);
6094 processingCompose = NO;
6100 if (NS_KEYLOG && !processingCompose)
6101 fprintf (stderr, "keyDown: Begin compose sequence.\n");
6103 processingCompose = YES;
6104 [nsEvArray addObject: theEvent];
6105 [self interpretKeyEvents: nsEvArray];
6106 [nsEvArray removeObject: theEvent];
6110 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6113 /* <NSTextInput>: called when done composing;
6114 NOTE: also called when we delete over working text, followed immed.
6115 by doCommandBySelector: deleteBackward: */
6116 - (void)insertText: (id)aString
6119 int len = [(NSString *)aString length];
6122 NSTRACE ("[EmacsView insertText:]");
6125 NSLog (@"insertText '%@'\tlen = %d", aString, len);
6126 processingCompose = NO;
6131 /* first, clear any working text */
6132 if (workingText != nil)
6133 [self deleteWorkingText];
6135 /* now insert the string as keystrokes */
6136 for (i =0; i<len; i++)
6138 code = [aString characterAtIndex: i];
6139 /* TODO: still need this? */
6141 code = '~'; /* 0x7E */
6142 if (code != 32) /* Space */
6143 emacs_event->modifiers = 0;
6145 = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6146 emacs_event->code = code;
6147 EV_TRAILER ((id)nil);
6152 /* <NSTextInput>: inserts display of composing characters */
6153 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6155 NSString *str = [aString respondsToSelector: @selector (string)] ?
6156 [aString string] : aString;
6158 NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6161 NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6162 str, (unsigned long)[str length],
6163 (unsigned long)selRange.length,
6164 (unsigned long)selRange.location);
6166 if (workingText != nil)
6167 [self deleteWorkingText];
6168 if ([str length] == 0)
6174 processingCompose = YES;
6175 workingText = [str copy];
6176 ns_working_text = build_string ([workingText UTF8String]);
6178 emacs_event->kind = NS_TEXT_EVENT;
6179 emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6180 EV_TRAILER ((id)nil);
6184 /* delete display of composing characters [not in <NSTextInput>] */
6185 - (void)deleteWorkingText
6187 NSTRACE ("[EmacsView deleteWorkingText]");
6189 if (workingText == nil)
6192 NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6193 [workingText release];
6195 processingCompose = NO;
6200 emacs_event->kind = NS_TEXT_EVENT;
6201 emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6202 EV_TRAILER ((id)nil);
6206 - (BOOL)hasMarkedText
6208 NSTRACE ("[EmacsView hasMarkedText]");
6210 return workingText != nil;
6214 - (NSRange)markedRange
6216 NSTRACE ("[EmacsView markedRange]");
6218 NSRange rng = workingText != nil
6219 ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6221 NSLog (@"markedRange request");
6228 NSTRACE ("[EmacsView unmarkText]");
6231 NSLog (@"unmark (accept) text");
6232 [self deleteWorkingText];
6233 processingCompose = NO;
6237 /* used to position char selection windows, etc. */
6238 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6242 struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6244 NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6247 NSLog (@"firstRectForCharRange request");
6249 rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6250 rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6251 pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6252 pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6253 +FRAME_LINE_HEIGHT (emacsframe));
6255 pt = [self convertPoint: pt toView: nil];
6256 #if !defined (NS_IMPL_COCOA) || \
6257 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
6258 pt = [[self window] convertBaseToScreen: pt];
6262 rect = [[self window] convertRectToScreen: rect];
6268 - (NSInteger)conversationIdentifier
6270 return (NSInteger)self;
6274 - (void)doCommandBySelector: (SEL)aSelector
6276 NSTRACE ("[EmacsView doCommandBySelector:]");
6279 NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6281 processingCompose = NO;
6282 if (aSelector == @selector (deleteBackward:))
6284 /* happens when user backspaces over an ongoing composition:
6285 throw a 'delete' into the event queue */
6288 emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6289 emacs_event->code = 0xFF08;
6290 EV_TRAILER ((id)nil);
6294 - (NSArray *)validAttributesForMarkedText
6296 static NSArray *arr = nil;
6297 if (arr == nil) arr = [NSArray new];
6298 /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6302 - (NSRange)selectedRange
6305 NSLog (@"selectedRange request");
6306 return NSMakeRange (NSNotFound, 0);
6309 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6310 GNUSTEP_GUI_MINOR_VERSION > 22
6311 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6313 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6317 NSLog (@"characterIndexForPoint request");
6321 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6323 static NSAttributedString *str = nil;
6324 if (str == nil) str = [NSAttributedString new];
6326 NSLog (@"attributedSubstringFromRange request");
6330 /* End <NSTextInput> impl. */
6331 /*****************************************************************************/
6334 /* This is what happens when the user presses a mouse button. */
6335 - (void)mouseDown: (NSEvent *)theEvent
6337 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6338 NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6340 NSTRACE ("[EmacsView mouseDown:]");
6342 [self deleteWorkingText];
6347 dpyinfo->last_mouse_frame = emacsframe;
6348 /* appears to be needed to prevent spurious movement events generated on
6350 emacsframe->mouse_moved = 0;
6352 if ([theEvent type] == NSEventTypeScrollWheel)
6354 CGFloat delta = [theEvent deltaY];
6355 /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6358 delta = [theEvent deltaX];
6361 NSTRACE_MSG ("deltaIsZero");
6364 emacs_event->kind = HORIZ_WHEEL_EVENT;
6367 emacs_event->kind = WHEEL_EVENT;
6369 emacs_event->code = 0;
6370 emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6371 ((delta > 0) ? up_modifier : down_modifier);
6375 emacs_event->kind = MOUSE_CLICK_EVENT;
6376 emacs_event->code = EV_BUTTON (theEvent);
6377 emacs_event->modifiers = EV_MODIFIERS (theEvent)
6378 | EV_UDMODIFIERS (theEvent);
6380 XSETINT (emacs_event->x, lrint (p.x));
6381 XSETINT (emacs_event->y, lrint (p.y));
6382 EV_TRAILER (theEvent);
6386 - (void)rightMouseDown: (NSEvent *)theEvent
6388 NSTRACE ("[EmacsView rightMouseDown:]");
6389 [self mouseDown: theEvent];
6393 - (void)otherMouseDown: (NSEvent *)theEvent
6395 NSTRACE ("[EmacsView otherMouseDown:]");
6396 [self mouseDown: theEvent];
6400 - (void)mouseUp: (NSEvent *)theEvent
6402 NSTRACE ("[EmacsView mouseUp:]");
6403 [self mouseDown: theEvent];
6407 - (void)rightMouseUp: (NSEvent *)theEvent
6409 NSTRACE ("[EmacsView rightMouseUp:]");
6410 [self mouseDown: theEvent];
6414 - (void)otherMouseUp: (NSEvent *)theEvent
6416 NSTRACE ("[EmacsView otherMouseUp:]");
6417 [self mouseDown: theEvent];
6421 - (void) scrollWheel: (NSEvent *)theEvent
6423 NSTRACE ("[EmacsView scrollWheel:]");
6424 [self mouseDown: theEvent];
6428 /* Tell emacs the mouse has moved. */
6429 - (void)mouseMoved: (NSEvent *)e
6431 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6432 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6436 NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6438 dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6439 pt = [self convertPoint: [e locationInWindow] fromView: nil];
6440 dpyinfo->last_mouse_motion_x = pt.x;
6441 dpyinfo->last_mouse_motion_y = pt.y;
6443 /* update any mouse face */
6444 if (hlinfo->mouse_face_hidden)
6446 hlinfo->mouse_face_hidden = 0;
6447 clear_mouse_face (hlinfo);
6450 /* tooltip handling */
6451 previous_help_echo_string = help_echo_string;
6452 help_echo_string = Qnil;
6454 if (!NILP (Vmouse_autoselect_window))
6456 NSTRACE_MSG ("mouse_autoselect_window");
6457 static Lisp_Object last_mouse_window;
6459 = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6461 if (WINDOWP (window)
6462 && !EQ (window, last_mouse_window)
6463 && !EQ (window, selected_window)
6464 && (!NILP (focus_follows_mouse)
6465 || (EQ (XWINDOW (window)->frame,
6466 XWINDOW (selected_window)->frame))))
6468 NSTRACE_MSG ("in_window");
6469 emacs_event->kind = SELECT_WINDOW_EVENT;
6470 emacs_event->frame_or_window = window;
6473 /* Remember the last window where we saw the mouse. */
6474 last_mouse_window = window;
6477 if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6478 help_echo_string = previous_help_echo_string;
6480 XSETFRAME (frame, emacsframe);
6481 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6483 /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6484 (note_mouse_highlight), which is called through the
6485 note_mouse_movement () call above */
6486 any_help_event_p = YES;
6487 gen_help_event (help_echo_string, frame, help_echo_window,
6488 help_echo_object, help_echo_pos);
6491 if (emacsframe->mouse_moved && send_appdefined)
6492 ns_send_appdefined (-1);
6496 - (void)mouseDragged: (NSEvent *)e
6498 NSTRACE ("[EmacsView mouseDragged:]");
6499 [self mouseMoved: e];
6503 - (void)rightMouseDragged: (NSEvent *)e
6505 NSTRACE ("[EmacsView rightMouseDragged:]");
6506 [self mouseMoved: e];
6510 - (void)otherMouseDragged: (NSEvent *)e
6512 NSTRACE ("[EmacsView otherMouseDragged:]");
6513 [self mouseMoved: e];
6517 - (BOOL)windowShouldClose: (id)sender
6519 NSEvent *e =[[self window] currentEvent];
6521 NSTRACE ("[EmacsView windowShouldClose:]");
6522 windowClosing = YES;
6525 emacs_event->kind = DELETE_WINDOW_EVENT;
6526 emacs_event->modifiers = 0;
6527 emacs_event->code = 0;
6529 /* Don't close this window, let this be done from lisp code. */
6533 - (void) updateFrameSize: (BOOL) delay
6535 NSWindow *window = [self window];
6536 NSRect wr = [window frame];
6538 int oldc = cols, oldr = rows;
6539 int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6540 int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6543 NSTRACE ("[EmacsView updateFrameSize:]");
6544 NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6545 NSTRACE_RECT ("Original frame", wr);
6546 NSTRACE_MSG ("Original columns: %d", cols);
6547 NSTRACE_MSG ("Original rows: %d", rows);
6549 if (! [self isFullscreen])
6551 #ifdef NS_IMPL_GNUSTEP
6552 // GNUstep does not always update the tool bar height. Force it.
6553 if (toolbar && [toolbar isVisible])
6554 update_frame_tool_bar (emacsframe);
6557 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6558 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6561 if (wait_for_tool_bar)
6563 if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6565 NSTRACE_MSG ("Waiting for toolbar");
6568 wait_for_tool_bar = NO;
6571 neww = (int)wr.size.width - emacsframe->border_width;
6572 newh = (int)wr.size.height - extra;
6574 NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6575 NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6576 NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6578 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6579 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6581 if (cols < MINWIDTH)
6584 if (rows < MINHEIGHT)
6587 NSTRACE_MSG ("New columns: %d", cols);
6588 NSTRACE_MSG ("New rows: %d", rows);
6590 if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6592 NSView *view = FRAME_NS_VIEW (emacsframe);
6594 change_frame_size (emacsframe,
6595 FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6596 FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6598 SET_FRAME_GARBAGED (emacsframe);
6599 cancel_mouse_face (emacsframe);
6601 /* The next two lines appear to be setting the frame to the same
6602 size as it already is. Why are they there? */
6603 // wr = NSMakeRect (0, 0, neww, newh);
6605 // [view setFrame: wr];
6607 // to do: consider using [NSNotificationCenter postNotificationName:].
6608 [self windowDidMove: // Update top/left.
6609 [NSNotification notificationWithName:NSWindowDidMoveNotification
6610 object:[view window]]];
6614 NSTRACE_MSG ("No change");
6618 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6619 /* normalize frame to gridded text size */
6623 NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6624 NSTRACE_ARG_SIZE (frameSize));
6625 NSTRACE_RECT ("[sender frame]", [sender frame]);
6626 NSTRACE_FSTYPE ("fs_state", fs_state);
6628 if (fs_state == FULLSCREEN_MAXIMIZED
6629 && (maximized_width != (int)frameSize.width
6630 || maximized_height != (int)frameSize.height))
6631 [self setFSValue: FULLSCREEN_NONE];
6632 else if (fs_state == FULLSCREEN_WIDTH
6633 && maximized_width != (int)frameSize.width)
6634 [self setFSValue: FULLSCREEN_NONE];
6635 else if (fs_state == FULLSCREEN_HEIGHT
6636 && maximized_height != (int)frameSize.height)
6637 [self setFSValue: FULLSCREEN_NONE];
6639 if (fs_state == FULLSCREEN_NONE)
6640 maximized_width = maximized_height = -1;
6642 if (! [self isFullscreen])
6644 extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6645 + FRAME_TOOLBAR_HEIGHT (emacsframe);
6648 cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6649 if (cols < MINWIDTH)
6652 rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6653 frameSize.height - extra);
6654 if (rows < MINHEIGHT)
6656 #ifdef NS_IMPL_COCOA
6658 /* this sets window title to have size in it; the wm does this under GS */
6659 NSRect r = [[self window] frame];
6660 if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6668 else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6669 && [[self window] title] != NULL)
6672 NSWindow *window = [self window];
6675 char *t = strdup ([[[self window] title] UTF8String]);
6676 char *pos = strstr (t, " — ");
6681 size_title = xmalloc (strlen (old_title) + 40);
6682 esprintf (size_title, "%s — (%d x %d)", old_title, cols, rows);
6683 [window setTitle: [NSString stringWithUTF8String: size_title]];
6688 #endif /* NS_IMPL_COCOA */
6690 NSTRACE_MSG ("cols: %d rows: %d", cols, rows);
6692 /* Restrict the new size to the text gird.
6694 Don't restrict the width if the user only adjusted the height, and
6695 vice versa. (Without this, the frame would shrink, and move
6696 slightly, if the window was resized by dragging one of its
6698 if (!frame_resize_pixelwise)
6700 NSRect r = [[self window] frame];
6702 if (r.size.width != frameSize.width)
6705 FRAME_TEXT_COLS_TO_PIXEL_WIDTH (emacsframe, cols);
6708 if (r.size.height != frameSize.height)
6711 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6715 NSTRACE_RETURN_SIZE (frameSize);
6721 - (void)windowDidResize: (NSNotification *)notification
6723 NSTRACE ("[EmacsView windowDidResize:]");
6724 if (!FRAME_LIVE_P (emacsframe))
6726 NSTRACE_MSG ("Ignored (frame dead)");
6729 if (emacsframe->output_data.ns->in_animation)
6731 NSTRACE_MSG ("Ignored (in animation)");
6735 if (! [self fsIsNative])
6737 NSWindow *theWindow = [notification object];
6738 /* We can get notification on the non-FS window when in
6740 if ([self window] != theWindow) return;
6743 NSTRACE_RECT ("frame", [[notification object] frame]);
6745 #ifdef NS_IMPL_GNUSTEP
6746 NSWindow *theWindow = [notification object];
6748 /* In GNUstep, at least currently, it's possible to get a didResize
6749 without getting a willResize.. therefore we need to act as if we got
6750 the willResize now */
6751 NSSize sz = [theWindow frame].size;
6752 sz = [self windowWillResize: theWindow toSize: sz];
6753 #endif /* NS_IMPL_GNUSTEP */
6755 if (cols > 0 && rows > 0)
6757 [self updateFrameSize: YES];
6760 ns_send_appdefined (-1);
6763 #ifdef NS_IMPL_COCOA
6764 - (void)viewDidEndLiveResize
6766 NSTRACE ("[EmacsView viewDidEndLiveResize]");
6768 [super viewDidEndLiveResize];
6771 [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6775 maximizing_resize = NO;
6777 #endif /* NS_IMPL_COCOA */
6780 - (void)windowDidBecomeKey: (NSNotification *)notification
6781 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6783 [self windowDidBecomeKey];
6787 - (void)windowDidBecomeKey /* for direct calls */
6789 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6790 struct frame *old_focus = dpyinfo->x_focus_frame;
6792 NSTRACE ("[EmacsView windowDidBecomeKey]");
6794 if (emacsframe != old_focus)
6795 dpyinfo->x_focus_frame = emacsframe;
6797 ns_frame_rehighlight (emacsframe);
6801 emacs_event->kind = FOCUS_IN_EVENT;
6802 EV_TRAILER ((id)nil);
6807 - (void)windowDidResignKey: (NSNotification *)notification
6808 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6810 struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6811 BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6812 NSTRACE ("[EmacsView windowDidResignKey:]");
6815 dpyinfo->x_focus_frame = 0;
6817 emacsframe->mouse_moved = 0;
6818 ns_frame_rehighlight (emacsframe);
6820 /* FIXME: for some reason needed on second and subsequent clicks away
6821 from sole-frame Emacs to get hollow box to show */
6822 if (!windowClosing && [[self window] isVisible] == YES)
6824 x_update_cursor (emacsframe, 1);
6825 x_set_frame_alpha (emacsframe);
6828 if (any_help_event_p)
6831 XSETFRAME (frame, emacsframe);
6832 help_echo_string = Qnil;
6833 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6836 if (emacs_event && is_focus_frame)
6838 [self deleteWorkingText];
6839 emacs_event->kind = FOCUS_OUT_EVENT;
6840 EV_TRAILER ((id)nil);
6845 - (void)windowWillMiniaturize: sender
6847 NSTRACE ("[EmacsView windowWillMiniaturize:]");
6851 - (void)setFrame:(NSRect)frameRect
6853 NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6854 NSTRACE_ARG_RECT (frameRect));
6856 [super setFrame:(NSRect)frameRect];
6872 - (void)createToolbar: (struct frame *)f
6874 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
6875 NSWindow *window = [view window];
6877 toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6878 [NSString stringWithFormat: @"Emacs Frame %d",
6880 [toolbar setVisible: NO];
6881 [window setToolbar: toolbar];
6883 /* Don't set frame garbaged until tool bar is up to date?
6884 This avoids an extra clear and redraw (flicker) at frame creation. */
6885 if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6886 else wait_for_tool_bar = NO;
6889 #ifdef NS_IMPL_COCOA
6891 NSButton *toggleButton;
6892 toggleButton = [window standardWindowButton: NSWindowToolbarButton];
6893 [toggleButton setTarget: self];
6894 [toggleButton setAction: @selector (toggleToolbar: )];
6900 - (instancetype) initFrameFromEmacs: (struct frame *)f
6908 NSTRACE ("[EmacsView initFrameFromEmacs:]");
6909 NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6912 processingCompose = NO;
6913 scrollbarsNeedingUpdate = 0;
6914 fs_state = FULLSCREEN_NONE;
6915 fs_before_fs = next_maximized = -1;
6916 #ifdef HAVE_NATIVE_FS
6917 fs_is_native = ns_use_native_fullscreen;
6921 maximized_width = maximized_height = -1;
6924 ns_userRect = NSMakeRect (0, 0, 0, 0);
6925 r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6926 FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6927 [self initWithFrame: r];
6928 [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6930 FRAME_NS_VIEW (f) = self;
6932 #ifdef NS_IMPL_COCOA
6934 maximizing_resize = NO;
6937 win = [[EmacsWindow alloc]
6938 initWithContentRect: r
6939 styleMask: (FRAME_UNDECORATED (f)
6940 ? FRAME_UNDECORATED_FLAGS
6941 : FRAME_DECORATED_FLAGS
6942 #ifdef NS_IMPL_COCOA
6943 | NSWindowStyleMaskResizable
6944 | NSWindowStyleMaskMiniaturizable
6945 | NSWindowStyleMaskClosable
6948 backing: NSBackingStoreBuffered
6951 #ifdef HAVE_NATIVE_FS
6952 [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6956 bwidth = f->border_width = wr.size.width - r.size.width;
6958 [win setAcceptsMouseMovedEvents: YES];
6959 [win setDelegate: self];
6960 #if !defined (NS_IMPL_COCOA) || \
6961 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6962 [win useOptimizedDrawing: YES];
6965 [[win contentView] addSubview: self];
6968 [self registerForDraggedTypes: ns_drag_types];
6971 name = [NSString stringWithUTF8String:
6972 NILP (tem) ? "Emacs" : SSDATA (tem)];
6973 [win setTitle: name];
6975 /* toolbar support */
6976 if (! FRAME_UNDECORATED (f))
6977 [self createToolbar: f];
6981 [win setMiniwindowTitle:
6982 [NSString stringWithUTF8String: SSDATA (tem)]];
6984 if (FRAME_PARENT_FRAME (f) != NULL)
6986 NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
6987 [parent addChildWindow: win
6988 ordered: NSWindowAbove];
6991 if (FRAME_Z_GROUP (f) != z_group_none)
6992 win.level = NSNormalWindowLevel
6993 + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
6996 NSScreen *screen = [win screen];
7000 NSPoint pt = NSMakePoint
7001 (IN_BOUND (-SCREENMAX, f->left_pos
7002 + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7003 IN_BOUND (-SCREENMAX,
7004 NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7007 [win setFrameTopLeftPoint: pt];
7009 NSTRACE_RECT ("new frame", [win frame]);
7013 [win makeFirstResponder: self];
7015 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7016 (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7018 [win setBackgroundColor: col];
7019 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7020 [win setOpaque: NO];
7022 #if !defined (NS_IMPL_COCOA) || \
7023 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7024 [self allocateGState];
7026 [NSApp registerServicesMenuSendTypes: ns_send_types
7027 returnTypes: [NSArray array]];
7029 /* macOS Sierra automatically enables tabbed windows. We can't
7030 allow this to be enabled until it's available on a Free system.
7031 Currently it only happens by accident and is buggy anyway. */
7032 #if defined (NS_IMPL_COCOA) && \
7033 MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
7034 [win setTabbingMode: NSWindowTabbingModeDisallowed];
7042 - (void)windowDidMove: sender
7044 NSWindow *win = [self window];
7045 NSRect r = [win frame];
7046 NSArray *screens = [NSScreen screens];
7047 NSScreen *screen = [screens objectAtIndex: 0];
7049 NSTRACE ("[EmacsView windowDidMove:]");
7051 if (!emacsframe->output_data.ns)
7055 emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7056 emacsframe->top_pos =
7057 NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7061 emacs_event->kind = MOVE_FRAME_EVENT;
7062 EV_TRAILER ((id)nil);
7068 /* Called AFTER method below, but before our windowWillResize call there leads
7069 to windowDidResize -> x_set_window_size. Update emacs' notion of frame
7070 location so set_window_size moves the frame. */
7071 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7073 NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7074 NSTRACE_FMT_RETURN "YES"),
7075 NSTRACE_ARG_RECT (newFrame));
7077 emacsframe->output_data.ns->zooming = 1;
7082 /* Override to do something slightly nonstandard, but nice. First click on
7083 zoom button will zoom vertically. Second will zoom completely. Third
7084 returns to original. */
7085 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7086 defaultFrame:(NSRect)defaultFrame
7088 // TODO: Rename to "currentFrame" and assign "result" properly in
7090 NSRect result = [sender frame];
7092 NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7093 NSTRACE_FMT_RECT "]"),
7094 NSTRACE_ARG_RECT (defaultFrame));
7095 NSTRACE_FSTYPE ("fs_state", fs_state);
7096 NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7097 NSTRACE_FSTYPE ("next_maximized", next_maximized);
7098 NSTRACE_RECT ("ns_userRect", ns_userRect);
7099 NSTRACE_RECT ("[sender frame]", [sender frame]);
7101 if (fs_before_fs != -1) /* Entering fullscreen */
7103 NSTRACE_MSG ("Entering fullscreen");
7104 result = defaultFrame;
7108 // Save the window size and position (frame) before the resize.
7109 if (fs_state != FULLSCREEN_MAXIMIZED
7110 && fs_state != FULLSCREEN_WIDTH)
7112 ns_userRect.size.width = result.size.width;
7113 ns_userRect.origin.x = result.origin.x;
7116 if (fs_state != FULLSCREEN_MAXIMIZED
7117 && fs_state != FULLSCREEN_HEIGHT)
7119 ns_userRect.size.height = result.size.height;
7120 ns_userRect.origin.y = result.origin.y;
7123 NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7125 if (next_maximized == FULLSCREEN_HEIGHT
7126 || (next_maximized == -1
7127 && abs ((int)(defaultFrame.size.height - result.size.height))
7128 > FRAME_LINE_HEIGHT (emacsframe)))
7131 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7132 maximized_height = result.size.height = defaultFrame.size.height;
7133 maximized_width = -1;
7134 result.origin.y = defaultFrame.origin.y;
7135 if (ns_userRect.size.height != 0)
7137 result.origin.x = ns_userRect.origin.x;
7138 result.size.width = ns_userRect.size.width;
7140 [self setFSValue: FULLSCREEN_HEIGHT];
7141 #ifdef NS_IMPL_COCOA
7142 maximizing_resize = YES;
7145 else if (next_maximized == FULLSCREEN_WIDTH)
7147 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7148 maximized_width = result.size.width = defaultFrame.size.width;
7149 maximized_height = -1;
7150 result.origin.x = defaultFrame.origin.x;
7151 if (ns_userRect.size.width != 0)
7153 result.origin.y = ns_userRect.origin.y;
7154 result.size.height = ns_userRect.size.height;
7156 [self setFSValue: FULLSCREEN_WIDTH];
7158 else if (next_maximized == FULLSCREEN_MAXIMIZED
7159 || (next_maximized == -1
7160 && abs ((int)(defaultFrame.size.width - result.size.width))
7161 > FRAME_COLUMN_WIDTH (emacsframe)))
7163 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7165 result = defaultFrame; /* second click */
7166 maximized_width = result.size.width;
7167 maximized_height = result.size.height;
7168 [self setFSValue: FULLSCREEN_MAXIMIZED];
7169 #ifdef NS_IMPL_COCOA
7170 maximizing_resize = YES;
7176 NSTRACE_MSG ("Restore");
7177 result = ns_userRect.size.height ? ns_userRect : result;
7178 NSTRACE_RECT ("restore (2)", result);
7179 ns_userRect = NSMakeRect (0, 0, 0, 0);
7180 #ifdef NS_IMPL_COCOA
7181 maximizing_resize = fs_state != FULLSCREEN_NONE;
7183 [self setFSValue: FULLSCREEN_NONE];
7184 maximized_width = maximized_height = -1;
7188 if (fs_before_fs == -1) next_maximized = -1;
7190 NSTRACE_RECT ("Final ns_userRect", ns_userRect);
7191 NSTRACE_MSG ("Final maximized_width: %d", maximized_width);
7192 NSTRACE_MSG ("Final maximized_height: %d", maximized_height);
7193 NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7195 [self windowWillResize: sender toSize: result.size];
7197 NSTRACE_RETURN_RECT (result);
7203 - (void)windowDidDeminiaturize: sender
7205 NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7206 if (!emacsframe->output_data.ns)
7209 SET_FRAME_ICONIFIED (emacsframe, 0);
7210 SET_FRAME_VISIBLE (emacsframe, 1);
7211 windows_or_buffers_changed = 63;
7215 emacs_event->kind = DEICONIFY_EVENT;
7216 EV_TRAILER ((id)nil);
7221 - (void)windowDidExpose: sender
7223 NSTRACE ("[EmacsView windowDidExpose:]");
7224 if (!emacsframe->output_data.ns)
7227 SET_FRAME_VISIBLE (emacsframe, 1);
7228 SET_FRAME_GARBAGED (emacsframe);
7230 if (send_appdefined)
7231 ns_send_appdefined (-1);
7235 - (void)windowDidMiniaturize: sender
7237 NSTRACE ("[EmacsView windowDidMiniaturize:]");
7238 if (!emacsframe->output_data.ns)
7241 SET_FRAME_ICONIFIED (emacsframe, 1);
7242 SET_FRAME_VISIBLE (emacsframe, 0);
7246 emacs_event->kind = ICONIFY_EVENT;
7247 EV_TRAILER ((id)nil);
7251 #ifdef HAVE_NATIVE_FS
7252 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7253 willUseFullScreenPresentationOptions:
7254 (NSApplicationPresentationOptions)proposedOptions
7256 return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7260 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7262 NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7263 [self windowWillEnterFullScreen];
7265 - (void)windowWillEnterFullScreen /* provided for direct calls */
7267 NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7268 fs_before_fs = fs_state;
7271 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7273 NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7274 [self windowDidEnterFullScreen];
7277 - (void)windowDidEnterFullScreen /* provided for direct calls */
7279 NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7280 [self setFSValue: FULLSCREEN_BOTH];
7281 if (! [self fsIsNative])
7283 [self windowDidBecomeKey];
7284 [nonfs_window orderOut:self];
7288 BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7289 #ifdef NS_IMPL_COCOA
7290 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7291 unsigned val = (unsigned)[NSApp presentationOptions];
7293 // Mac OS X 10.7 bug fix, the menu won't appear without this.
7294 // val is non-zero on other macOS versions.
7297 NSApplicationPresentationOptions options
7298 = NSApplicationPresentationAutoHideDock
7299 | NSApplicationPresentationAutoHideMenuBar
7300 | NSApplicationPresentationFullScreen
7301 | NSApplicationPresentationAutoHideToolbar;
7303 [NSApp setPresentationOptions: options];
7307 [toolbar setVisible:tbar_visible];
7311 - (void)windowWillExitFullScreen:(NSNotification *)notification
7313 NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7314 [self windowWillExitFullScreen];
7317 - (void)windowWillExitFullScreen /* provided for direct calls */
7319 NSTRACE ("[EmacsView windowWillExitFullScreen]");
7320 if (!FRAME_LIVE_P (emacsframe))
7322 NSTRACE_MSG ("Ignored (frame dead)");
7325 if (next_maximized != -1)
7326 fs_before_fs = next_maximized;
7329 - (void)windowDidExitFullScreen:(NSNotification *)notification
7331 NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7332 [self windowDidExitFullScreen];
7335 - (void)windowDidExitFullScreen /* provided for direct calls */
7337 NSTRACE ("[EmacsView windowDidExitFullScreen]");
7338 if (!FRAME_LIVE_P (emacsframe))
7340 NSTRACE_MSG ("Ignored (frame dead)");
7343 [self setFSValue: fs_before_fs];
7345 #ifdef HAVE_NATIVE_FS
7346 [self updateCollectionBehavior];
7348 if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7350 [toolbar setVisible:YES];
7351 update_frame_tool_bar (emacsframe);
7352 [self updateFrameSize:YES];
7353 [[self window] display];
7356 [toolbar setVisible:NO];
7358 if (next_maximized != -1)
7359 [[self window] performZoom:self];
7364 return fs_is_native;
7367 - (BOOL)isFullscreen
7373 res = (nonfs_window != nil);
7377 #ifdef HAVE_NATIVE_FS
7378 res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7384 NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7390 #ifdef HAVE_NATIVE_FS
7391 - (void)updateCollectionBehavior
7393 NSTRACE ("[EmacsView updateCollectionBehavior]");
7395 if (! [self isFullscreen])
7397 NSWindow *win = [self window];
7398 NSWindowCollectionBehavior b = [win collectionBehavior];
7399 if (ns_use_native_fullscreen)
7400 b |= NSWindowCollectionBehaviorFullScreenPrimary;
7402 b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7404 [win setCollectionBehavior: b];
7405 fs_is_native = ns_use_native_fullscreen;
7410 - (void)toggleFullScreen: (id)sender
7418 NSTRACE ("[EmacsView toggleFullScreen:]");
7422 #ifdef HAVE_NATIVE_FS
7423 [[self window] toggleFullScreen:sender];
7429 onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7432 col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7433 (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7436 if (fs_state != FULLSCREEN_BOTH)
7438 NSScreen *screen = [w screen];
7440 #if defined (NS_IMPL_COCOA) && \
7441 MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7442 /* Hide ghost menu bar on secondary monitor? */
7443 if (! onFirstScreen)
7444 onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7446 /* Hide dock and menubar if we are on the primary screen. */
7449 #ifdef NS_IMPL_COCOA
7450 NSApplicationPresentationOptions options
7451 = NSApplicationPresentationAutoHideDock
7452 | NSApplicationPresentationAutoHideMenuBar;
7454 [NSApp setPresentationOptions: options];
7456 [NSMenu setMenuBarVisible:NO];
7460 fw = [[EmacsFSWindow alloc]
7461 initWithContentRect:[w contentRectForFrameRect:wr]
7462 styleMask:NSWindowStyleMaskBorderless
7463 backing:NSBackingStoreBuffered
7467 [fw setContentView:[w contentView]];
7468 [fw setTitle:[w title]];
7469 [fw setDelegate:self];
7470 [fw setAcceptsMouseMovedEvents: YES];
7471 #if !defined (NS_IMPL_COCOA) || \
7472 MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7473 [fw useOptimizedDrawing: YES];
7475 [fw setBackgroundColor: col];
7476 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7479 f->border_width = 0;
7483 [self windowWillEnterFullScreen];
7484 [fw makeKeyAndOrderFront:NSApp];
7485 [fw makeFirstResponder:self];
7487 r = [fw frameRectForContentRect:[screen frame]];
7488 [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7489 [self windowDidEnterFullScreen];
7500 #ifdef NS_IMPL_COCOA
7501 [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7503 [NSMenu setMenuBarVisible:YES];
7507 [w setContentView:[fw contentView]];
7508 [w setBackgroundColor: col];
7509 if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7512 f->border_width = bwidth;
7514 // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7516 [self windowWillExitFullScreen];
7517 [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7519 [w makeKeyAndOrderFront:NSApp];
7520 [self windowDidExitFullScreen];
7521 [self updateFrameSize:YES];
7527 NSTRACE ("[EmacsView handleFS]");
7529 if (fs_state != emacsframe->want_fullscreen)
7531 if (fs_state == FULLSCREEN_BOTH)
7533 NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7534 [self toggleFullScreen:self];
7537 switch (emacsframe->want_fullscreen)
7539 case FULLSCREEN_BOTH:
7540 NSTRACE_MSG ("FULLSCREEN_BOTH");
7541 [self toggleFullScreen:self];
7543 case FULLSCREEN_WIDTH:
7544 NSTRACE_MSG ("FULLSCREEN_WIDTH");
7545 next_maximized = FULLSCREEN_WIDTH;
7546 if (fs_state != FULLSCREEN_BOTH)
7547 [[self window] performZoom:self];
7549 case FULLSCREEN_HEIGHT:
7550 NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7551 next_maximized = FULLSCREEN_HEIGHT;
7552 if (fs_state != FULLSCREEN_BOTH)
7553 [[self window] performZoom:self];
7555 case FULLSCREEN_MAXIMIZED:
7556 NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7557 next_maximized = FULLSCREEN_MAXIMIZED;
7558 if (fs_state != FULLSCREEN_BOTH)
7559 [[self window] performZoom:self];
7561 case FULLSCREEN_NONE:
7562 NSTRACE_MSG ("FULLSCREEN_NONE");
7563 if (fs_state != FULLSCREEN_BOTH)
7565 next_maximized = FULLSCREEN_NONE;
7566 [[self window] performZoom:self];
7571 emacsframe->want_fullscreen = FULLSCREEN_NONE;
7576 - (void) setFSValue: (int)value
7578 NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7579 NSTRACE_ARG_FSTYPE(value));
7581 Lisp_Object lval = Qnil;
7584 case FULLSCREEN_BOTH:
7587 case FULLSCREEN_WIDTH:
7590 case FULLSCREEN_HEIGHT:
7593 case FULLSCREEN_MAXIMIZED:
7597 store_frame_param (emacsframe, Qfullscreen, lval);
7601 - (void)mouseEntered: (NSEvent *)theEvent
7603 NSTRACE ("[EmacsView mouseEntered:]");
7605 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7606 = EV_TIMESTAMP (theEvent);
7610 - (void)mouseExited: (NSEvent *)theEvent
7612 Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7614 NSTRACE ("[EmacsView mouseExited:]");
7619 FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7620 = EV_TIMESTAMP (theEvent);
7622 if (emacsframe == hlinfo->mouse_face_mouse_frame)
7624 clear_mouse_face (hlinfo);
7625 hlinfo->mouse_face_mouse_frame = 0;
7630 - (instancetype)menuDown: sender
7632 NSTRACE ("[EmacsView menuDown:]");
7633 if (context_menu_value == -1)
7634 context_menu_value = [sender tag];
7637 NSInteger tag = [sender tag];
7638 find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7639 emacsframe->menu_bar_vector,
7643 ns_send_appdefined (-1);
7648 - (EmacsToolbar *)toolbar
7654 /* this gets called on toolbar button click */
7655 - (instancetype)toolbarClicked: (id)item
7658 int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7660 NSTRACE ("[EmacsView toolbarClicked:]");
7665 /* send first event (for some reason two needed) */
7666 theEvent = [[self window] currentEvent];
7667 emacs_event->kind = TOOL_BAR_EVENT;
7668 XSETFRAME (emacs_event->arg, emacsframe);
7669 EV_TRAILER (theEvent);
7671 emacs_event->kind = TOOL_BAR_EVENT;
7672 /* XSETINT (emacs_event->code, 0); */
7673 emacs_event->arg = AREF (emacsframe->tool_bar_items,
7674 idx + TOOL_BAR_ITEM_KEY);
7675 emacs_event->modifiers = EV_MODIFIERS (theEvent);
7676 EV_TRAILER (theEvent);
7681 - (instancetype)toggleToolbar: (id)sender
7683 NSTRACE ("[EmacsView toggleToolbar:]");
7688 emacs_event->kind = NS_NONKEY_EVENT;
7689 emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7690 EV_TRAILER ((id)nil);
7695 - (void)drawRect: (NSRect)rect
7697 int x = NSMinX (rect), y = NSMinY (rect);
7698 int width = NSWidth (rect), height = NSHeight (rect);
7700 NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7701 NSTRACE_ARG_RECT(rect));
7703 if (!emacsframe || !emacsframe->output_data.ns)
7706 ns_clear_frame_area (emacsframe, x, y, width, height);
7708 expose_frame (emacsframe, x, y, width, height);
7712 drawRect: may be called (at least in Mac OS X 10.5) for invisible
7713 views as well for some reason. Thus, do not infer visibility
7716 emacsframe->async_visible = 1;
7717 emacsframe->async_iconified = 0;
7722 /* NSDraggingDestination protocol methods. Actually this is not really a
7723 protocol, but a category of Object. O well... */
7725 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7727 NSTRACE ("[EmacsView draggingEntered:]");
7728 return NSDragOperationGeneric;
7732 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7738 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7743 NSEvent *theEvent = [[self window] currentEvent];
7745 NSDragOperation op = [sender draggingSourceOperationMask];
7748 NSTRACE ("[EmacsView performDragOperation:]");
7753 position = [self convertPoint: [sender draggingLocation] fromView: nil];
7754 x = lrint (position.x); y = lrint (position.y);
7756 pb = [sender draggingPasteboard];
7757 type = [pb availableTypeFromArray: ns_drag_types];
7759 if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7760 // URL drags contain all operations (0xf), don't allow all to be set.
7763 if (op & NSDragOperationLink)
7764 modifiers |= NSEventModifierFlagControl;
7765 if (op & NSDragOperationCopy)
7766 modifiers |= NSEventModifierFlagOption;
7767 if (op & NSDragOperationGeneric)
7768 modifiers |= NSEventModifierFlagCommand;
7771 modifiers = EV_MODIFIERS2 (modifiers);
7776 else if ([type isEqualToString: NSFilenamesPboardType])
7779 NSEnumerator *fenum;
7782 if (!(files = [pb propertyListForType: type]))
7785 fenum = [files objectEnumerator];
7786 while ( (file = [fenum nextObject]) )
7788 emacs_event->kind = DRAG_N_DROP_EVENT;
7789 XSETINT (emacs_event->x, x);
7790 XSETINT (emacs_event->y, y);
7791 ns_input_file = append2 (ns_input_file,
7792 build_string ([file UTF8String]));
7793 emacs_event->modifiers = modifiers;
7794 emacs_event->arg = list2 (Qfile, build_string ([file UTF8String]));
7795 EV_TRAILER (theEvent);
7799 else if ([type isEqualToString: NSURLPboardType])
7801 NSURL *url = [NSURL URLFromPasteboard: pb];
7802 if (url == nil) return NO;
7804 emacs_event->kind = DRAG_N_DROP_EVENT;
7805 XSETINT (emacs_event->x, x);
7806 XSETINT (emacs_event->y, y);
7807 emacs_event->modifiers = modifiers;
7808 emacs_event->arg = list2 (Qurl,
7809 build_string ([[url absoluteString]
7811 EV_TRAILER (theEvent);
7813 if ([url isFileURL] != NO)
7815 NSString *file = [url path];
7816 ns_input_file = append2 (ns_input_file,
7817 build_string ([file UTF8String]));
7821 else if ([type isEqualToString: NSStringPboardType]
7822 || [type isEqualToString: NSTabularTextPboardType])
7826 if (! (data = [pb stringForType: type]))
7829 emacs_event->kind = DRAG_N_DROP_EVENT;
7830 XSETINT (emacs_event->x, x);
7831 XSETINT (emacs_event->y, y);
7832 emacs_event->modifiers = modifiers;
7833 emacs_event->arg = list2 (Qnil, build_string ([data UTF8String]));
7834 EV_TRAILER (theEvent);
7839 fprintf (stderr, "Invalid data type in dragging pasteboard");
7845 - (id) validRequestorForSendType: (NSString *)typeSent
7846 returnType: (NSString *)typeReturned
7848 NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7849 if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7850 && typeReturned == nil)
7852 if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7856 return [super validRequestorForSendType: typeSent
7857 returnType: typeReturned];
7861 /* The next two methods are part of NSServicesRequests informal protocol,
7862 supposedly called when a services menu item is chosen from this app.
7863 But this should not happen because we override the services menu with our
7864 own entries which call ns-perform-service.
7865 Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7866 So let's at least stub them out until further investigation can be done. */
7868 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7870 /* we could call ns_string_from_pasteboard(pboard) here but then it should
7871 be written into the buffer in place of the existing selection..
7872 ordinary service calls go through functions defined in ns-win.el */
7876 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7878 NSArray *typesDeclared;
7881 NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7883 /* We only support NSStringPboardType */
7884 if ([types containsObject:NSStringPboardType] == NO) {
7888 val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7889 if (CONSP (val) && SYMBOLP (XCAR (val)))
7892 if (CONSP (val) && NILP (XCDR (val)))
7895 if (! STRINGP (val))
7898 typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7899 [pb declareTypes:typesDeclared owner:nil];
7900 ns_string_to_pasteboard (pb, val);
7905 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7906 (gives a miniaturized version of the window); currently we use the latter for
7907 frames whose active buffer doesn't correspond to any file
7908 (e.g., '*scratch*') */
7909 - (instancetype)setMiniwindowImage: (BOOL) setMini
7911 id image = [[self window] miniwindowImage];
7912 NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7914 /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7915 about "AppleDockIconEnabled" notwithstanding, however the set message
7916 below has its effect nonetheless. */
7917 if (image != emacsframe->output_data.ns->miniimage)
7919 if (image && [image isKindOfClass: [EmacsImage class]])
7921 [[self window] setMiniwindowImage:
7922 setMini ? emacsframe->output_data.ns->miniimage : nil];
7929 - (void) setRows: (int) r andColumns: (int) c
7931 NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7936 - (int) fullscreenState
7941 @end /* EmacsView */
7945 /* ==========================================================================
7947 EmacsWindow implementation
7949 ========================================================================== */
7951 @implementation EmacsWindow
7953 #ifdef NS_IMPL_COCOA
7954 - (id)accessibilityAttributeValue:(NSString *)attribute
7956 Lisp_Object str = Qnil;
7957 struct frame *f = SELECTED_FRAME ();
7958 struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7960 NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7962 if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7963 return NSAccessibilityTextFieldRole;
7965 if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7966 && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7968 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7970 else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7972 if (! NILP (BVAR (curbuf, mark_active)))
7973 str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7977 ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7978 ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7979 ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7981 if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7982 str = make_uninit_multibyte_string (range, byte_range);
7984 str = make_uninit_string (range);
7985 /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7986 Is this a problem? */
7987 memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7994 if (CONSP (str) && SYMBOLP (XCAR (str)))
7997 if (CONSP (str) && NILP (XCDR (str)))
8002 const char *utfStr = SSDATA (str);
8003 NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8008 return [super accessibilityAttributeValue:attribute];
8010 #endif /* NS_IMPL_COCOA */
8012 /* Constrain size and placement of a frame.
8014 By returning the original "frameRect", the frame is not
8015 constrained. This can lead to unwanted situations where, for
8016 example, the menu bar covers the frame.
8018 The default implementation (accessed using "super") constrains the
8019 frame to the visible area of SCREEN, minus the menu bar (if
8020 present) and the Dock. Note that default implementation also calls
8021 windowWillResize, with the frame it thinks should have. (This can
8022 make the frame exit maximized mode.)
8024 Note that this should work in situations where multiple monitors
8025 are present. Common configurations are side-by-side monitors and a
8026 monitor on top of another (e.g. when a laptop is placed under a
8028 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8030 NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8031 NSTRACE_ARG_RECT (frameRect));
8033 #ifdef NS_IMPL_COCOA
8034 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
8035 // If separate spaces is on, it is like each screen is independent. There is
8036 // no spanning of frames across screens.
8037 if ([NSScreen screensHaveSeparateSpaces])
8039 NSTRACE_MSG ("Screens have separate spaces");
8040 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8041 NSTRACE_RETURN_RECT (frameRect);
8045 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 */
8046 // Check that the proposed frameRect is visible in at least one
8047 // screen. If it is not, ask the system to reposition it (only
8048 // for non-child windows).
8050 if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8052 NSArray *screens = [NSScreen screens];
8053 NSUInteger nr_screens = [screens count];
8056 BOOL frame_on_screen = NO;
8058 for (i = 0; i < nr_screens; ++i)
8060 NSScreen *s = [screens objectAtIndex: i];
8061 NSRect scrRect = [s frame];
8063 if (NSIntersectsRect(frameRect, scrRect))
8065 frame_on_screen = YES;
8070 if (!frame_on_screen)
8072 NSTRACE_MSG ("Frame outside screens; constraining");
8073 frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8074 NSTRACE_RETURN_RECT (frameRect);
8080 return constrain_frame_rect(frameRect,
8081 [(EmacsView *)[self delegate] isFullscreen]);
8085 - (void)performZoom:(id)sender
8087 NSTRACE ("[EmacsWindow performZoom:]");
8089 return [super performZoom:sender];
8092 - (void)zoom:(id)sender
8094 NSTRACE ("[EmacsWindow zoom:]");
8096 ns_update_auto_hide_menu_bar();
8098 // Below are three zoom implementations. In the final commit, the
8099 // idea is that the last should be included.
8102 // Native zoom done using the standard zoom animation. Size of the
8103 // resulting frame reduced to accommodate the Dock and, if present,
8105 [super zoom:sender];
8108 // Native zoom done using the standard zoom animation, plus an
8109 // explicit resize to cover the full screen, except the menu-bar and
8110 // dock, if present.
8111 [super zoom:sender];
8113 // After the native zoom, resize the resulting frame to fill the
8114 // entire screen, except the menu-bar.
8116 // This works for all practical purposes. (The only minor oddity is
8117 // when transiting from full-height frame to a maximized, the
8118 // animation reduces the height of the frame slightly (to the 4
8119 // pixels needed to accommodate the Doc) before it snaps back into
8120 // full height. The user would need a very trained eye to spot
8122 NSScreen * screen = [self screen];
8125 int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8127 NSTRACE_FSTYPE ("fullscreenState", fs_state);
8129 NSRect sr = [screen frame];
8130 struct EmacsMargins margins
8131 = ns_screen_margins_ignoring_hidden_dock(screen);
8133 NSRect wr = [self frame];
8134 NSTRACE_RECT ("Rect after zoom", wr);
8138 if (fs_state == FULLSCREEN_MAXIMIZED
8139 || fs_state == FULLSCREEN_HEIGHT)
8141 newWr.origin.y = sr.origin.y + margins.bottom;
8142 newWr.size.height = sr.size.height - margins.top - margins.bottom;
8145 if (fs_state == FULLSCREEN_MAXIMIZED
8146 || fs_state == FULLSCREEN_WIDTH)
8148 newWr.origin.x = sr.origin.x + margins.left;
8149 newWr.size.width = sr.size.width - margins.right - margins.left;
8152 if (newWr.size.width != wr.size.width
8153 || newWr.size.height != wr.size.height
8154 || newWr.origin.x != wr.origin.x
8155 || newWr.origin.y != wr.origin.y)
8157 NSTRACE_MSG ("New frame different");
8158 [self setFrame: newWr display: NO];
8162 // Non-native zoom which is done instantaneously. The resulting
8163 // frame covers the entire screen, except the menu-bar and dock, if
8165 NSScreen * screen = [self screen];
8168 NSRect sr = [screen frame];
8169 struct EmacsMargins margins
8170 = ns_screen_margins_ignoring_hidden_dock(screen);
8172 sr.size.height -= (margins.top + margins.bottom);
8173 sr.size.width -= (margins.left + margins.right);
8174 sr.origin.x += margins.left;
8175 sr.origin.y += margins.bottom;
8177 sr = [[self delegate] windowWillUseStandardFrame:self
8179 [self setFrame: sr display: NO];
8184 - (void)setFrame:(NSRect)windowFrame
8185 display:(BOOL)displayViews
8187 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8188 NSTRACE_ARG_RECT (windowFrame), displayViews);
8190 [super setFrame:windowFrame display:displayViews];
8193 - (void)setFrame:(NSRect)windowFrame
8194 display:(BOOL)displayViews
8195 animate:(BOOL)performAnimation
8197 NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8198 " display:%d performAnimation:%d]",
8199 NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8201 [super setFrame:windowFrame display:displayViews animate:performAnimation];
8204 - (void)setFrameTopLeftPoint:(NSPoint)point
8206 NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8207 NSTRACE_ARG_POINT (point));
8209 [super setFrameTopLeftPoint:point];
8212 - (BOOL)canBecomeKeyWindow
8214 return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8216 @end /* EmacsWindow */
8219 @implementation EmacsFSWindow
8221 - (BOOL)canBecomeKeyWindow
8226 - (BOOL)canBecomeMainWindow
8233 /* ==========================================================================
8235 EmacsScroller implementation
8237 ========================================================================== */
8240 @implementation EmacsScroller
8242 /* for repeat button push */
8243 #define SCROLL_BAR_FIRST_DELAY 0.5
8244 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8246 + (CGFloat) scrollerWidth
8248 /* TODO: if we want to allow variable widths, this is the place to do it,
8249 however neither GNUstep nor Cocoa support it very well */
8251 #if !defined (NS_IMPL_COCOA) || \
8252 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
8253 r = [NSScroller scrollerWidth];
8255 r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8256 scrollerStyle: NSScrollerStyleLegacy];
8261 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8263 NSTRACE ("[EmacsScroller initFrame: window:]");
8265 if (r.size.width > r.size.height)
8270 [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8271 [self setContinuous: YES];
8272 [self setEnabled: YES];
8274 /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8275 locked against the top and bottom edges, and right edge on macOS, where
8276 scrollers are on right. */
8277 #ifdef NS_IMPL_GNUSTEP
8278 [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8280 [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8283 window = XWINDOW (nwin);
8286 pixel_length = NSWidth (r);
8288 pixel_length = NSHeight (r);
8289 if (pixel_length == 0) pixel_length = 1;
8290 min_portion = 20 / pixel_length;
8292 frame = XFRAME (window->frame);
8293 if (FRAME_LIVE_P (frame))
8296 EmacsView *view = FRAME_NS_VIEW (frame);
8297 NSView *sview = [[view window] contentView];
8298 NSArray *subs = [sview subviews];
8300 /* disable optimization stopping redraw of other scrollbars */
8301 view->scrollbarsNeedingUpdate = 0;
8302 for (i =[subs count]-1; i >= 0; i--)
8303 if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8304 view->scrollbarsNeedingUpdate++;
8305 [sview addSubview: self];
8308 /* [self setFrame: r]; */
8314 - (void)setFrame: (NSRect)newRect
8316 NSTRACE ("[EmacsScroller setFrame:]");
8318 /* block_input (); */
8320 pixel_length = NSWidth (newRect);
8322 pixel_length = NSHeight (newRect);
8323 if (pixel_length == 0) pixel_length = 1;
8324 min_portion = 20 / pixel_length;
8325 [super setFrame: newRect];
8326 /* unblock_input (); */
8332 NSTRACE ("[EmacsScroller dealloc]");
8336 wset_horizontal_scroll_bar (window, Qnil);
8338 wset_vertical_scroll_bar (window, Qnil);
8345 - (instancetype)condemn
8347 NSTRACE ("[EmacsScroller condemn]");
8353 - (instancetype)reprieve
8355 NSTRACE ("[EmacsScroller reprieve]");
8363 NSTRACE ("[EmacsScroller judge]");
8364 bool ret = condemned;
8369 /* ensure other scrollbar updates after deletion */
8370 view = (EmacsView *)FRAME_NS_VIEW (frame);
8372 view->scrollbarsNeedingUpdate++;
8376 wset_horizontal_scroll_bar (window, Qnil);
8378 wset_vertical_scroll_bar (window, Qnil);
8381 [self removeFromSuperview];
8389 - (void)resetCursorRects
8391 NSRect visible = [self visibleRect];
8392 NSTRACE ("[EmacsScroller resetCursorRects]");
8394 if (!NSIsEmptyRect (visible))
8395 [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8396 [[NSCursor arrowCursor] setOnMouseEntered: YES];
8400 - (int) checkSamePosition: (int) position portion: (int) portion
8403 return em_position ==position && em_portion ==portion && em_whole ==whole
8404 && portion != whole; /* needed for resize empty buf */
8408 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8410 NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8412 em_position = position;
8413 em_portion = portion;
8416 if (portion >= whole)
8418 #ifdef NS_IMPL_COCOA
8419 [self setKnobProportion: 1.0];
8420 [self setDoubleValue: 1.0];
8422 [self setFloatValue: 0.0 knobProportion: 1.0];
8429 portion = max ((float)whole*min_portion/pixel_length, portion);
8430 pos = (float)position / (whole - portion);
8431 por = (CGFloat)portion/whole;
8432 #ifdef NS_IMPL_COCOA
8433 [self setKnobProportion: por];
8434 [self setDoubleValue: pos];
8436 [self setFloatValue: pos knobProportion: por];
8443 /* set up emacs_event */
8444 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8448 NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8453 emacs_event->part = last_hit_part;
8454 emacs_event->code = 0;
8455 emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8456 XSETWINDOW (win, window);
8457 emacs_event->frame_or_window = win;
8458 emacs_event->timestamp = EV_TIMESTAMP (e);
8459 emacs_event->arg = Qnil;
8463 emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8464 XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8465 XSETINT (emacs_event->y, em_whole);
8469 emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8470 XSETINT (emacs_event->x, loc);
8471 XSETINT (emacs_event->y, pixel_length-20);
8476 n_emacs_events_pending++;
8477 kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8480 hold_event (emacs_event);
8481 EVENT_INIT (*emacs_event);
8482 ns_send_appdefined (-1);
8486 /* called manually thru timer to implement repeated button action w/hold-down */
8487 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8489 NSEvent *e = [[self window] currentEvent];
8490 NSPoint p = [[self window] mouseLocationOutsideOfEventStream];
8491 BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8493 NSTRACE ("[EmacsScroller repeatScroll:]");
8495 /* clear timer if need be */
8496 if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8498 [scroll_repeat_entry invalidate];
8499 [scroll_repeat_entry release];
8500 scroll_repeat_entry = nil;
8506 = [[NSTimer scheduledTimerWithTimeInterval:
8507 SCROLL_BAR_CONTINUOUS_DELAY
8509 selector: @selector (repeatScroll:)
8515 [self sendScrollEventAtLoc: 0 fromEvent: e];
8520 /* Asynchronous mouse tracking for scroller. This allows us to dispatch
8521 mouseDragged events without going into a modal loop. */
8522 - (void)mouseDown: (NSEvent *)e
8525 /* hitPart is only updated AFTER event is passed on */
8526 NSScrollerPart part = [self testPart: [e locationInWindow]];
8527 CGFloat loc, kloc, pos UNINIT;
8530 NSTRACE ("[EmacsScroller mouseDown:]");
8534 case NSScrollerDecrementPage:
8535 last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8536 case NSScrollerIncrementPage:
8537 last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8538 case NSScrollerDecrementLine:
8539 last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8540 case NSScrollerIncrementLine:
8541 last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8542 case NSScrollerKnob:
8543 last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8544 case NSScrollerKnobSlot: /* GNUstep-only */
8545 last_hit_part = scroll_bar_move_ratio; break;
8546 default: /* NSScrollerNoPart? */
8547 fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8552 if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8554 /* handle, or on GNUstep possibly slot */
8555 NSEvent *fake_event;
8558 /* compute float loc in slot and mouse offset on knob */
8559 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8563 length = NSWidth (sr);
8564 loc = ([e locationInWindow].x - NSMinX (sr));
8568 length = NSHeight (sr);
8569 loc = length - ([e locationInWindow].y - NSMinY (sr));
8577 else if (loc >= length)
8587 kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8590 kloc = ([e locationInWindow].x - NSMinX (kr));
8592 kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8594 last_mouse_offset = kloc;
8596 if (part != NSScrollerKnob)
8597 /* this is a slot click on GNUstep: go straight there */
8600 /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8601 fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8602 location: [e locationInWindow]
8603 modifierFlags: [e modifierFlags]
8604 timestamp: [e timestamp]
8605 windowNumber: [e windowNumber]
8607 eventNumber: [e eventNumber]
8608 clickCount: [e clickCount]
8609 pressure: [e pressure]];
8610 [super mouseUp: fake_event];
8614 pos = 0; /* ignored */
8616 /* set a timer to repeat, as we can't let superclass do this modally */
8618 = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8620 selector: @selector (repeatScroll:)
8626 if (part != NSScrollerKnob)
8627 [self sendScrollEventAtLoc: pos fromEvent: e];
8631 /* Called as we manually track scroller drags, rather than superclass. */
8632 - (void)mouseDragged: (NSEvent *)e
8638 NSTRACE ("[EmacsScroller mouseDragged:]");
8640 sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8645 length = NSWidth (sr);
8646 loc = ([e locationInWindow].x - NSMinX (sr));
8650 length = NSHeight (sr);
8651 loc = length - ([e locationInWindow].y - NSMinY (sr));
8658 else if (loc >= length + last_mouse_offset)
8660 loc = length + last_mouse_offset;
8663 pos = (loc - last_mouse_offset);
8664 [self sendScrollEventAtLoc: pos fromEvent: e];
8668 - (void)mouseUp: (NSEvent *)e
8670 NSTRACE ("[EmacsScroller mouseUp:]");
8672 if (scroll_repeat_entry)
8674 [scroll_repeat_entry invalidate];
8675 [scroll_repeat_entry release];
8676 scroll_repeat_entry = nil;
8678 last_hit_part = scroll_bar_above_handle;
8682 /* treat scrollwheel events in the bar as though they were in the main window */
8683 - (void) scrollWheel: (NSEvent *)theEvent
8685 NSTRACE ("[EmacsScroller scrollWheel:]");
8687 EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8688 [view mouseDown: theEvent];
8691 @end /* EmacsScroller */
8694 #ifdef NS_IMPL_GNUSTEP
8695 /* Dummy class to get rid of startup warnings. */
8696 @implementation EmacsDocument
8702 /* ==========================================================================
8704 Font-related functions; these used to be in nsfaces.m
8706 ========================================================================== */
8710 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8712 struct font *font = XFONT_OBJECT (font_object);
8713 EmacsView *view = FRAME_NS_VIEW (f);
8714 int font_ascent, font_descent;
8717 fontset = fontset_from_font (font_object);
8718 FRAME_FONTSET (f) = fontset;
8720 if (FRAME_FONT (f) == font)
8721 /* This font is already set in frame F. There's nothing more to
8725 FRAME_FONT (f) = font;
8727 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8728 FRAME_COLUMN_WIDTH (f) = font->average_width;
8729 get_font_ascent_descent (font, &font_ascent, &font_descent);
8730 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8732 /* Compute the scroll bar width in character columns. */
8733 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8735 int wid = FRAME_COLUMN_WIDTH (f);
8736 FRAME_CONFIG_SCROLL_BAR_COLS (f)
8737 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8741 int wid = FRAME_COLUMN_WIDTH (f);
8742 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8745 /* Compute the scroll bar height in character lines. */
8746 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8748 int height = FRAME_LINE_HEIGHT (f);
8749 FRAME_CONFIG_SCROLL_BAR_LINES (f)
8750 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8754 int height = FRAME_LINE_HEIGHT (f);
8755 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8758 /* Now make the frame display the given font. */
8759 if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8760 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8761 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8768 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8769 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8773 ns_xlfd_to_fontname (const char *xlfd)
8774 /* --------------------------------------------------------------------------
8775 Convert an X font name (XLFD) to an NS font name.
8776 Only family is used.
8777 The string returned is temporarily allocated.
8778 -------------------------------------------------------------------------- */
8780 char *name = xmalloc (180);
8784 if (!strncmp (xlfd, "--", 2))
8785 sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8787 sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8789 /* stopgap for malformed XLFD input */
8790 if (strlen (name) == 0)
8791 strcpy (name, "Monaco");
8793 /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8794 also uppercase after '-' or ' ' */
8795 name[0] = c_toupper (name[0]);
8796 for (len =strlen (name), i =0; i<len; i++)
8802 name[i+1] = c_toupper (name[i+1]);
8804 else if (name[i] == '_')
8808 name[i+1] = c_toupper (name[i+1]);
8811 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
8812 ret = [[NSString stringWithUTF8String: name] UTF8String];
8819 syms_of_nsterm (void)
8821 NSTRACE ("syms_of_nsterm");
8823 ns_antialias_threshold = 10.0;
8825 /* from 23+ we need to tell emacs what modifiers there are.. */
8826 DEFSYM (Qmodifier_value, "modifier-value");
8827 DEFSYM (Qalt, "alt");
8828 DEFSYM (Qhyper, "hyper");
8829 DEFSYM (Qmeta, "meta");
8830 DEFSYM (Qsuper, "super");
8831 DEFSYM (Qcontrol, "control");
8832 DEFSYM (QUTF8_STRING, "UTF8_STRING");
8834 DEFSYM (Qfile, "file");
8835 DEFSYM (Qurl, "url");
8837 Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8838 Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8839 Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8840 Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8841 Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8843 DEFVAR_LISP ("ns-input-file", ns_input_file,
8844 "The file specified in the last NS event.");
8845 ns_input_file =Qnil;
8847 DEFVAR_LISP ("ns-working-text", ns_working_text,
8848 "String for visualizing working composition sequence.");
8849 ns_working_text =Qnil;
8851 DEFVAR_LISP ("ns-input-font", ns_input_font,
8852 "The font specified in the last NS event.");
8853 ns_input_font =Qnil;
8855 DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8856 "The fontsize specified in the last NS event.");
8857 ns_input_fontsize =Qnil;
8859 DEFVAR_LISP ("ns-input-line", ns_input_line,
8860 "The line specified in the last NS event.");
8861 ns_input_line =Qnil;
8863 DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8864 "The service name specified in the last NS event.");
8865 ns_input_spi_name =Qnil;
8867 DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8868 "The service argument specified in the last NS event.");
8869 ns_input_spi_arg =Qnil;
8871 DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8872 "This variable describes the behavior of the alternate or option key.\n\
8873 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8875 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8876 at all, allowing it to be used at a lower level for accented character entry.");
8877 ns_alternate_modifier = Qmeta;
8879 DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8880 "This variable describes the behavior of the right alternate or option key.\n\
8881 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8883 Set to left means be the same key as `ns-alternate-modifier'.\n\
8884 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8885 at all, allowing it to be used at a lower level for accented character entry.");
8886 ns_right_alternate_modifier = Qleft;
8888 DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8889 "This variable describes the behavior of the command key.\n\
8890 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8892 ns_command_modifier = Qsuper;
8894 DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8895 "This variable describes the behavior of the right command key.\n\
8896 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8898 Set to left means be the same key as `ns-command-modifier'.\n\
8899 Set to none means that the command / option key is not interpreted by Emacs\n\
8900 at all, allowing it to be used at a lower level for accented character entry.");
8901 ns_right_command_modifier = Qleft;
8903 DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8904 "This variable describes the behavior of the control key.\n\
8905 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8907 ns_control_modifier = Qcontrol;
8909 DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8910 "This variable describes the behavior of the right control key.\n\
8911 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8913 Set to left means be the same key as `ns-control-modifier'.\n\
8914 Set to none means that the control / option key is not interpreted by Emacs\n\
8915 at all, allowing it to be used at a lower level for accented character entry.");
8916 ns_right_control_modifier = Qleft;
8918 DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8919 "This variable describes the behavior of the function key (on laptops).\n\
8920 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8922 Set to none means that the function key is not interpreted by Emacs at all,\n\
8923 allowing it to be used at a lower level for accented character entry.");
8924 ns_function_modifier = Qnone;
8926 DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8927 "Non-nil (the default) means to render text antialiased.");
8928 ns_antialias_text = Qt;
8930 DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8931 "Whether to confirm application quit using dialog.");
8932 ns_confirm_quit = Qnil;
8934 DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8935 doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8936 Only works on Mac OS X 10.6 or later. */);
8937 ns_auto_hide_menu_bar = Qnil;
8939 DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8940 doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
8941 Nil means use fullscreen the old (< 10.7) way. The old way works better with
8942 multiple monitors, but lacks tool bar. This variable is ignored on
8943 Mac OS X < 10.7. Default is t for 10.7 and later, nil otherwise. */);
8944 #ifdef HAVE_NATIVE_FS
8945 ns_use_native_fullscreen = YES;
8947 ns_use_native_fullscreen = NO;
8949 ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8951 DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8952 doc: /*Non-nil means use animation on non-native fullscreen.
8953 For native fullscreen, this does nothing.
8954 Default is nil. */);
8955 ns_use_fullscreen_animation = NO;
8957 DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8958 doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
8959 Note that this does not apply to images.
8960 This variable is ignored on Mac OS X < 10.7 and GNUstep. */);
8961 ns_use_srgb_colorspace = YES;
8963 /* TODO: move to common code */
8964 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8965 doc: /* Which toolkit scroll bars Emacs uses, if any.
8966 A value of nil means Emacs doesn't use toolkit scroll bars.
8967 With the X Window system, the value is a symbol describing the
8968 X toolkit. Possible values are: gtk, motif, xaw, or xaw3d.
8969 With MS Windows or Nextstep, the value is t. */);
8970 Vx_toolkit_scroll_bars = Qt;
8972 DEFVAR_BOOL ("x-use-underline-position-properties",
8973 x_use_underline_position_properties,
8974 doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8975 A value of nil means ignore them. If you encounter fonts with bogus
8976 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8977 to 4.1, set this to nil. */);
8978 x_use_underline_position_properties = 0;
8980 DEFVAR_BOOL ("x-underline-at-descent-line",
8981 x_underline_at_descent_line,
8982 doc: /* Non-nil means to draw the underline at the same place as the descent line.
8983 A value of nil means to draw the underline according to the value of the
8984 variable `x-use-underline-position-properties', which is usually at the
8985 baseline level. The default value is nil. */);
8986 x_underline_at_descent_line = 0;
8988 /* Tell Emacs about this window system. */
8989 Fprovide (Qns, Qnil);
8991 DEFSYM (Qcocoa, "cocoa");
8992 DEFSYM (Qgnustep, "gnustep");
8994 #ifdef NS_IMPL_COCOA
8995 Fprovide (Qcocoa, Qnil);
8998 Fprovide (Qgnustep, Qnil);