Tell user about read-integer-overflow-as-float
[emacs.git] / src / nsterm.m
blob3c95fedadc9f10f1515e4a1a434dc4e198486833
1 /* NeXT/Open/GNUstep / macOS communication module.      -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2018 Free Software
4 Foundation, Inc.
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 <https://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.  */
31 #include <config.h>
33 #include <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
40 #include <stdbool.h>
42 #include <c-ctype.h>
43 #include <c-strcase.h>
44 #include <ftoastr.h>
46 #include "lisp.h"
47 #include "blockinput.h"
48 #include "sysselect.h"
49 #include "nsterm.h"
50 #include "systime.h"
51 #include "character.h"
52 #include "fontset.h"
53 #include "composite.h"
54 #include "ccl.h"
56 #include "termhooks.h"
57 #include "termchar.h"
58 #include "menu.h"
59 #include "window.h"
60 #include "keyboard.h"
61 #include "buffer.h"
62 #include "font.h"
64 #ifdef NS_IMPL_GNUSTEP
65 #include "process.h"
66 #endif
68 #ifdef NS_IMPL_COCOA
69 #include "macfont.h"
70 #include <Carbon/Carbon.h>
71 #endif
73 static EmacsMenu *dockMenu;
74 #ifdef NS_IMPL_COCOA
75 static EmacsMenu *mainMenu;
76 #endif
78 /* ==========================================================================
80    NSTRACE, Trace support.
82    ========================================================================== */
84 #if NSTRACE_ENABLED
86 /* The following use "volatile" since they can be accessed from
87    parallel threads.  */
88 volatile int nstrace_num = 0;
89 volatile int nstrace_depth = 0;
91 /* When 0, no trace is emitted.  This is used by NSTRACE_WHEN and
92    NSTRACE_UNLESS to silence functions called.
94    TODO: This should really be a thread-local variable, to avoid that
95    a function with disabled trace thread silence trace output in
96    another.  However, in practice this seldom is a problem.  */
97 volatile int nstrace_enabled_global = 1;
99 /* Called when nstrace_enabled goes out of scope.  */
100 void nstrace_leave(int * pointer_to_nstrace_enabled)
102   if (*pointer_to_nstrace_enabled)
103     {
104       --nstrace_depth;
105     }
109 /* Called when nstrace_saved_enabled_global goes out of scope.  */
110 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
112   nstrace_enabled_global = *pointer_to_saved_enabled_global;
116 char const * nstrace_fullscreen_type_name (int fs_type)
118   switch (fs_type)
119     {
120     case -1:                   return "-1";
121     case FULLSCREEN_NONE:      return "FULLSCREEN_NONE";
122     case FULLSCREEN_WIDTH:     return "FULLSCREEN_WIDTH";
123     case FULLSCREEN_HEIGHT:    return "FULLSCREEN_HEIGHT";
124     case FULLSCREEN_BOTH:      return "FULLSCREEN_BOTH";
125     case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
126     default:                   return "FULLSCREEN_?????";
127     }
129 #endif
132 /* ==========================================================================
134    NSColor, EmacsColor category.
136    ========================================================================== */
137 @implementation NSColor (EmacsColor)
138 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
139                          blue:(CGFloat)blue alpha:(CGFloat)alpha
141 #if defined (NS_IMPL_COCOA) \
142   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
143   if (ns_use_srgb_colorspace
144 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
145       && [NSColor respondsToSelector:
146                     @selector(colorWithSRGBRed:green:blue:alpha:)]
147 #endif
148       )
149     return [NSColor colorWithSRGBRed: red
150                                green: green
151                                 blue: blue
152                                alpha: alpha];
153 #endif
154   return [NSColor colorWithCalibratedRed: red
155                                    green: green
156                                     blue: blue
157                                    alpha: alpha];
160 - (NSColor *)colorUsingDefaultColorSpace
162   /* FIXMES: We're checking for colorWithSRGBRed here so this will
163      only work in the same place as in the method above.  It should
164      really be a check whether we're on macOS 10.7 or above.  */
165 #if defined (NS_IMPL_COCOA) \
166   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
167   if (ns_use_srgb_colorspace
168 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
169       && [NSColor respondsToSelector:
170                     @selector(colorWithSRGBRed:green:blue:alpha:)]
171 #endif
172       )
173     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
174 #endif
175   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
178 @end
180 /* ==========================================================================
182     Local declarations
184    ========================================================================== */
186 /* Convert a symbol indexed with an NSxxx value to a value as defined
187    in keyboard.c (lispy_function_key). I hope this is a correct way
188    of doing things...  */
189 static unsigned convert_ns_to_X_keysym[] =
191   NSHomeFunctionKey,            0x50,
192   NSLeftArrowFunctionKey,       0x51,
193   NSUpArrowFunctionKey,         0x52,
194   NSRightArrowFunctionKey,      0x53,
195   NSDownArrowFunctionKey,       0x54,
196   NSPageUpFunctionKey,          0x55,
197   NSPageDownFunctionKey,        0x56,
198   NSEndFunctionKey,             0x57,
199   NSBeginFunctionKey,           0x58,
200   NSSelectFunctionKey,          0x60,
201   NSPrintFunctionKey,           0x61,
202   NSClearLineFunctionKey,       0x0B,
203   NSExecuteFunctionKey,         0x62,
204   NSInsertFunctionKey,          0x63,
205   NSUndoFunctionKey,            0x65,
206   NSRedoFunctionKey,            0x66,
207   NSMenuFunctionKey,            0x67,
208   NSFindFunctionKey,            0x68,
209   NSHelpFunctionKey,            0x6A,
210   NSBreakFunctionKey,           0x6B,
212   NSF1FunctionKey,              0xBE,
213   NSF2FunctionKey,              0xBF,
214   NSF3FunctionKey,              0xC0,
215   NSF4FunctionKey,              0xC1,
216   NSF5FunctionKey,              0xC2,
217   NSF6FunctionKey,              0xC3,
218   NSF7FunctionKey,              0xC4,
219   NSF8FunctionKey,              0xC5,
220   NSF9FunctionKey,              0xC6,
221   NSF10FunctionKey,             0xC7,
222   NSF11FunctionKey,             0xC8,
223   NSF12FunctionKey,             0xC9,
224   NSF13FunctionKey,             0xCA,
225   NSF14FunctionKey,             0xCB,
226   NSF15FunctionKey,             0xCC,
227   NSF16FunctionKey,             0xCD,
228   NSF17FunctionKey,             0xCE,
229   NSF18FunctionKey,             0xCF,
230   NSF19FunctionKey,             0xD0,
231   NSF20FunctionKey,             0xD1,
232   NSF21FunctionKey,             0xD2,
233   NSF22FunctionKey,             0xD3,
234   NSF23FunctionKey,             0xD4,
235   NSF24FunctionKey,             0xD5,
237   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs.  */
238   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right.  */
239   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array.  */
241   NSTabCharacter,               0x09,
242   0x19,                         0x09,  /* left tab->regular since pass shift */
243   NSCarriageReturnCharacter,    0x0D,
244   NSNewlineCharacter,           0x0D,
245   NSEnterCharacter,             0x8D,
247   0x41|NSEventModifierFlagNumericPad,   0xAE,  /* KP_Decimal */
248   0x43|NSEventModifierFlagNumericPad,   0xAA,  /* KP_Multiply */
249   0x45|NSEventModifierFlagNumericPad,   0xAB,  /* KP_Add */
250   0x4B|NSEventModifierFlagNumericPad,   0xAF,  /* KP_Divide */
251   0x4E|NSEventModifierFlagNumericPad,   0xAD,  /* KP_Subtract */
252   0x51|NSEventModifierFlagNumericPad,   0xBD,  /* KP_Equal */
253   0x52|NSEventModifierFlagNumericPad,   0xB0,  /* KP_0 */
254   0x53|NSEventModifierFlagNumericPad,   0xB1,  /* KP_1 */
255   0x54|NSEventModifierFlagNumericPad,   0xB2,  /* KP_2 */
256   0x55|NSEventModifierFlagNumericPad,   0xB3,  /* KP_3 */
257   0x56|NSEventModifierFlagNumericPad,   0xB4,  /* KP_4 */
258   0x57|NSEventModifierFlagNumericPad,   0xB5,  /* KP_5 */
259   0x58|NSEventModifierFlagNumericPad,   0xB6,  /* KP_6 */
260   0x59|NSEventModifierFlagNumericPad,   0xB7,  /* KP_7 */
261   0x5B|NSEventModifierFlagNumericPad,   0xB8,  /* KP_8 */
262   0x5C|NSEventModifierFlagNumericPad,   0xB9,  /* KP_9 */
264   0x1B,                         0x1B   /* escape */
267 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
268    the maximum font size to NOT antialias.  On GNUstep there is currently
269    no way to control this behavior.  */
270 float ns_antialias_threshold;
272 NSArray *ns_send_types = 0, *ns_return_types = 0;
273 static NSArray *ns_drag_types = 0;
274 NSString *ns_app_name = @"Emacs";  /* default changed later */
276 /* Display variables */
277 struct ns_display_info *x_display_list; /* Chain of existing displays */
278 long context_menu_value = 0;
280 /* display update */
281 static struct frame *ns_updating_frame;
282 static NSView *focus_view = NULL;
283 static int ns_window_num = 0;
284 #ifdef NS_IMPL_GNUSTEP
285 static NSRect uRect;            // TODO: This is dead, remove it?
286 #endif
287 static BOOL gsaved = NO;
288 static BOOL ns_fake_keydown = NO;
289 #ifdef NS_IMPL_COCOA
290 static BOOL ns_menu_bar_is_hidden = NO;
292 /* The number of times NSDisableScreenUpdates has been called.  */
293 static int disable_screen_updates_count = 0;
294 #endif
295 /* static int debug_lock = 0; */
297 /* event loop */
298 static BOOL send_appdefined = YES;
299 #define NO_APPDEFINED_DATA (-8)
300 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
301 static NSTimer *timed_entry = 0;
302 static NSTimer *scroll_repeat_entry = nil;
303 static fd_set select_readfds, select_writefds;
304 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
305 static int select_nfds = 0, select_valid = 0;
306 static struct timespec select_timeout = { 0, 0 };
307 static int selfds[2] = { -1, -1 };
308 static pthread_mutex_t select_mutex;
309 static NSAutoreleasePool *outerpool;
310 static struct input_event *emacs_event = NULL;
311 static struct input_event *q_event_ptr = NULL;
312 static int n_emacs_events_pending = 0;
313 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
314   *ns_pending_service_args;
315 static BOOL ns_do_open_file = NO;
316 static BOOL ns_last_use_native_fullscreen;
318 /* Non-zero means that a HELP_EVENT has been generated since Emacs
319    start.  */
321 static BOOL any_help_event_p = NO;
323 static struct {
324   struct input_event *q;
325   int nr, cap;
326 } hold_event_q = {
327   NULL, 0, 0
330 #ifdef NS_IMPL_COCOA
332  * State for pending menu activation:
333  * MENU_NONE     Normal state
334  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
335  *               run lisp to update the menu.
336  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
337  *               will open.
338  */
339 #define MENU_NONE 0
340 #define MENU_PENDING 1
341 #define MENU_OPENING 2
342 static int menu_will_open_state = MENU_NONE;
344 /* Saved position for menu click.  */
345 static CGPoint menu_mouse_point;
346 #endif
348 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
349 #define NS_FUNCTION_KEY_MASK 0x800000
350 #define NSLeftControlKeyMask    (0x000001 | NSEventModifierFlagControl)
351 #define NSRightControlKeyMask   (0x002000 | NSEventModifierFlagControl)
352 #define NSLeftCommandKeyMask    (0x000008 | NSEventModifierFlagCommand)
353 #define NSRightCommandKeyMask   (0x000010 | NSEventModifierFlagCommand)
354 #define NSLeftAlternateKeyMask  (0x000020 | NSEventModifierFlagOption)
355 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
357 static unsigned int
358 ev_modifiers_helper (unsigned int flags, unsigned int left_mask,
359                      unsigned int right_mask, unsigned int either_mask,
360                      Lisp_Object left_modifier, Lisp_Object right_modifier)
362   unsigned int modifiers = 0;
364   if (flags & either_mask)
365     {
366       BOOL left_key = (flags & left_mask) == left_mask;
367       BOOL right_key = (flags & right_mask) == right_mask
368         && ! EQ (right_modifier, Qleft);
370       if (right_key)
371         modifiers |= parse_solitary_modifier (right_modifier);
373       /* GNUstep (and possibly macOS in certain circumstances) doesn't
374          differentiate between the left and right keys, so if we can't
375          identify which key it is, we use the left key setting.  */
376       if (left_key || ! right_key)
377         modifiers |= parse_solitary_modifier (left_modifier);
378     }
380   return modifiers;
383 #define EV_MODIFIERS2(flags)                                            \
384   (((flags & NSEventModifierFlagHelp) ?                                 \
385     hyper_modifier : 0)                                                 \
386    | ((flags & NSEventModifierFlagShift) ?                              \
387       shift_modifier : 0)                                               \
388    | ((flags & NS_FUNCTION_KEY_MASK) ?                                  \
389       parse_solitary_modifier (ns_function_modifier) : 0)               \
390    | ev_modifiers_helper (flags, NSLeftControlKeyMask,                  \
391                           NSRightControlKeyMask,                        \
392                           NSEventModifierFlagControl,                   \
393                           ns_control_modifier,                          \
394                           ns_right_control_modifier)                    \
395    | ev_modifiers_helper (flags, NSLeftCommandKeyMask,                  \
396                           NSRightCommandKeyMask,                        \
397                           NSEventModifierFlagCommand,                   \
398                           ns_command_modifier,                          \
399                           ns_right_command_modifier)                    \
400    | ev_modifiers_helper (flags, NSLeftAlternateKeyMask,                \
401                           NSRightAlternateKeyMask,                      \
402                           NSEventModifierFlagOption,                    \
403                           ns_alternate_modifier,                        \
404                           ns_right_alternate_modifier))
406 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
408 #define EV_UDMODIFIERS(e)                                      \
409     ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0)       \
410      | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0)    \
411      | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0)    \
412      | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0)  \
413      | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
414      | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
415      | (([e type] == NSEventTypeLeftMouseUp)   ? up_modifier   : 0)     \
416      | (([e type] == NSEventTypeRightMouseUp)   ? up_modifier   : 0)    \
417      | (([e type] == NSEventTypeOtherMouseUp)   ? up_modifier   : 0))
419 #define EV_BUTTON(e)                                                         \
420     ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 :    \
421       (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
422      [e buttonNumber] - 1)
424 /* Convert the time field to a timestamp in milliseconds.  */
425 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
427 /* This is a piece of code which is common to all the event handling
428    methods.  Maybe it should even be a function.  */
429 #define EV_TRAILER(e)                                                   \
430   {                                                                     \
431     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
432     EV_TRAILER2 (e);                                                    \
433   }
435 #define EV_TRAILER2(e)                                                  \
436   {                                                                     \
437       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
438       if (q_event_ptr)                                                  \
439         {                                                               \
440           Lisp_Object tem = Vinhibit_quit;                              \
441           Vinhibit_quit = Qt;                                           \
442           n_emacs_events_pending++;                                     \
443           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
444           Vinhibit_quit = tem;                                          \
445         }                                                               \
446       else                                                              \
447         hold_event (emacs_event);                                       \
448       EVENT_INIT (*emacs_event);                                        \
449       ns_send_appdefined (-1);                                          \
450     }
453 /* These flags will be OR'd or XOR'd with the NSWindow's styleMask
454    property depending on what we're doing.  */
455 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled              \
456                                | NSWindowStyleMaskResizable         \
457                                | NSWindowStyleMaskMiniaturizable    \
458                                | NSWindowStyleMaskClosable)
459 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
461 /* TODO: Get rid of need for these forward declarations.  */
462 static void ns_condemn_scroll_bars (struct frame *f);
463 static void ns_judge_scroll_bars (struct frame *f);
466 /* ==========================================================================
468     Utilities
470    ========================================================================== */
472 void
473 ns_init_events (struct input_event *ev)
475   EVENT_INIT (*ev);
476   emacs_event = ev;
479 void
480 ns_finish_events (void)
482   emacs_event = NULL;
485 static void
486 hold_event (struct input_event *event)
488   if (hold_event_q.nr == hold_event_q.cap)
489     {
490       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
491       else hold_event_q.cap *= 2;
492       hold_event_q.q =
493         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
494     }
496   hold_event_q.q[hold_event_q.nr++] = *event;
497   /* Make sure ns_read_socket is called, i.e. we have input.  */
498   raise (SIGIO);
499   send_appdefined = YES;
502 static Lisp_Object
503 append2 (Lisp_Object list, Lisp_Object item)
504 /* --------------------------------------------------------------------------
505    Utility to append to a list
506    -------------------------------------------------------------------------- */
508   return CALLN (Fnconc, list, list1 (item));
512 const char *
513 ns_etc_directory (void)
514 /* If running as a self-contained app bundle, return as a string the
515    filename of the etc directory, if present; else nil.  */
517   NSBundle *bundle = [NSBundle mainBundle];
518   NSString *resourceDir = [bundle resourcePath];
519   NSString *resourcePath;
520   NSFileManager *fileManager = [NSFileManager defaultManager];
521   BOOL isDir;
523   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
524   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
525     {
526       if (isDir) return [resourcePath UTF8String];
527     }
528   return NULL;
532 const char *
533 ns_exec_path (void)
534 /* If running as a self-contained app bundle, return as a path string
535    the filenames of the libexec and bin directories, ie libexec:bin.
536    Otherwise, return nil.
537    Normally, Emacs does not add its own bin/ directory to the PATH.
538    However, a self-contained NS build has a different layout, with
539    bin/ and libexec/ subdirectories in the directory that contains
540    Emacs.app itself.
541    We put libexec first, because init_callproc_1 uses the first
542    element to initialize exec-directory.  An alternative would be
543    for init_callproc to check for invocation-directory/libexec.
546   NSBundle *bundle = [NSBundle mainBundle];
547   NSString *resourceDir = [bundle resourcePath];
548   NSString *binDir = [bundle bundlePath];
549   NSString *resourcePath, *resourcePaths;
550   NSRange range;
551   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
552   NSFileManager *fileManager = [NSFileManager defaultManager];
553   NSArray *paths;
554   NSEnumerator *pathEnum;
555   BOOL isDir;
557   range = [resourceDir rangeOfString: @"Contents"];
558   if (range.location != NSNotFound)
559     {
560       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
561 #ifdef NS_IMPL_COCOA
562       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
563 #endif
564     }
566   paths = [binDir stringsByAppendingPaths:
567                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
568   pathEnum = [paths objectEnumerator];
569   resourcePaths = @"";
571   while ((resourcePath = [pathEnum nextObject]))
572     {
573       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
574         if (isDir)
575           {
576             if ([resourcePaths length] > 0)
577               resourcePaths
578                 = [resourcePaths stringByAppendingString: pathSeparator];
579             resourcePaths
580               = [resourcePaths stringByAppendingString: resourcePath];
581           }
582     }
583   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
585   return NULL;
589 const char *
590 ns_load_path (void)
591 /* If running as a self-contained app bundle, return as a path string
592    the filenames of the site-lisp and lisp directories.
593    Ie, site-lisp:lisp.  Otherwise, return nil.  */
595   NSBundle *bundle = [NSBundle mainBundle];
596   NSString *resourceDir = [bundle resourcePath];
597   NSString *resourcePath, *resourcePaths;
598   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
599   NSFileManager *fileManager = [NSFileManager defaultManager];
600   BOOL isDir;
601   NSArray *paths = [resourceDir stringsByAppendingPaths:
602                               [NSArray arrayWithObjects:
603                                          @"site-lisp", @"lisp", nil]];
604   NSEnumerator *pathEnum = [paths objectEnumerator];
605   resourcePaths = @"";
607   /* Hack to skip site-lisp.  */
608   if (no_site_lisp) resourcePath = [pathEnum nextObject];
610   while ((resourcePath = [pathEnum nextObject]))
611     {
612       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
613         if (isDir)
614           {
615             if ([resourcePaths length] > 0)
616               resourcePaths
617                 = [resourcePaths stringByAppendingString: pathSeparator];
618             resourcePaths
619               = [resourcePaths stringByAppendingString: resourcePath];
620           }
621     }
622   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
624   return NULL;
628 void
629 ns_init_locale (void)
630 /* macOS doesn't set any environment variables for the locale when run
631    from the GUI. Get the locale from the OS and set LANG.  */
633   NSLocale *locale = [NSLocale currentLocale];
635   NSTRACE ("ns_init_locale");
637   @try
638     {
639       /* It seems macOS should probably use UTF-8 everywhere.
640          'localeIdentifier' does not specify the encoding, and I can't
641          find any way to get the OS to tell us which encoding to use,
642          so hard-code '.UTF-8'.  */
643       NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
644                                      [locale localeIdentifier]];
646       /* Set LANG to locale, but not if LANG is already set.  */
647       setenv("LANG", [localeID UTF8String], 0);
648     }
649   @catch (NSException *e)
650     {
651       NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
652     }
656 void
657 ns_release_object (void *obj)
658 /* --------------------------------------------------------------------------
659     Release an object (callable from C)
660    -------------------------------------------------------------------------- */
662     [(id)obj release];
666 void
667 ns_retain_object (void *obj)
668 /* --------------------------------------------------------------------------
669      Retain an object (callable from C)
670    -------------------------------------------------------------------------- */
672     [(id)obj retain];
676 void *
677 ns_alloc_autorelease_pool (void)
678 /* --------------------------------------------------------------------------
679      Allocate a pool for temporary objects (callable from C)
680    -------------------------------------------------------------------------- */
682   return [[NSAutoreleasePool alloc] init];
686 void
687 ns_release_autorelease_pool (void *pool)
688 /* --------------------------------------------------------------------------
689      Free a pool and temporary objects it refers to (callable from C)
690    -------------------------------------------------------------------------- */
692   ns_release_object (pool);
696 #ifdef NS_IMPL_COCOA
697 /* Disabling screen updates can be used to make several actions appear
698    "atomic" to the end user.  It seems some actions can still update
699    the display, though.
701    When we re-enable screen updates the number of calls to
702    NSEnableScreenUpdates should match the number to
703    NSDisableScreenUpdates.
705    We use these functions to prevent the user seeing a blank frame
706    after it has been resized.  x_set_window_size disables updates and
707    when redisplay completes unwind_redisplay enables them again
708    (bug#30699).  */
710 static void
711 ns_disable_screen_updates (void)
713   NSDisableScreenUpdates ();
714   disable_screen_updates_count++;
717 void
718 ns_enable_screen_updates (void)
719 /* Re-enable screen updates.  Called from unwind_redisplay.  */
721   while (disable_screen_updates_count > 0)
722     {
723       NSEnableScreenUpdates ();
724       disable_screen_updates_count--;
725     }
727 #endif
730 static BOOL
731 ns_menu_bar_should_be_hidden (void)
732 /* True, if the menu bar should be hidden.  */
734   return !NILP (ns_auto_hide_menu_bar)
735     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
739 struct EmacsMargins
741   CGFloat top;
742   CGFloat bottom;
743   CGFloat left;
744   CGFloat right;
748 static struct EmacsMargins
749 ns_screen_margins (NSScreen *screen)
750 /* The parts of SCREEN used by the operating system.  */
752   NSTRACE ("ns_screen_margins");
754   struct EmacsMargins margins;
756   NSRect screenFrame = [screen frame];
757   NSRect screenVisibleFrame = [screen visibleFrame];
759   /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
760      menu bar, check this explicitly.  */
761   if (ns_menu_bar_should_be_hidden())
762     {
763       margins.top = 0;
764     }
765   else
766     {
767       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
768       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
769                                  + screenVisibleFrame.size.height);
771       margins.top = frameTop - visibleFrameTop;
772     }
774   {
775     CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
776     CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
777                                  + screenVisibleFrame.size.width);
778     margins.right = frameRight - visibleFrameRight;
779   }
781   margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
782   margins.left   = screenVisibleFrame.origin.x - screenFrame.origin.x;
784   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
785                margins.left,
786                margins.right,
787                margins.top,
788                margins.bottom);
790   return margins;
794 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
795    assumed to contain a hidden dock.  macOS currently use 4 pixels for
796    this, however, to be future compatible, a larger value is used.  */
797 #define DOCK_IGNORE_LIMIT 6
799 static struct EmacsMargins
800 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
801 /* The parts of SCREEN used by the operating system, excluding the parts
802    reserved for a hidden dock.  */
804   NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
806   struct EmacsMargins margins = ns_screen_margins(screen);
808   /* macOS (currently) reserved 4 pixels along the edge where a hidden
809      dock is located.  Unfortunately, it's not possible to find the
810      location and information about if the dock is hidden.  Instead,
811      it is assumed that if the margin of an edge is less than
812      DOCK_IGNORE_LIMIT, it contains a hidden dock.  */
813   if (margins.left <= DOCK_IGNORE_LIMIT)
814     {
815       margins.left = 0;
816     }
817   if (margins.right <= DOCK_IGNORE_LIMIT)
818     {
819       margins.right = 0;
820     }
821   if (margins.top <= DOCK_IGNORE_LIMIT)
822     {
823       margins.top = 0;
824     }
825   /* Note: This doesn't occur in current versions of macOS, but
826      included for completeness and future compatibility.  */
827   if (margins.bottom <= DOCK_IGNORE_LIMIT)
828     {
829       margins.bottom = 0;
830     }
832   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
833                margins.left,
834                margins.right,
835                margins.top,
836                margins.bottom);
838   return margins;
842 static CGFloat
843 ns_menu_bar_height (NSScreen *screen)
844 /* The height of the menu bar, if visible.
846    Note: Don't use this when fullscreen is enabled -- the screen
847    sometimes includes, sometimes excludes the menu bar area.  */
849   struct EmacsMargins margins = ns_screen_margins(screen);
851   CGFloat res = margins.top;
853   NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
855   return res;
859 /* ==========================================================================
861     Focus (clipping) and screen update
863    ========================================================================== */
866 // Window constraining
867 // -------------------
869 // To ensure that the windows are not placed under the menu bar, they
870 // are typically moved by the call-back constrainFrameRect. However,
871 // by overriding it, it's possible to inhibit this, leaving the window
872 // in it's original position.
874 // It's possible to hide the menu bar. However, technically, it's only
875 // possible to hide it when the application is active. To ensure that
876 // this work properly, the menu bar and window constraining are
877 // deferred until the application becomes active.
879 // Even though it's not possible to manually move a window above the
880 // top of the screen, it is allowed if it's done programmatically,
881 // when the menu is hidden. This allows the editable area to cover the
882 // full screen height.
884 // Test cases
885 // ----------
887 // Use the following extra files:
889 //    init.el:
890 //       ;; Hide menu and place frame slightly above the top of the screen.
891 //       (setq ns-auto-hide-menu-bar t)
892 //       (set-frame-position (selected-frame) 0 -20)
894 // Test 1:
896 //    emacs -Q -l init.el
898 //    Result: No menu bar, and the title bar should be above the screen.
900 // Test 2:
902 //    emacs -Q
904 //    Result: Menu bar visible, frame placed immediately below the menu.
907 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
909   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
910              NSTRACE_ARG_RECT (frameRect));
912   // --------------------
913   // Collect information about the screen the frame is covering.
914   //
916   NSArray *screens = [NSScreen screens];
917   NSUInteger nr_screens = [screens count];
919   int i;
921   // The height of the menu bar, if present in any screen the frame is
922   // displayed in.
923   int menu_bar_height = 0;
925   // A rectangle covering all the screen the frame is displayed in.
926   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
927   for (i = 0; i < nr_screens; ++i )
928     {
929       NSScreen *s = [screens objectAtIndex: i];
930       NSRect scrRect = [s frame];
932       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
933                    i, NSTRACE_ARG_RECT (scrRect));
935       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
936         {
937           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
939           if (!isFullscreen)
940             {
941               CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
942               menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
943             }
944         }
945     }
947   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
949   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
951   if (multiscreenRect.size.width == 0
952       || multiscreenRect.size.height == 0)
953     {
954       // Failed to find any monitor, give up.
955       NSTRACE_MSG ("multiscreenRect empty");
956       NSTRACE_RETURN_RECT (frameRect);
957       return frameRect;
958     }
961   // --------------------
962   // Find a suitable placement.
963   //
965   if (ns_menu_bar_should_be_hidden())
966     {
967       // When the menu bar is hidden, the user may place part of the
968       // frame above the top of the screen, for example to hide the
969       // title bar.
970       //
971       // Hence, keep the original position.
972     }
973   else
974     {
975       // Ensure that the frame is below the menu bar, or below the top
976       // of the screen.
977       //
978       // This assume that the menu bar is placed at the top in the
979       // rectangle that covers the monitors.  (It doesn't have to be,
980       // but if it's not it's hard to do anything useful.)
981       CGFloat topOfWorkArea = (multiscreenRect.origin.y
982                                + multiscreenRect.size.height
983                                - menu_bar_height);
985       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
986       if (topOfFrame > topOfWorkArea)
987         {
988           frameRect.origin.y -= topOfFrame - topOfWorkArea;
989           NSTRACE_RECT ("After placement adjust", frameRect);
990         }
991     }
993   // Include the following section to restrict frame to the screens.
994   // (If so, update it to allow the frame to stretch down below the
995   // screen.)
996 #if 0
997   // --------------------
998   // Ensure frame doesn't stretch below the screens.
999   //
1001   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
1003   if (diff > 0)
1004     {
1005       frameRect.origin.y = multiscreenRect.origin.y;
1006       frameRect.size.height -= diff;
1007     }
1008 #endif
1010   NSTRACE_RETURN_RECT (frameRect);
1011   return frameRect;
1015 static void
1016 ns_constrain_all_frames (void)
1017 /* --------------------------------------------------------------------------
1018      Ensure that the menu bar doesn't cover any frames.
1019    -------------------------------------------------------------------------- */
1021   Lisp_Object tail, frame;
1023   NSTRACE ("ns_constrain_all_frames");
1025   block_input ();
1027   FOR_EACH_FRAME (tail, frame)
1028     {
1029       struct frame *f = XFRAME (frame);
1030       if (FRAME_NS_P (f))
1031         {
1032           EmacsView *view = FRAME_NS_VIEW (f);
1034           if (![view isFullscreen])
1035             {
1036               [[view window]
1037                 setFrame:constrain_frame_rect([[view window] frame], false)
1038                  display:NO];
1039             }
1040         }
1041     }
1043   unblock_input ();
1047 static void
1048 ns_update_auto_hide_menu_bar (void)
1049 /* --------------------------------------------------------------------------
1050      Show or hide the menu bar, based on user setting.
1051    -------------------------------------------------------------------------- */
1053 #ifdef NS_IMPL_COCOA
1054   NSTRACE ("ns_update_auto_hide_menu_bar");
1056   block_input ();
1058   if (NSApp != nil && [NSApp isActive])
1059     {
1060       // Note, "setPresentationOptions" triggers an error unless the
1061       // application is active.
1062       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1064       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1065         {
1066           NSApplicationPresentationOptions options
1067             = NSApplicationPresentationDefault;
1069           if (menu_bar_should_be_hidden)
1070             options |= NSApplicationPresentationAutoHideMenuBar
1071               | NSApplicationPresentationAutoHideDock;
1073           [NSApp setPresentationOptions: options];
1075           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1077           if (!ns_menu_bar_is_hidden)
1078             {
1079               ns_constrain_all_frames ();
1080             }
1081         }
1082     }
1084   unblock_input ();
1085 #endif
1089 static void
1090 ns_update_begin (struct frame *f)
1091 /* --------------------------------------------------------------------------
1092    Prepare for a grouped sequence of drawing calls
1093    external (RIF) call; whole frame, called before update_window_begin
1094    -------------------------------------------------------------------------- */
1096   EmacsView *view = FRAME_NS_VIEW (f);
1097   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1099   ns_update_auto_hide_menu_bar ();
1101 #ifdef NS_IMPL_COCOA
1102   if ([view isFullscreen] && [view fsIsNative])
1103   {
1104     // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1105     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1106     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1107     if (! tbar_visible != ! [toolbar isVisible])
1108       [toolbar setVisible: tbar_visible];
1109   }
1110 #endif
1112   ns_updating_frame = f;
1113   [view lockFocus];
1115   /* drawRect may have been called for say the minibuffer, and then clip path
1116      is for the minibuffer.  But the display engine may draw more because
1117      we have set the frame as garbaged.  So reset clip path to the whole
1118      view.  */
1119 #ifdef NS_IMPL_COCOA
1120   {
1121     NSBezierPath *bp;
1122     NSRect r = [view frame];
1123     NSRect cr = [[view window] frame];
1124     /* If a large frame size is set, r may be larger than the window frame
1125        before constrained.  In that case don't change the clip path, as we
1126        will clear in to the tool bar and title bar.  */
1127     if (r.size.height
1128         + FRAME_NS_TITLEBAR_HEIGHT (f)
1129         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1130       {
1131         bp = [[NSBezierPath bezierPathWithRect: r] retain];
1132         [bp setClip];
1133         [bp release];
1134       }
1135   }
1136 #endif
1138 #ifdef NS_IMPL_GNUSTEP
1139   uRect = NSMakeRect (0, 0, 0, 0);
1140 #endif
1144 static void
1145 ns_update_window_begin (struct window *w)
1146 /* --------------------------------------------------------------------------
1147    Prepare for a grouped sequence of drawing calls
1148    external (RIF) call; for one window, called after update_begin
1149    -------------------------------------------------------------------------- */
1151   struct frame *f = XFRAME (WINDOW_FRAME (w));
1152   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1154   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1155   w->output_cursor = w->cursor;
1157   block_input ();
1159   if (f == hlinfo->mouse_face_mouse_frame)
1160     {
1161       /* Don't do highlighting for mouse motion during the update.  */
1162       hlinfo->mouse_face_defer = 1;
1164         /* If the frame needs to be redrawn,
1165            simply forget about any prior mouse highlighting.  */
1166       if (FRAME_GARBAGED_P (f))
1167         hlinfo->mouse_face_window = Qnil;
1169       /* (further code for mouse faces ifdef'd out in other terms elided) */
1170     }
1172   unblock_input ();
1176 static void
1177 ns_update_window_end (struct window *w, bool cursor_on_p,
1178                       bool mouse_face_overwritten_p)
1179 /* --------------------------------------------------------------------------
1180    Finished a grouped sequence of drawing calls
1181    external (RIF) call; for one window called before update_end
1182    -------------------------------------------------------------------------- */
1184   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1186   /* note: this fn is nearly identical in all terms */
1187   if (!w->pseudo_window_p)
1188     {
1189       block_input ();
1191       if (cursor_on_p)
1192         display_and_set_cursor (w, 1,
1193                                 w->output_cursor.hpos, w->output_cursor.vpos,
1194                                 w->output_cursor.x, w->output_cursor.y);
1196       if (draw_window_fringes (w, 1))
1197         {
1198           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1199             x_draw_right_divider (w);
1200           else
1201             x_draw_vertical_border (w);
1202         }
1204       unblock_input ();
1205     }
1207   /* If a row with mouse-face was overwritten, arrange for
1208      frame_up_to_date to redisplay the mouse highlight.  */
1209   if (mouse_face_overwritten_p)
1210     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1214 static void
1215 ns_update_end (struct frame *f)
1216 /* --------------------------------------------------------------------------
1217    Finished a grouped sequence of drawing calls
1218    external (RIF) call; for whole frame, called after update_window_end
1219    -------------------------------------------------------------------------- */
1221   EmacsView *view = FRAME_NS_VIEW (f);
1223   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1225 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1226   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1228   block_input ();
1230   [view unlockFocus];
1231   [[view window] flushWindow];
1233   unblock_input ();
1234   ns_updating_frame = NULL;
1237 static void
1238 ns_focus (struct frame *f, NSRect *r, int n)
1239 /* --------------------------------------------------------------------------
1240    Internal: Focus on given frame.  During small local updates this is used to
1241      draw, however during large updates, ns_update_begin and ns_update_end are
1242      called to wrap the whole thing, in which case these calls are stubbed out.
1243      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1244      the back end won't do this automatically, and will just end up flushing
1245      the entire window.
1246    -------------------------------------------------------------------------- */
1248   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1249   if (r != NULL)
1250     {
1251       NSTRACE_RECT ("r", *r);
1252     }
1254   if (f != ns_updating_frame)
1255     {
1256       NSView *view = FRAME_NS_VIEW (f);
1257       if (view != focus_view)
1258         {
1259           if (focus_view != NULL)
1260             {
1261               [focus_view unlockFocus];
1262               [[focus_view window] flushWindow];
1263 /* debug_lock--; */
1264             }
1266           if (view)
1267             [view lockFocus];
1268           focus_view = view;
1269 /* if (view) debug_lock++; */
1270         }
1271     }
1273   /* clipping */
1274   if (r)
1275     {
1276       [[NSGraphicsContext currentContext] saveGraphicsState];
1277       if (n == 2)
1278         NSRectClipList (r, 2);
1279       else
1280         NSRectClip (*r);
1281       gsaved = YES;
1282     }
1286 static void
1287 ns_unfocus (struct frame *f)
1288 /* --------------------------------------------------------------------------
1289      Internal: Remove focus on given frame
1290    -------------------------------------------------------------------------- */
1292   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1294   if (gsaved)
1295     {
1296       [[NSGraphicsContext currentContext] restoreGraphicsState];
1297       gsaved = NO;
1298     }
1300   if (f != ns_updating_frame)
1301     {
1302       if (focus_view != NULL)
1303         {
1304           [focus_view unlockFocus];
1305           [[focus_view window] flushWindow];
1306           focus_view = NULL;
1307 /* debug_lock--; */
1308         }
1309     }
1313 static void
1314 ns_clip_to_row (struct window *w, struct glyph_row *row,
1315                 enum glyph_row_area area, BOOL gc)
1316 /* --------------------------------------------------------------------------
1317      Internal (but parallels other terms): Focus drawing on given row
1318    -------------------------------------------------------------------------- */
1320   struct frame *f = XFRAME (WINDOW_FRAME (w));
1321   NSRect clip_rect;
1322   int window_x, window_y, window_width;
1324   window_box (w, area, &window_x, &window_y, &window_width, 0);
1326   clip_rect.origin.x = window_x;
1327   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1328   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1329   clip_rect.size.width = window_width;
1330   clip_rect.size.height = row->visible_height;
1332   ns_focus (f, &clip_rect, 1);
1336 /* ==========================================================================
1338     Visible bell and beep.
1340    ========================================================================== */
1343 // This bell implementation shows the visual bell image asynchronously
1344 // from the rest of Emacs. This is done by adding a NSView to the
1345 // superview of the Emacs window and removing it using a timer.
1347 // Unfortunately, some Emacs operations, like scrolling, is done using
1348 // low-level primitives that copy the content of the window, including
1349 // the bell image. To some extent, this is handled by removing the
1350 // image prior to scrolling and marking that the window is in need for
1351 // redisplay.
1353 // To test this code, make sure that there is no artifacts of the bell
1354 // image in the following situations. Use a non-empty buffer (like the
1355 // tutorial) to ensure that a scroll is performed:
1357 // * Single-window: C-g C-v
1359 // * Side-by-windows: C-x 3 C-g C-v
1361 // * Windows above each other: C-x 2 C-g C-v
1363 @interface EmacsBell : NSImageView
1365   // Number of currently active bells.
1366   unsigned int nestCount;
1367   NSView * mView;
1368   bool isAttached;
1370 - (void)show:(NSView *)view;
1371 - (void)hide;
1372 - (void)remove;
1373 @end
1375 @implementation EmacsBell
1377 - (id)init
1379   NSTRACE ("[EmacsBell init]");
1380   if ((self = [super init]))
1381     {
1382       nestCount = 0;
1383       isAttached = false;
1384 #ifdef NS_IMPL_GNUSTEP
1385       // GNUstep doesn't provide named images.  This was reported in
1386       // 2011, see https://savannah.gnu.org/bugs/?33396
1387       //
1388       // As a drop in replacement, a semitransparent gray square is used.
1389       self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1390       [self.image lockFocus];
1391       [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1392       NSRectFill(NSMakeRect(0, 0, 32, 32));
1393       [self.image unlockFocus];
1394 #else
1395       self.image = [NSImage imageNamed:NSImageNameCaution];
1396       [self.image setSize:NSMakeSize(self.image.size.width * 5,
1397                                      self.image.size.height * 5)];
1398 #endif
1399     }
1400   return self;
1403 - (void)show:(NSView *)view
1405   NSTRACE ("[EmacsBell show:]");
1406   NSTRACE_MSG ("nestCount: %u", nestCount);
1408   // Show the image, unless it's already shown.
1409   if (nestCount == 0)
1410     {
1411       NSRect rect = [view bounds];
1412       NSPoint pos;
1413       pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
1414       pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1416       [self setFrameOrigin:pos];
1417       [self setFrameSize:self.image.size];
1419       isAttached = true;
1420       mView = view;
1421       [[[view window] contentView] addSubview:self
1422                                    positioned:NSWindowAbove
1423                                    relativeTo:nil];
1424     }
1426   ++nestCount;
1428   [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1432 - (void)hide
1434   // Note: Trace output from this method isn't shown, reason unknown.
1435   // NSTRACE ("[EmacsBell hide]");
1437   if (nestCount > 0)
1438     --nestCount;
1440   // Remove the image once the last bell became inactive.
1441   if (nestCount == 0)
1442     {
1443       [self remove];
1444     }
1448 -(void)remove
1450   NSTRACE ("[EmacsBell remove]");
1451   if (isAttached)
1452     {
1453       NSTRACE_MSG ("removeFromSuperview");
1454       [self removeFromSuperview];
1455       mView.needsDisplay = YES;
1456       isAttached = false;
1457     }
1460 @end
1463 static EmacsBell * bell_view = nil;
1465 static void
1466 ns_ring_bell (struct frame *f)
1467 /* --------------------------------------------------------------------------
1468      "Beep" routine
1469    -------------------------------------------------------------------------- */
1471   NSTRACE ("ns_ring_bell");
1472   if (visible_bell)
1473     {
1474       struct frame *frame = SELECTED_FRAME ();
1475       NSView *view;
1477       if (bell_view == nil)
1478         {
1479           bell_view = [[EmacsBell alloc] init];
1480           [bell_view retain];
1481         }
1483       block_input ();
1485       view = FRAME_NS_VIEW (frame);
1486       if (view != nil)
1487         {
1488           [bell_view show:view];
1489         }
1491       unblock_input ();
1492     }
1493   else
1494     {
1495       NSBeep ();
1496     }
1500 static void
1501 hide_bell (void)
1502 /* --------------------------------------------------------------------------
1503      Ensure the bell is hidden.
1504    -------------------------------------------------------------------------- */
1506   NSTRACE ("hide_bell");
1508   if (bell_view != nil)
1509     {
1510       [bell_view remove];
1511     }
1515 /* ==========================================================================
1517     Frame / window manager related functions
1519    ========================================================================== */
1522 static void
1523 ns_raise_frame (struct frame *f, BOOL make_key)
1524 /* --------------------------------------------------------------------------
1525      Bring window to foreground and if make_key is YES, give it focus.
1526    -------------------------------------------------------------------------- */
1528   NSView *view;
1530   check_window_system (f);
1531   view = FRAME_NS_VIEW (f);
1532   block_input ();
1533   if (FRAME_VISIBLE_P (f))
1534     {
1535       if (make_key)
1536         [[view window] makeKeyAndOrderFront: NSApp];
1537       else
1538         [[view window] orderFront: NSApp];
1539     }
1540   unblock_input ();
1544 static void
1545 ns_lower_frame (struct frame *f)
1546 /* --------------------------------------------------------------------------
1547      Send window to back
1548    -------------------------------------------------------------------------- */
1550   NSView *view;
1552   check_window_system (f);
1553   view = FRAME_NS_VIEW (f);
1554   block_input ();
1555   [[view window] orderBack: NSApp];
1556   unblock_input ();
1560 static void
1561 ns_frame_raise_lower (struct frame *f, bool raise)
1562 /* --------------------------------------------------------------------------
1563      External (hook)
1564    -------------------------------------------------------------------------- */
1566   NSTRACE ("ns_frame_raise_lower");
1568   if (raise)
1569     ns_raise_frame (f, YES);
1570   else
1571     ns_lower_frame (f);
1575 static void
1576 ns_frame_rehighlight (struct frame *frame)
1577 /* --------------------------------------------------------------------------
1578      External (hook): called on things like window switching within frame
1579    -------------------------------------------------------------------------- */
1581   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1582   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1584   NSTRACE ("ns_frame_rehighlight");
1585   if (dpyinfo->x_focus_frame)
1586     {
1587       dpyinfo->x_highlight_frame
1588         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1589            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1590            : dpyinfo->x_focus_frame);
1591       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1592         {
1593           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1594           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1595         }
1596     }
1597   else
1598       dpyinfo->x_highlight_frame = 0;
1600   if (dpyinfo->x_highlight_frame &&
1601          dpyinfo->x_highlight_frame != old_highlight)
1602     {
1603       if (old_highlight)
1604         {
1605           x_update_cursor (old_highlight, 1);
1606           x_set_frame_alpha (old_highlight);
1607         }
1608       if (dpyinfo->x_highlight_frame)
1609         {
1610           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1611           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1612         }
1613     }
1617 void
1618 x_make_frame_visible (struct frame *f)
1619 /* --------------------------------------------------------------------------
1620      External: Show the window (X11 semantics)
1621    -------------------------------------------------------------------------- */
1623   NSTRACE ("x_make_frame_visible");
1624   /* XXX: at some points in past this was not needed, as the only place that
1625      called this (frame.c:Fraise_frame ()) also called raise_lower;
1626      if this ends up the case again, comment this out again.  */
1627   if (!FRAME_VISIBLE_P (f))
1628     {
1629       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1630       NSWindow *window = [view window];
1632       SET_FRAME_VISIBLE (f, 1);
1633       ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1635       /* Making a new frame from a fullscreen frame will make the new frame
1636          fullscreen also.  So skip handleFS as this will print an error.  */
1637       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1638           && [view isFullscreen])
1639         return;
1641       if (f->want_fullscreen != FULLSCREEN_NONE)
1642         {
1643           block_input ();
1644           [view handleFS];
1645           unblock_input ();
1646         }
1648       /* Making a frame invisible seems to break the parent->child
1649          relationship, so reinstate it.  */
1650       if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1651         {
1652           NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1654           block_input ();
1655           [parent addChildWindow: window
1656                          ordered: NSWindowAbove];
1657           unblock_input ();
1659           /* If the parent frame moved while the child frame was
1660              invisible, the child frame's position won't have been
1661              updated.  Make sure it's in the right place now.  */
1662           x_set_offset(f, f->left_pos, f->top_pos, 0);
1663         }
1664     }
1668 void
1669 x_make_frame_invisible (struct frame *f)
1670 /* --------------------------------------------------------------------------
1671      External: Hide the window (X11 semantics)
1672    -------------------------------------------------------------------------- */
1674   NSView *view;
1675   NSTRACE ("x_make_frame_invisible");
1676   check_window_system (f);
1677   view = FRAME_NS_VIEW (f);
1678   [[view window] orderOut: NSApp];
1679   SET_FRAME_VISIBLE (f, 0);
1680   SET_FRAME_ICONIFIED (f, 0);
1684 void
1685 x_iconify_frame (struct frame *f)
1686 /* --------------------------------------------------------------------------
1687      External: Iconify window
1688    -------------------------------------------------------------------------- */
1690   NSView *view;
1691   struct ns_display_info *dpyinfo;
1693   NSTRACE ("x_iconify_frame");
1694   check_window_system (f);
1695   view = FRAME_NS_VIEW (f);
1696   dpyinfo = FRAME_DISPLAY_INFO (f);
1698   if (dpyinfo->x_highlight_frame == f)
1699     dpyinfo->x_highlight_frame = 0;
1701   if ([[view window] windowNumber] <= 0)
1702     {
1703       /* The window is still deferred.  Make it very small, bring it
1704          on screen and order it out.  */
1705       NSRect s = { { 100, 100}, {0, 0} };
1706       NSRect t;
1707       t = [[view window] frame];
1708       [[view window] setFrame: s display: NO];
1709       [[view window] orderBack: NSApp];
1710       [[view window] orderOut: NSApp];
1711       [[view window] setFrame: t display: NO];
1712     }
1714   /* Processing input while Emacs is being minimized can cause a
1715      crash, so block it for the duration.  */
1716   block_input();
1717   [[view window] miniaturize: NSApp];
1718   unblock_input();
1721 /* Free X resources of frame F.  */
1723 void
1724 x_free_frame_resources (struct frame *f)
1726   NSView *view;
1727   struct ns_display_info *dpyinfo;
1728   Mouse_HLInfo *hlinfo;
1730   NSTRACE ("x_free_frame_resources");
1731   check_window_system (f);
1732   view = FRAME_NS_VIEW (f);
1733   dpyinfo = FRAME_DISPLAY_INFO (f);
1734   hlinfo = MOUSE_HL_INFO (f);
1736   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1738   block_input ();
1740   free_frame_menubar (f);
1741   free_frame_faces (f);
1743   if (f == dpyinfo->x_focus_frame)
1744     dpyinfo->x_focus_frame = 0;
1745   if (f == dpyinfo->x_highlight_frame)
1746     dpyinfo->x_highlight_frame = 0;
1747   if (f == hlinfo->mouse_face_mouse_frame)
1748     reset_mouse_highlight (hlinfo);
1750   if (f->output_data.ns->miniimage != nil)
1751     [f->output_data.ns->miniimage release];
1753   [[view window] close];
1754   [view release];
1756   xfree (f->output_data.ns);
1758   unblock_input ();
1761 void
1762 x_destroy_window (struct frame *f)
1763 /* --------------------------------------------------------------------------
1764      External: Delete the window
1765    -------------------------------------------------------------------------- */
1767   NSTRACE ("x_destroy_window");
1769   /* If this frame has a parent window, detach it as not doing so can
1770      cause a crash in GNUStep.  */
1771   if (FRAME_PARENT_FRAME (f) != NULL)
1772     {
1773       NSWindow *child = [FRAME_NS_VIEW (f) window];
1774       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1776       [parent removeChildWindow: child];
1777     }
1779   check_window_system (f);
1780   x_free_frame_resources (f);
1781   ns_window_num--;
1785 void
1786 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1787 /* --------------------------------------------------------------------------
1788      External: Position the window
1789    -------------------------------------------------------------------------- */
1791   NSView *view = FRAME_NS_VIEW (f);
1792   NSScreen *screen = [[view window] screen];
1794   NSTRACE ("x_set_offset");
1796   block_input ();
1798   f->left_pos = xoff;
1799   f->top_pos = yoff;
1801   if (view != nil)
1802     {
1803       if (FRAME_PARENT_FRAME (f) == NULL && screen)
1804         {
1805           f->left_pos = f->size_hint_flags & XNegative
1806             ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1807             : f->left_pos;
1808           /* We use visibleFrame here to take menu bar into account.
1809              Ideally we should also adjust left/top with visibleFrame.origin.  */
1811           f->top_pos = f->size_hint_flags & YNegative
1812             ? ([screen visibleFrame].size.height + f->top_pos
1813                - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1814                - FRAME_TOOLBAR_HEIGHT (f))
1815             : f->top_pos;
1816 #ifdef NS_IMPL_GNUSTEP
1817           if (f->left_pos < 100)
1818             f->left_pos = 100;  /* don't overlap menu */
1819 #endif
1820         }
1821       else if (FRAME_PARENT_FRAME (f) != NULL)
1822         {
1823           struct frame *parent = FRAME_PARENT_FRAME (f);
1825           /* On X negative values for child frames always result in
1826              positioning relative to the bottom right corner of the
1827              parent frame.  */
1828           if (f->left_pos < 0)
1829             f->left_pos = FRAME_PIXEL_WIDTH (parent) - FRAME_PIXEL_WIDTH (f) + f->left_pos;
1831           if (f->top_pos < 0)
1832             f->top_pos = FRAME_PIXEL_HEIGHT (parent) + FRAME_TOOLBAR_HEIGHT (parent)
1833               - FRAME_PIXEL_HEIGHT (f) + f->top_pos;
1834         }
1836       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1837          menu bar.  */
1838       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1839                                                 + NS_PARENT_WINDOW_LEFT_POS (f)),
1840                                 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1841                                                 - f->top_pos));
1842       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1843       [[view window] setFrameTopLeftPoint: pt];
1844       f->size_hint_flags &= ~(XNegative|YNegative);
1845     }
1847   unblock_input ();
1851 void
1852 x_set_window_size (struct frame *f,
1853                    bool change_gravity,
1854                    int width,
1855                    int height,
1856                    bool pixelwise)
1857 /* --------------------------------------------------------------------------
1858      Adjust window pixel size based on given character grid size
1859      Impl is a bit more complex than other terms, need to do some
1860      internal clipping.
1861    -------------------------------------------------------------------------- */
1863   EmacsView *view = FRAME_NS_VIEW (f);
1864   NSWindow *window = [view window];
1865   NSRect wr = [window frame];
1866   int pixelwidth, pixelheight;
1867   int orig_height = wr.size.height;
1869   NSTRACE ("x_set_window_size");
1871   if (view == nil)
1872     return;
1874   NSTRACE_RECT ("current", wr);
1875   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1876   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1878   block_input ();
1880 #ifdef NS_IMPL_COCOA
1881   /* To prevent showing the user a blank frame, stop updates being
1882      flushed to the screen until after redisplay has completed.  This
1883      breaks live resize (resizing with a mouse), so don't do it if
1884      we're in a live resize loop.  */
1885   if (![view inLiveResize])
1886     ns_disable_screen_updates ();
1887 #endif
1889   if (pixelwise)
1890     {
1891       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1892       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1893     }
1894   else
1895     {
1896       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1897       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1898     }
1900   wr.size.width = pixelwidth + f->border_width;
1901   wr.size.height = pixelheight;
1902   if (! [view isFullscreen])
1903     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1904       + FRAME_TOOLBAR_HEIGHT (f);
1906   /* Do not try to constrain to this screen.  We may have multiple
1907      screens, and want Emacs to span those.  Constraining to screen
1908      prevents that, and that is not nice to the user.  */
1909  if (f->output_data.ns->zooming)
1910    f->output_data.ns->zooming = 0;
1911  else
1912    wr.origin.y += orig_height - wr.size.height;
1914  frame_size_history_add
1915    (f, Qx_set_window_size_1, width, height,
1916     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1917            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1918            make_number (f->border_width),
1919            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1920            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1922   [window setFrame: wr display: YES];
1924   [view updateFrameSize: NO];
1925   unblock_input ();
1928 #ifdef NS_IMPL_COCOA
1929 void
1930 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1931 /* --------------------------------------------------------------------------
1932      Set frame F's `undecorated' parameter.  If non-nil, F's window-system
1933      window is drawn without decorations, title, minimize/maximize boxes
1934      and external borders.  This usually means that the window cannot be
1935      dragged, resized, iconified, maximized or deleted with the mouse.  If
1936      nil, draw the frame with all the elements listed above unless these
1937      have been suspended via window manager settings.
1939      GNUStep cannot change an existing window's style.
1940    -------------------------------------------------------------------------- */
1942   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1943   NSWindow *window = [view window];
1945   NSTRACE ("x_set_undecorated");
1947   if (!EQ (new_value, old_value))
1948     {
1949       block_input ();
1951       if (NILP (new_value))
1952         {
1953           FRAME_UNDECORATED (f) = false;
1954           [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1955                                   ^ FRAME_UNDECORATED_FLAGS)];
1957           [view createToolbar: f];
1958         }
1959       else
1960         {
1961           [window setToolbar: nil];
1962           /* Do I need to release the toolbar here?  */
1964           FRAME_UNDECORATED (f) = true;
1965           [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1966                                  ^ FRAME_DECORATED_FLAGS)];
1967         }
1969       /* At this point it seems we don't have an active NSResponder,
1970          so some key presses (TAB) are swallowed by the system.  */
1971       [window makeFirstResponder: view];
1973       [view updateFrameSize: NO];
1974       unblock_input ();
1975     }
1977 #endif /* NS_IMPL_COCOA */
1979 void
1980 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1981 /* --------------------------------------------------------------------------
1982      Set frame F's `parent-frame' parameter.  If non-nil, make F a child
1983      frame of the frame specified by that parameter.  Technically, this
1984      makes F's window-system window a child window of the parent frame's
1985      window-system window.  If nil, make F's window-system window a
1986      top-level window--a child of its display's root window.
1988      A child frame's `left' and `top' parameters specify positions
1989      relative to the top-left corner of its parent frame's native
1990      rectangle.  On macOS moving a parent frame moves all its child
1991      frames too, keeping their position relative to the parent
1992      unaltered.  When a parent frame is iconified or made invisible, its
1993      child frames are made invisible.  When a parent frame is deleted,
1994      its child frames are deleted too.
1996      Whether a child frame has a tool bar may be window-system or window
1997      manager dependent.  It's advisable to disable it via the frame
1998      parameter settings.
2000      Some window managers may not honor this parameter.
2001    -------------------------------------------------------------------------- */
2003   struct frame *p = NULL;
2004   NSWindow *parent, *child;
2006   NSTRACE ("x_set_parent_frame");
2008   if (!NILP (new_value)
2009       && (!FRAMEP (new_value)
2010           || !FRAME_LIVE_P (p = XFRAME (new_value))
2011           || !FRAME_NS_P (p)))
2012     {
2013       store_frame_param (f, Qparent_frame, old_value);
2014       error ("Invalid specification of `parent-frame'");
2015     }
2017   if (p != FRAME_PARENT_FRAME (f))
2018     {
2019       parent = [FRAME_NS_VIEW (p) window];
2020       child = [FRAME_NS_VIEW (f) window];
2022       block_input ();
2023       [parent addChildWindow: child
2024                      ordered: NSWindowAbove];
2025       unblock_input ();
2027       fset_parent_frame (f, new_value);
2028     }
2031 void
2032 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2033 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
2034  * that F's window-system window does not want to receive input focus
2035  * when it is mapped.  (A frame's window is mapped when the frame is
2036  * displayed for the first time and when the frame changes its state
2037  * from `iconified' or `invisible' to `visible'.)
2039  * Some window managers may not honor this parameter.  */
2041   NSTRACE ("x_set_no_focus_on_map");
2043   if (!EQ (new_value, old_value))
2044     {
2045       FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
2046     }
2049 void
2050 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2051 /*  Set frame F's `no-accept-focus' parameter which, if non-nil, hints
2052  * that F's window-system window does not want to receive input focus
2053  * via mouse clicks or by moving the mouse into it.
2055  * If non-nil, this may have the unwanted side-effect that a user cannot
2056  * scroll a non-selected frame with the mouse.
2058  * Some window managers may not honor this parameter.  */
2060   NSTRACE ("x_set_no_accept_focus");
2062   if (!EQ (new_value, old_value))
2063     FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
2066 void
2067 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2068 /* Set frame F's `z-group' parameter.  If `above', F's window-system
2069    window is displayed above all windows that do not have the `above'
2070    property set.  If nil, F's window is shown below all windows that
2071    have the `above' property set and above all windows that have the
2072    `below' property set.  If `below', F's window is displayed below
2073    all windows that do.
2075    Some window managers may not honor this parameter.  */
2077   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2078   NSWindow *window = [view window];
2080   NSTRACE ("x_set_z_group");
2082   if (NILP (new_value))
2083     {
2084       window.level = NSNormalWindowLevel;
2085       FRAME_Z_GROUP (f) = z_group_none;
2086     }
2087   else if (EQ (new_value, Qabove))
2088     {
2089       window.level = NSNormalWindowLevel + 1;
2090       FRAME_Z_GROUP (f) = z_group_above;
2091     }
2092   else if (EQ (new_value, Qabove_suspended))
2093     {
2094       /* Not sure what level this should be.  */
2095       window.level = NSNormalWindowLevel + 1;
2096       FRAME_Z_GROUP (f) = z_group_above_suspended;
2097     }
2098   else if (EQ (new_value, Qbelow))
2099     {
2100       window.level = NSNormalWindowLevel - 1;
2101       FRAME_Z_GROUP (f) = z_group_below;
2102     }
2103   else
2104     error ("Invalid z-group specification");
2107 #ifdef NS_IMPL_COCOA
2108 void
2109 ns_set_appearance (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2111 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2112   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2113   NSWindow *window = [view window];
2115   NSTRACE ("ns_set_appearance");
2117 #ifndef NSAppKitVersionNumber10_10
2118 #define NSAppKitVersionNumber10_10 1343
2119 #endif
2121   if (NSAppKitVersionNumber < NSAppKitVersionNumber10_10)
2122     return;
2124   if (EQ (new_value, Qdark))
2125     {
2126       window.appearance = [NSAppearance
2127                             appearanceNamed: NSAppearanceNameVibrantDark];
2128       FRAME_NS_APPEARANCE (f) = ns_appearance_vibrant_dark;
2129     }
2130   else
2131     {
2132       window.appearance = [NSAppearance
2133                             appearanceNamed: NSAppearanceNameAqua];
2134       FRAME_NS_APPEARANCE (f) = ns_appearance_aqua;
2135     }
2136 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2139 void
2140 ns_set_transparent_titlebar (struct frame *f, Lisp_Object new_value,
2141                              Lisp_Object old_value)
2143 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
2144   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2145   NSWindow *window = [view window];
2147   NSTRACE ("ns_set_transparent_titlebar");
2149   if ([window respondsToSelector: @selector(titlebarAppearsTransparent)]
2150       && !EQ (new_value, old_value))
2151     {
2152       window.titlebarAppearsTransparent = !NILP (new_value);
2153       FRAME_NS_TRANSPARENT_TITLEBAR (f) = !NILP (new_value);
2154     }
2155 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 */
2157 #endif /* NS_IMPL_COCOA */
2159 static void
2160 ns_fullscreen_hook (struct frame *f)
2162   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2164   NSTRACE ("ns_fullscreen_hook");
2166   if (!FRAME_VISIBLE_P (f))
2167     return;
2169    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2170     {
2171       /* Old style fs don't initiate correctly if created from
2172          init/default-frame alist, so use a timer (not nice...).  */
2173       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2174                                      selector: @selector (handleFS)
2175                                      userInfo: nil repeats: NO];
2176       return;
2177     }
2179   block_input ();
2180   [view handleFS];
2181   unblock_input ();
2184 /* ==========================================================================
2186     Color management
2188    ========================================================================== */
2191 NSColor *
2192 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2194   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2195   if (idx < 1 || idx >= color_table->avail)
2196     return nil;
2197   return color_table->colors[idx];
2201 unsigned long
2202 ns_index_color (NSColor *color, struct frame *f)
2204   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2205   ptrdiff_t idx;
2206   ptrdiff_t i;
2208   if (!color_table->colors)
2209     {
2210       color_table->size = NS_COLOR_CAPACITY;
2211       color_table->avail = 1; /* skip idx=0 as marker */
2212       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2213       color_table->colors[0] = nil;
2214       color_table->empty_indices = [[NSMutableSet alloc] init];
2215     }
2217   /* Do we already have this color?  */
2218   for (i = 1; i < color_table->avail; i++)
2219     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2220       return i;
2222   if ([color_table->empty_indices count] > 0)
2223     {
2224       NSNumber *index = [color_table->empty_indices anyObject];
2225       [color_table->empty_indices removeObject: index];
2226       idx = [index unsignedLongValue];
2227     }
2228   else
2229     {
2230       if (color_table->avail == color_table->size)
2231         color_table->colors =
2232           xpalloc (color_table->colors, &color_table->size, 1,
2233                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2234       idx = color_table->avail++;
2235     }
2237   color_table->colors[idx] = color;
2238   [color retain];
2239   /* fprintf(stderr, "color_table: allocated %d\n",idx); */
2240   return idx;
2244 static int
2245 ns_get_color (const char *name, NSColor **col)
2246 /* --------------------------------------------------------------------------
2247      Parse a color name
2248    -------------------------------------------------------------------------- */
2249 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2250    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2251    See https://lists.gnu.org/r/emacs-devel/2009-07/msg01203.html.  */
2253   NSColor *new = nil;
2254   static char hex[20];
2255   int scaling = 0;
2256   float r = -1.0, g, b;
2257   NSString *nsname = [NSString stringWithUTF8String: name];
2259   NSTRACE ("ns_get_color(%s, **)", name);
2261   block_input ();
2263   if ([nsname isEqualToString: @"ns_selection_bg_color"])
2264     {
2265 #ifdef NS_IMPL_COCOA
2266       NSString *defname = [[NSUserDefaults standardUserDefaults]
2267                             stringForKey: @"AppleHighlightColor"];
2268       if (defname != nil)
2269         nsname = defname;
2270       else
2271 #endif
2272       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2273         {
2274           *col = [new colorUsingDefaultColorSpace];
2275           unblock_input ();
2276           return 0;
2277         }
2278       else
2279         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2281       name = [nsname UTF8String];
2282     }
2283   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2284     {
2285       /* NOTE: macOS applications normally don't set foreground
2286          selection, but text may be unreadable if we don't.  */
2287       if ((new = [NSColor selectedTextColor]) != nil)
2288         {
2289           *col = [new colorUsingDefaultColorSpace];
2290           unblock_input ();
2291           return 0;
2292         }
2294       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2295       name = [nsname UTF8String];
2296     }
2298   /* First, check for some sort of numeric specification.  */
2299   hex[0] = '\0';
2301   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
2302     {
2303       NSScanner *scanner = [NSScanner scannerWithString: nsname];
2304       [scanner scanFloat: &r];
2305       [scanner scanFloat: &g];
2306       [scanner scanFloat: &b];
2307     }
2308   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
2309     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2310   else if (name[0] == '#')        /* An old X11 format; convert to newer */
2311     {
2312       int len = (strlen(name) - 1);
2313       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2314       int i;
2315       scaling = strlen(name+start) / 3;
2316       for (i = 0; i < 3; i++)
2317         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2318                  name + start + i * scaling);
2319       hex[3 * (scaling + 1) - 1] = '\0';
2320     }
2322   if (hex[0])
2323     {
2324       unsigned int rr, gg, bb;
2325       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2326       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2327         {
2328           r = rr / fscale;
2329           g = gg / fscale;
2330           b = bb / fscale;
2331         }
2332     }
2334   if (r >= 0.0F)
2335     {
2336       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2337       unblock_input ();
2338       return 0;
2339     }
2341   /* Otherwise, color is expected to be from a list */
2342   {
2343     NSEnumerator *lenum, *cenum;
2344     NSString *name;
2345     NSColorList *clist;
2347 #ifdef NS_IMPL_GNUSTEP
2348     /* XXX: who is wrong, the requestor or the implementation?  */
2349     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2350         == NSOrderedSame)
2351       nsname = @"highlightColor";
2352 #endif
2354     lenum = [[NSColorList availableColorLists] objectEnumerator];
2355     while ( (clist = [lenum nextObject]) && new == nil)
2356       {
2357         cenum = [[clist allKeys] objectEnumerator];
2358         while ( (name = [cenum nextObject]) && new == nil )
2359           {
2360             if ([name compare: nsname
2361                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
2362               new = [clist colorWithKey: name];
2363           }
2364       }
2365   }
2367   if (new)
2368     *col = [new colorUsingDefaultColorSpace];
2369   unblock_input ();
2370   return new ? 0 : 1;
2375 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2376 /* --------------------------------------------------------------------------
2377      Convert a Lisp string object to a NS color.
2378    -------------------------------------------------------------------------- */
2380   NSTRACE ("ns_lisp_to_color");
2381   if (STRINGP (color))
2382     return ns_get_color (SSDATA (color), col);
2383   else if (SYMBOLP (color))
2384     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2385   return 1;
2389 void
2390 ns_query_color(void *col, XColor *color_def, int setPixel)
2391 /* --------------------------------------------------------------------------
2392          Get ARGB values out of NSColor col and put them into color_def.
2393          If setPixel, set the pixel to a concatenated version.
2394          and set color_def pixel to the resulting index.
2395    -------------------------------------------------------------------------- */
2397   EmacsCGFloat r, g, b, a;
2399   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2400   color_def->red   = r * 65535;
2401   color_def->green = g * 65535;
2402   color_def->blue  = b * 65535;
2404   if (setPixel == YES)
2405     color_def->pixel
2406       = ARGB_TO_ULONG((int)(a*255),
2407                       (int)(r*255), (int)(g*255), (int)(b*255));
2411 bool
2412 ns_defined_color (struct frame *f,
2413                   const char *name,
2414                   XColor *color_def,
2415                   bool alloc,
2416                   bool makeIndex)
2417 /* --------------------------------------------------------------------------
2418          Return true if named color found, and set color_def rgb accordingly.
2419          If makeIndex and alloc are nonzero put the color in the color_table,
2420          and set color_def pixel to the resulting index.
2421          If makeIndex is zero, set color_def pixel to ARGB.
2422          Return false if not found.
2423    -------------------------------------------------------------------------- */
2425   NSColor *col;
2426   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2428   block_input ();
2429   if (ns_get_color (name, &col) != 0) /* Color not found  */
2430     {
2431       unblock_input ();
2432       return 0;
2433     }
2434   if (makeIndex && alloc)
2435     color_def->pixel = ns_index_color (col, f);
2436   ns_query_color (col, color_def, !makeIndex);
2437   unblock_input ();
2438   return 1;
2442 void
2443 x_set_frame_alpha (struct frame *f)
2444 /* --------------------------------------------------------------------------
2445      change the entire-frame transparency
2446    -------------------------------------------------------------------------- */
2448   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2449   double alpha = 1.0;
2450   double alpha_min = 1.0;
2452   NSTRACE ("x_set_frame_alpha");
2454   if (dpyinfo->x_highlight_frame == f)
2455     alpha = f->alpha[0];
2456   else
2457     alpha = f->alpha[1];
2459   if (FLOATP (Vframe_alpha_lower_limit))
2460     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2461   else if (INTEGERP (Vframe_alpha_lower_limit))
2462     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2464   if (alpha < 0.0)
2465     return;
2466   else if (1.0 < alpha)
2467     alpha = 1.0;
2468   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2469     alpha = alpha_min;
2471 #ifdef NS_IMPL_COCOA
2472   {
2473     EmacsView *view = FRAME_NS_VIEW (f);
2474   [[view window] setAlphaValue: alpha];
2475   }
2476 #endif
2480 /* ==========================================================================
2482     Mouse handling
2484    ========================================================================== */
2487 void
2488 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2489 /* --------------------------------------------------------------------------
2490      Programmatically reposition mouse pointer in pixel coordinates
2491    -------------------------------------------------------------------------- */
2493   NSTRACE ("frame_set_mouse_pixel_position");
2495   /* FIXME: what about GNUstep?  */
2496 #ifdef NS_IMPL_COCOA
2497   CGPoint mouse_pos =
2498     CGPointMake(f->left_pos + pix_x,
2499                 f->top_pos + pix_y +
2500                 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2501   CGWarpMouseCursorPosition (mouse_pos);
2502 #endif
2505 static int
2506 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2507 /*   ------------------------------------------------------------------------
2508      Called by EmacsView on mouseMovement events.  Passes on
2509      to emacs mainstream code if we moved off of a rect of interest
2510      known as last_mouse_glyph.
2511      ------------------------------------------------------------------------ */
2513   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2514   NSRect *r;
2516   // NSTRACE ("note_mouse_movement");
2518   dpyinfo->last_mouse_motion_frame = frame;
2519   r = &dpyinfo->last_mouse_glyph;
2521   /* Note, this doesn't get called for enter/leave, since we don't have a
2522      position.  Those are taken care of in the corresponding NSView methods.  */
2524   /* Has movement gone beyond last rect we were tracking?  */
2525   if (x < r->origin.x || x >= r->origin.x + r->size.width
2526       || y < r->origin.y || y >= r->origin.y + r->size.height)
2527     {
2528       ns_update_begin (frame);
2529       frame->mouse_moved = 1;
2530       note_mouse_highlight (frame, x, y);
2531       remember_mouse_glyph (frame, x, y, r);
2532       ns_update_end (frame);
2533       return 1;
2534     }
2536   return 0;
2540 static void
2541 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2542                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2543                    Time *time)
2544 /* --------------------------------------------------------------------------
2545     External (hook): inform emacs about mouse position and hit parts.
2546     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2547     x & y should be position in the scrollbar (the whole bar, not the handle)
2548     and length of scrollbar respectively.
2549    -------------------------------------------------------------------------- */
2551   id view;
2552   NSPoint position;
2553   Lisp_Object frame, tail;
2554   struct frame *f;
2555   struct ns_display_info *dpyinfo;
2557   NSTRACE ("ns_mouse_position");
2559   if (*fp == NULL)
2560     {
2561       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2562       return;
2563     }
2565   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2567   block_input ();
2569   /* Clear the mouse-moved flag for every frame on this display.  */
2570   FOR_EACH_FRAME (tail, frame)
2571     if (FRAME_NS_P (XFRAME (frame))
2572         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2573       XFRAME (frame)->mouse_moved = 0;
2575   dpyinfo->last_mouse_scroll_bar = nil;
2576   if (dpyinfo->last_mouse_frame
2577       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2578     f = dpyinfo->last_mouse_frame;
2579   else
2580     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2582   if (f && FRAME_NS_P (f))
2583     {
2584       view = FRAME_NS_VIEW (*fp);
2586       position = [[view window] mouseLocationOutsideOfEventStream];
2587       position = [view convertPoint: position fromView: nil];
2588       remember_mouse_glyph (f, position.x, position.y,
2589                             &dpyinfo->last_mouse_glyph);
2590       NSTRACE_POINT ("position", position);
2592       if (bar_window) *bar_window = Qnil;
2593       if (part) *part = scroll_bar_above_handle;
2595       if (x) XSETINT (*x, lrint (position.x));
2596       if (y) XSETINT (*y, lrint (position.y));
2597       if (time)
2598         *time = dpyinfo->last_mouse_movement_time;
2599       *fp = f;
2600     }
2602   unblock_input ();
2606 static void
2607 ns_frame_up_to_date (struct frame *f)
2608 /* --------------------------------------------------------------------------
2609     External (hook): Fix up mouse highlighting right after a full update.
2610     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2611    -------------------------------------------------------------------------- */
2613   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2615   if (FRAME_NS_P (f))
2616     {
2617       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2618       if (f == hlinfo->mouse_face_mouse_frame)
2619         {
2620           block_input ();
2621           ns_update_begin(f);
2622           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2623                                 hlinfo->mouse_face_mouse_x,
2624                                 hlinfo->mouse_face_mouse_y);
2625           ns_update_end(f);
2626           unblock_input ();
2627         }
2628     }
2632 static void
2633 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2634 /* --------------------------------------------------------------------------
2635     External (RIF): set frame mouse pointer type.
2636    -------------------------------------------------------------------------- */
2638   NSTRACE ("ns_define_frame_cursor");
2639   if (FRAME_POINTER_TYPE (f) != cursor)
2640     {
2641       EmacsView *view = FRAME_NS_VIEW (f);
2642       FRAME_POINTER_TYPE (f) = cursor;
2643       [[view window] invalidateCursorRectsForView: view];
2644       /* Redisplay assumes this function also draws the changed frame
2645          cursor, but this function doesn't, so do it explicitly.  */
2646       x_update_cursor (f, 1);
2647     }
2652 /* ==========================================================================
2654     Keyboard handling
2656    ========================================================================== */
2659 static unsigned
2660 ns_convert_key (unsigned code)
2661 /* --------------------------------------------------------------------------
2662     Internal call used by NSView-keyDown.
2663    -------------------------------------------------------------------------- */
2665   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2666   unsigned keysym;
2667   /* An array would be faster, but less easy to read.  */
2668   for (keysym = 0; keysym < last_keysym; keysym += 2)
2669     if (code == convert_ns_to_X_keysym[keysym])
2670       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2671   return 0;
2672 /* if decide to use keyCode and Carbon table, use this line:
2673      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2677 char *
2678 x_get_keysym_name (int keysym)
2679 /* --------------------------------------------------------------------------
2680     Called by keyboard.c.  Not sure if the return val is important, except
2681     that it be unique.
2682    -------------------------------------------------------------------------- */
2684   static char value[16];
2685   NSTRACE ("x_get_keysym_name");
2686   sprintf (value, "%d", keysym);
2687   return value;
2690 #ifdef NS_IMPL_COCOA
2691 static UniChar
2692 ns_get_shifted_character (NSEvent *event)
2693 /* Look up the character corresponding to the key pressed on the
2694    current keyboard layout and the currently configured shift-like
2695    modifiers.  This ignores the control-like modifiers that cause
2696    [event characters] to give us the wrong result.
2698    Although UCKeyTranslate doesn't require the Carbon framework, some
2699    of the surrounding paraphernalia does, so this function makes
2700    Carbon a requirement.  */
2702   static UInt32 dead_key_state;
2704   /* UCKeyTranslate may return up to 255 characters.  If the buffer
2705      isn't large enough then it produces an error.  What kind of
2706      keyboard inputs 255 characters in a single keypress?  */
2707   UniChar buf[255];
2708   UniCharCount max_string_length = 255;
2709   UniCharCount actual_string_length = 0;
2710   OSStatus result;
2712   CFDataRef layout_ref = (CFDataRef) TISGetInputSourceProperty
2713     (TISCopyCurrentKeyboardLayoutInputSource (), kTISPropertyUnicodeKeyLayoutData);
2714   UCKeyboardLayout* layout = (UCKeyboardLayout*) CFDataGetBytePtr (layout_ref);
2716   UInt32 flags = [event modifierFlags];
2717   UInt32 modifiers = (flags & NSEventModifierFlagShift) ? shiftKey : 0;
2719   NSTRACE ("ns_get_shifted_character");
2721   if ((flags & NSRightAlternateKeyMask) == NSRightAlternateKeyMask
2722       && (EQ (ns_right_alternate_modifier, Qnone)
2723           || (EQ (ns_right_alternate_modifier, Qleft)
2724               && EQ (ns_alternate_modifier, Qnone))))
2725     modifiers |= rightOptionKey;
2727   if ((flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
2728       && EQ (ns_alternate_modifier, Qnone))
2729     modifiers |= optionKey;
2731   if ((flags & NSRightCommandKeyMask) == NSRightCommandKeyMask
2732       && (EQ (ns_right_command_modifier, Qnone)
2733           || (EQ (ns_right_command_modifier, Qleft)
2734               && EQ (ns_command_modifier, Qnone))))
2735     /* Carbon doesn't differentiate between left and right command
2736        keys.  */
2737     modifiers |= cmdKey;
2739   if ((flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
2740       && EQ (ns_command_modifier, Qnone))
2741     modifiers |= cmdKey;
2743   result = UCKeyTranslate (layout, [event keyCode], kUCKeyActionDown,
2744                            (modifiers >> 8) & 0xFF, LMGetKbdType (),
2745                            kUCKeyTranslateNoDeadKeysBit, &dead_key_state,
2746                            max_string_length, &actual_string_length, buf);
2748   if (result != 0)
2749     {
2750       NSLog(@"Failed to translate character '%@' with modifiers %x",
2751             [event characters], modifiers);
2752       return 0;
2753     }
2755   /* FIXME: What do we do if more than one code unit is returned?  */
2756   if (actual_string_length > 0)
2757     return buf[0];
2759   return 0;
2761 #endif /* NS_IMPL_COCOA */
2763 /* ==========================================================================
2765     Block drawing operations
2767    ========================================================================== */
2770 static void
2771 ns_redraw_scroll_bars (struct frame *f)
2773   int i;
2774   id view;
2775   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2776   NSTRACE ("ns_redraw_scroll_bars");
2777   for (i =[subviews count]-1; i >= 0; i--)
2778     {
2779       view = [subviews objectAtIndex: i];
2780       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2781       [view display];
2782     }
2786 void
2787 ns_clear_frame (struct frame *f)
2788 /* --------------------------------------------------------------------------
2789       External (hook): Erase the entire frame
2790    -------------------------------------------------------------------------- */
2792   NSView *view = FRAME_NS_VIEW (f);
2793   NSRect r;
2795   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2797  /* comes on initial frame because we have
2798     after-make-frame-functions = select-frame */
2799  if (!FRAME_DEFAULT_FACE (f))
2800    return;
2802   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2804   r = [view bounds];
2806   block_input ();
2807   ns_focus (f, &r, 1);
2808   [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2809                             (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2810   NSRectFill (r);
2811   ns_unfocus (f);
2813   /* as of 2006/11 or so this is now needed */
2814   ns_redraw_scroll_bars (f);
2815   unblock_input ();
2819 static void
2820 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2821 /* --------------------------------------------------------------------------
2822     External (RIF):  Clear section of frame
2823    -------------------------------------------------------------------------- */
2825   NSRect r = NSMakeRect (x, y, width, height);
2826   NSView *view = FRAME_NS_VIEW (f);
2827   struct face *face = FRAME_DEFAULT_FACE (f);
2829   if (!view || !face)
2830     return;
2832   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2834   r = NSIntersectionRect (r, [view frame]);
2835   ns_focus (f, &r, 1);
2836   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2838   NSRectFill (r);
2840   ns_unfocus (f);
2841   return;
2844 static void
2845 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2847   NSTRACE ("ns_copy_bits");
2849   if (FRAME_NS_VIEW (f))
2850     {
2851       hide_bell();              // Ensure the bell image isn't scrolled.
2853       ns_focus (f, &dest, 1);
2854       [FRAME_NS_VIEW (f) scrollRect: src
2855                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2856                                                  dest.origin.y - src.origin.y)];
2857       ns_unfocus (f);
2858     }
2861 static void
2862 ns_scroll_run (struct window *w, struct run *run)
2863 /* --------------------------------------------------------------------------
2864     External (RIF):  Insert or delete n lines at line vpos.
2865    -------------------------------------------------------------------------- */
2867   struct frame *f = XFRAME (w->frame);
2868   int x, y, width, height, from_y, to_y, bottom_y;
2870   NSTRACE ("ns_scroll_run");
2872   /* begin copy from other terms */
2873   /* Get frame-relative bounding box of the text display area of W,
2874      without mode lines.  Include in this box the left and right
2875      fringe of W.  */
2876   window_box (w, ANY_AREA, &x, &y, &width, &height);
2878   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2879   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2880   bottom_y = y + height;
2882   if (to_y < from_y)
2883     {
2884       /* Scrolling up.  Make sure we don't copy part of the mode
2885          line at the bottom.  */
2886       if (from_y + run->height > bottom_y)
2887         height = bottom_y - from_y;
2888       else
2889         height = run->height;
2890     }
2891   else
2892     {
2893       /* Scrolling down.  Make sure we don't copy over the mode line.
2894          at the bottom.  */
2895       if (to_y + run->height > bottom_y)
2896         height = bottom_y - to_y;
2897       else
2898         height = run->height;
2899     }
2900   /* end copy from other terms */
2902   if (height == 0)
2903       return;
2905   block_input ();
2907   x_clear_cursor (w);
2909   {
2910     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2911     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2913     ns_copy_bits (f, srcRect , dstRect);
2914   }
2916   unblock_input ();
2920 static void
2921 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2922 /* --------------------------------------------------------------------------
2923     External (RIF): preparatory to fringe update after text was updated
2924    -------------------------------------------------------------------------- */
2926   struct frame *f;
2927   int width, height;
2929   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2931   /* begin copy from other terms */
2932   eassert (w);
2934   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2935     desired_row->redraw_fringe_bitmaps_p = 1;
2937   /* When a window has disappeared, make sure that no rest of
2938      full-width rows stays visible in the internal border.  */
2939   if (windows_or_buffers_changed
2940       && desired_row->full_width_p
2941       && (f = XFRAME (w->frame),
2942           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2943           width != 0)
2944       && (height = desired_row->visible_height,
2945           height > 0))
2946     {
2947       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2949       block_input ();
2950       ns_clear_frame_area (f, 0, y, width, height);
2951       ns_clear_frame_area (f,
2952                            FRAME_PIXEL_WIDTH (f) - width,
2953                            y, width, height);
2954       unblock_input ();
2955     }
2959 static void
2960 ns_shift_glyphs_for_insert (struct frame *f,
2961                            int x, int y, int width, int height,
2962                            int shift_by)
2963 /* --------------------------------------------------------------------------
2964     External (RIF): copy an area horizontally, don't worry about clearing src
2965    -------------------------------------------------------------------------- */
2967   NSRect srcRect = NSMakeRect (x, y, width, height);
2968   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2970   NSTRACE ("ns_shift_glyphs_for_insert");
2972   ns_copy_bits (f, srcRect, dstRect);
2977 /* ==========================================================================
2979     Character encoding and metrics
2981    ========================================================================== */
2984 static void
2985 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2986 /* --------------------------------------------------------------------------
2987      External (RIF); compute left/right overhang of whole string and set in s
2988    -------------------------------------------------------------------------- */
2990   struct font *font = s->font;
2992   if (s->char2b)
2993     {
2994       struct font_metrics metrics;
2995       unsigned int codes[2];
2996       codes[0] = *(s->char2b);
2997       codes[1] = *(s->char2b + s->nchars - 1);
2999       font->driver->text_extents (font, codes, 2, &metrics);
3000       s->left_overhang = -metrics.lbearing;
3001       s->right_overhang
3002         = metrics.rbearing > metrics.width
3003         ? metrics.rbearing - metrics.width : 0;
3004     }
3005   else
3006     {
3007       s->left_overhang = 0;
3008       if (EQ (font->driver->type, Qns))
3009         s->right_overhang = ((struct nsfont_info *)font)->ital ?
3010           FONT_HEIGHT (font) * 0.2 : 0;
3011       else
3012         s->right_overhang = 0;
3013     }
3018 /* ==========================================================================
3020     Fringe and cursor drawing
3022    ========================================================================== */
3025 extern int max_used_fringe_bitmap;
3026 static void
3027 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3028                       struct draw_fringe_bitmap_params *p)
3029 /* --------------------------------------------------------------------------
3030     External (RIF); fringe-related
3031    -------------------------------------------------------------------------- */
3033   /* Fringe bitmaps comes in two variants, normal and periodic.  A
3034      periodic bitmap is used to create a continuous pattern.  Since a
3035      bitmap is rendered one text line at a time, the start offset (dh)
3036      of the bitmap varies.  Concretely, this is used for the empty
3037      line indicator.
3039      For a bitmap, "h + dh" is the full height and is always
3040      invariant.  For a normal bitmap "dh" is zero.
3042      For example, when the period is three and the full height is 72
3043      the following combinations exists:
3045        h=72 dh=0
3046        h=71 dh=1
3047        h=70 dh=2 */
3049   struct frame *f = XFRAME (WINDOW_FRAME (w));
3050   struct face *face = p->face;
3051   static EmacsImage **bimgs = NULL;
3052   static int nBimgs = 0;
3054   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
3055   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
3056                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
3058   /* grow bimgs if needed */
3059   if (nBimgs < max_used_fringe_bitmap)
3060     {
3061       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
3062       memset (bimgs + nBimgs, 0,
3063               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
3064       nBimgs = max_used_fringe_bitmap;
3065     }
3067   /* Must clip because of partially visible lines.  */
3068   ns_clip_to_row (w, row, ANY_AREA, YES);
3070   if (!p->overlay_p)
3071     {
3072       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
3074       if (bx >= 0 && nx > 0)
3075         {
3076           NSRect r = NSMakeRect (bx, by, nx, ny);
3077           NSRectClip (r);
3078           [ns_lookup_indexed_color (face->background, f) set];
3079           NSRectFill (r);
3080         }
3081     }
3083   if (p->which)
3084     {
3085       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
3086       EmacsImage *img = bimgs[p->which - 1];
3088       if (!img)
3089         {
3090           // Note: For "periodic" images, allocate one EmacsImage for
3091           // the base image, and use it for all dh:s.
3092           unsigned short *bits = p->bits;
3093           int full_height = p->h + p->dh;
3094           int i;
3095           unsigned char *cbits = xmalloc (full_height);
3097           for (i = 0; i < full_height; i++)
3098             cbits[i] = bits[i];
3099           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
3100                                          height: full_height
3101                                              fg: 0 bg: 0];
3102           bimgs[p->which - 1] = img;
3103           xfree (cbits);
3104         }
3106       NSTRACE_RECT ("r", r);
3108       NSRectClip (r);
3109       /* Since we composite the bitmap instead of just blitting it, we need
3110          to erase the whole background.  */
3111       [ns_lookup_indexed_color(face->background, f) set];
3112       NSRectFill (r);
3114       {
3115         NSColor *bm_color;
3116         if (!p->cursor_p)
3117           bm_color = ns_lookup_indexed_color(face->foreground, f);
3118         else if (p->overlay_p)
3119           bm_color = ns_lookup_indexed_color(face->background, f);
3120         else
3121           bm_color = f->output_data.ns->cursor_color;
3122         [img setXBMColor: bm_color];
3123       }
3125 #ifdef NS_IMPL_COCOA
3126       // Note: For periodic images, the full image height is "h + hd".
3127       // By using the height h, a suitable part of the image is used.
3128       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
3130       NSTRACE_RECT ("fromRect", fromRect);
3132       [img drawInRect: r
3133               fromRect: fromRect
3134              operation: NSCompositingOperationSourceOver
3135               fraction: 1.0
3136            respectFlipped: YES
3137                 hints: nil];
3138 #else
3139       {
3140         NSPoint pt = r.origin;
3141         pt.y += p->h;
3142         [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
3143       }
3144 #endif
3145     }
3146   ns_unfocus (f);
3150 static void
3151 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
3152                        int x, int y, enum text_cursor_kinds cursor_type,
3153                        int cursor_width, bool on_p, bool active_p)
3154 /* --------------------------------------------------------------------------
3155      External call (RIF): draw cursor.
3156      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
3157    -------------------------------------------------------------------------- */
3159   NSRect r, s;
3160   int fx, fy, h, cursor_height;
3161   struct frame *f = WINDOW_XFRAME (w);
3162   struct glyph *phys_cursor_glyph;
3163   struct glyph *cursor_glyph;
3164   struct face *face;
3165   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
3167   /* If cursor is out of bounds, don't draw garbage.  This can happen
3168      in mini-buffer windows when switching between echo area glyphs
3169      and mini-buffer.  */
3171   NSTRACE ("ns_draw_window_cursor");
3173   if (!on_p)
3174     return;
3176   w->phys_cursor_type = cursor_type;
3177   w->phys_cursor_on_p = on_p;
3179   if (cursor_type == NO_CURSOR)
3180     {
3181       w->phys_cursor_width = 0;
3182       return;
3183     }
3185   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
3186     {
3187       if (glyph_row->exact_window_width_line_p
3188           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3189         {
3190           glyph_row->cursor_in_fringe_p = 1;
3191           draw_fringe_bitmap (w, glyph_row, 0);
3192         }
3193       return;
3194     }
3196   /* We draw the cursor (with NSRectFill), then draw the glyph on top
3197      (other terminals do it the other way round).  We must set
3198      w->phys_cursor_width to the cursor width.  For bar cursors, that
3199      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
3200   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3202   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3203      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors.  */
3204   if (cursor_type == BAR_CURSOR)
3205     {
3206       if (cursor_width < 1)
3207         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3209       /* The bar cursor should never be wider than the glyph.  */
3210       if (cursor_width < w->phys_cursor_width)
3211         w->phys_cursor_width = cursor_width;
3212     }
3213   /* If we have an HBAR, "cursor_width" MAY specify height.  */
3214   else if (cursor_type == HBAR_CURSOR)
3215     {
3216       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3217       if (cursor_height > glyph_row->height)
3218         cursor_height = glyph_row->height;
3219       if (h > cursor_height) // Cursor smaller than line height, move down
3220         fy += h - cursor_height;
3221       h = cursor_height;
3222     }
3224   r.origin.x = fx, r.origin.y = fy;
3225   r.size.height = h;
3226   r.size.width = w->phys_cursor_width;
3228   /* Prevent the cursor from being drawn outside the text area.  */
3229   ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3232   face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3233   if (face && NS_FACE_BACKGROUND (face)
3234       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3235     {
3236       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3237       hollow_color = FRAME_CURSOR_COLOR (f);
3238     }
3239   else
3240     [FRAME_CURSOR_COLOR (f) set];
3242 #ifdef NS_IMPL_COCOA
3243   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3244            atomic.  Cleaner ways of doing this should be investigated.
3245            One way would be to set a global variable DRAWING_CURSOR
3246            when making the call to draw_phys..(), don't focus in that
3247            case, then move the ns_unfocus() here after that call.  */
3248   NSDisableScreenUpdates ();
3249 #endif
3251   switch (cursor_type)
3252     {
3253     case DEFAULT_CURSOR:
3254     case NO_CURSOR:
3255       break;
3256     case FILLED_BOX_CURSOR:
3257       NSRectFill (r);
3258       break;
3259     case HOLLOW_BOX_CURSOR:
3260       NSRectFill (r);
3261       [hollow_color set];
3262       NSRectFill (NSInsetRect (r, 1, 1));
3263       [FRAME_CURSOR_COLOR (f) set];
3264       break;
3265     case HBAR_CURSOR:
3266       NSRectFill (r);
3267       break;
3268     case BAR_CURSOR:
3269       s = r;
3270       /* If the character under cursor is R2L, draw the bar cursor
3271          on the right of its glyph, rather than on the left.  */
3272       cursor_glyph = get_phys_cursor_glyph (w);
3273       if ((cursor_glyph->resolved_level & 1) != 0)
3274         s.origin.x += cursor_glyph->pixel_width - s.size.width;
3276       NSRectFill (s);
3277       break;
3278     }
3279   ns_unfocus (f);
3281   /* draw the character under the cursor */
3282   if (cursor_type != NO_CURSOR)
3283     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3285 #ifdef NS_IMPL_COCOA
3286   NSEnableScreenUpdates ();
3287 #endif
3292 static void
3293 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3294 /* --------------------------------------------------------------------------
3295      External (RIF): Draw a vertical line.
3296    -------------------------------------------------------------------------- */
3298   struct frame *f = XFRAME (WINDOW_FRAME (w));
3299   struct face *face;
3300   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3302   NSTRACE ("ns_draw_vertical_window_border");
3304   face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3306   ns_focus (f, &r, 1);
3307   if (face)
3308     [ns_lookup_indexed_color(face->foreground, f) set];
3310   NSRectFill(r);
3311   ns_unfocus (f);
3315 static void
3316 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3317 /* --------------------------------------------------------------------------
3318      External (RIF): Draw a window divider.
3319    -------------------------------------------------------------------------- */
3321   struct frame *f = XFRAME (WINDOW_FRAME (w));
3322   struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3323   struct face *face_first
3324     = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
3325   struct face *face_last
3326     = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
3327   unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
3328   unsigned long color_first = (face_first
3329                                ? face_first->foreground
3330                                : FRAME_FOREGROUND_PIXEL (f));
3331   unsigned long color_last = (face_last
3332                               ? face_last->foreground
3333                               : FRAME_FOREGROUND_PIXEL (f));
3334   NSRect divider = NSMakeRect (x0, y0, x1-x0, y1-y0);
3336   NSTRACE ("ns_draw_window_divider");
3338   ns_focus (f, &divider, 1);
3340   if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3))
3341     /* A vertical divider, at least three pixels wide: Draw first and
3342        last pixels differently.  */
3343     {
3344       [ns_lookup_indexed_color(color_first, f) set];
3345       NSRectFill(NSMakeRect (x0, y0, 1, y1 - y0));
3346       [ns_lookup_indexed_color(color, f) set];
3347       NSRectFill(NSMakeRect (x0 + 1, y0, x1 - x0 - 2, y1 - y0));
3348       [ns_lookup_indexed_color(color_last, f) set];
3349       NSRectFill(NSMakeRect (x1 - 1, y0, 1, y1 - y0));
3350     }
3351   else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3))
3352     /* A horizontal divider, at least three pixels high: Draw first and
3353        last pixels differently.  */
3354     {
3355       [ns_lookup_indexed_color(color_first, f) set];
3356       NSRectFill(NSMakeRect (x0, y0, x1 - x0, 1));
3357       [ns_lookup_indexed_color(color, f) set];
3358       NSRectFill(NSMakeRect (x0, y0 + 1, x1 - x0, y1 - y0 - 2));
3359       [ns_lookup_indexed_color(color_last, f) set];
3360       NSRectFill(NSMakeRect (x0, y1 - 1, x1 - x0, 1));
3361     }
3362   else
3363     {
3364       /* In any other case do not draw the first and last pixels
3365          differently.  */
3366       [ns_lookup_indexed_color(color, f) set];
3367       NSRectFill(divider);
3368     }
3370   ns_unfocus (f);
3373 static void
3374 ns_show_hourglass (struct frame *f)
3376   /* TODO: add NSProgressIndicator to all frames.  */
3379 static void
3380 ns_hide_hourglass (struct frame *f)
3382   /* TODO: remove NSProgressIndicator from all frames.  */
3385 /* ==========================================================================
3387     Glyph drawing operations
3389    ========================================================================== */
3391 static int
3392 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3393 /* --------------------------------------------------------------------------
3394     Wrapper utility to account for internal border width on full-width lines,
3395     and allow top full-width rows to hit the frame top.  nr should be pointer
3396     to two successive NSRects.  Number of rects actually used is returned.
3397    -------------------------------------------------------------------------- */
3399   int n = get_glyph_string_clip_rects (s, nr, 2);
3400   return n;
3403 /* --------------------------------------------------------------------
3404    Draw a wavy line under glyph string s. The wave fills wave_height
3405    pixels from y.
3407                     x          wave_length = 2
3408                                  --
3409                 y    *   *   *   *   *
3410                      |* * * * * * * * *
3411     wave_height = 3  | *   *   *   *
3412   --------------------------------------------------------------------- */
3414 static void
3415 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3417   int wave_height = 3, wave_length = 2;
3418   int y, dx, dy, odd, xmax;
3419   NSPoint a, b;
3420   NSRect waveClip;
3422   dx = wave_length;
3423   dy = wave_height - 1;
3424   y =  s->ybase - wave_height + 3;
3425   xmax = x + width;
3427   /* Find and set clipping rectangle */
3428   waveClip = NSMakeRect (x, y, width, wave_height);
3429   [[NSGraphicsContext currentContext] saveGraphicsState];
3430   NSRectClip (waveClip);
3432   /* Draw the waves */
3433   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3434   b.x = a.x + dx;
3435   odd = (int)(a.x/dx) % 2;
3436   a.y = b.y = y + 0.5;
3438   if (odd)
3439     a.y += dy;
3440   else
3441     b.y += dy;
3443   while (a.x <= xmax)
3444     {
3445       [NSBezierPath strokeLineFromPoint:a toPoint:b];
3446       a.x = b.x, a.y = b.y;
3447       b.x += dx, b.y = y + 0.5 + odd*dy;
3448       odd = !odd;
3449     }
3451   /* Restore previous clipping rectangle(s) */
3452   [[NSGraphicsContext currentContext] restoreGraphicsState];
3457 static void
3458 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3459                          NSColor *defaultCol, CGFloat width, CGFloat x)
3460 /* --------------------------------------------------------------------------
3461    Draw underline, overline, and strike-through on glyph string s.
3462    -------------------------------------------------------------------------- */
3464   if (s->for_overlaps)
3465     return;
3467   /* Do underline.  */
3468   if (face->underline_p)
3469     {
3470       if (s->face->underline_type == FACE_UNDER_WAVE)
3471         {
3472           if (face->underline_defaulted_p)
3473             [defaultCol set];
3474           else
3475             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3477           ns_draw_underwave (s, width, x);
3478         }
3479       else if (s->face->underline_type == FACE_UNDER_LINE)
3480         {
3482           NSRect r;
3483           unsigned long thickness, position;
3485           /* If the prev was underlined, match its appearance.  */
3486           if (s->prev && s->prev->face->underline_p
3487               && s->prev->face->underline_type == FACE_UNDER_LINE
3488               && s->prev->underline_thickness > 0)
3489             {
3490               thickness = s->prev->underline_thickness;
3491               position = s->prev->underline_position;
3492             }
3493           else
3494             {
3495               struct font *font = font_for_underline_metrics (s);
3496               unsigned long descent = s->y + s->height - s->ybase;
3497               unsigned long minimum_offset;
3498               BOOL underline_at_descent_line, use_underline_position_properties;
3499               Lisp_Object val = buffer_local_value (Qunderline_minimum_offset,
3500                                                     s->w->contents);
3501               if (INTEGERP (val))
3502                 minimum_offset = XFASTINT (val);
3503               else
3504                 minimum_offset = 1;
3505               val = buffer_local_value (Qx_underline_at_descent_line,
3506                                         s->w->contents);
3507               underline_at_descent_line = !(NILP (val) || EQ (val, Qunbound));
3508               val = buffer_local_value (Qx_use_underline_position_properties,
3509                                         s->w->contents);
3510               use_underline_position_properties =
3511                 !(NILP (val) || EQ (val, Qunbound));
3513               /* Use underline thickness of font, defaulting to 1.  */
3514               thickness = (font && font->underline_thickness > 0)
3515                 ? font->underline_thickness : 1;
3517               /* Determine the offset of underlining from the baseline.  */
3518               if (underline_at_descent_line)
3519                 position = descent - thickness;
3520               else if (use_underline_position_properties
3521                        && font && font->underline_position >= 0)
3522                 position = font->underline_position;
3523               else if (font)
3524                 position = lround (font->descent / 2);
3525               else
3526                 position = minimum_offset;
3528               position = max (position, minimum_offset);
3530               /* Ensure underlining is not cropped.  */
3531               if (descent <= position)
3532                 {
3533                   position = descent - 1;
3534                   thickness = 1;
3535                 }
3536               else if (descent < position + thickness)
3537                 thickness = 1;
3538             }
3540           s->underline_thickness = thickness;
3541           s->underline_position = position;
3543           r = NSMakeRect (x, s->ybase + position, width, thickness);
3545           if (face->underline_defaulted_p)
3546             [defaultCol set];
3547           else
3548             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3549           NSRectFill (r);
3550         }
3551     }
3552   /* Do overline. We follow other terms in using a thickness of 1
3553      and ignoring overline_margin.  */
3554   if (face->overline_p)
3555     {
3556       NSRect r;
3557       r = NSMakeRect (x, s->y, width, 1);
3559       if (face->overline_color_defaulted_p)
3560         [defaultCol set];
3561       else
3562         [ns_lookup_indexed_color (face->overline_color, s->f) set];
3563       NSRectFill (r);
3564     }
3566   /* Do strike-through.  We follow other terms for thickness and
3567      vertical position.  */
3568   if (face->strike_through_p)
3569     {
3570       NSRect r;
3571       /* Y-coordinate and height of the glyph string's first glyph.
3572          We cannot use s->y and s->height because those could be
3573          larger if there are taller display elements (e.g., characters
3574          displayed with a larger font) in the same glyph row.  */
3575       int glyph_y = s->ybase - s->first_glyph->ascent;
3576       int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3577       /* Strike-through width and offset from the glyph string's
3578          top edge.  */
3579       unsigned long h = 1;
3580       unsigned long dy;
3582       dy = lrint ((glyph_height - h) / 2);
3583       r = NSMakeRect (x, glyph_y + dy, width, 1);
3585       if (face->strike_through_color_defaulted_p)
3586         [defaultCol set];
3587       else
3588         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3589       NSRectFill (r);
3590     }
3593 static void
3594 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3595              char left_p, char right_p)
3596 /* --------------------------------------------------------------------------
3597     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3598     Note we can't just use an NSDrawRect command, because of the possibility
3599     of some sides not being drawn, and because the rect will be filled.
3600    -------------------------------------------------------------------------- */
3602   NSRect s = r;
3603   [col set];
3605   /* top, bottom */
3606   s.size.height = thickness;
3607   NSRectFill (s);
3608   s.origin.y += r.size.height - thickness;
3609   NSRectFill (s);
3611   s.size.height = r.size.height;
3612   s.origin.y = r.origin.y;
3614   /* left, right (optional) */
3615   s.size.width = thickness;
3616   if (left_p)
3617     NSRectFill (s);
3618   if (right_p)
3619     {
3620       s.origin.x += r.size.width - thickness;
3621       NSRectFill (s);
3622     }
3626 static void
3627 ns_draw_relief (NSRect r, int thickness, char raised_p,
3628                char top_p, char bottom_p, char left_p, char right_p,
3629                struct glyph_string *s)
3630 /* --------------------------------------------------------------------------
3631     Draw a relief rect inside r, optionally leaving some sides open.
3632     Note we can't just use an NSDrawBezel command, because of the possibility
3633     of some sides not being drawn, and because the rect will be filled.
3634    -------------------------------------------------------------------------- */
3636   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3637   NSColor *newBaseCol = nil;
3638   NSRect sr = r;
3640   NSTRACE ("ns_draw_relief");
3642   /* set up colors */
3644   if (s->face->use_box_color_for_shadows_p)
3645     {
3646       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3647     }
3648 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3649            && s->img->pixmap
3650            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3651        {
3652          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3653        } */
3654   else
3655     {
3656       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3657     }
3659   if (newBaseCol == nil)
3660     newBaseCol = [NSColor grayColor];
3662   if (newBaseCol != baseCol)  /* TODO: better check */
3663     {
3664       [baseCol release];
3665       baseCol = [newBaseCol retain];
3666       [lightCol release];
3667       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3668       [darkCol release];
3669       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3670     }
3672   [(raised_p ? lightCol : darkCol) set];
3674   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch.  */
3676   /* top */
3677   sr.size.height = thickness;
3678   if (top_p) NSRectFill (sr);
3680   /* left */
3681   sr.size.height = r.size.height;
3682   sr.size.width = thickness;
3683   if (left_p) NSRectFill (sr);
3685   [(raised_p ? darkCol : lightCol) set];
3687   /* bottom */
3688   sr.size.width = r.size.width;
3689   sr.size.height = thickness;
3690   sr.origin.y += r.size.height - thickness;
3691   if (bottom_p) NSRectFill (sr);
3693   /* right */
3694   sr.size.height = r.size.height;
3695   sr.origin.y = r.origin.y;
3696   sr.size.width = thickness;
3697   sr.origin.x += r.size.width - thickness;
3698   if (right_p) NSRectFill (sr);
3702 static void
3703 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3704 /* --------------------------------------------------------------------------
3705       Function modeled after x_draw_glyph_string_box ().
3706       Sets up parameters for drawing.
3707    -------------------------------------------------------------------------- */
3709   int right_x, last_x;
3710   char left_p, right_p;
3711   struct glyph *last_glyph;
3712   NSRect r;
3713   int thickness;
3714   struct face *face;
3716   if (s->hl == DRAW_MOUSE_FACE)
3717     {
3718       face = FACE_FROM_ID_OR_NULL (s->f,
3719                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3720       if (!face)
3721         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3722     }
3723   else
3724     face = s->face;
3726   thickness = face->box_line_width;
3728   NSTRACE ("ns_dumpglyphs_box_or_relief");
3730   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3731             ? WINDOW_RIGHT_EDGE_X (s->w)
3732             : window_box_right (s->w, s->area));
3733   last_glyph = (s->cmp || s->img
3734                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3736   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3737               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3739   left_p = (s->first_glyph->left_box_line_p
3740             || (s->hl == DRAW_MOUSE_FACE
3741                 && (s->prev == NULL || s->prev->hl != s->hl)));
3742   right_p = (last_glyph->right_box_line_p
3743              || (s->hl == DRAW_MOUSE_FACE
3744                  && (s->next == NULL || s->next->hl != s->hl)));
3746   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3748   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate.  */
3749   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3750     {
3751       ns_draw_box (r, abs (thickness),
3752                    ns_lookup_indexed_color (face->box_color, s->f),
3753                   left_p, right_p);
3754     }
3755   else
3756     {
3757       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3758                      1, 1, left_p, right_p, s);
3759     }
3763 static void
3764 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3765 /* --------------------------------------------------------------------------
3766       Modeled after x_draw_glyph_string_background, which draws BG in
3767       certain cases.  Others are left to the text rendering routine.
3768    -------------------------------------------------------------------------- */
3770   NSTRACE ("ns_maybe_dumpglyphs_background");
3772   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3773     {
3774       int box_line_width = max (s->face->box_line_width, 0);
3775       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3776           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3777              dimensions, since the actual glyphs might be much
3778              smaller.  So in that case we always clear the rectangle
3779              with background color.  */
3780           || FONT_TOO_HIGH (s->font)
3781           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3782         {
3783           struct face *face;
3784           if (s->hl == DRAW_MOUSE_FACE)
3785             {
3786               face
3787                 = FACE_FROM_ID_OR_NULL (s->f,
3788                                         MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3789               if (!face)
3790                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3791             }
3792           else
3793             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3794           if (!face->stipple)
3795             [(NS_FACE_BACKGROUND (face) != 0
3796               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3797               : FRAME_BACKGROUND_COLOR (s->f)) set];
3798           else
3799             {
3800               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3801               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3802             }
3804           if (s->hl != DRAW_CURSOR)
3805             {
3806               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3807                                     s->background_width,
3808                                     s->height-2*box_line_width);
3809               NSRectFill (r);
3810             }
3812           s->background_filled_p = 1;
3813         }
3814     }
3818 static void
3819 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3820 /* --------------------------------------------------------------------------
3821       Renders an image and associated borders.
3822    -------------------------------------------------------------------------- */
3824   EmacsImage *img = s->img->pixmap;
3825   int box_line_vwidth = max (s->face->box_line_width, 0);
3826   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3827   int bg_x, bg_y, bg_height;
3828   int th;
3829   char raised_p;
3830   NSRect br;
3831   struct face *face;
3832   NSColor *tdCol;
3834   NSTRACE ("ns_dumpglyphs_image");
3836   if (s->face->box != FACE_NO_BOX
3837       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3838     x += abs (s->face->box_line_width);
3840   bg_x = x;
3841   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3842   bg_height = s->height;
3843   /* other terms have this, but was causing problems w/tabbar mode */
3844   /* - 2 * box_line_vwidth; */
3846   if (s->slice.x == 0) x += s->img->hmargin;
3847   if (s->slice.y == 0) y += s->img->vmargin;
3849   /* Draw BG: if we need larger area than image itself cleared, do that,
3850      otherwise, since we composite the image under NS (instead of mucking
3851      with its background color), we must clear just the image area.  */
3852   if (s->hl == DRAW_MOUSE_FACE)
3853     {
3854       face = FACE_FROM_ID_OR_NULL (s->f,
3855                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3856       if (!face)
3857        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3858     }
3859   else
3860     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3862   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3864   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3865       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3866     {
3867       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3868       s->background_filled_p = 1;
3869     }
3870   else
3871     {
3872       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3873     }
3875   NSRectFill (br);
3877   /* Draw the image... do we need to draw placeholder if img == nil?  */
3878   if (img != nil)
3879     {
3880 #ifdef NS_IMPL_COCOA
3881       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3882       NSRect ir = NSMakeRect (s->slice.x,
3883                               s->img->height - s->slice.y - s->slice.height,
3884                               s->slice.width, s->slice.height);
3885       [img drawInRect: dr
3886              fromRect: ir
3887              operation: NSCompositingOperationSourceOver
3888               fraction: 1.0
3889            respectFlipped: YES
3890                 hints: nil];
3891 #else
3892       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3893                   operation: NSCompositingOperationSourceOver];
3894 #endif
3895     }
3897   if (s->hl == DRAW_CURSOR)
3898     {
3899     [FRAME_CURSOR_COLOR (s->f) set];
3900     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3901       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3902     else
3903       /* Currently on NS img->mask is always 0.  Since
3904          get_window_cursor_type specifies a hollow box cursor when on
3905          a non-masked image we never reach this clause.  But we put it
3906          in, in anticipation of better support for image masks on
3907          NS.  */
3908       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3909     }
3910   else
3911     {
3912       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3913     }
3915   /* Draw underline, overline, strike-through.  */
3916   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3918   /* Draw relief, if requested */
3919   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3920     {
3921       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3922         {
3923           th = tool_bar_button_relief >= 0 ?
3924             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3925           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3926         }
3927       else
3928         {
3929           th = abs (s->img->relief);
3930           raised_p = (s->img->relief > 0);
3931         }
3933       r.origin.x = x - th;
3934       r.origin.y = y - th;
3935       r.size.width = s->slice.width + 2*th-1;
3936       r.size.height = s->slice.height + 2*th-1;
3937       ns_draw_relief (r, th, raised_p,
3938                       s->slice.y == 0,
3939                       s->slice.y + s->slice.height == s->img->height,
3940                       s->slice.x == 0,
3941                       s->slice.x + s->slice.width == s->img->width, s);
3942     }
3944   /* If there is no mask, the background won't be seen,
3945      so draw a rectangle on the image for the cursor.
3946      Do this for all images, getting transparency right is not reliable.  */
3947   if (s->hl == DRAW_CURSOR)
3948     {
3949       int thickness = abs (s->img->relief);
3950       if (thickness == 0) thickness = 1;
3951       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3952     }
3956 static void
3957 ns_dumpglyphs_stretch (struct glyph_string *s)
3959   NSRect r[2];
3960   int n, i;
3961   struct face *face;
3962   NSColor *fgCol, *bgCol;
3964   if (!s->background_filled_p)
3965     {
3966       n = ns_get_glyph_string_clip_rect (s, r);
3967       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3969       ns_focus (s->f, r, n);
3971       if (s->hl == DRAW_MOUSE_FACE)
3972        {
3973          face = FACE_FROM_ID_OR_NULL (s->f,
3974                                       MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3975          if (!face)
3976            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3977        }
3978       else
3979        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3981       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3982       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3984       for (i = 0; i < n; ++i)
3985         {
3986           if (!s->row->full_width_p)
3987             {
3988               int overrun, leftoverrun;
3990               /* truncate to avoid overwriting fringe and/or scrollbar */
3991               overrun = max (0, (s->x + s->background_width)
3992                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3993                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3994               r[i].size.width -= overrun;
3996               /* truncate to avoid overwriting to left of the window box */
3997               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3998                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
4000               if (leftoverrun > 0)
4001                 {
4002                   r[i].origin.x += leftoverrun;
4003                   r[i].size.width -= leftoverrun;
4004                 }
4006               /* XXX: Try to work between problem where a stretch glyph on
4007                  a partially-visible bottom row will clear part of the
4008                  modeline, and another where list-buffers headers and similar
4009                  rows erroneously have visible_height set to 0.  Not sure
4010                  where this is coming from as other terms seem not to show.  */
4011               r[i].size.height = min (s->height, s->row->visible_height);
4012             }
4014           [bgCol set];
4016           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
4017              overwriting cursor (usually when cursor on a tab).  */
4018           if (s->hl == DRAW_CURSOR)
4019             {
4020               CGFloat x, width;
4022               x = r[i].origin.x;
4023               width = s->w->phys_cursor_width;
4024               r[i].size.width -= width;
4025               r[i].origin.x += width;
4027               NSRectFill (r[i]);
4029               /* Draw overlining, etc. on the cursor.  */
4030               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4031                 ns_draw_text_decoration (s, face, bgCol, width, x);
4032               else
4033                 ns_draw_text_decoration (s, face, fgCol, width, x);
4034             }
4035           else
4036             {
4037               NSRectFill (r[i]);
4038             }
4040           /* Draw overlining, etc. on the stretch glyph (or the part
4041              of the stretch glyph after the cursor).  */
4042           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
4043                                    r[i].origin.x);
4044         }
4045       ns_unfocus (s->f);
4046       s->background_filled_p = 1;
4047     }
4051 static void
4052 ns_draw_glyph_string_foreground (struct glyph_string *s)
4054   int x, flags;
4055   struct font *font = s->font;
4057   /* If first glyph of S has a left box line, start drawing the text
4058      of S to the right of that box line.  */
4059   if (s->face && s->face->box != FACE_NO_BOX
4060       && s->first_glyph->left_box_line_p)
4061     x = s->x + eabs (s->face->box_line_width);
4062   else
4063     x = s->x;
4065   flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
4066     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
4067      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
4068       NS_DUMPGLYPH_NORMAL));
4070   font->driver->draw
4071     (s, s->cmp_from, s->nchars, x, s->ybase,
4072      (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
4073      || flags == NS_DUMPGLYPH_MOUSEFACE);
4077 static void
4078 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
4080   int i, j, x;
4081   struct font *font = s->font;
4083   /* If first glyph of S has a left box line, start drawing the text
4084      of S to the right of that box line.  */
4085   if (s->face && s->face->box != FACE_NO_BOX
4086       && s->first_glyph->left_box_line_p)
4087     x = s->x + eabs (s->face->box_line_width);
4088   else
4089     x = s->x;
4091   /* S is a glyph string for a composition.  S->cmp_from is the index
4092      of the first character drawn for glyphs of this composition.
4093      S->cmp_from == 0 means we are drawing the very first character of
4094      this composition.  */
4096   /* Draw a rectangle for the composition if the font for the very
4097      first character of the composition could not be loaded.  */
4098   if (s->font_not_found_p)
4099     {
4100       if (s->cmp_from == 0)
4101         {
4102           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
4103           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
4104         }
4105     }
4106   else if (! s->first_glyph->u.cmp.automatic)
4107     {
4108       int y = s->ybase;
4110       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
4111         /* TAB in a composition means display glyphs with padding
4112            space on the left or right.  */
4113         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
4114           {
4115             int xx = x + s->cmp->offsets[j * 2];
4116             int yy = y - s->cmp->offsets[j * 2 + 1];
4118             font->driver->draw (s, j, j + 1, xx, yy, false);
4119             if (s->face->overstrike)
4120               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
4121           }
4122     }
4123   else
4124     {
4125       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
4126       Lisp_Object glyph;
4127       int y = s->ybase;
4128       int width = 0;
4130       for (i = j = s->cmp_from; i < s->cmp_to; i++)
4131         {
4132           glyph = LGSTRING_GLYPH (gstring, i);
4133           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
4134             width += LGLYPH_WIDTH (glyph);
4135           else
4136             {
4137               int xoff, yoff, wadjust;
4139               if (j < i)
4140                 {
4141                   font->driver->draw (s, j, i, x, y, false);
4142                   if (s->face->overstrike)
4143                     font->driver->draw (s, j, i, x + 1, y, false);
4144                   x += width;
4145                 }
4146               xoff = LGLYPH_XOFF (glyph);
4147               yoff = LGLYPH_YOFF (glyph);
4148               wadjust = LGLYPH_WADJUST (glyph);
4149               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
4150               if (s->face->overstrike)
4151                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
4152                                     false);
4153               x += wadjust;
4154               j = i + 1;
4155               width = 0;
4156             }
4157         }
4158       if (j < i)
4159         {
4160           font->driver->draw (s, j, i, x, y, false);
4161           if (s->face->overstrike)
4162             font->driver->draw (s, j, i, x + 1, y, false);
4163         }
4164     }
4167 static void
4168 ns_draw_glyph_string (struct glyph_string *s)
4169 /* --------------------------------------------------------------------------
4170       External (RIF): Main draw-text call.
4171    -------------------------------------------------------------------------- */
4173   /* TODO (optimize): focus for box and contents draw */
4174   NSRect r[2];
4175   int n;
4176   char box_drawn_p = 0;
4177   struct font *font = s->face->font;
4178   if (! font) font = FRAME_FONT (s->f);
4180   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
4182   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
4183     {
4184       int width;
4185       struct glyph_string *next;
4187       for (width = 0, next = s->next;
4188            next && width < s->right_overhang;
4189            width += next->width, next = next->next)
4190         if (next->first_glyph->type != IMAGE_GLYPH)
4191           {
4192             if (next->first_glyph->type != STRETCH_GLYPH)
4193               {
4194                 n = ns_get_glyph_string_clip_rect (s->next, r);
4195                 ns_focus (s->f, r, n);
4196                 ns_maybe_dumpglyphs_background (s->next, 1);
4197                 ns_unfocus (s->f);
4198               }
4199             else
4200               {
4201                 ns_dumpglyphs_stretch (s->next);
4202               }
4203             next->num_clips = 0;
4204           }
4205     }
4207   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
4208         && (s->first_glyph->type == CHAR_GLYPH
4209             || s->first_glyph->type == COMPOSITE_GLYPH))
4210     {
4211       n = ns_get_glyph_string_clip_rect (s, r);
4212       ns_focus (s->f, r, n);
4213       ns_maybe_dumpglyphs_background (s, 1);
4214       ns_dumpglyphs_box_or_relief (s);
4215       ns_unfocus (s->f);
4216       box_drawn_p = 1;
4217     }
4219   switch (s->first_glyph->type)
4220     {
4222     case IMAGE_GLYPH:
4223       n = ns_get_glyph_string_clip_rect (s, r);
4224       ns_focus (s->f, r, n);
4225       ns_dumpglyphs_image (s, r[0]);
4226       ns_unfocus (s->f);
4227       break;
4229     case STRETCH_GLYPH:
4230       ns_dumpglyphs_stretch (s);
4231       break;
4233     case CHAR_GLYPH:
4234     case COMPOSITE_GLYPH:
4235       n = ns_get_glyph_string_clip_rect (s, r);
4236       ns_focus (s->f, r, n);
4238       if (s->for_overlaps || (s->cmp_from > 0
4239                               && ! s->first_glyph->u.cmp.automatic))
4240         s->background_filled_p = 1;
4241       else
4242         ns_maybe_dumpglyphs_background
4243           (s, s->first_glyph->type == COMPOSITE_GLYPH);
4245       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4246         {
4247           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4248           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4249           NS_FACE_FOREGROUND (s->face) = tmp;
4250         }
4252       {
4253         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4255         if (isComposite)
4256           ns_draw_composite_glyph_string_foreground (s);
4257         else
4258           ns_draw_glyph_string_foreground (s);
4259       }
4261       {
4262         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4263                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4264                                                    s->f)
4265                         : FRAME_FOREGROUND_COLOR (s->f));
4266         [col set];
4268         /* Draw underline, overline, strike-through.  */
4269         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4270       }
4272       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4273         {
4274           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4275           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4276           NS_FACE_FOREGROUND (s->face) = tmp;
4277         }
4279       ns_unfocus (s->f);
4280       break;
4282     case GLYPHLESS_GLYPH:
4283       n = ns_get_glyph_string_clip_rect (s, r);
4284       ns_focus (s->f, r, n);
4286       if (s->for_overlaps || (s->cmp_from > 0
4287                               && ! s->first_glyph->u.cmp.automatic))
4288         s->background_filled_p = 1;
4289       else
4290         ns_maybe_dumpglyphs_background
4291           (s, s->first_glyph->type == COMPOSITE_GLYPH);
4292       /* ... */
4293       /* Not yet implemented.  */
4294       /* ... */
4295       ns_unfocus (s->f);
4296       break;
4298     default:
4299       emacs_abort ();
4300     }
4302   /* Draw box if not done already.  */
4303   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4304     {
4305       n = ns_get_glyph_string_clip_rect (s, r);
4306       ns_focus (s->f, r, n);
4307       ns_dumpglyphs_box_or_relief (s);
4308       ns_unfocus (s->f);
4309     }
4311   s->num_clips = 0;
4316 /* ==========================================================================
4318     Event loop
4320    ========================================================================== */
4323 static void
4324 ns_send_appdefined (int value)
4325 /* --------------------------------------------------------------------------
4326     Internal: post an appdefined event which EmacsApp-sendEvent will
4327               recognize and take as a command to halt the event loop.
4328    -------------------------------------------------------------------------- */
4330   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4332   // GNUstep needs postEvent to happen on the main thread.
4333   // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4334   if (! [[NSThread currentThread] isMainThread])
4335     {
4336       EmacsApp *app = (EmacsApp *)NSApp;
4337       app->nextappdefined = value;
4338       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4339                             withObject:nil
4340                          waitUntilDone:NO];
4341       return;
4342     }
4344   /* Only post this event if we haven't already posted one.  This will end
4345      the [NXApp run] main loop after having processed all events queued at
4346      this moment.  */
4348 #ifdef NS_IMPL_COCOA
4349   if (! send_appdefined)
4350     {
4351       /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4352          in certain situations (rapid incoming events).
4353          So check if we have one, if not add one.  */
4354       NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4355                                           untilDate:[NSDate distantPast]
4356                                              inMode:NSDefaultRunLoopMode
4357                                             dequeue:NO];
4358       if (! appev) send_appdefined = YES;
4359     }
4360 #endif
4362   if (send_appdefined)
4363     {
4364       NSEvent *nxev;
4366       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
4367       send_appdefined = NO;
4369       /* Don't need wakeup timer any more.  */
4370       if (timed_entry)
4371         {
4372           [timed_entry invalidate];
4373           [timed_entry release];
4374           timed_entry = nil;
4375         }
4377       nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4378                                 location: NSMakePoint (0, 0)
4379                            modifierFlags: 0
4380                                timestamp: 0
4381                             windowNumber: [[NSApp mainWindow] windowNumber]
4382                                  context: [NSApp context]
4383                                  subtype: 0
4384                                    data1: value
4385                                    data2: 0];
4387       /* Post an application defined event on the event queue.  When this is
4388          received the [NXApp run] will return, thus having processed all
4389          events which are currently queued.  */
4390       [NSApp postEvent: nxev atStart: NO];
4391     }
4394 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4395 static void
4396 check_native_fs ()
4398   Lisp_Object frame, tail;
4400   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4401     return;
4403   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4405   FOR_EACH_FRAME (tail, frame)
4406     {
4407       struct frame *f = XFRAME (frame);
4408       if (FRAME_NS_P (f))
4409         {
4410           EmacsView *view = FRAME_NS_VIEW (f);
4411           [view updateCollectionBehavior];
4412         }
4413     }
4415 #endif
4417 /* GNUstep does not have cancelTracking.  */
4418 #ifdef NS_IMPL_COCOA
4419 /* Check if menu open should be canceled or continued as normal.  */
4420 void
4421 ns_check_menu_open (NSMenu *menu)
4423   /* Click in menu bar?  */
4424   NSArray *a = [[NSApp mainMenu] itemArray];
4425   int i;
4426   BOOL found = NO;
4428   if (menu == nil) // Menu tracking ended.
4429     {
4430       if (menu_will_open_state == MENU_OPENING)
4431         menu_will_open_state = MENU_NONE;
4432       return;
4433     }
4435   for (i = 0; ! found && i < [a count]; i++)
4436     found = menu == [[a objectAtIndex:i] submenu];
4437   if (found)
4438     {
4439       if (menu_will_open_state == MENU_NONE && emacs_event)
4440         {
4441           NSEvent *theEvent = [NSApp currentEvent];
4442           struct frame *emacsframe = SELECTED_FRAME ();
4444           [menu cancelTracking];
4445           menu_will_open_state = MENU_PENDING;
4446           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4447           EV_TRAILER (theEvent);
4449           CGEventRef ourEvent = CGEventCreate (NULL);
4450           menu_mouse_point = CGEventGetLocation (ourEvent);
4451           CFRelease (ourEvent);
4452         }
4453       else if (menu_will_open_state == MENU_OPENING)
4454         {
4455           menu_will_open_state = MENU_NONE;
4456         }
4457     }
4460 /* Redo saved menu click if state is MENU_PENDING.  */
4461 void
4462 ns_check_pending_open_menu ()
4464   if (menu_will_open_state == MENU_PENDING)
4465     {
4466       CGEventSourceRef source
4467         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4469       CGEventRef event = CGEventCreateMouseEvent (source,
4470                                                   kCGEventLeftMouseDown,
4471                                                   menu_mouse_point,
4472                                                   kCGMouseButtonLeft);
4473       CGEventSetType (event, kCGEventLeftMouseDown);
4474       CGEventPost (kCGHIDEventTap, event);
4475       CFRelease (event);
4476       CFRelease (source);
4478       menu_will_open_state = MENU_OPENING;
4479     }
4481 #endif /* NS_IMPL_COCOA */
4483 static int
4484 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4485 /* --------------------------------------------------------------------------
4486      External (hook): Post an event to ourself and keep reading events until
4487      we read it back again.  In effect process all events which were waiting.
4488      From 21+ we have to manage the event buffer ourselves.
4489    -------------------------------------------------------------------------- */
4491   struct input_event ev;
4492   int nevents;
4494   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4496 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4497   check_native_fs ();
4498 #endif
4500   if ([NSApp modalWindow] != nil)
4501     return -1;
4503   if (hold_event_q.nr > 0)
4504     {
4505       int i;
4506       for (i = 0; i < hold_event_q.nr; ++i)
4507         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4508       hold_event_q.nr = 0;
4509       return i;
4510     }
4512   if ([NSThread isMainThread])
4513     {
4514       block_input ();
4515       n_emacs_events_pending = 0;
4516       ns_init_events (&ev);
4517       q_event_ptr = hold_quit;
4519       /* We manage autorelease pools by allocate/reallocate each time around
4520          the loop; strict nesting is occasionally violated but seems not to
4521          matter... earlier methods using full nesting caused major memory leaks.  */
4522       [outerpool release];
4523       outerpool = [[NSAutoreleasePool alloc] init];
4525       /* If have pending open-file requests, attend to the next one of those.  */
4526       if (ns_pending_files && [ns_pending_files count] != 0
4527           && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4528         {
4529           [ns_pending_files removeObjectAtIndex: 0];
4530         }
4531       /* Deal with pending service requests.  */
4532       else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4533                && [(EmacsApp *)
4534                     NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4535                                  withArg: [ns_pending_service_args objectAtIndex: 0]])
4536         {
4537           [ns_pending_service_names removeObjectAtIndex: 0];
4538           [ns_pending_service_args removeObjectAtIndex: 0];
4539         }
4540       else
4541         {
4542           /* Run and wait for events.  We must always send one NX_APPDEFINED event
4543              to ourself, otherwise [NXApp run] will never exit.  */
4544           send_appdefined = YES;
4545           ns_send_appdefined (-1);
4547           [NSApp run];
4548         }
4550       nevents = n_emacs_events_pending;
4551       n_emacs_events_pending = 0;
4552       ns_finish_events ();
4553       q_event_ptr = NULL;
4554       unblock_input ();
4555     }
4556   else
4557     return -1;
4559   return nevents;
4564 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4565            fd_set *exceptfds, struct timespec *timeout,
4566            sigset_t *sigmask)
4567 /* --------------------------------------------------------------------------
4568      Replacement for select, checking for events
4569    -------------------------------------------------------------------------- */
4571   int result;
4572   int t, k, nr = 0;
4573   struct input_event event;
4574   char c;
4576   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4578 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4579   check_native_fs ();
4580 #endif
4582   if (hold_event_q.nr > 0)
4583     {
4584       /* We already have events pending.  */
4585       raise (SIGIO);
4586       errno = EINTR;
4587       return -1;
4588     }
4590   for (k = 0; k < nfds+1; k++)
4591     {
4592       if (readfds && FD_ISSET(k, readfds)) ++nr;
4593       if (writefds && FD_ISSET(k, writefds)) ++nr;
4594     }
4596   if (NSApp == nil
4597       || ![NSThread isMainThread]
4598       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4599     return thread_select(pselect, nfds, readfds, writefds,
4600                          exceptfds, timeout, sigmask);
4601   else
4602     {
4603       struct timespec t = {0, 0};
4604       thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4605     }
4607   [outerpool release];
4608   outerpool = [[NSAutoreleasePool alloc] init];
4611   send_appdefined = YES;
4612   if (nr > 0)
4613     {
4614       pthread_mutex_lock (&select_mutex);
4615       select_nfds = nfds;
4616       select_valid = 0;
4617       if (readfds)
4618         {
4619           select_readfds = *readfds;
4620           select_valid += SELECT_HAVE_READ;
4621         }
4622       if (writefds)
4623         {
4624           select_writefds = *writefds;
4625           select_valid += SELECT_HAVE_WRITE;
4626         }
4628       if (timeout)
4629         {
4630           select_timeout = *timeout;
4631           select_valid += SELECT_HAVE_TMO;
4632         }
4634       pthread_mutex_unlock (&select_mutex);
4636       /* Inform fd_handler that select should be called.  */
4637       c = 'g';
4638       emacs_write_sig (selfds[1], &c, 1);
4639     }
4640   else if (nr == 0 && timeout)
4641     {
4642       /* No file descriptor, just a timeout, no need to wake fd_handler.  */
4643       double time = timespectod (*timeout);
4644       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4645                                                       target: NSApp
4646                                                     selector:
4647                                   @selector (timeout_handler:)
4648                                                     userInfo: 0
4649                                                      repeats: NO]
4650                       retain];
4651     }
4652   else /* No timeout and no file descriptors, can this happen?  */
4653     {
4654       /* Send appdefined so we exit from the loop.  */
4655       ns_send_appdefined (-1);
4656     }
4658   block_input ();
4659   ns_init_events (&event);
4661   [NSApp run];
4663   ns_finish_events ();
4664   if (nr > 0 && readfds)
4665     {
4666       c = 's';
4667       emacs_write_sig (selfds[1], &c, 1);
4668     }
4669   unblock_input ();
4671   t = last_appdefined_event_data;
4673   if (t != NO_APPDEFINED_DATA)
4674     {
4675       last_appdefined_event_data = NO_APPDEFINED_DATA;
4677       if (t == -2)
4678         {
4679           /* The NX_APPDEFINED event we received was a timeout.  */
4680           result = 0;
4681         }
4682       else if (t == -1)
4683         {
4684           /* The NX_APPDEFINED event we received was the result of
4685              at least one real input event arriving.  */
4686           errno = EINTR;
4687           result = -1;
4688         }
4689       else
4690         {
4691           /* Received back from select () in fd_handler; copy the results.  */
4692           pthread_mutex_lock (&select_mutex);
4693           if (readfds) *readfds = select_readfds;
4694           if (writefds) *writefds = select_writefds;
4695           pthread_mutex_unlock (&select_mutex);
4696           result = t;
4697         }
4698     }
4699   else
4700     {
4701       errno = EINTR;
4702       result = -1;
4703     }
4705   return result;
4708 #ifdef HAVE_PTHREAD
4709 void
4710 ns_run_loop_break ()
4711 /* Break out of the NS run loop in ns_select or ns_read_socket.  */
4713   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4715   /* If we don't have a GUI, don't send the event.  */
4716   if (NSApp != NULL)
4717     ns_send_appdefined(-1);
4719 #endif
4722 /* ==========================================================================
4724     Scrollbar handling
4726    ========================================================================== */
4729 static void
4730 ns_set_vertical_scroll_bar (struct window *window,
4731                            int portion, int whole, int position)
4732 /* --------------------------------------------------------------------------
4733       External (hook): Update or add scrollbar
4734    -------------------------------------------------------------------------- */
4736   Lisp_Object win;
4737   NSRect r, v;
4738   struct frame *f = XFRAME (WINDOW_FRAME (window));
4739   EmacsView *view = FRAME_NS_VIEW (f);
4740   EmacsScroller *bar;
4741   int window_y, window_height;
4742   int top, left, height, width;
4743   BOOL update_p = YES;
4745   /* Optimization; display engine sends WAY too many of these.  */
4746   if (!NILP (window->vertical_scroll_bar))
4747     {
4748       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4749       if ([bar checkSamePosition: position portion: portion whole: whole])
4750         {
4751           if (view->scrollbarsNeedingUpdate == 0)
4752             {
4753               if (!windows_or_buffers_changed)
4754                   return;
4755             }
4756           else
4757             view->scrollbarsNeedingUpdate--;
4758           update_p = NO;
4759         }
4760     }
4762   NSTRACE ("ns_set_vertical_scroll_bar");
4764   /* Get dimensions.  */
4765   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4766   top = window_y;
4767   height = window_height;
4768   width = NS_SCROLL_BAR_WIDTH (f);
4769   left = WINDOW_SCROLL_BAR_AREA_X (window);
4771   r = NSMakeRect (left, top, width, height);
4772   /* The parent view is flipped, so we need to flip y value.  */
4773   v = [view frame];
4774   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4776   XSETWINDOW (win, window);
4777   block_input ();
4779   /* We want at least 5 lines to display a scrollbar.  */
4780   if (WINDOW_TOTAL_LINES (window) < 5)
4781     {
4782       if (!NILP (window->vertical_scroll_bar))
4783         {
4784           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4785           [bar removeFromSuperview];
4786           wset_vertical_scroll_bar (window, Qnil);
4787           [bar release];
4788         }
4789       ns_clear_frame_area (f, left, top, width, height);
4790       unblock_input ();
4791       return;
4792     }
4794   if (NILP (window->vertical_scroll_bar))
4795     {
4796       if (width > 0 && height > 0)
4797         ns_clear_frame_area (f, left, top, width, height);
4799       bar = [[EmacsScroller alloc] initFrame: r window: win];
4800       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4801       update_p = YES;
4802     }
4803   else
4804     {
4805       NSRect oldRect;
4806       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4807       oldRect = [bar frame];
4808       r.size.width = oldRect.size.width;
4809       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4810         {
4811           if (oldRect.origin.x != r.origin.x)
4812               ns_clear_frame_area (f, left, top, width, height);
4813           [bar setFrame: r];
4814         }
4815     }
4817   if (update_p)
4818     [bar setPosition: position portion: portion whole: whole];
4819   unblock_input ();
4823 static void
4824 ns_set_horizontal_scroll_bar (struct window *window,
4825                               int portion, int whole, int position)
4826 /* --------------------------------------------------------------------------
4827       External (hook): Update or add scrollbar.
4828    -------------------------------------------------------------------------- */
4830   Lisp_Object win;
4831   NSRect r, v;
4832   struct frame *f = XFRAME (WINDOW_FRAME (window));
4833   EmacsView *view = FRAME_NS_VIEW (f);
4834   EmacsScroller *bar;
4835   int top, height, left, width;
4836   int window_x, window_width;
4837   BOOL update_p = YES;
4839   /* Optimization; display engine sends WAY too many of these.  */
4840   if (!NILP (window->horizontal_scroll_bar))
4841     {
4842       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4843       if ([bar checkSamePosition: position portion: portion whole: whole])
4844         {
4845           if (view->scrollbarsNeedingUpdate == 0)
4846             {
4847               if (!windows_or_buffers_changed)
4848                   return;
4849             }
4850           else
4851             view->scrollbarsNeedingUpdate--;
4852           update_p = NO;
4853         }
4854     }
4856   NSTRACE ("ns_set_horizontal_scroll_bar");
4858   /* Get dimensions.  */
4859   window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4860   left = window_x;
4861   width = window_width;
4862   height = NS_SCROLL_BAR_HEIGHT (f);
4863   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4865   r = NSMakeRect (left, top, width, height);
4866   /* The parent view is flipped, so we need to flip y value.  */
4867   v = [view frame];
4868   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4870   XSETWINDOW (win, window);
4871   block_input ();
4873   if (NILP (window->horizontal_scroll_bar))
4874     {
4875       if (width > 0 && height > 0)
4876         ns_clear_frame_area (f, left, top, width, height);
4878       bar = [[EmacsScroller alloc] initFrame: r window: win];
4879       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4880       update_p = YES;
4881     }
4882   else
4883     {
4884       NSRect oldRect;
4885       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4886       oldRect = [bar frame];
4887       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4888         {
4889           if (oldRect.origin.y != r.origin.y)
4890             ns_clear_frame_area (f, left, top, width, height);
4891           [bar setFrame: r];
4892           update_p = YES;
4893         }
4894     }
4896   /* If there are both horizontal and vertical scroll-bars they leave
4897      a square that belongs to neither. We need to clear it otherwise
4898      it fills with junk.  */
4899   if (!NILP (window->vertical_scroll_bar))
4900     ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4901                          NS_SCROLL_BAR_HEIGHT (f), height);
4903   if (update_p)
4904     [bar setPosition: position portion: portion whole: whole];
4905   unblock_input ();
4909 static void
4910 ns_condemn_scroll_bars (struct frame *f)
4911 /* --------------------------------------------------------------------------
4912      External (hook): arrange for all frame's scrollbars to be removed
4913      at next call to judge_scroll_bars, except for those redeemed.
4914    -------------------------------------------------------------------------- */
4916   int i;
4917   id view;
4918   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4920   NSTRACE ("ns_condemn_scroll_bars");
4922   for (i =[subviews count]-1; i >= 0; i--)
4923     {
4924       view = [subviews objectAtIndex: i];
4925       if ([view isKindOfClass: [EmacsScroller class]])
4926         [view condemn];
4927     }
4931 static void
4932 ns_redeem_scroll_bar (struct window *window)
4933 /* --------------------------------------------------------------------------
4934      External (hook): arrange to spare this window's scrollbar
4935      at next call to judge_scroll_bars.
4936    -------------------------------------------------------------------------- */
4938   id bar;
4939   NSTRACE ("ns_redeem_scroll_bar");
4940   if (!NILP (window->vertical_scroll_bar)
4941       && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4942     {
4943       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4944       [bar reprieve];
4945     }
4947   if (!NILP (window->horizontal_scroll_bar)
4948       && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4949     {
4950       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4951       [bar reprieve];
4952     }
4956 static void
4957 ns_judge_scroll_bars (struct frame *f)
4958 /* --------------------------------------------------------------------------
4959      External (hook): destroy all scrollbars on frame that weren't
4960      redeemed after call to condemn_scroll_bars.
4961    -------------------------------------------------------------------------- */
4963   int i;
4964   id view;
4965   EmacsView *eview = FRAME_NS_VIEW (f);
4966   NSArray *subviews = [[eview superview] subviews];
4967   BOOL removed = NO;
4969   NSTRACE ("ns_judge_scroll_bars");
4970   for (i = [subviews count]-1; i >= 0; --i)
4971     {
4972       view = [subviews objectAtIndex: i];
4973       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4974       if ([view judge])
4975         removed = YES;
4976     }
4978   if (removed)
4979     [eview updateFrameSize: NO];
4982 /* ==========================================================================
4984     Initialization
4986    ========================================================================== */
4989 x_display_pixel_height (struct ns_display_info *dpyinfo)
4991   NSArray *screens = [NSScreen screens];
4992   NSEnumerator *enumerator = [screens objectEnumerator];
4993   NSScreen *screen;
4994   NSRect frame;
4996   frame = NSZeroRect;
4997   while ((screen = [enumerator nextObject]) != nil)
4998     frame = NSUnionRect (frame, [screen frame]);
5000   return NSHeight (frame);
5004 x_display_pixel_width (struct ns_display_info *dpyinfo)
5006   NSArray *screens = [NSScreen screens];
5007   NSEnumerator *enumerator = [screens objectEnumerator];
5008   NSScreen *screen;
5009   NSRect frame;
5011   frame = NSZeroRect;
5012   while ((screen = [enumerator nextObject]) != nil)
5013     frame = NSUnionRect (frame, [screen frame]);
5015   return NSWidth (frame);
5019 static Lisp_Object ns_string_to_lispmod (const char *s)
5020 /* --------------------------------------------------------------------------
5021      Convert modifier name to lisp symbol.
5022    -------------------------------------------------------------------------- */
5024   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
5025     return Qmeta;
5026   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
5027     return Qsuper;
5028   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
5029     return Qcontrol;
5030   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
5031     return Qalt;
5032   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
5033     return Qhyper;
5034   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
5035     return Qnone;
5036   else
5037     return Qnil;
5041 static void
5042 ns_default (const char *parameter, Lisp_Object *result,
5043            Lisp_Object yesval, Lisp_Object noval,
5044            BOOL is_float, BOOL is_modstring)
5045 /* --------------------------------------------------------------------------
5046       Check a parameter value in user's preferences.
5047    -------------------------------------------------------------------------- */
5049   const char *value = ns_get_defaults_value (parameter);
5051   if (value)
5052     {
5053       double f;
5054       char *pos;
5055       if (c_strcasecmp (value, "YES") == 0)
5056         *result = yesval;
5057       else if (c_strcasecmp (value, "NO") == 0)
5058         *result = noval;
5059       else if (is_float && (f = strtod (value, &pos), pos != value))
5060         *result = make_float (f);
5061       else if (is_modstring && value)
5062         *result = ns_string_to_lispmod (value);
5063       else fprintf (stderr,
5064                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
5065     }
5069 static void
5070 ns_initialize_display_info (struct ns_display_info *dpyinfo)
5071 /* --------------------------------------------------------------------------
5072       Initialize global info and storage for display.
5073    -------------------------------------------------------------------------- */
5075     NSScreen *screen = [NSScreen mainScreen];
5076     NSWindowDepth depth = [screen depth];
5078     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
5079     dpyinfo->resy = 72.27;
5080     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
5081                                                   NSColorSpaceFromDepth (depth)]
5082                 && ![NSCalibratedWhiteColorSpace isEqualToString:
5083                                                  NSColorSpaceFromDepth (depth)];
5084     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
5085     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
5086     dpyinfo->color_table->colors = NULL;
5087     dpyinfo->root_window = 42; /* A placeholder.  */
5088     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
5089     dpyinfo->n_fonts = 0;
5090     dpyinfo->smallest_font_height = 1;
5091     dpyinfo->smallest_char_width = 1;
5093     reset_mouse_highlight (&dpyinfo->mouse_highlight);
5097 /* This and next define (many of the) public functions in this file.  */
5098 /* x_... are generic versions in xdisp.c that we, and other terms, get away
5099          with using despite presence in the "system dependent" redisplay
5100          interface.  In addition, many of the ns_ methods have code that is
5101          shared with all terms, indicating need for further refactoring.  */
5102 extern frame_parm_handler ns_frame_parm_handlers[];
5103 static struct redisplay_interface ns_redisplay_interface =
5105   ns_frame_parm_handlers,
5106   x_produce_glyphs,
5107   x_write_glyphs,
5108   x_insert_glyphs,
5109   x_clear_end_of_line,
5110   ns_scroll_run,
5111   ns_after_update_window_line,
5112   ns_update_window_begin,
5113   ns_update_window_end,
5114   0, /* flush_display */
5115   x_clear_window_mouse_face,
5116   x_get_glyph_overhangs,
5117   x_fix_overlapping_area,
5118   ns_draw_fringe_bitmap,
5119   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
5120   0, /* destroy_fringe_bitmap */
5121   ns_compute_glyph_string_overhangs,
5122   ns_draw_glyph_string,
5123   ns_define_frame_cursor,
5124   ns_clear_frame_area,
5125   ns_draw_window_cursor,
5126   ns_draw_vertical_window_border,
5127   ns_draw_window_divider,
5128   ns_shift_glyphs_for_insert,
5129   ns_show_hourglass,
5130   ns_hide_hourglass
5134 static void
5135 ns_delete_display (struct ns_display_info *dpyinfo)
5137   /* TODO...  */
5141 /* This function is called when the last frame on a display is deleted.  */
5142 static void
5143 ns_delete_terminal (struct terminal *terminal)
5145   struct ns_display_info *dpyinfo = terminal->display_info.ns;
5147   NSTRACE ("ns_delete_terminal");
5149   /* Protect against recursive calls.  delete_frame in
5150      delete_terminal calls us back when it deletes our last frame.  */
5151   if (!terminal->name)
5152     return;
5154   block_input ();
5156   x_destroy_all_bitmaps (dpyinfo);
5157   ns_delete_display (dpyinfo);
5158   unblock_input ();
5162 static struct terminal *
5163 ns_create_terminal (struct ns_display_info *dpyinfo)
5164 /* --------------------------------------------------------------------------
5165       Set up use of NS before we make the first connection.
5166    -------------------------------------------------------------------------- */
5168   struct terminal *terminal;
5170   NSTRACE ("ns_create_terminal");
5172   terminal = create_terminal (output_ns, &ns_redisplay_interface);
5174   terminal->display_info.ns = dpyinfo;
5175   dpyinfo->terminal = terminal;
5177   terminal->clear_frame_hook = ns_clear_frame;
5178   terminal->ring_bell_hook = ns_ring_bell;
5179   terminal->update_begin_hook = ns_update_begin;
5180   terminal->update_end_hook = ns_update_end;
5181   terminal->read_socket_hook = ns_read_socket;
5182   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
5183   terminal->mouse_position_hook = ns_mouse_position;
5184   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
5185   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
5186   terminal->fullscreen_hook = ns_fullscreen_hook;
5187   terminal->menu_show_hook = ns_menu_show;
5188   terminal->popup_dialog_hook = ns_popup_dialog;
5189   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
5190   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
5191   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
5192   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
5193   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
5194   terminal->delete_frame_hook = x_destroy_window;
5195   terminal->delete_terminal_hook = ns_delete_terminal;
5196   /* Other hooks are NULL by default.  */
5198   return terminal;
5202 struct ns_display_info *
5203 ns_term_init (Lisp_Object display_name)
5204 /* --------------------------------------------------------------------------
5205      Start the Application and get things rolling.
5206    -------------------------------------------------------------------------- */
5208   struct terminal *terminal;
5209   struct ns_display_info *dpyinfo;
5210   static int ns_initialized = 0;
5211   Lisp_Object tmp;
5213   if (ns_initialized) return x_display_list;
5214   ns_initialized = 1;
5216   block_input ();
5218   NSTRACE ("ns_term_init");
5220   [outerpool release];
5221   outerpool = [[NSAutoreleasePool alloc] init];
5223   /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
5224   /*GSDebugAllocationActive (YES); */
5225   block_input ();
5227   baud_rate = 38400;
5228   Fset_input_interrupt_mode (Qnil);
5230   if (selfds[0] == -1)
5231     {
5232       if (emacs_pipe (selfds) != 0)
5233         {
5234           fprintf (stderr, "Failed to create pipe: %s\n",
5235                    emacs_strerror (errno));
5236           emacs_abort ();
5237         }
5239       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
5240       FD_ZERO (&select_readfds);
5241       FD_ZERO (&select_writefds);
5242       pthread_mutex_init (&select_mutex, NULL);
5243     }
5245   ns_pending_files = [[NSMutableArray alloc] init];
5246   ns_pending_service_names = [[NSMutableArray alloc] init];
5247   ns_pending_service_args = [[NSMutableArray alloc] init];
5249   /* Start app and create the main menu, window, view.
5250      Needs to be here because ns_initialize_display_info () uses AppKit classes.
5251      The view will then ask the NSApp to stop and return to Emacs.  */
5252   [EmacsApp sharedApplication];
5253   if (NSApp == nil)
5254     return NULL;
5255   [NSApp setDelegate: NSApp];
5257   /* Start the select thread.  */
5258   [NSThread detachNewThreadSelector:@selector (fd_handler:)
5259                            toTarget:NSApp
5260                          withObject:nil];
5262   /* debugging: log all notifications */
5263   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
5264                                          selector: @selector (logNotification:)
5265                                              name: nil object: nil]; */
5267   dpyinfo = xzalloc (sizeof *dpyinfo);
5269   ns_initialize_display_info (dpyinfo);
5270   terminal = ns_create_terminal (dpyinfo);
5272   terminal->kboard = allocate_kboard (Qns);
5273   /* Don't let the initial kboard remain current longer than necessary.
5274      That would cause problems if a file loaded on startup tries to
5275      prompt in the mini-buffer.  */
5276   if (current_kboard == initial_kboard)
5277     current_kboard = terminal->kboard;
5278   terminal->kboard->reference_count++;
5280   dpyinfo->next = x_display_list;
5281   x_display_list = dpyinfo;
5283   dpyinfo->name_list_element = Fcons (display_name, Qnil);
5285   terminal->name = xlispstrdup (display_name);
5287   unblock_input ();
5289   if (!inhibit_x_resources)
5290     {
5291       ns_default ("GSFontAntiAlias", &ns_antialias_text,
5292                  Qt, Qnil, NO, NO);
5293       tmp = Qnil;
5294       /* this is a standard variable */
5295       ns_default ("AppleAntiAliasingThreshold", &tmp,
5296                  make_float (10.0), make_float (6.0), YES, NO);
5297       ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5298     }
5300   NSTRACE_MSG ("Colors");
5302   {
5303     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5305     if ( cl == nil )
5306       {
5307         Lisp_Object color_file, color_map, color;
5308         unsigned long c;
5309         char *name;
5311         color_file = Fexpand_file_name (build_string ("rgb.txt"),
5312                          Fsymbol_value (intern ("data-directory")));
5314         color_map = Fx_load_color_file (color_file);
5315         if (NILP (color_map))
5316           fatal ("Could not read %s.\n", SDATA (color_file));
5318         cl = [[NSColorList alloc] initWithName: @"Emacs"];
5319         for ( ; CONSP (color_map); color_map = XCDR (color_map))
5320           {
5321             color = XCAR (color_map);
5322             name = SSDATA (XCAR (color));
5323             c = XINT (XCDR (color));
5324             [cl setColor:
5325                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5326                                       green: GREEN_FROM_ULONG (c) / 255.0
5327                                        blue: BLUE_FROM_ULONG (c) / 255.0
5328                                       alpha: 1.0]
5329                   forKey: [NSString stringWithUTF8String: name]];
5330           }
5331         [cl writeToFile: nil];
5332       }
5333   }
5335   NSTRACE_MSG ("Versions");
5337   {
5338 #ifdef NS_IMPL_GNUSTEP
5339     Vwindow_system_version = build_string (gnustep_base_version);
5340 #else
5341     /* PSnextrelease (128, c); */
5342     char c[DBL_BUFSIZE_BOUND];
5343     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5344     Vwindow_system_version = make_unibyte_string (c, len);
5345 #endif
5346   }
5348   delete_keyboard_wait_descriptor (0);
5350   ns_app_name = [[NSProcessInfo processInfo] processName];
5352   /* Set up macOS app menu */
5354   NSTRACE_MSG ("Menu init");
5356 #ifdef NS_IMPL_COCOA
5357   {
5358     NSMenu *appMenu;
5359     NSMenuItem *item;
5360     /* set up the application menu */
5361     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5362     [svcsMenu setAutoenablesItems: NO];
5363     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5364     [appMenu setAutoenablesItems: NO];
5365     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5366     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5368     [appMenu insertItemWithTitle: @"About Emacs"
5369                           action: @selector (orderFrontStandardAboutPanel:)
5370                    keyEquivalent: @""
5371                          atIndex: 0];
5372     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5373     [appMenu insertItemWithTitle: @"Preferences..."
5374                           action: @selector (showPreferencesWindow:)
5375                    keyEquivalent: @","
5376                          atIndex: 2];
5377     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5378     item = [appMenu insertItemWithTitle: @"Services"
5379                                  action: @selector (menuDown:)
5380                           keyEquivalent: @""
5381                                 atIndex: 4];
5382     [appMenu setSubmenu: svcsMenu forItem: item];
5383     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5384     [appMenu insertItemWithTitle: @"Hide Emacs"
5385                           action: @selector (hide:)
5386                    keyEquivalent: @"h"
5387                          atIndex: 6];
5388     item =  [appMenu insertItemWithTitle: @"Hide Others"
5389                           action: @selector (hideOtherApplications:)
5390                    keyEquivalent: @"h"
5391                          atIndex: 7];
5392     [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5393     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5394     [appMenu insertItemWithTitle: @"Quit Emacs"
5395                           action: @selector (terminate:)
5396                    keyEquivalent: @"q"
5397                          atIndex: 9];
5399     item = [mainMenu insertItemWithTitle: ns_app_name
5400                                   action: @selector (menuDown:)
5401                            keyEquivalent: @""
5402                                  atIndex: 0];
5403     [mainMenu setSubmenu: appMenu forItem: item];
5404     [dockMenu insertItemWithTitle: @"New Frame"
5405                            action: @selector (newFrame:)
5406                     keyEquivalent: @""
5407                           atIndex: 0];
5409     [NSApp setMainMenu: mainMenu];
5410     [NSApp setAppleMenu: appMenu];
5411     [NSApp setServicesMenu: svcsMenu];
5412     /* Needed at least on Cocoa, to get dock menu to show windows */
5413     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5415     [[NSNotificationCenter defaultCenter]
5416       addObserver: mainMenu
5417          selector: @selector (trackingNotification:)
5418              name: NSMenuDidBeginTrackingNotification object: mainMenu];
5419     [[NSNotificationCenter defaultCenter]
5420       addObserver: mainMenu
5421          selector: @selector (trackingNotification:)
5422              name: NSMenuDidEndTrackingNotification object: mainMenu];
5423   }
5424 #endif /* macOS menu setup */
5426   /* Register our external input/output types, used for determining
5427      applicable services and also drag/drop eligibility.  */
5429   NSTRACE_MSG ("Input/output types");
5431   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5432   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5433                       retain];
5434   ns_drag_types = [[NSArray arrayWithObjects:
5435                             NSStringPboardType,
5436                             NSTabularTextPboardType,
5437                             NSFilenamesPboardType,
5438                             NSURLPboardType, nil] retain];
5440   /* If fullscreen is in init/default-frame-alist, focus isn't set
5441      right for fullscreen windows, so set this.  */
5442   [NSApp activateIgnoringOtherApps:YES];
5444   NSTRACE_MSG ("Call NSApp run");
5446   [NSApp run];
5447   ns_do_open_file = YES;
5449 #ifdef NS_IMPL_GNUSTEP
5450   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5451      We must re-catch it so subprocess works.  */
5452   catch_child_signal ();
5453 #endif
5455   NSTRACE_MSG ("ns_term_init done");
5457   unblock_input ();
5459   return dpyinfo;
5463 void
5464 ns_term_shutdown (int sig)
5466   [[NSUserDefaults standardUserDefaults] synchronize];
5468   /* code not reached in emacs.c after this is called by shut_down_emacs: */
5469   if (STRINGP (Vauto_save_list_file_name))
5470     unlink (SSDATA (Vauto_save_list_file_name));
5472   if (sig == 0 || sig == SIGTERM)
5473     {
5474       [NSApp terminate: NSApp];
5475     }
5476   else // force a stack trace to happen
5477     {
5478       emacs_abort ();
5479     }
5483 /* ==========================================================================
5485     EmacsApp implementation
5487    ========================================================================== */
5490 @implementation EmacsApp
5492 - (id)init
5494   NSTRACE ("[EmacsApp init]");
5496   if ((self = [super init]))
5497     {
5498 #ifdef NS_IMPL_COCOA
5499       self->isFirst = YES;
5500 #endif
5501 #ifdef NS_IMPL_GNUSTEP
5502       self->applicationDidFinishLaunchingCalled = NO;
5503 #endif
5504     }
5506   return self;
5509 #ifdef NS_IMPL_COCOA
5510 - (void)run
5512   NSTRACE ("[EmacsApp run]");
5514 #ifndef NSAppKitVersionNumber10_9
5515 #define NSAppKitVersionNumber10_9 1265
5516 #endif
5518     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5519       {
5520         [super run];
5521         return;
5522       }
5524   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5526   if (isFirst) [self finishLaunching];
5527   isFirst = NO;
5529   shouldKeepRunning = YES;
5530   do
5531     {
5532       [pool release];
5533       pool = [[NSAutoreleasePool alloc] init];
5535       NSEvent *event =
5536         [self nextEventMatchingMask:NSEventMaskAny
5537                           untilDate:[NSDate distantFuture]
5538                              inMode:NSDefaultRunLoopMode
5539                             dequeue:YES];
5541       [self sendEvent:event];
5542       [self updateWindows];
5543     } while (shouldKeepRunning);
5545   [pool release];
5548 - (void)stop: (id)sender
5550   NSTRACE ("[EmacsApp stop:]");
5552     shouldKeepRunning = NO;
5553     // Stop possible dialog also.  Noop if no dialog present.
5554     // The file dialog still leaks 7k - 10k on 10.9 though.
5555     [super stop:sender];
5557 #endif /* NS_IMPL_COCOA */
5559 - (void)logNotification: (NSNotification *)notification
5561   NSTRACE ("[EmacsApp logNotification:]");
5563   const char *name = [[notification name] UTF8String];
5564   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5565       && !strstr (name, "WindowNumber"))
5566     NSLog (@"notification: '%@'", [notification name]);
5570 - (void)sendEvent: (NSEvent *)theEvent
5571 /* --------------------------------------------------------------------------
5572      Called when NSApp is running for each event received.  Used to stop
5573      the loop when we choose, since there's no way to just run one iteration.
5574    -------------------------------------------------------------------------- */
5576   int type = [theEvent type];
5577   NSWindow *window = [theEvent window];
5579   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5580   NSTRACE_MSG ("Type: %d", type);
5582 #ifdef NS_IMPL_GNUSTEP
5583   // Keyboard events aren't propagated to file dialogs for some reason.
5584   if ([NSApp modalWindow] != nil &&
5585       (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5586     {
5587       [[NSApp modalWindow] sendEvent: theEvent];
5588       return;
5589     }
5590 #endif
5592   if (type == NSEventTypeApplicationDefined)
5593     {
5594       switch ([theEvent data2])
5595         {
5596 #ifdef NS_IMPL_COCOA
5597         case NSAPP_DATA2_RUNASSCRIPT:
5598           ns_run_ascript ();
5599           [self stop: self];
5600           return;
5601 #endif
5602         case NSAPP_DATA2_RUNFILEDIALOG:
5603           ns_run_file_dialog ();
5604           [self stop: self];
5605           return;
5606         }
5607     }
5609   if (type == NSEventTypeCursorUpdate && window == nil)
5610     {
5611       fprintf (stderr, "Dropping external cursor update event.\n");
5612       return;
5613     }
5615   if (type == NSEventTypeApplicationDefined)
5616     {
5617       /* Events posted by ns_send_appdefined interrupt the run loop here.
5618          But, if a modal window is up, an appdefined can still come through,
5619          (e.g., from a makeKeyWindow event) but stopping self also stops the
5620          modal loop. Just defer it until later.  */
5621       if ([NSApp modalWindow] == nil)
5622         {
5623           last_appdefined_event_data = [theEvent data1];
5624           [self stop: self];
5625         }
5626       else
5627         {
5628           send_appdefined = YES;
5629         }
5630     }
5633 #ifdef NS_IMPL_COCOA
5634   /* If no dialog and none of our frames have focus and it is a move, skip it.
5635      It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5636      such as Wifi, sound, date or similar.
5637      This prevents "spooky" highlighting in the frame under the menu.  */
5638   if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5639     {
5640       struct ns_display_info *di;
5641       BOOL has_focus = NO;
5642       for (di = x_display_list; ! has_focus && di; di = di->next)
5643         has_focus = di->x_focus_frame != 0;
5644       if (! has_focus)
5645         return;
5646     }
5647 #endif
5649   NSTRACE_UNSILENCE();
5651   [super sendEvent: theEvent];
5655 - (void)showPreferencesWindow: (id)sender
5657   struct frame *emacsframe = SELECTED_FRAME ();
5658   NSEvent *theEvent = [NSApp currentEvent];
5660   if (!emacs_event)
5661     return;
5662   emacs_event->kind = NS_NONKEY_EVENT;
5663   emacs_event->code = KEY_NS_SHOW_PREFS;
5664   emacs_event->modifiers = 0;
5665   EV_TRAILER (theEvent);
5669 - (void)newFrame: (id)sender
5671   NSTRACE ("[EmacsApp newFrame:]");
5673   struct frame *emacsframe = SELECTED_FRAME ();
5674   NSEvent *theEvent = [NSApp currentEvent];
5676   if (!emacs_event)
5677     return;
5678   emacs_event->kind = NS_NONKEY_EVENT;
5679   emacs_event->code = KEY_NS_NEW_FRAME;
5680   emacs_event->modifiers = 0;
5681   EV_TRAILER (theEvent);
5685 /* Open a file (used by below, after going into queue read by ns_read_socket).  */
5686 - (BOOL) openFile: (NSString *)fileName
5688   NSTRACE ("[EmacsApp openFile:]");
5690   struct frame *emacsframe = SELECTED_FRAME ();
5691   NSEvent *theEvent = [NSApp currentEvent];
5693   if (!emacs_event)
5694     return NO;
5696   emacs_event->kind = NS_NONKEY_EVENT;
5697   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5698   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5699   ns_input_line = Qnil; /* can be start or cons start,end */
5700   emacs_event->modifiers =0;
5701   EV_TRAILER (theEvent);
5703   return YES;
5707 /* **************************************************************************
5709       EmacsApp delegate implementation
5711    ************************************************************************** */
5713 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5714 /* --------------------------------------------------------------------------
5715      When application is loaded, terminate event loop in ns_term_init.
5716    -------------------------------------------------------------------------- */
5718   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5720 #ifdef NS_IMPL_GNUSTEP
5721   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5722 #endif
5723   [NSApp setServicesProvider: NSApp];
5725   [self antialiasThresholdDidChange:nil];
5726 #ifdef NS_IMPL_COCOA
5727   [[NSNotificationCenter defaultCenter]
5728     addObserver:self
5729        selector:@selector(antialiasThresholdDidChange:)
5730            name:NSAntialiasThresholdChangedNotification
5731          object:nil];
5732 #endif
5734 #ifdef NS_IMPL_COCOA
5735   if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
5736     /* Set the app's activation policy to regular when we run outside
5737        of a bundle.  This is already done for us by Info.plist when we
5738        run inside a bundle.  */
5739     [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
5740     [NSApp setApplicationIconImage:
5741              [EmacsImage
5742                allocInitFromFile:
5743                  build_string("icons/hicolor/128x128/apps/emacs.png")]];
5744   }
5745 #endif
5747   ns_send_appdefined (-2);
5750 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5752 #ifdef NS_IMPL_COCOA
5753   macfont_update_antialias_threshold ();
5754 #endif
5758 /* Termination sequences:
5759     C-x C-c:
5760     Cmd-Q:
5761     MenuBar | File | Exit:
5762     Select Quit from App menubar:
5763         -terminate
5764         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5765         ns_term_shutdown()
5767     Select Quit from Dock menu:
5768     Logout attempt:
5769         -appShouldTerminate
5770           Cancel -> Nothing else
5771           Accept ->
5773           -terminate
5774           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5775           ns_term_shutdown()
5779 - (void) terminate: (id)sender
5781   NSTRACE ("[EmacsApp terminate:]");
5783   struct frame *emacsframe = SELECTED_FRAME ();
5785   if (!emacs_event)
5786     return;
5788   emacs_event->kind = NS_NONKEY_EVENT;
5789   emacs_event->code = KEY_NS_POWER_OFF;
5790   emacs_event->arg = Qt; /* mark as non-key event */
5791   EV_TRAILER ((id)nil);
5794 static bool
5795 runAlertPanel(NSString *title,
5796               NSString *msgFormat,
5797               NSString *defaultButton,
5798               NSString *alternateButton)
5800 #ifdef NS_IMPL_GNUSTEP
5801   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5802     == NSAlertDefaultReturn;
5803 #else
5804   NSAlert *alert = [[NSAlert alloc] init];
5805   [alert setAlertStyle: NSAlertStyleCritical];
5806   [alert setMessageText: msgFormat];
5807   [alert addButtonWithTitle: defaultButton];
5808   [alert addButtonWithTitle: alternateButton];
5809   NSInteger ret = [alert runModal];
5810   [alert release];
5811   return ret == NSAlertFirstButtonReturn;
5812 #endif
5816 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5818   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5820   bool ret;
5822   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5823     return NSTerminateNow;
5825   ret = runAlertPanel(ns_app_name,
5826                       @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5827                       @"Save Buffers and Exit", @"Cancel");
5829   return ret ? NSTerminateNow : NSTerminateCancel;
5832 static int
5833 not_in_argv (NSString *arg)
5835   int k;
5836   const char *a = [arg UTF8String];
5837   for (k = 1; k < initial_argc; ++k)
5838     if (strcmp (a, initial_argv[k]) == 0) return 0;
5839   return 1;
5842 /* Notification from the Workspace to open a file.  */
5843 - (BOOL)application: sender openFile: (NSString *)file
5845   if (ns_do_open_file || not_in_argv (file))
5846     [ns_pending_files addObject: file];
5847   return YES;
5851 /* Open a file as a temporary file.  */
5852 - (BOOL)application: sender openTempFile: (NSString *)file
5854   if (ns_do_open_file || not_in_argv (file))
5855     [ns_pending_files addObject: file];
5856   return YES;
5860 /* Notification from the Workspace to open a file noninteractively (?).  */
5861 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5863   if (ns_do_open_file || not_in_argv (file))
5864     [ns_pending_files addObject: file];
5865   return YES;
5868 /* Notification from the Workspace to open multiple files.  */
5869 - (void)application: sender openFiles: (NSArray *)fileList
5871   NSEnumerator *files = [fileList objectEnumerator];
5872   NSString *file;
5873   /* Don't open files from the command line unconditionally,
5874      Cocoa parses the command line wrong, --option value tries to open value
5875      if --option is the last option.  */
5876   while ((file = [files nextObject]) != nil)
5877     if (ns_do_open_file || not_in_argv (file))
5878       [ns_pending_files addObject: file];
5880   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5885 /* Handle dock menu requests.  */
5886 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5888   return dockMenu;
5892 /* TODO: these may help w/IO switching between terminal and NSApp.  */
5893 - (void)applicationWillBecomeActive: (NSNotification *)notification
5895   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5896   // ns_app_active=YES;
5899 - (void)applicationDidBecomeActive: (NSNotification *)notification
5901   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5903 #ifdef NS_IMPL_GNUSTEP
5904   if (! applicationDidFinishLaunchingCalled)
5905     [self applicationDidFinishLaunching:notification];
5906 #endif
5907   // ns_app_active=YES;
5909   ns_update_auto_hide_menu_bar ();
5910   // No constraining takes place when the application is not active.
5911   ns_constrain_all_frames ();
5913 - (void)applicationDidResignActive: (NSNotification *)notification
5915   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5917   // ns_app_active=NO;
5918   ns_send_appdefined (-1);
5923 /* ==========================================================================
5925     EmacsApp aux handlers for managing event loop
5927    ========================================================================== */
5930 - (void)timeout_handler: (NSTimer *)timedEntry
5931 /* --------------------------------------------------------------------------
5932      The timeout specified to ns_select has passed.
5933    -------------------------------------------------------------------------- */
5935   /* NSTRACE ("timeout_handler"); */
5936   ns_send_appdefined (-2);
5939 - (void)sendFromMainThread:(id)unused
5941   ns_send_appdefined (nextappdefined);
5944 - (void)fd_handler:(id)unused
5945 /* --------------------------------------------------------------------------
5946      Check data waiting on file descriptors and terminate if so.
5947    -------------------------------------------------------------------------- */
5949   int result;
5950   int waiting = 1, nfds;
5951   char c;
5953   fd_set readfds, writefds, *wfds;
5954   struct timespec timeout, *tmo;
5955   NSAutoreleasePool *pool = nil;
5957   /* NSTRACE ("fd_handler"); */
5959   for (;;)
5960     {
5961       [pool release];
5962       pool = [[NSAutoreleasePool alloc] init];
5964       if (waiting)
5965         {
5966           fd_set fds;
5967           FD_ZERO (&fds);
5968           FD_SET (selfds[0], &fds);
5969           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5970           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5971             waiting = 0;
5972         }
5973       else
5974         {
5975           pthread_mutex_lock (&select_mutex);
5976           nfds = select_nfds;
5978           if (select_valid & SELECT_HAVE_READ)
5979             readfds = select_readfds;
5980           else
5981             FD_ZERO (&readfds);
5983           if (select_valid & SELECT_HAVE_WRITE)
5984             {
5985               writefds = select_writefds;
5986               wfds = &writefds;
5987             }
5988           else
5989             wfds = NULL;
5990           if (select_valid & SELECT_HAVE_TMO)
5991             {
5992               timeout = select_timeout;
5993               tmo = &timeout;
5994             }
5995           else
5996             tmo = NULL;
5998           pthread_mutex_unlock (&select_mutex);
6000           FD_SET (selfds[0], &readfds);
6001           if (selfds[0] >= nfds) nfds = selfds[0]+1;
6003           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
6005           if (result == 0)
6006             ns_send_appdefined (-2);
6007           else if (result > 0)
6008             {
6009               if (FD_ISSET (selfds[0], &readfds))
6010                 {
6011                   if (read (selfds[0], &c, 1) == 1 && c == 's')
6012                     waiting = 1;
6013                 }
6014               else
6015                 {
6016                   pthread_mutex_lock (&select_mutex);
6017                   if (select_valid & SELECT_HAVE_READ)
6018                     select_readfds = readfds;
6019                   if (select_valid & SELECT_HAVE_WRITE)
6020                     select_writefds = writefds;
6021                   if (select_valid & SELECT_HAVE_TMO)
6022                     select_timeout = timeout;
6023                   pthread_mutex_unlock (&select_mutex);
6025                   ns_send_appdefined (result);
6026                 }
6027             }
6028           waiting = 1;
6029         }
6030     }
6035 /* ==========================================================================
6037     Service provision
6039    ========================================================================== */
6041 /* Called from system: queue for next pass through event loop.  */
6042 - (void)requestService: (NSPasteboard *)pboard
6043               userData: (NSString *)userData
6044                  error: (NSString **)error
6046   [ns_pending_service_names addObject: userData];
6047   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
6048       SSDATA (ns_string_from_pasteboard (pboard))]];
6052 /* Called from ns_read_socket to clear queue.  */
6053 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
6055   struct frame *emacsframe = SELECTED_FRAME ();
6056   NSEvent *theEvent = [NSApp currentEvent];
6058   NSTRACE ("[EmacsApp fulfillService:withArg:]");
6060   if (!emacs_event)
6061     return NO;
6063   emacs_event->kind = NS_NONKEY_EVENT;
6064   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
6065   ns_input_spi_name = build_string ([name UTF8String]);
6066   ns_input_spi_arg = build_string ([arg UTF8String]);
6067   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6068   EV_TRAILER (theEvent);
6070   return YES;
6074 @end  /* EmacsApp */
6077 /* ==========================================================================
6079     EmacsView implementation
6081    ========================================================================== */
6084 @implementation EmacsView
6086 /* Needed to inform when window closed from lisp.  */
6087 - (void) setWindowClosing: (BOOL)closing
6089   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
6091   windowClosing = closing;
6095 - (void)dealloc
6097   NSTRACE ("[EmacsView dealloc]");
6098   [toolbar release];
6099   if (fs_state == FULLSCREEN_BOTH)
6100     [nonfs_window release];
6101   [super dealloc];
6105 /* Called on font panel selection.  */
6106 - (void)changeFont: (id)sender
6108   NSEvent *e = [[self window] currentEvent];
6109   struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
6110   struct font *font = face->font;
6111   id newFont;
6112   CGFloat size;
6113   NSFont *nsfont;
6115   NSTRACE ("[EmacsView changeFont:]");
6117   if (!emacs_event)
6118     return;
6120 #ifdef NS_IMPL_GNUSTEP
6121   nsfont = ((struct nsfont_info *)font)->nsfont;
6122 #endif
6123 #ifdef NS_IMPL_COCOA
6124   nsfont = (NSFont *) macfont_get_nsctfont (font);
6125 #endif
6127   if ((newFont = [sender convertFont: nsfont]))
6128     {
6129       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
6131       emacs_event->kind = NS_NONKEY_EVENT;
6132       emacs_event->modifiers = 0;
6133       emacs_event->code = KEY_NS_CHANGE_FONT;
6135       size = [newFont pointSize];
6136       ns_input_fontsize = make_number (lrint (size));
6137       ns_input_font = build_string ([[newFont familyName] UTF8String]);
6138       EV_TRAILER (e);
6139     }
6143 - (BOOL)acceptsFirstResponder
6145   NSTRACE ("[EmacsView acceptsFirstResponder]");
6146   return YES;
6150 - (void)resetCursorRects
6152   NSRect visible = [self visibleRect];
6153   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
6154   NSTRACE ("[EmacsView resetCursorRects]");
6156   if (currentCursor == nil)
6157     currentCursor = [NSCursor arrowCursor];
6159   if (!NSIsEmptyRect (visible))
6160     [self addCursorRect: visible cursor: currentCursor];
6162 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
6163 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
6164   if ([currentCursor respondsToSelector: @selector(setOnMouseEntered)])
6165 #endif
6166     [currentCursor setOnMouseEntered: YES];
6167 #endif
6172 /*****************************************************************************/
6173 /* Keyboard handling.  */
6174 #define NS_KEYLOG 0
6176 - (void)keyDown: (NSEvent *)theEvent
6178   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6179   int code;
6180   unsigned fnKeysym = 0;
6181   static NSMutableArray *nsEvArray;
6182   unsigned int flags = [theEvent modifierFlags];
6184   NSTRACE ("[EmacsView keyDown:]");
6186   /* Rhapsody and macOS give up and down events for the arrow keys.  */
6187   if (ns_fake_keydown == YES)
6188     ns_fake_keydown = NO;
6189   else if ([theEvent type] != NSEventTypeKeyDown)
6190     return;
6192   if (!emacs_event)
6193     return;
6195  if (![[self window] isKeyWindow]
6196      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
6197      /* We must avoid an infinite loop here.  */
6198      && (EmacsView *)[[theEvent window] delegate] != self)
6199    {
6200      /* XXX: There is an occasional condition in which, when Emacs display
6201          updates a different frame from the current one, and temporarily
6202          selects it, then processes some interrupt-driven input
6203          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
6204          for some reason that window has its first responder set to the NSView
6205          most recently updated (I guess), which is not the correct one.  */
6206      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
6207      return;
6208    }
6210   if (nsEvArray == nil)
6211     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
6213   [NSCursor setHiddenUntilMouseMoves: YES];
6215   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
6216     {
6217       clear_mouse_face (hlinfo);
6218       hlinfo->mouse_face_hidden = 1;
6219     }
6221   if (!processingCompose)
6222     {
6223       /* FIXME: What should happen for key sequences with more than
6224          one character?  */
6225       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6226         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6228       /* Is it a "function key"?  */
6229       /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
6230          flag set (this is probably a bug in the OS).  */
6231       if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
6232         {
6233           fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
6234         }
6235       if (fnKeysym == 0)
6236         {
6237           fnKeysym = ns_convert_key (code);
6238         }
6240       if (fnKeysym)
6241         {
6242           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
6243              because Emacs treats Delete and KP-Delete same (in simple.el).  */
6244           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6245 #ifdef NS_IMPL_GNUSTEP
6246               /*  GNUstep uses incompatible keycodes, even for those that are
6247                   supposed to be hardware independent.  Just check for delete.
6248                   Keypad delete does not have keysym 0xFFFF.
6249                   See https://savannah.gnu.org/bugs/?25395  */
6250               || (fnKeysym == 0xFFFF && code == 127)
6251 #endif
6252             )
6253             code = 0xFF08; /* backspace */
6254           else
6255             code = fnKeysym;
6256         }
6258       /* The âŒ˜ and âŒ¥ modifiers can be either shift-like (for alternate
6259          character input) or control-like (as command prefix).  If we
6260          have only shift-like modifiers, then we should use the
6261          translated characters (returned by the characters method); if
6262          we have only control-like modifiers, then we should use the
6263          untranslated characters (returned by the
6264          charactersIgnoringModifiers method).  An annoyance happens if
6265          we have both shift-like and control-like modifiers because
6266          the NSEvent API doesn’t let us ignore only some modifiers.
6267          In that case we use UCKeyTranslate (ns_get_shifted_character)
6268          to look up the correct character.  */
6270       /* EV_MODIFIERS2 uses parse_solitary_modifier on all known
6271          modifier keys, which returns 0 for shift-like modifiers.
6272          Therefore its return value is the set of control-like
6273          modifiers.  */
6274       emacs_event->modifiers = EV_MODIFIERS2 (flags);
6276       /* Function keys (such as the F-keys, arrow keys, etc.) set
6277          modifiers as though the fn key has been pressed when it
6278          hasn't.  Also some combinations of fn and a function key
6279          return a different key than was pressed (e.g. fn-<left> gives
6280          <home>).  We need to unset the fn modifier in these cases.
6281          FIXME: Can we avoid setting it in the first place?  */
6282       if (fnKeysym && (flags & NS_FUNCTION_KEY_MASK))
6283         emacs_event->modifiers ^= parse_solitary_modifier (ns_function_modifier);
6285       if (NS_KEYLOG)
6286         fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6287                  code, fnKeysym, flags, emacs_event->modifiers);
6289       /* If it was a function key or had control-like modifiers, pass
6290          it directly to Emacs.  */
6291       if (fnKeysym || (emacs_event->modifiers
6292                        && (emacs_event->modifiers != shift_modifier)
6293                        && [[theEvent charactersIgnoringModifiers] length] > 0))
6294         {
6295           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6296           /* FIXME: What are the next four lines supposed to do?  */
6297           if (code < 0x20)
6298             code |= (1<<28)|(3<<16);
6299           else if (code == 0x7f)
6300             code |= (1<<28)|(3<<16);
6301           else if (!fnKeysym)
6302             {
6303 #ifdef NS_IMPL_COCOA
6304               /* We potentially have both shift- and control-like
6305                  modifiers in use, so find the correct character
6306                  ignoring any control-like ones.  */
6307               code = ns_get_shifted_character (theEvent);
6308 #endif
6310               /* FIXME: This seems wrong, characters in the range
6311                  [0x80, 0xFF] are not ASCII characters.  Can’t we just
6312                  use MULTIBYTE_CHAR_KEYSTROKE_EVENT here for all kinds
6313                  of characters?  */
6314               emacs_event->kind = code > 0xFF
6315                 ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6316             }
6318           emacs_event->code = code;
6319           EV_TRAILER (theEvent);
6320           processingCompose = NO;
6321           return;
6322         }
6323     }
6325   /* If we get here, a non-function key without control-like modifiers
6326      was hit.  Use interpretKeyEvents, which in turn will call
6327      insertText; see
6328      https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/EventOverview/HandlingKeyEvents/HandlingKeyEvents.html.  */
6330   if (NS_KEYLOG && !processingCompose)
6331     fprintf (stderr, "keyDown: Begin compose sequence.\n");
6333   /* FIXME: interpretKeyEvents doesn’t seem to send insertText if âŒ˜ is
6334      used as shift-like modifier, at least on El Capitan.  Mask it
6335      out.  This shouldn’t be needed though; we should figure out what
6336      the correct way of handling âŒ˜ is.  */
6337   if ([theEvent modifierFlags] & NSEventModifierFlagCommand)
6338     theEvent = [NSEvent keyEventWithType:[theEvent type]
6339                                 location:[theEvent locationInWindow]
6340                            modifierFlags:[theEvent modifierFlags] & ~NSEventModifierFlagCommand
6341                                timestamp:[theEvent timestamp]
6342                             windowNumber:[theEvent windowNumber]
6343                                  context:nil
6344                               characters:[theEvent characters]
6345                         charactersIgnoringModifiers:[theEvent charactersIgnoringModifiers]
6346                                isARepeat:[theEvent isARepeat]
6347                                  keyCode:[theEvent keyCode]];
6349   processingCompose = YES;
6350   /* FIXME: Use [NSArray arrayWithObject:theEvent]?  */
6351   [nsEvArray addObject: theEvent];
6352   [self interpretKeyEvents: nsEvArray];
6353   [nsEvArray removeObject: theEvent];
6357 /* <NSTextInput> implementation (called through [super interpretKeyEvents:]).  */
6360 /* <NSTextInput>: called when done composing;
6361    NOTE: also called when we delete over working text, followed
6362    immediately by doCommandBySelector: deleteBackward:  */
6363 - (void)insertText: (id)aString
6365   NSString *s;
6366   NSUInteger len;
6368   NSTRACE ("[EmacsView insertText:]");
6370   if ([aString isKindOfClass:[NSAttributedString class]])
6371     s = [aString string];
6372   else
6373     s = aString;
6375   len = [s length];
6377   if (NS_KEYLOG)
6378     NSLog (@"insertText '%@'\tlen = %lu", aString, (unsigned long) len);
6379   processingCompose = NO;
6381   if (!emacs_event)
6382     return;
6384   /* First, clear any working text.  */
6385   if (workingText != nil)
6386     [self deleteWorkingText];
6388   /* It might be preferable to use getCharacters:range: below,
6389      cf. https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CocoaPerformance/Articles/StringDrawing.html#//apple_ref/doc/uid/TP40001445-112378.
6390      However, we probably can't use SAFE_NALLOCA here because it might
6391      exit nonlocally.  */
6393   /* Now insert the string as keystrokes.  */
6394   for (NSUInteger i = 0; i < len; i++)
6395     {
6396       NSUInteger code = [s characterAtIndex:i];
6397       if (UTF_16_HIGH_SURROGATE_P (code) && i < len - 1)
6398         {
6399           unichar low = [s characterAtIndex:i + 1];
6400           if (UTF_16_LOW_SURROGATE_P (low))
6401             {
6402               code = surrogates_to_codepoint (low, code);
6403               ++i;
6404             }
6405         }
6406       /* TODO: still need this?  */
6407       if (code == 0x2DC)
6408         code = '~'; /* 0x7E */
6409       if (code != 32) /* Space */
6410         emacs_event->modifiers = 0;
6411       emacs_event->kind
6412         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6413       emacs_event->code = code;
6414       EV_TRAILER ((id)nil);
6415     }
6419 /* <NSTextInput>: inserts display of composing characters.  */
6420 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6422   NSString *str = [aString respondsToSelector: @selector (string)] ?
6423     [aString string] : aString;
6425   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6427   if (NS_KEYLOG)
6428     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6429            str, (unsigned long)[str length],
6430            (unsigned long)selRange.length,
6431            (unsigned long)selRange.location);
6433   if (workingText != nil)
6434     [self deleteWorkingText];
6435   if ([str length] == 0)
6436     return;
6438   if (!emacs_event)
6439     return;
6441   processingCompose = YES;
6442   workingText = [str copy];
6443   ns_working_text = build_string ([workingText UTF8String]);
6445   emacs_event->kind = NS_TEXT_EVENT;
6446   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6447   EV_TRAILER ((id)nil);
6451 /* Delete display of composing characters [not in <NSTextInput>].  */
6452 - (void)deleteWorkingText
6454   NSTRACE ("[EmacsView deleteWorkingText]");
6456   if (workingText == nil)
6457     return;
6458   if (NS_KEYLOG)
6459     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6460   [workingText release];
6461   workingText = nil;
6462   processingCompose = NO;
6464   if (!emacs_event)
6465     return;
6467   emacs_event->kind = NS_TEXT_EVENT;
6468   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6469   EV_TRAILER ((id)nil);
6473 - (BOOL)hasMarkedText
6475   NSTRACE ("[EmacsView hasMarkedText]");
6477   return workingText != nil;
6481 - (NSRange)markedRange
6483   NSTRACE ("[EmacsView markedRange]");
6485   NSRange rng = workingText != nil
6486     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6487   if (NS_KEYLOG)
6488     NSLog (@"markedRange request");
6489   return rng;
6493 - (void)unmarkText
6495   NSTRACE ("[EmacsView unmarkText]");
6497   if (NS_KEYLOG)
6498     NSLog (@"unmark (accept) text");
6499   [self deleteWorkingText];
6500   processingCompose = NO;
6504 /* Used to position char selection windows, etc.  */
6505 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6507   NSRect rect;
6508   NSPoint pt;
6509   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6511   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6513   if (NS_KEYLOG)
6514     NSLog (@"firstRectForCharRange request");
6516   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6517   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6518   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6519   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6520                                        +FRAME_LINE_HEIGHT (emacsframe));
6522   pt = [self convertPoint: pt toView: nil];
6524 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6525 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6526   if ([[self window] respondsToSelector: @selector(convertRectToScreen:)])
6527     {
6528 #endif
6529       rect.origin = pt;
6530       rect = [(EmacsWindow *) [self window] convertRectToScreen: rect];
6531 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6532     }
6533   else
6534 #endif
6535 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6536 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
6537   || defined (NS_IMPL_GNUSTEP)
6538     {
6539       pt = [[self window] convertBaseToScreen: pt];
6540       rect.origin = pt;
6541     }
6542 #endif
6544   return rect;
6548 - (NSInteger)conversationIdentifier
6550   return (NSInteger)self;
6554 - (void)doCommandBySelector: (SEL)aSelector
6556   NSTRACE ("[EmacsView doCommandBySelector:]");
6558   if (NS_KEYLOG)
6559     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6561   processingCompose = NO;
6562   if (aSelector == @selector (deleteBackward:))
6563     {
6564       /* Happens when user backspaces over an ongoing composition:
6565          throw a 'delete' into the event queue.  */
6566       if (!emacs_event)
6567         return;
6568       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6569       emacs_event->code = 0xFF08;
6570       EV_TRAILER ((id)nil);
6571     }
6574 - (NSArray *)validAttributesForMarkedText
6576   static NSArray *arr = nil;
6577   if (arr == nil) arr = [NSArray new];
6578  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6579   return arr;
6582 - (NSRange)selectedRange
6584   if (NS_KEYLOG)
6585     NSLog (@"selectedRange request");
6586   return NSMakeRange (NSNotFound, 0);
6589 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6590     GNUSTEP_GUI_MINOR_VERSION > 22
6591 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6592 #else
6593 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6594 #endif
6596   if (NS_KEYLOG)
6597     NSLog (@"characterIndexForPoint request");
6598   return 0;
6601 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6603   static NSAttributedString *str = nil;
6604   if (str == nil) str = [NSAttributedString new];
6605   if (NS_KEYLOG)
6606     NSLog (@"attributedSubstringFromRange request");
6607   return str;
6610 /* End <NSTextInput> implementation.  */
6611 /*****************************************************************************/
6614 /* This is what happens when the user presses a mouse button.  */
6615 - (void)mouseDown: (NSEvent *)theEvent
6617   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6618   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6620   NSTRACE ("[EmacsView mouseDown:]");
6622   [self deleteWorkingText];
6624   if (!emacs_event)
6625     return;
6627   dpyinfo->last_mouse_frame = emacsframe;
6628   /* Appears to be needed to prevent spurious movement events generated on
6629      button clicks.  */
6630   emacsframe->mouse_moved = 0;
6632   if ([theEvent type] == NSEventTypeScrollWheel)
6633     {
6634 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6635 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6636       if ([theEvent respondsToSelector:@selector(hasPreciseScrollingDeltas)])
6637         {
6638 #endif
6639           /* If the input device is a touchpad or similar, use precise
6640            * scrolling deltas.  These are measured in pixels, so we
6641            * have to add them up until they exceed one line height,
6642            * then we can send a scroll wheel event.
6643            *
6644            * If the device only has coarse scrolling deltas, like a
6645            * real mousewheel, the deltas represent a ratio of whole
6646            * lines, so round up the number of lines.  This means we
6647            * always send one scroll event per click, but can still
6648            * scroll more than one line if the OS tells us to.
6649            */
6650           bool horizontal;
6651           int lines = 0;
6652           int scrollUp = NO;
6654           /* FIXME: At the top or bottom of the buffer we should
6655            * ignore momentum-phase events.  */
6656           if (! ns_use_mwheel_momentum
6657               && [theEvent momentumPhase] != NSEventPhaseNone)
6658             return;
6660           if ([theEvent hasPreciseScrollingDeltas])
6661             {
6662               static int totalDeltaX, totalDeltaY;
6663               int lineHeight;
6665               if (NUMBERP (ns_mwheel_line_height))
6666                 lineHeight = XINT (ns_mwheel_line_height);
6667               else
6668                 {
6669                   /* FIXME: Use actual line height instead of the default.  */
6670                   lineHeight = default_line_pixel_height
6671                     (XWINDOW (FRAME_SELECTED_WINDOW (emacsframe)));
6672                 }
6674               if ([theEvent phase] == NSEventPhaseBegan)
6675                 {
6676                   totalDeltaX = 0;
6677                   totalDeltaY = 0;
6678                 }
6680               totalDeltaX += [theEvent scrollingDeltaX];
6681               totalDeltaY += [theEvent scrollingDeltaY];
6683               /* Calculate the number of lines, if any, to scroll, and
6684                * reset the total delta for the direction we're NOT
6685                * scrolling so that small movements don't add up.  */
6686               if (abs (totalDeltaX) > abs (totalDeltaY)
6687                   && abs (totalDeltaX) > lineHeight)
6688                 {
6689                   horizontal = YES;
6690                   scrollUp = totalDeltaX > 0;
6692                   lines = abs (totalDeltaX / lineHeight);
6693                   totalDeltaX = totalDeltaX % lineHeight;
6694                   totalDeltaY = 0;
6695                 }
6696               else if (abs (totalDeltaY) >= abs (totalDeltaX)
6697                        && abs (totalDeltaY) > lineHeight)
6698                 {
6699                   horizontal = NO;
6700                   scrollUp = totalDeltaY > 0;
6702                   lines = abs (totalDeltaY / lineHeight);
6703                   totalDeltaY = totalDeltaY % lineHeight;
6704                   totalDeltaX = 0;
6705                 }
6707               if (lines > 1 && ! ns_use_mwheel_acceleration)
6708                 lines = 1;
6709             }
6710           else
6711             {
6712               CGFloat delta;
6714               if ([theEvent scrollingDeltaY] == 0)
6715                 {
6716                   horizontal = YES;
6717                   delta = [theEvent scrollingDeltaX];
6718                 }
6719               else
6720                 {
6721                   horizontal = NO;
6722                   delta = [theEvent scrollingDeltaY];
6723                 }
6725               lines = (ns_use_mwheel_acceleration)
6726                 ? ceil (fabs (delta)) : 1;
6728               scrollUp = delta > 0;
6729             }
6731           if (lines == 0)
6732             return;
6734           emacs_event->kind = horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT;
6735           emacs_event->arg = (make_number (lines));
6737           emacs_event->code = 0;
6738           emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6739             (scrollUp ? up_modifier : down_modifier);
6740 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6741         }
6742       else
6743 #endif
6744 #endif /* defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6745 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6746         {
6747           CGFloat delta = [theEvent deltaY];
6748           /* Mac notebooks send wheel events with delta equal to 0
6749              when trackpad scrolling.  */
6750           if (delta == 0)
6751             {
6752               delta = [theEvent deltaX];
6753               if (delta == 0)
6754                 {
6755                   NSTRACE_MSG ("deltaIsZero");
6756                   return;
6757                 }
6758               emacs_event->kind = HORIZ_WHEEL_EVENT;
6759             }
6760           else
6761             emacs_event->kind = WHEEL_EVENT;
6763           emacs_event->code = 0;
6764           emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6765             ((delta > 0) ? up_modifier : down_modifier);
6766         }
6767 #endif
6768     }
6769   else
6770     {
6771       emacs_event->kind = MOUSE_CLICK_EVENT;
6772       emacs_event->code = EV_BUTTON (theEvent);
6773       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6774                              | EV_UDMODIFIERS (theEvent);
6775     }
6777   XSETINT (emacs_event->x, lrint (p.x));
6778   XSETINT (emacs_event->y, lrint (p.y));
6779   EV_TRAILER (theEvent);
6780   return;
6784 - (void)rightMouseDown: (NSEvent *)theEvent
6786   NSTRACE ("[EmacsView rightMouseDown:]");
6787   [self mouseDown: theEvent];
6791 - (void)otherMouseDown: (NSEvent *)theEvent
6793   NSTRACE ("[EmacsView otherMouseDown:]");
6794   [self mouseDown: theEvent];
6798 - (void)mouseUp: (NSEvent *)theEvent
6800   NSTRACE ("[EmacsView mouseUp:]");
6801   [self mouseDown: theEvent];
6805 - (void)rightMouseUp: (NSEvent *)theEvent
6807   NSTRACE ("[EmacsView rightMouseUp:]");
6808   [self mouseDown: theEvent];
6812 - (void)otherMouseUp: (NSEvent *)theEvent
6814   NSTRACE ("[EmacsView otherMouseUp:]");
6815   [self mouseDown: theEvent];
6819 - (void) scrollWheel: (NSEvent *)theEvent
6821   NSTRACE ("[EmacsView scrollWheel:]");
6822   [self mouseDown: theEvent];
6826 /* Tell emacs the mouse has moved.  */
6827 - (void)mouseMoved: (NSEvent *)e
6829   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6830   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6831   Lisp_Object frame;
6832   NSPoint pt;
6834   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6836   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6837   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6838   dpyinfo->last_mouse_motion_x = pt.x;
6839   dpyinfo->last_mouse_motion_y = pt.y;
6841   /* Update any mouse face.  */
6842   if (hlinfo->mouse_face_hidden)
6843     {
6844       hlinfo->mouse_face_hidden = 0;
6845       clear_mouse_face (hlinfo);
6846     }
6848   /* Tooltip handling.  */
6849   previous_help_echo_string = help_echo_string;
6850   help_echo_string = Qnil;
6852   if (!NILP (Vmouse_autoselect_window))
6853     {
6854       NSTRACE_MSG ("mouse_autoselect_window");
6855       static Lisp_Object last_mouse_window;
6856       Lisp_Object window
6857         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6859       if (WINDOWP (window)
6860           && !EQ (window, last_mouse_window)
6861           && !EQ (window, selected_window)
6862           && (!NILP (focus_follows_mouse)
6863               || (EQ (XWINDOW (window)->frame,
6864                       XWINDOW (selected_window)->frame))))
6865         {
6866           NSTRACE_MSG ("in_window");
6867           emacs_event->kind = SELECT_WINDOW_EVENT;
6868           emacs_event->frame_or_window = window;
6869           EV_TRAILER2 (e);
6870         }
6871       /* Remember the last window where we saw the mouse.  */
6872       last_mouse_window = window;
6873     }
6875   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6876     help_echo_string = previous_help_echo_string;
6878   XSETFRAME (frame, emacsframe);
6879   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6880     {
6881       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6882          (note_mouse_highlight), which is called through the
6883          note_mouse_movement () call above.  */
6884       any_help_event_p = YES;
6885       gen_help_event (help_echo_string, frame, help_echo_window,
6886                       help_echo_object, help_echo_pos);
6887     }
6889   if (emacsframe->mouse_moved && send_appdefined)
6890     ns_send_appdefined (-1);
6894 - (void)mouseDragged: (NSEvent *)e
6896   NSTRACE ("[EmacsView mouseDragged:]");
6897   [self mouseMoved: e];
6901 - (void)rightMouseDragged: (NSEvent *)e
6903   NSTRACE ("[EmacsView rightMouseDragged:]");
6904   [self mouseMoved: e];
6908 - (void)otherMouseDragged: (NSEvent *)e
6910   NSTRACE ("[EmacsView otherMouseDragged:]");
6911   [self mouseMoved: e];
6915 - (BOOL)windowShouldClose: (id)sender
6917   NSEvent *e =[[self window] currentEvent];
6919   NSTRACE ("[EmacsView windowShouldClose:]");
6920   windowClosing = YES;
6921   if (!emacs_event)
6922     return NO;
6923   emacs_event->kind = DELETE_WINDOW_EVENT;
6924   emacs_event->modifiers = 0;
6925   emacs_event->code = 0;
6926   EV_TRAILER (e);
6927   /* Don't close this window, let this be done from lisp code.  */
6928   return NO;
6931 - (void) updateFrameSize: (BOOL) delay
6933   NSWindow *window = [self window];
6934   NSRect wr = [window frame];
6935   int extra = 0;
6936   int oldc = cols, oldr = rows;
6937   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6938   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6939   int neww, newh;
6941   NSTRACE ("[EmacsView updateFrameSize:]");
6942   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6943   NSTRACE_RECT ("Original frame", wr);
6944   NSTRACE_MSG  ("Original columns: %d", cols);
6945   NSTRACE_MSG  ("Original rows: %d", rows);
6947   if (! [self isFullscreen])
6948     {
6949       int toolbar_height;
6950 #ifdef NS_IMPL_GNUSTEP
6951       // GNUstep does not always update the tool bar height.  Force it.
6952       if (toolbar && [toolbar isVisible])
6953           update_frame_tool_bar (emacsframe);
6954 #endif
6956       toolbar_height = FRAME_TOOLBAR_HEIGHT (emacsframe);
6957       if (toolbar_height < 0)
6958         toolbar_height = 35;
6960       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6961         + toolbar_height;
6962     }
6964   if (wait_for_tool_bar)
6965     {
6966       /* The toolbar height is always 0 in fullscreen and undecorated
6967          frames, so don't wait for it to become available.  */
6968       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6969           && FRAME_UNDECORATED (emacsframe) == false
6970           && ! [self isFullscreen])
6971         {
6972           NSTRACE_MSG ("Waiting for toolbar");
6973           return;
6974         }
6975       wait_for_tool_bar = NO;
6976     }
6978   neww = (int)wr.size.width - emacsframe->border_width;
6979   newh = (int)wr.size.height - extra;
6981   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6982   NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6983   NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6985   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6986   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6988   if (cols < MINWIDTH)
6989     cols = MINWIDTH;
6991   if (rows < MINHEIGHT)
6992     rows = MINHEIGHT;
6994   NSTRACE_MSG ("New columns: %d", cols);
6995   NSTRACE_MSG ("New rows: %d", rows);
6997   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6998     {
6999       NSView *view = FRAME_NS_VIEW (emacsframe);
7001       change_frame_size (emacsframe,
7002                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
7003                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
7004                          0, delay, 0, 1);
7005       SET_FRAME_GARBAGED (emacsframe);
7006       cancel_mouse_face (emacsframe);
7008       /* The next two lines set the frame to the same size as we've
7009          already set above.  We need to do this when we switch back
7010          from non-native fullscreen, in other circumstances it appears
7011          to be a noop.  (bug#28872) */
7012       wr = NSMakeRect (0, 0, neww, newh);
7013       [view setFrame: wr];
7015       // To do: consider using [NSNotificationCenter postNotificationName:].
7016       [self windowDidMove: // Update top/left.
7017               [NSNotification notificationWithName:NSWindowDidMoveNotification
7018                                             object:[view window]]];
7019     }
7020   else
7021     {
7022       NSTRACE_MSG ("No change");
7023     }
7026 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
7027 /* Normalize frame to gridded text size.  */
7029   int extra = 0;
7031   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
7032            NSTRACE_ARG_SIZE (frameSize));
7033   NSTRACE_RECT   ("[sender frame]", [sender frame]);
7034   NSTRACE_FSTYPE ("fs_state", fs_state);
7036   if (!FRAME_LIVE_P (emacsframe))
7037     return frameSize;
7039   if (fs_state == FULLSCREEN_MAXIMIZED
7040       && (maximized_width != (int)frameSize.width
7041           || maximized_height != (int)frameSize.height))
7042     [self setFSValue: FULLSCREEN_NONE];
7043   else if (fs_state == FULLSCREEN_WIDTH
7044            && maximized_width != (int)frameSize.width)
7045     [self setFSValue: FULLSCREEN_NONE];
7046   else if (fs_state == FULLSCREEN_HEIGHT
7047            && maximized_height != (int)frameSize.height)
7048     [self setFSValue: FULLSCREEN_NONE];
7050   if (fs_state == FULLSCREEN_NONE)
7051     maximized_width = maximized_height = -1;
7053   if (! [self isFullscreen])
7054     {
7055       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
7056         + FRAME_TOOLBAR_HEIGHT (emacsframe);
7057     }
7059   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
7060   if (cols < MINWIDTH)
7061     cols = MINWIDTH;
7063   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
7064                                            frameSize.height - extra);
7065   if (rows < MINHEIGHT)
7066     rows = MINHEIGHT;
7067 #ifdef NS_IMPL_COCOA
7068   {
7069     /* This sets window title to have size in it; the wm does this under GS.  */
7070     NSRect r = [[self window] frame];
7071     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
7072       {
7073         if (old_title != 0)
7074           {
7075             xfree (old_title);
7076             old_title = 0;
7077           }
7078       }
7079     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
7080              && [[self window] title] != NULL)
7081       {
7082         char *size_title;
7083         NSWindow *window = [self window];
7084         if (old_title == 0)
7085           {
7086             char *t = strdup ([[[self window] title] UTF8String]);
7087             char *pos = strstr (t, "  â€”  ");
7088             if (pos)
7089               *pos = '\0';
7090             old_title = t;
7091           }
7092         size_title = xmalloc (strlen (old_title) + 40);
7093         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
7094         [window setTitle: [NSString stringWithUTF8String: size_title]];
7095         [window display];
7096         xfree (size_title);
7097       }
7098   }
7099 #endif /* NS_IMPL_COCOA */
7101   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
7103   /* Restrict the new size to the text grid.
7105      Don't restrict the width if the user only adjusted the height, and
7106      vice versa.  (Without this, the frame would shrink, and move
7107      slightly, if the window was resized by dragging one of its
7108      borders.)  */
7109   if (!frame_resize_pixelwise)
7110     {
7111       NSRect r = [[self window] frame];
7113       if (r.size.width != frameSize.width)
7114         {
7115           frameSize.width =
7116             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
7117         }
7119       if (r.size.height != frameSize.height)
7120         {
7121           frameSize.height =
7122             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
7123         }
7124     }
7126   NSTRACE_RETURN_SIZE (frameSize);
7128   return frameSize;
7132 - (void)windowDidResize: (NSNotification *)notification
7134   NSTRACE ("[EmacsView windowDidResize:]");
7135   if (!FRAME_LIVE_P (emacsframe))
7136     {
7137       NSTRACE_MSG ("Ignored (frame dead)");
7138       return;
7139     }
7140   if (emacsframe->output_data.ns->in_animation)
7141     {
7142       NSTRACE_MSG ("Ignored (in animation)");
7143       return;
7144     }
7146   if (! [self fsIsNative])
7147     {
7148       NSWindow *theWindow = [notification object];
7149       /* We can get notification on the non-FS window when in
7150          fullscreen mode.  */
7151       if ([self window] != theWindow) return;
7152     }
7154   NSTRACE_RECT ("frame", [[notification object] frame]);
7156 #ifdef NS_IMPL_GNUSTEP
7157   NSWindow *theWindow = [notification object];
7159    /* In GNUstep, at least currently, it's possible to get a didResize
7160       without getting a willResize, therefore we need to act as if we got
7161       the willResize now.  */
7162   NSSize sz = [theWindow frame].size;
7163   sz = [self windowWillResize: theWindow toSize: sz];
7164 #endif /* NS_IMPL_GNUSTEP */
7166   if (cols > 0 && rows > 0)
7167     {
7168       [self updateFrameSize: YES];
7169     }
7171   ns_send_appdefined (-1);
7174 #ifdef NS_IMPL_COCOA
7175 - (void)viewDidEndLiveResize
7177   NSTRACE ("[EmacsView viewDidEndLiveResize]");
7179   [super viewDidEndLiveResize];
7180   if (old_title != 0)
7181     {
7182       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
7183       xfree (old_title);
7184       old_title = 0;
7185     }
7186   maximizing_resize = NO;
7188 #endif /* NS_IMPL_COCOA */
7191 - (void)windowDidBecomeKey: (NSNotification *)notification
7192 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7194   [self windowDidBecomeKey];
7198 - (void)windowDidBecomeKey      /* for direct calls */
7200   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7201   struct frame *old_focus = dpyinfo->x_focus_frame;
7203   NSTRACE ("[EmacsView windowDidBecomeKey]");
7205   if (emacsframe != old_focus)
7206     dpyinfo->x_focus_frame = emacsframe;
7208   ns_frame_rehighlight (emacsframe);
7210   if (emacs_event)
7211     {
7212       emacs_event->kind = FOCUS_IN_EVENT;
7213       EV_TRAILER ((id)nil);
7214     }
7218 - (void)windowDidResignKey: (NSNotification *)notification
7219 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
7221   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
7222   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
7223   NSTRACE ("[EmacsView windowDidResignKey:]");
7225   if (is_focus_frame)
7226     dpyinfo->x_focus_frame = 0;
7228   emacsframe->mouse_moved = 0;
7229   ns_frame_rehighlight (emacsframe);
7231   /* FIXME: for some reason needed on second and subsequent clicks away
7232             from sole-frame Emacs to get hollow box to show.  */
7233   if (!windowClosing && [[self window] isVisible] == YES)
7234     {
7235       x_update_cursor (emacsframe, 1);
7236       x_set_frame_alpha (emacsframe);
7237     }
7239   if (any_help_event_p)
7240     {
7241       Lisp_Object frame;
7242       XSETFRAME (frame, emacsframe);
7243       help_echo_string = Qnil;
7244       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
7245     }
7247   if (emacs_event && is_focus_frame)
7248     {
7249       [self deleteWorkingText];
7250       emacs_event->kind = FOCUS_OUT_EVENT;
7251       EV_TRAILER ((id)nil);
7252     }
7256 - (void)windowWillMiniaturize: sender
7258   NSTRACE ("[EmacsView windowWillMiniaturize:]");
7262 - (void)setFrame:(NSRect)frameRect
7264   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
7265            NSTRACE_ARG_RECT (frameRect));
7267   [super setFrame:(NSRect)frameRect];
7271 - (BOOL)isFlipped
7273   return YES;
7277 - (BOOL)isOpaque
7279   return NO;
7283 - (void)createToolbar: (struct frame *)f
7285   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
7286   NSWindow *window = [view window];
7288   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
7289                    [NSString stringWithFormat: @"Emacs Frame %d",
7290                              ns_window_num]];
7291   [toolbar setVisible: NO];
7292   [window setToolbar: toolbar];
7294   /* Don't set frame garbaged until tool bar is up to date?
7295      This avoids an extra clear and redraw (flicker) at frame creation.  */
7296   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
7297   else wait_for_tool_bar = NO;
7300 #ifdef NS_IMPL_COCOA
7301   {
7302     NSButton *toggleButton;
7303     toggleButton = [window standardWindowButton: NSWindowToolbarButton];
7304     [toggleButton setTarget: self];
7305     [toggleButton setAction: @selector (toggleToolbar: )];
7306   }
7307 #endif
7311 - (instancetype) initFrameFromEmacs: (struct frame *)f
7313   NSRect r, wr;
7314   Lisp_Object tem;
7315   NSWindow *win;
7316   NSColor *col;
7317   NSString *name;
7319   NSTRACE ("[EmacsView initFrameFromEmacs:]");
7320   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7322   windowClosing = NO;
7323   processingCompose = NO;
7324   scrollbarsNeedingUpdate = 0;
7325   fs_state = FULLSCREEN_NONE;
7326   fs_before_fs = next_maximized = -1;
7328   fs_is_native = NO;
7329 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7330 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7331   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7332 #endif
7333     fs_is_native = ns_use_native_fullscreen;
7334 #endif
7336   maximized_width = maximized_height = -1;
7337   nonfs_window = nil;
7339   ns_userRect = NSMakeRect (0, 0, 0, 0);
7340   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7341                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7342   [self initWithFrame: r];
7343   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7345   FRAME_NS_VIEW (f) = self;
7346   emacsframe = f;
7347 #ifdef NS_IMPL_COCOA
7348   old_title = 0;
7349   maximizing_resize = NO;
7350 #endif
7352   win = [[EmacsWindow alloc]
7353             initWithContentRect: r
7354                       styleMask: (FRAME_UNDECORATED (f)
7355                                   ? FRAME_UNDECORATED_FLAGS
7356                                   : FRAME_DECORATED_FLAGS)
7357                         backing: NSBackingStoreBuffered
7358                           defer: YES];
7360 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7361 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7362   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7363 #endif
7364     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7365 #endif
7367   wr = [win frame];
7368   bwidth = f->border_width = wr.size.width - r.size.width;
7370   [win setAcceptsMouseMovedEvents: YES];
7371   [win setDelegate: self];
7372 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7373 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7374   if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7375 #endif
7376     [win useOptimizedDrawing: YES];
7377 #endif
7379   [[win contentView] addSubview: self];
7381   if (ns_drag_types)
7382     [self registerForDraggedTypes: ns_drag_types];
7384   tem = f->name;
7385   name = [NSString stringWithUTF8String:
7386                    NILP (tem) ? "Emacs" : SSDATA (tem)];
7387   [win setTitle: name];
7389   /* toolbar support */
7390   if (! FRAME_UNDECORATED (f))
7391     [self createToolbar: f];
7393 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7394 #ifndef NSAppKitVersionNumber10_10
7395 #define NSAppKitVersionNumber10_10 1343
7396 #endif
7398   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_10
7399       && FRAME_NS_APPEARANCE (f) != ns_appearance_aqua)
7400     win.appearance = [NSAppearance
7401                           appearanceNamed: NSAppearanceNameVibrantDark];
7402 #endif
7404 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 101000
7405   if ([win respondsToSelector: @selector(titlebarAppearsTransparent)])
7406     win.titlebarAppearsTransparent = FRAME_NS_TRANSPARENT_TITLEBAR (f);
7407 #endif
7409   tem = f->icon_name;
7410   if (!NILP (tem))
7411     [win setMiniwindowTitle:
7412            [NSString stringWithUTF8String: SSDATA (tem)]];
7414   if (FRAME_PARENT_FRAME (f) != NULL)
7415     {
7416       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7417       [parent addChildWindow: win
7418                      ordered: NSWindowAbove];
7419     }
7421   if (FRAME_Z_GROUP (f) != z_group_none)
7422       win.level = NSNormalWindowLevel
7423         + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7425   {
7426     NSScreen *screen = [win screen];
7428     if (screen != 0)
7429       {
7430         NSPoint pt = NSMakePoint
7431           (IN_BOUND (-SCREENMAX, f->left_pos
7432                      + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7433            IN_BOUND (-SCREENMAX,
7434                      NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7435                      SCREENMAX));
7437         [win setFrameTopLeftPoint: pt];
7439         NSTRACE_RECT ("new frame", [win frame]);
7440       }
7441   }
7443   [win makeFirstResponder: self];
7445   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7446                                  (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7447                                  emacsframe);
7448   [win setBackgroundColor: col];
7449   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7450     [win setOpaque: NO];
7452 #if !defined (NS_IMPL_COCOA) \
7453   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7454 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7455   if ([self respondsToSelector: @selector(allocateGState)])
7456 #endif
7457     [self allocateGState];
7458 #endif
7459   [NSApp registerServicesMenuSendTypes: ns_send_types
7460                            returnTypes: [NSArray array]];
7462   /* macOS Sierra automatically enables tabbed windows.  We can't
7463      allow this to be enabled until it's available on a Free system.
7464      Currently it only happens by accident and is buggy anyway.  */
7465 #if defined (NS_IMPL_COCOA) \
7466   && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7467 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7468   if ([win respondsToSelector: @selector(setTabbingMode:)])
7469 #endif
7470     [win setTabbingMode: NSWindowTabbingModeDisallowed];
7471 #endif
7473   ns_window_num++;
7474   return self;
7478 - (void)windowDidMove: sender
7480   NSWindow *win = [self window];
7481   NSRect r = [win frame];
7482   NSArray *screens = [NSScreen screens];
7483   NSScreen *screen = [screens objectAtIndex: 0];
7485   NSTRACE ("[EmacsView windowDidMove:]");
7487   if (!emacsframe->output_data.ns)
7488     return;
7489   if (screen != nil)
7490     {
7491       emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7492       emacsframe->top_pos =
7493         NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7495       if (emacs_event)
7496         {
7497           emacs_event->kind = MOVE_FRAME_EVENT;
7498           EV_TRAILER ((id)nil);
7499         }
7500     }
7504 /* Called AFTER method below, but before our windowWillResize call there leads
7505    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
7506    location so set_window_size moves the frame.  */
7507 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7509   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7510             NSTRACE_FMT_RETURN "YES"),
7511            NSTRACE_ARG_RECT (newFrame));
7513   emacsframe->output_data.ns->zooming = 1;
7514   return YES;
7518 /* Override to do something slightly nonstandard, but nice.  First click on
7519    zoom button will zoom vertically.  Second will zoom completely.  Third
7520    returns to original.  */
7521 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7522                         defaultFrame:(NSRect)defaultFrame
7524   // TODO: Rename to "currentFrame" and assign "result" properly in
7525   // all paths.
7526   NSRect result = [sender frame];
7528   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7529             NSTRACE_FMT_RECT "]"),
7530            NSTRACE_ARG_RECT (defaultFrame));
7531   NSTRACE_FSTYPE ("fs_state", fs_state);
7532   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7533   NSTRACE_FSTYPE ("next_maximized", next_maximized);
7534   NSTRACE_RECT   ("ns_userRect", ns_userRect);
7535   NSTRACE_RECT   ("[sender frame]", [sender frame]);
7537   if (fs_before_fs != -1) /* Entering fullscreen */
7538     {
7539       NSTRACE_MSG ("Entering fullscreen");
7540       result = defaultFrame;
7541     }
7542   else
7543     {
7544       // Save the window size and position (frame) before the resize.
7545       if (fs_state != FULLSCREEN_MAXIMIZED
7546           && fs_state != FULLSCREEN_WIDTH)
7547         {
7548           ns_userRect.size.width = result.size.width;
7549           ns_userRect.origin.x   = result.origin.x;
7550         }
7552       if (fs_state != FULLSCREEN_MAXIMIZED
7553           && fs_state != FULLSCREEN_HEIGHT)
7554         {
7555           ns_userRect.size.height = result.size.height;
7556           ns_userRect.origin.y    = result.origin.y;
7557         }
7559       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7561       if (next_maximized == FULLSCREEN_HEIGHT
7562           || (next_maximized == -1
7563               && abs ((int)(defaultFrame.size.height - result.size.height))
7564               > FRAME_LINE_HEIGHT (emacsframe)))
7565         {
7566           /* first click */
7567           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7568           maximized_height = result.size.height = defaultFrame.size.height;
7569           maximized_width = -1;
7570           result.origin.y = defaultFrame.origin.y;
7571           if (ns_userRect.size.height != 0)
7572             {
7573               result.origin.x = ns_userRect.origin.x;
7574               result.size.width = ns_userRect.size.width;
7575             }
7576           [self setFSValue: FULLSCREEN_HEIGHT];
7577 #ifdef NS_IMPL_COCOA
7578           maximizing_resize = YES;
7579 #endif
7580         }
7581       else if (next_maximized == FULLSCREEN_WIDTH)
7582         {
7583           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7584           maximized_width = result.size.width = defaultFrame.size.width;
7585           maximized_height = -1;
7586           result.origin.x = defaultFrame.origin.x;
7587           if (ns_userRect.size.width != 0)
7588             {
7589               result.origin.y = ns_userRect.origin.y;
7590               result.size.height = ns_userRect.size.height;
7591             }
7592           [self setFSValue: FULLSCREEN_WIDTH];
7593         }
7594       else if (next_maximized == FULLSCREEN_MAXIMIZED
7595                || (next_maximized == -1
7596                    && abs ((int)(defaultFrame.size.width - result.size.width))
7597                    > FRAME_COLUMN_WIDTH (emacsframe)))
7598         {
7599           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7601           result = defaultFrame; /* second click */
7602           maximized_width = result.size.width;
7603           maximized_height = result.size.height;
7604           [self setFSValue: FULLSCREEN_MAXIMIZED];
7605 #ifdef NS_IMPL_COCOA
7606           maximizing_resize = YES;
7607 #endif
7608         }
7609       else
7610         {
7611           /* restore */
7612           NSTRACE_MSG ("Restore");
7613           result = ns_userRect.size.height ? ns_userRect : result;
7614           NSTRACE_RECT ("restore (2)", result);
7615           ns_userRect = NSMakeRect (0, 0, 0, 0);
7616 #ifdef NS_IMPL_COCOA
7617           maximizing_resize = fs_state != FULLSCREEN_NONE;
7618 #endif
7619           [self setFSValue: FULLSCREEN_NONE];
7620           maximized_width = maximized_height = -1;
7621         }
7622     }
7624   if (fs_before_fs == -1) next_maximized = -1;
7626   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
7627   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
7628   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
7629   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7631   [self windowWillResize: sender toSize: result.size];
7633   NSTRACE_RETURN_RECT (result);
7635   return result;
7639 - (void)windowDidDeminiaturize: sender
7641   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7642   if (!emacsframe->output_data.ns)
7643     return;
7645   SET_FRAME_ICONIFIED (emacsframe, 0);
7646   SET_FRAME_VISIBLE (emacsframe, 1);
7647   windows_or_buffers_changed = 63;
7649   if (emacs_event)
7650     {
7651       emacs_event->kind = DEICONIFY_EVENT;
7652       EV_TRAILER ((id)nil);
7653     }
7657 - (void)windowDidExpose: sender
7659   NSTRACE ("[EmacsView windowDidExpose:]");
7660   if (!emacsframe->output_data.ns)
7661     return;
7663   SET_FRAME_VISIBLE (emacsframe, 1);
7664   SET_FRAME_GARBAGED (emacsframe);
7666   if (send_appdefined)
7667     ns_send_appdefined (-1);
7671 - (void)windowDidMiniaturize: sender
7673   NSTRACE ("[EmacsView windowDidMiniaturize:]");
7674   if (!emacsframe->output_data.ns)
7675     return;
7677   SET_FRAME_ICONIFIED (emacsframe, 1);
7678   SET_FRAME_VISIBLE (emacsframe, 0);
7680   if (emacs_event)
7681     {
7682       emacs_event->kind = ICONIFY_EVENT;
7683       EV_TRAILER ((id)nil);
7684     }
7687 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7688 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7689       willUseFullScreenPresentationOptions:
7690   (NSApplicationPresentationOptions)proposedOptions
7692   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7694 #endif
7696 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7698   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7699   [self windowWillEnterFullScreen];
7701 - (void)windowWillEnterFullScreen /* provided for direct calls */
7703   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7704   fs_before_fs = fs_state;
7707 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7709   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7710   [self windowDidEnterFullScreen];
7713 - (void)windowDidEnterFullScreen /* provided for direct calls */
7715   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7716   [self setFSValue: FULLSCREEN_BOTH];
7717   if (! [self fsIsNative])
7718     {
7719       [self windowDidBecomeKey];
7720       [nonfs_window orderOut:self];
7721     }
7722   else
7723     {
7724       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7725 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7726   && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7727       unsigned val = (unsigned)[NSApp presentationOptions];
7729       // Mac OS X 10.7 bug fix, the menu won't appear without this.
7730       // val is non-zero on other macOS versions.
7731       if (val == 0)
7732         {
7733           NSApplicationPresentationOptions options
7734             = NSApplicationPresentationAutoHideDock
7735             | NSApplicationPresentationAutoHideMenuBar
7736             | NSApplicationPresentationFullScreen
7737             | NSApplicationPresentationAutoHideToolbar;
7739           [NSApp setPresentationOptions: options];
7740         }
7741 #endif
7742       [toolbar setVisible:tbar_visible];
7743     }
7746 - (void)windowWillExitFullScreen:(NSNotification *)notification
7748   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7749   [self windowWillExitFullScreen];
7752 - (void)windowWillExitFullScreen /* provided for direct calls */
7754   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7755   if (!FRAME_LIVE_P (emacsframe))
7756     {
7757       NSTRACE_MSG ("Ignored (frame dead)");
7758       return;
7759     }
7760   if (next_maximized != -1)
7761     fs_before_fs = next_maximized;
7764 - (void)windowDidExitFullScreen:(NSNotification *)notification
7766   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7767   [self windowDidExitFullScreen];
7770 - (void)windowDidExitFullScreen /* provided for direct calls */
7772   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7773   if (!FRAME_LIVE_P (emacsframe))
7774     {
7775       NSTRACE_MSG ("Ignored (frame dead)");
7776       return;
7777     }
7778   [self setFSValue: fs_before_fs];
7779   fs_before_fs = -1;
7780 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7781   [self updateCollectionBehavior];
7782 #endif
7783   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7784     {
7785       [toolbar setVisible:YES];
7786       update_frame_tool_bar (emacsframe);
7787       [self updateFrameSize:YES];
7788       [[self window] display];
7789     }
7790   else
7791     [toolbar setVisible:NO];
7793   if (next_maximized != -1)
7794     [[self window] performZoom:self];
7797 - (BOOL)fsIsNative
7799   return fs_is_native;
7802 - (BOOL)isFullscreen
7804   BOOL res;
7806   if (! fs_is_native)
7807     {
7808       res = (nonfs_window != nil);
7809     }
7810   else
7811     {
7812 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7813       res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7814 #else
7815       res = NO;
7816 #endif
7817     }
7819   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7820            (int) res);
7822   return res;
7825 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7826 - (void)updateCollectionBehavior
7828   NSTRACE ("[EmacsView updateCollectionBehavior]");
7830   if (! [self isFullscreen])
7831     {
7832       NSWindow *win = [self window];
7833       NSWindowCollectionBehavior b = [win collectionBehavior];
7834       if (ns_use_native_fullscreen)
7835         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7836       else
7837         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7839       [win setCollectionBehavior: b];
7840 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7841       if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7842 #endif
7843         fs_is_native = ns_use_native_fullscreen;
7844     }
7846 #endif
7848 - (void)toggleFullScreen: (id)sender
7850   NSWindow *w, *fw;
7851   BOOL onFirstScreen;
7852   struct frame *f;
7853   NSRect r, wr;
7854   NSColor *col;
7856   NSTRACE ("[EmacsView toggleFullScreen:]");
7858   if (fs_is_native)
7859     {
7860 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7861 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7862       if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7863 #endif
7864         [[self window] toggleFullScreen:sender];
7865 #endif
7866       return;
7867     }
7869   w = [self window];
7870   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7871   f = emacsframe;
7872   wr = [w frame];
7873   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7874                                  (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7875                                  f);
7877   if (fs_state != FULLSCREEN_BOTH)
7878     {
7879       NSScreen *screen = [w screen];
7881 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7882       /* Hide ghost menu bar on secondary monitor?  */
7883       if (! onFirstScreen
7884 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7885           && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7886 #endif
7887           )
7888         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7889 #endif
7890       /* Hide dock and menubar if we are on the primary screen.  */
7891       if (onFirstScreen)
7892         {
7893 #ifdef NS_IMPL_COCOA
7894           NSApplicationPresentationOptions options
7895             = NSApplicationPresentationAutoHideDock
7896             | NSApplicationPresentationAutoHideMenuBar;
7898           [NSApp setPresentationOptions: options];
7899 #else
7900           [NSMenu setMenuBarVisible:NO];
7901 #endif
7902         }
7904       fw = [[EmacsFSWindow alloc]
7905                        initWithContentRect:[w contentRectForFrameRect:wr]
7906                                  styleMask:NSWindowStyleMaskBorderless
7907                                    backing:NSBackingStoreBuffered
7908                                      defer:YES
7909                                     screen:screen];
7911       [fw setContentView:[w contentView]];
7912       [fw setTitle:[w title]];
7913       [fw setDelegate:self];
7914       [fw setAcceptsMouseMovedEvents: YES];
7915 #if !defined (NS_IMPL_COCOA) \
7916   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7917 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7918       if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7919 #endif
7920         [fw useOptimizedDrawing: YES];
7921 #endif
7922       [fw setBackgroundColor: col];
7923       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7924         [fw setOpaque: NO];
7926       f->border_width = 0;
7928       nonfs_window = w;
7930       [self windowWillEnterFullScreen];
7931       [fw makeKeyAndOrderFront:NSApp];
7932       [fw makeFirstResponder:self];
7933       [w orderOut:self];
7934       r = [fw frameRectForContentRect:[screen frame]];
7935       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7936       [self windowDidEnterFullScreen];
7937       [fw display];
7938     }
7939   else
7940     {
7941       fw = w;
7942       w = nonfs_window;
7943       nonfs_window = nil;
7945       if (onFirstScreen)
7946         {
7947 #ifdef NS_IMPL_COCOA
7948           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7949 #else
7950           [NSMenu setMenuBarVisible:YES];
7951 #endif
7952         }
7954       [w setContentView:[fw contentView]];
7955       [w setBackgroundColor: col];
7956       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7957         [w setOpaque: NO];
7959       f->border_width = bwidth;
7961       // To do: consider using [NSNotificationCenter postNotificationName:] to
7962       // send notifications.
7964       [self windowWillExitFullScreen];
7965       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7966       [fw close];
7967       [w makeKeyAndOrderFront:NSApp];
7968       [self windowDidExitFullScreen];
7969       [self updateFrameSize:YES];
7970     }
7973 - (void)handleFS
7975   NSTRACE ("[EmacsView handleFS]");
7977   if (fs_state != emacsframe->want_fullscreen)
7978     {
7979       if (fs_state == FULLSCREEN_BOTH)
7980         {
7981           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7982           [self toggleFullScreen:self];
7983         }
7985       switch (emacsframe->want_fullscreen)
7986         {
7987         case FULLSCREEN_BOTH:
7988           NSTRACE_MSG ("FULLSCREEN_BOTH");
7989           [self toggleFullScreen:self];
7990           break;
7991         case FULLSCREEN_WIDTH:
7992           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7993           next_maximized = FULLSCREEN_WIDTH;
7994           if (fs_state != FULLSCREEN_BOTH)
7995             [[self window] performZoom:self];
7996           break;
7997         case FULLSCREEN_HEIGHT:
7998           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7999           next_maximized = FULLSCREEN_HEIGHT;
8000           if (fs_state != FULLSCREEN_BOTH)
8001             [[self window] performZoom:self];
8002           break;
8003         case FULLSCREEN_MAXIMIZED:
8004           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
8005           next_maximized = FULLSCREEN_MAXIMIZED;
8006           if (fs_state != FULLSCREEN_BOTH)
8007             [[self window] performZoom:self];
8008           break;
8009         case FULLSCREEN_NONE:
8010           NSTRACE_MSG ("FULLSCREEN_NONE");
8011           if (fs_state != FULLSCREEN_BOTH)
8012             {
8013               next_maximized = FULLSCREEN_NONE;
8014               [[self window] performZoom:self];
8015             }
8016           break;
8017         }
8019       emacsframe->want_fullscreen = FULLSCREEN_NONE;
8020     }
8024 - (void) setFSValue: (int)value
8026   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
8027            NSTRACE_ARG_FSTYPE(value));
8029   Lisp_Object lval = Qnil;
8030   switch (value)
8031     {
8032     case FULLSCREEN_BOTH:
8033       lval = Qfullboth;
8034       break;
8035     case FULLSCREEN_WIDTH:
8036       lval = Qfullwidth;
8037       break;
8038     case FULLSCREEN_HEIGHT:
8039       lval = Qfullheight;
8040       break;
8041     case FULLSCREEN_MAXIMIZED:
8042       lval = Qmaximized;
8043       break;
8044     }
8045   store_frame_param (emacsframe, Qfullscreen, lval);
8046   fs_state = value;
8049 - (void)mouseEntered: (NSEvent *)theEvent
8051   NSTRACE ("[EmacsView mouseEntered:]");
8052   if (emacsframe)
8053     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
8054       = EV_TIMESTAMP (theEvent);
8058 - (void)mouseExited: (NSEvent *)theEvent
8060   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
8062   NSTRACE ("[EmacsView mouseExited:]");
8064   if (!hlinfo)
8065     return;
8067   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
8068     = EV_TIMESTAMP (theEvent);
8070   if (emacsframe == hlinfo->mouse_face_mouse_frame)
8071     {
8072       clear_mouse_face (hlinfo);
8073       hlinfo->mouse_face_mouse_frame = 0;
8074     }
8078 - (instancetype)menuDown: sender
8080   NSTRACE ("[EmacsView menuDown:]");
8081   if (context_menu_value == -1)
8082     context_menu_value = [sender tag];
8083   else
8084     {
8085       NSInteger tag = [sender tag];
8086       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
8087                                     emacsframe->menu_bar_vector,
8088                                     (void *)tag);
8089     }
8091   ns_send_appdefined (-1);
8092   return self;
8096 - (EmacsToolbar *)toolbar
8098   return toolbar;
8102 /* This gets called on toolbar button click.  */
8103 - (instancetype)toolbarClicked: (id)item
8105   NSEvent *theEvent;
8106   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
8108   NSTRACE ("[EmacsView toolbarClicked:]");
8110   if (!emacs_event)
8111     return self;
8113   /* Send first event (for some reason two needed).  */
8114   theEvent = [[self window] currentEvent];
8115   emacs_event->kind = TOOL_BAR_EVENT;
8116   XSETFRAME (emacs_event->arg, emacsframe);
8117   EV_TRAILER (theEvent);
8119   emacs_event->kind = TOOL_BAR_EVENT;
8120   /* XSETINT (emacs_event->code, 0); */
8121   emacs_event->arg = AREF (emacsframe->tool_bar_items,
8122                            idx + TOOL_BAR_ITEM_KEY);
8123   emacs_event->modifiers = EV_MODIFIERS (theEvent);
8124   EV_TRAILER (theEvent);
8125   return self;
8129 - (instancetype)toggleToolbar: (id)sender
8131   NSTRACE ("[EmacsView toggleToolbar:]");
8133   if (!emacs_event)
8134     return self;
8136   emacs_event->kind = NS_NONKEY_EVENT;
8137   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
8138   EV_TRAILER ((id)nil);
8139   return self;
8143 - (void)drawRect: (NSRect)rect
8145   int x = NSMinX (rect), y = NSMinY (rect);
8146   int width = NSWidth (rect), height = NSHeight (rect);
8148   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
8149            NSTRACE_ARG_RECT(rect));
8151   if (!emacsframe || !emacsframe->output_data.ns)
8152     return;
8154   ns_clear_frame_area (emacsframe, x, y, width, height);
8155   block_input ();
8156   expose_frame (emacsframe, x, y, width, height);
8157   unblock_input ();
8159   /*
8160     drawRect: may be called (at least in Mac OS X 10.5) for invisible
8161     views as well for some reason.  Thus, do not infer visibility
8162     here.
8164     emacsframe->async_visible = 1;
8165     emacsframe->async_iconified = 0;
8166   */
8170 /* NSDraggingDestination protocol methods.  Actually this is not really a
8171    protocol, but a category of Object.  O well...  */
8173 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
8175   NSTRACE ("[EmacsView draggingEntered:]");
8176   return NSDragOperationGeneric;
8180 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
8182   return YES;
8186 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
8188   id pb;
8189   int x, y;
8190   NSString *type;
8191   NSEvent *theEvent = [[self window] currentEvent];
8192   NSPoint position;
8193   NSDragOperation op = [sender draggingSourceOperationMask];
8194   int modifiers = 0;
8196   NSTRACE ("[EmacsView performDragOperation:]");
8198   if (!emacs_event)
8199     return NO;
8201   position = [self convertPoint: [sender draggingLocation] fromView: nil];
8202   x = lrint (position.x);  y = lrint (position.y);
8204   pb = [sender draggingPasteboard];
8205   type = [pb availableTypeFromArray: ns_drag_types];
8207   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
8208       // URL drags contain all operations (0xf), don't allow all to be set.
8209       (op & 0xf) != 0xf)
8210     {
8211       if (op & NSDragOperationLink)
8212         modifiers |= NSEventModifierFlagControl;
8213       if (op & NSDragOperationCopy)
8214         modifiers |= NSEventModifierFlagOption;
8215       if (op & NSDragOperationGeneric)
8216         modifiers |= NSEventModifierFlagCommand;
8217     }
8219   modifiers = EV_MODIFIERS2 (modifiers);
8220   if (type == 0)
8221     {
8222       return NO;
8223     }
8224   else if ([type isEqualToString: NSFilenamesPboardType])
8225     {
8226       NSArray *files;
8227       NSEnumerator *fenum;
8228       NSString *file;
8230       if (!(files = [pb propertyListForType: type]))
8231         return NO;
8233       fenum = [files objectEnumerator];
8234       while ( (file = [fenum nextObject]) )
8235         {
8236           emacs_event->kind = DRAG_N_DROP_EVENT;
8237           XSETINT (emacs_event->x, x);
8238           XSETINT (emacs_event->y, y);
8239           emacs_event->modifiers = modifiers;
8240           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
8241           EV_TRAILER (theEvent);
8242         }
8243       return YES;
8244     }
8245   else if ([type isEqualToString: NSURLPboardType])
8246     {
8247       NSURL *url = [NSURL URLFromPasteboard: pb];
8248       if (url == nil) return NO;
8250       emacs_event->kind = DRAG_N_DROP_EVENT;
8251       XSETINT (emacs_event->x, x);
8252       XSETINT (emacs_event->y, y);
8253       emacs_event->modifiers = modifiers;
8254       emacs_event->arg =  list2 (Qurl,
8255                                  build_string ([[url absoluteString]
8256                                                  UTF8String]));
8257       EV_TRAILER (theEvent);
8259       if ([url isFileURL] != NO)
8260         {
8261           NSString *file = [url path];
8262           ns_input_file = append2 (ns_input_file,
8263                                    build_string ([file UTF8String]));
8264         }
8265       return YES;
8266     }
8267   else if ([type isEqualToString: NSStringPboardType]
8268            || [type isEqualToString: NSTabularTextPboardType])
8269     {
8270       NSString *data;
8272       if (! (data = [pb stringForType: type]))
8273         return NO;
8275       emacs_event->kind = DRAG_N_DROP_EVENT;
8276       XSETINT (emacs_event->x, x);
8277       XSETINT (emacs_event->y, y);
8278       emacs_event->modifiers = modifiers;
8279       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
8280       EV_TRAILER (theEvent);
8281       return YES;
8282     }
8283   else
8284     {
8285       fprintf (stderr, "Invalid data type in dragging pasteboard");
8286       return NO;
8287     }
8291 - (id) validRequestorForSendType: (NSString *)typeSent
8292                       returnType: (NSString *)typeReturned
8294   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
8295   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
8296       && typeReturned == nil)
8297     {
8298       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
8299         return self;
8300     }
8302   return [super validRequestorForSendType: typeSent
8303                                returnType: typeReturned];
8307 /* The next two methods are part of NSServicesRequests informal protocol,
8308    supposedly called when a services menu item is chosen from this app.
8309    But this should not happen because we override the services menu with our
8310    own entries which call ns-perform-service.
8311    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
8312    So let's at least stub them out until further investigation can be done.  */
8314 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
8316   /* We could call ns_string_from_pasteboard(pboard) here but then it should
8317      be written into the buffer in place of the existing selection.
8318      Ordinary service calls go through functions defined in ns-win.el.  */
8319   return NO;
8322 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8324   NSArray *typesDeclared;
8325   Lisp_Object val;
8327   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8329   /* We only support NSStringPboardType.  */
8330   if ([types containsObject:NSStringPboardType] == NO) {
8331     return NO;
8332   }
8334   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8335   if (CONSP (val) && SYMBOLP (XCAR (val)))
8336     {
8337       val = XCDR (val);
8338       if (CONSP (val) && NILP (XCDR (val)))
8339         val = XCAR (val);
8340     }
8341   if (! STRINGP (val))
8342     return NO;
8344   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8345   [pb declareTypes:typesDeclared owner:nil];
8346   ns_string_to_pasteboard (pb, val);
8347   return YES;
8351 /* setMini = YES means set from internal (gives a finder icon), NO means set nil
8352    (gives a miniaturized version of the window); currently we use the latter for
8353    frames whose active buffer doesn't correspond to any file
8354    (e.g., '*scratch*').  */
8355 - (instancetype)setMiniwindowImage: (BOOL) setMini
8357   id image = [[self window] miniwindowImage];
8358   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8360   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8361      about "AppleDockIconEnabled" notwithstanding, however the set message
8362      below has its effect nonetheless.  */
8363   if (image != emacsframe->output_data.ns->miniimage)
8364     {
8365       if (image && [image isKindOfClass: [EmacsImage class]])
8366         [image release];
8367       [[self window] setMiniwindowImage:
8368                        setMini ? emacsframe->output_data.ns->miniimage : nil];
8369     }
8371   return self;
8375 - (void) setRows: (int) r andColumns: (int) c
8377   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8378   rows = r;
8379   cols = c;
8382 - (int) fullscreenState
8384   return fs_state;
8387 @end  /* EmacsView */
8391 /* ==========================================================================
8393     EmacsWindow implementation
8395    ========================================================================== */
8397 @implementation EmacsWindow
8399 #ifdef NS_IMPL_COCOA
8400 - (id)accessibilityAttributeValue:(NSString *)attribute
8402   Lisp_Object str = Qnil;
8403   struct frame *f = SELECTED_FRAME ();
8404   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8406   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8408   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8409     return NSAccessibilityTextFieldRole;
8411   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8412       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8413     {
8414       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8415     }
8416   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8417     {
8418       if (! NILP (BVAR (curbuf, mark_active)))
8419           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8421       if (NILP (str))
8422         {
8423           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8424           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8425           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8427           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8428             str = make_uninit_multibyte_string (range, byte_range);
8429           else
8430             str = make_uninit_string (range);
8431           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8432              Is this a problem?  */
8433           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8434         }
8435     }
8438   if (! NILP (str))
8439     {
8440       if (CONSP (str) && SYMBOLP (XCAR (str)))
8441         {
8442           str = XCDR (str);
8443           if (CONSP (str) && NILP (XCDR (str)))
8444             str = XCAR (str);
8445         }
8446       if (STRINGP (str))
8447         {
8448           const char *utfStr = SSDATA (str);
8449           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8450           return nsStr;
8451         }
8452     }
8454   return [super accessibilityAttributeValue:attribute];
8456 #endif /* NS_IMPL_COCOA */
8458 /* Constrain size and placement of a frame.
8460    By returning the original "frameRect", the frame is not
8461    constrained. This can lead to unwanted situations where, for
8462    example, the menu bar covers the frame.
8464    The default implementation (accessed using "super") constrains the
8465    frame to the visible area of SCREEN, minus the menu bar (if
8466    present) and the Dock.  Note that default implementation also calls
8467    windowWillResize, with the frame it thinks should have.  (This can
8468    make the frame exit maximized mode.)
8470    Note that this should work in situations where multiple monitors
8471    are present.  Common configurations are side-by-side monitors and a
8472    monitor on top of another (e.g. when a laptop is placed under a
8473    large screen).  */
8474 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8476   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8477              NSTRACE_ARG_RECT (frameRect));
8479 #ifdef NS_IMPL_COCOA
8480 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8481   // If separate spaces is on, it is like each screen is independent.  There is
8482   // no spanning of frames across screens.
8483   if (
8484 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8485       [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8486 #endif
8487       [NSScreen screensHaveSeparateSpaces])
8488     {
8489       NSTRACE_MSG ("Screens have separate spaces");
8490       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8491       NSTRACE_RETURN_RECT (frameRect);
8492       return frameRect;
8493     }
8494   else
8495 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8497     // Check that the proposed frameRect is visible in at least one
8498     // screen.  If it is not, ask the system to reposition it (only
8499     // for non-child windows).
8501     if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8502     {
8503       NSArray *screens = [NSScreen screens];
8504       NSUInteger nr_screens = [screens count];
8506       int i;
8507       BOOL frame_on_screen = NO;
8509       for (i = 0; i < nr_screens; ++i)
8510         {
8511           NSScreen *s = [screens objectAtIndex: i];
8512           NSRect scrRect = [s frame];
8514           if (NSIntersectsRect(frameRect, scrRect))
8515             {
8516               frame_on_screen = YES;
8517               break;
8518             }
8519         }
8521       if (!frame_on_screen)
8522         {
8523           NSTRACE_MSG ("Frame outside screens; constraining");
8524           frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8525           NSTRACE_RETURN_RECT (frameRect);
8526           return frameRect;
8527         }
8528     }
8529 #endif
8531   return constrain_frame_rect(frameRect,
8532                               [(EmacsView *)[self delegate] isFullscreen]);
8536 - (void)performZoom:(id)sender
8538   NSTRACE ("[EmacsWindow performZoom:]");
8540   return [super performZoom:sender];
8543 - (void)zoom:(id)sender
8545   NSTRACE ("[EmacsWindow zoom:]");
8547   ns_update_auto_hide_menu_bar();
8549   // Below are three zoom implementations.  In the final commit, the
8550   // idea is that the last should be included.
8552 #if 0
8553   // Native zoom done using the standard zoom animation.  Size of the
8554   // resulting frame reduced to accommodate the Dock and, if present,
8555   // the menu-bar.
8556   [super zoom:sender];
8558 #elif 0
8559   // Native zoom done using the standard zoom animation, plus an
8560   // explicit resize to cover the full screen, except the menu-bar and
8561   // dock, if present.
8562   [super zoom:sender];
8564   // After the native zoom, resize the resulting frame to fill the
8565   // entire screen, except the menu-bar.
8566   //
8567   // This works for all practical purposes.  (The only minor oddity is
8568   // when transiting from full-height frame to a maximized, the
8569   // animation reduces the height of the frame slightly (to the 4
8570   // pixels needed to accommodate the Doc) before it snaps back into
8571   // full height.  The user would need a very trained eye to spot
8572   // this.)
8573   NSScreen * screen = [self screen];
8574   if (screen != nil)
8575     {
8576       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8578       NSTRACE_FSTYPE ("fullscreenState", fs_state);
8580       NSRect sr = [screen frame];
8581       struct EmacsMargins margins
8582         = ns_screen_margins_ignoring_hidden_dock(screen);
8584       NSRect wr = [self frame];
8585       NSTRACE_RECT ("Rect after zoom", wr);
8587       NSRect newWr = wr;
8589       if (fs_state == FULLSCREEN_MAXIMIZED
8590           || fs_state == FULLSCREEN_HEIGHT)
8591         {
8592           newWr.origin.y = sr.origin.y + margins.bottom;
8593           newWr.size.height = sr.size.height - margins.top - margins.bottom;
8594         }
8596       if (fs_state == FULLSCREEN_MAXIMIZED
8597           || fs_state == FULLSCREEN_WIDTH)
8598         {
8599           newWr.origin.x = sr.origin.x + margins.left;
8600           newWr.size.width = sr.size.width - margins.right - margins.left;
8601         }
8603       if (newWr.size.width     != wr.size.width
8604           || newWr.size.height != wr.size.height
8605           || newWr.origin.x    != wr.origin.x
8606           || newWr.origin.y    != wr.origin.y)
8607         {
8608           NSTRACE_MSG ("New frame different");
8609           [self setFrame: newWr display: NO];
8610         }
8611     }
8612 #else
8613   // Non-native zoom which is done instantaneously.  The resulting
8614   // frame covers the entire screen, except the menu-bar and dock, if
8615   // present.
8616   NSScreen * screen = [self screen];
8617   if (screen != nil)
8618     {
8619       NSRect sr = [screen frame];
8620       struct EmacsMargins margins
8621         = ns_screen_margins_ignoring_hidden_dock(screen);
8623       sr.size.height -= (margins.top + margins.bottom);
8624       sr.size.width  -= (margins.left + margins.right);
8625       sr.origin.x += margins.left;
8626       sr.origin.y += margins.bottom;
8628       sr = [[self delegate] windowWillUseStandardFrame:self
8629                                           defaultFrame:sr];
8630       [self setFrame: sr display: NO];
8631     }
8632 #endif
8635 - (void)setFrame:(NSRect)windowFrame
8636          display:(BOOL)displayViews
8638   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8639            NSTRACE_ARG_RECT (windowFrame), displayViews);
8641   [super setFrame:windowFrame display:displayViews];
8644 - (void)setFrame:(NSRect)windowFrame
8645          display:(BOOL)displayViews
8646          animate:(BOOL)performAnimation
8648   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8649            " display:%d performAnimation:%d]",
8650            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8652   [super setFrame:windowFrame display:displayViews animate:performAnimation];
8655 - (void)setFrameTopLeftPoint:(NSPoint)point
8657   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8658            NSTRACE_ARG_POINT (point));
8660   [super setFrameTopLeftPoint:point];
8663 - (BOOL)canBecomeKeyWindow
8665   return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8667 @end /* EmacsWindow */
8670 @implementation EmacsFSWindow
8672 - (BOOL)canBecomeKeyWindow
8674   return YES;
8677 - (BOOL)canBecomeMainWindow
8679   return YES;
8682 @end
8684 /* ==========================================================================
8686     EmacsScroller implementation
8688    ========================================================================== */
8691 @implementation EmacsScroller
8693 /* for repeat button push */
8694 #define SCROLL_BAR_FIRST_DELAY 0.5
8695 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8697 + (CGFloat) scrollerWidth
8699   /* TODO: if we want to allow variable widths, this is the place to do it,
8700            however neither GNUstep nor Cocoa support it very well.  */
8701   CGFloat r;
8702 #if defined (NS_IMPL_COCOA) \
8703   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8704 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8705   if ([NSScroller respondsToSelector:
8706                     @selector(scrollerWidthForControlSize:scrollerStyle:)])
8707 #endif
8708     r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8709                                   scrollerStyle: NSScrollerStyleLegacy];
8710 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8711   else
8712 #endif
8713 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8714 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8715   || defined (NS_IMPL_GNUSTEP)
8716     r = [NSScroller scrollerWidth];
8717 #endif
8718   return r;
8721 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8723   NSTRACE ("[EmacsScroller initFrame: window:]");
8725   if (r.size.width > r.size.height)
8726       horizontal = YES;
8727   else
8728       horizontal = NO;
8730   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8731   [self setContinuous: YES];
8732   [self setEnabled: YES];
8734   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8735      locked against the top and bottom edges, and right edge on macOS, where
8736      scrollers are on right.  */
8737 #ifdef NS_IMPL_GNUSTEP
8738   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8739 #else
8740   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8741 #endif
8743   window = XWINDOW (nwin);
8744   condemned = NO;
8745   if (horizontal)
8746     pixel_length = NSWidth (r);
8747   else
8748     pixel_length = NSHeight (r);
8749   if (pixel_length == 0) pixel_length = 1;
8750   min_portion = 20 / pixel_length;
8752   frame = XFRAME (window->frame);
8753   if (FRAME_LIVE_P (frame))
8754     {
8755       int i;
8756       EmacsView *view = FRAME_NS_VIEW (frame);
8757       NSView *sview = [[view window] contentView];
8758       NSArray *subs = [sview subviews];
8760       /* Disable optimization stopping redraw of other scrollbars.  */
8761       view->scrollbarsNeedingUpdate = 0;
8762       for (i =[subs count]-1; i >= 0; i--)
8763         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8764           view->scrollbarsNeedingUpdate++;
8765       [sview addSubview: self];
8766     }
8768   /* [self setFrame: r]; */
8770   return self;
8774 - (void)setFrame: (NSRect)newRect
8776   NSTRACE ("[EmacsScroller setFrame:]");
8778   /* block_input (); */
8779   if (horizontal)
8780     pixel_length = NSWidth (newRect);
8781   else
8782     pixel_length = NSHeight (newRect);
8783   if (pixel_length == 0) pixel_length = 1;
8784   min_portion = 20 / pixel_length;
8785   [super setFrame: newRect];
8786   /* unblock_input (); */
8790 - (void)dealloc
8792   NSTRACE ("[EmacsScroller dealloc]");
8793   if (window)
8794     {
8795       if (horizontal)
8796         wset_horizontal_scroll_bar (window, Qnil);
8797       else
8798         wset_vertical_scroll_bar (window, Qnil);
8799     }
8800   window = 0;
8801   [super dealloc];
8805 - (instancetype)condemn
8807   NSTRACE ("[EmacsScroller condemn]");
8808   condemned =YES;
8809   return self;
8813 - (instancetype)reprieve
8815   NSTRACE ("[EmacsScroller reprieve]");
8816   condemned =NO;
8817   return self;
8821 -(bool)judge
8823   NSTRACE ("[EmacsScroller judge]");
8824   bool ret = condemned;
8825   if (condemned)
8826     {
8827       EmacsView *view;
8828       block_input ();
8829       /* Ensure other scrollbar updates after deletion.  */
8830       view = (EmacsView *)FRAME_NS_VIEW (frame);
8831       if (view != nil)
8832         view->scrollbarsNeedingUpdate++;
8833       if (window)
8834         {
8835           if (horizontal)
8836             wset_horizontal_scroll_bar (window, Qnil);
8837           else
8838             wset_vertical_scroll_bar (window, Qnil);
8839         }
8840       window = 0;
8841       [self removeFromSuperview];
8842       [self release];
8843       unblock_input ();
8844     }
8845   return ret;
8849 - (void)resetCursorRects
8851   NSRect visible = [self visibleRect];
8852   NSTRACE ("[EmacsScroller resetCursorRects]");
8854   if (!NSIsEmptyRect (visible))
8855     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8857 #if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101300
8858 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
8859   if ([[NSCursor arrowCursor] respondsToSelector:
8860                                 @selector(setOnMouseEntered)])
8861 #endif
8862     [[NSCursor arrowCursor] setOnMouseEntered: YES];
8863 #endif
8867 - (int) checkSamePosition: (int) position portion: (int) portion
8868                     whole: (int) whole
8870   return em_position ==position && em_portion ==portion && em_whole ==whole
8871     && portion != whole; /* Needed for resizing empty buffer.  */
8875 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8877   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8879   em_position = position;
8880   em_portion = portion;
8881   em_whole = whole;
8883   if (portion >= whole)
8884     {
8885 #ifdef NS_IMPL_COCOA
8886       [self setKnobProportion: 1.0];
8887       [self setDoubleValue: 1.0];
8888 #else
8889       [self setFloatValue: 0.0 knobProportion: 1.0];
8890 #endif
8891     }
8892   else
8893     {
8894       float pos;
8895       CGFloat por;
8896       portion = max ((float)whole*min_portion/pixel_length, portion);
8897       pos = (float)position / (whole - portion);
8898       por = (CGFloat)portion/whole;
8899 #ifdef NS_IMPL_COCOA
8900       [self setKnobProportion: por];
8901       [self setDoubleValue: pos];
8902 #else
8903       [self setFloatValue: pos knobProportion: por];
8904 #endif
8905     }
8907   return self;
8910 /* Set up emacs_event.  */
8911 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8913   Lisp_Object win;
8915   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8917   if (!emacs_event)
8918     return;
8920   emacs_event->part = last_hit_part;
8921   emacs_event->code = 0;
8922   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8923   XSETWINDOW (win, window);
8924   emacs_event->frame_or_window = win;
8925   emacs_event->timestamp = EV_TIMESTAMP (e);
8926   emacs_event->arg = Qnil;
8928   if (horizontal)
8929     {
8930       emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8931       XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8932       XSETINT (emacs_event->y, em_whole);
8933     }
8934   else
8935     {
8936       emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8937       XSETINT (emacs_event->x, loc);
8938       XSETINT (emacs_event->y, pixel_length-20);
8939     }
8941   if (q_event_ptr)
8942     {
8943       n_emacs_events_pending++;
8944       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8945     }
8946   else
8947     hold_event (emacs_event);
8948   EVENT_INIT (*emacs_event);
8949   ns_send_appdefined (-1);
8953 /* Called manually through timer to implement repeated button action
8954    with hold-down.  */
8955 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8957   NSEvent *e = [[self window] currentEvent];
8958   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8959   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8961   NSTRACE ("[EmacsScroller repeatScroll:]");
8963   /* Clear timer if need be.  */
8964   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8965     {
8966         [scroll_repeat_entry invalidate];
8967         [scroll_repeat_entry release];
8968         scroll_repeat_entry = nil;
8970         if (inKnob)
8971           return self;
8973         scroll_repeat_entry
8974           = [[NSTimer scheduledTimerWithTimeInterval:
8975                         SCROLL_BAR_CONTINUOUS_DELAY
8976                                             target: self
8977                                           selector: @selector (repeatScroll:)
8978                                           userInfo: 0
8979                                            repeats: YES]
8980               retain];
8981     }
8983   [self sendScrollEventAtLoc: 0 fromEvent: e];
8984   return self;
8988 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8989    mouseDragged events without going into a modal loop.  */
8990 - (void)mouseDown: (NSEvent *)e
8992   NSRect sr, kr;
8993   /* hitPart is only updated AFTER event is passed on.  */
8994   NSScrollerPart part = [self testPart: [e locationInWindow]];
8995   CGFloat loc, kloc, pos UNINIT;
8996   int edge = 0;
8998   NSTRACE ("[EmacsScroller mouseDown:]");
9000   switch (part)
9001     {
9002     case NSScrollerDecrementPage:
9003       last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
9004     case NSScrollerIncrementPage:
9005       last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
9006     case NSScrollerDecrementLine:
9007       last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
9008     case NSScrollerIncrementLine:
9009       last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
9010     case NSScrollerKnob:
9011       last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
9012     case NSScrollerKnobSlot:  /* GNUstep-only */
9013       last_hit_part = scroll_bar_move_ratio; break;
9014     default:  /* NSScrollerNoPart? */
9015       fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
9016                (long) part);
9017       return;
9018     }
9020   if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
9021     {
9022       /* handle, or on GNUstep possibly slot */
9023       NSEvent *fake_event;
9024       int length;
9026       /* compute float loc in slot and mouse offset on knob */
9027       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
9028                       toView: nil];
9029       if (horizontal)
9030         {
9031           length = NSWidth (sr);
9032           loc = ([e locationInWindow].x - NSMinX (sr));
9033         }
9034       else
9035         {
9036           length = NSHeight (sr);
9037           loc = length - ([e locationInWindow].y - NSMinY (sr));
9038         }
9040       if (loc <= 0.0)
9041         {
9042           loc = 0.0;
9043           edge = -1;
9044         }
9045       else if (loc >= length)
9046         {
9047           loc = length;
9048           edge = 1;
9049         }
9051       if (edge)
9052         kloc = 0.5 * edge;
9053       else
9054         {
9055           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
9056                           toView: nil];
9057           if (horizontal)
9058             kloc = ([e locationInWindow].x - NSMinX (kr));
9059           else
9060             kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
9061         }
9062       last_mouse_offset = kloc;
9064       /* if knob, tell emacs a location offset by knob pos
9065          (to indicate top of handle) */
9066       if (part == NSScrollerKnob)
9067         pos = (loc - last_mouse_offset);
9068       else
9069         /* else this is a slot click on GNUstep: go straight there */
9070         pos = loc;
9072       /* If there are buttons in the scroller area, we need to
9073          recalculate pos as emacs expects the scroller slot to take up
9074          the entire available length.  */
9075       if (length != pixel_length)
9076         pos = pos * pixel_length / length;
9078       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
9079       fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
9080                                       location: [e locationInWindow]
9081                                  modifierFlags: [e modifierFlags]
9082                                      timestamp: [e timestamp]
9083                                   windowNumber: [e windowNumber]
9084                                        context: nil
9085                                    eventNumber: [e eventNumber]
9086                                     clickCount: [e clickCount]
9087                                       pressure: [e pressure]];
9088       [super mouseUp: fake_event];
9089     }
9090   else
9091     {
9092       pos = 0; /* ignored */
9094       /* Set a timer to repeat, as we can't let superclass do this modally.  */
9095       scroll_repeat_entry
9096         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
9097                                             target: self
9098                                           selector: @selector (repeatScroll:)
9099                                           userInfo: 0
9100                                            repeats: YES]
9101             retain];
9102     }
9104   if (part != NSScrollerKnob)
9105     [self sendScrollEventAtLoc: pos fromEvent: e];
9109 /* Called as we manually track scroller drags, rather than superclass.  */
9110 - (void)mouseDragged: (NSEvent *)e
9112     NSRect sr;
9113     double loc, pos;
9114     int length;
9116     NSTRACE ("[EmacsScroller mouseDragged:]");
9118       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
9119                       toView: nil];
9121       if (horizontal)
9122         {
9123           length = NSWidth (sr);
9124           loc = ([e locationInWindow].x - NSMinX (sr));
9125         }
9126       else
9127         {
9128           length = NSHeight (sr);
9129           loc = length - ([e locationInWindow].y - NSMinY (sr));
9130         }
9132       if (loc <= 0.0)
9133         {
9134           loc = 0.0;
9135         }
9136       else if (loc >= length + last_mouse_offset)
9137         {
9138           loc = length + last_mouse_offset;
9139         }
9141       pos = (loc - last_mouse_offset);
9143       /* If there are buttons in the scroller area, we need to
9144          recalculate pos as emacs expects the scroller slot to take up
9145          the entire available length.  */
9146       if (length != pixel_length)
9147         pos = pos * pixel_length / length;
9149       [self sendScrollEventAtLoc: pos fromEvent: e];
9153 - (void)mouseUp: (NSEvent *)e
9155   NSTRACE ("[EmacsScroller mouseUp:]");
9157   if (scroll_repeat_entry)
9158     {
9159       [scroll_repeat_entry invalidate];
9160       [scroll_repeat_entry release];
9161       scroll_repeat_entry = nil;
9162     }
9163   last_hit_part = scroll_bar_above_handle;
9167 /* Treat scrollwheel events in the bar as though they were in the main window.  */
9168 - (void) scrollWheel: (NSEvent *)theEvent
9170   NSTRACE ("[EmacsScroller scrollWheel:]");
9172   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
9173   [view mouseDown: theEvent];
9176 @end  /* EmacsScroller */
9179 #ifdef NS_IMPL_GNUSTEP
9180 /* Dummy class to get rid of startup warnings.  */
9181 @implementation EmacsDocument
9183 @end
9184 #endif
9187 /* ==========================================================================
9189    Font-related functions; these used to be in nsfaces.m
9191    ========================================================================== */
9194 Lisp_Object
9195 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
9197   struct font *font = XFONT_OBJECT (font_object);
9198   EmacsView *view = FRAME_NS_VIEW (f);
9199   int font_ascent, font_descent;
9201   if (fontset < 0)
9202     fontset = fontset_from_font (font_object);
9203   FRAME_FONTSET (f) = fontset;
9205   if (FRAME_FONT (f) == font)
9206     /* This font is already set in frame F.  There's nothing more to
9207        do.  */
9208     return font_object;
9210   FRAME_FONT (f) = font;
9212   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
9213   FRAME_COLUMN_WIDTH (f) = font->average_width;
9214   get_font_ascent_descent (font, &font_ascent, &font_descent);
9215   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
9217   /* Compute the scroll bar width in character columns.  */
9218   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
9219     {
9220       int wid = FRAME_COLUMN_WIDTH (f);
9221       FRAME_CONFIG_SCROLL_BAR_COLS (f)
9222         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
9223     }
9224   else
9225     {
9226       int wid = FRAME_COLUMN_WIDTH (f);
9227       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
9228     }
9230   /* Compute the scroll bar height in character lines.  */
9231   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
9232     {
9233       int height = FRAME_LINE_HEIGHT (f);
9234       FRAME_CONFIG_SCROLL_BAR_LINES (f)
9235         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
9236     }
9237   else
9238     {
9239       int height = FRAME_LINE_HEIGHT (f);
9240       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
9241     }
9243   /* Now make the frame display the given font.  */
9244   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
9245     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
9246                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
9247                        false, Qfont);
9249   return font_object;
9253 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
9254 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
9255          in 1.43.  */
9257 const char *
9258 ns_xlfd_to_fontname (const char *xlfd)
9259 /* --------------------------------------------------------------------------
9260     Convert an X font name (XLFD) to an NS font name.
9261     Only family is used.
9262     The string returned is temporarily allocated.
9263    -------------------------------------------------------------------------- */
9265   char *name = xmalloc (180);
9266   int i, len;
9267   const char *ret;
9269   if (!strncmp (xlfd, "--", 2))
9270     sscanf (xlfd, "--%*[^-]-%179[^-]-", name);
9271   else
9272     sscanf (xlfd, "-%*[^-]-%179[^-]-", name);
9274   /* stopgap for malformed XLFD input */
9275   if (strlen (name) == 0)
9276     strcpy (name, "Monaco");
9278   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
9279      also uppercase after '-' or ' ' */
9280   name[0] = c_toupper (name[0]);
9281   for (len =strlen (name), i =0; i<len; i++)
9282     {
9283       if (name[i] == '$')
9284         {
9285           name[i] = '-';
9286           if (i+1<len)
9287             name[i+1] = c_toupper (name[i+1]);
9288         }
9289       else if (name[i] == '_')
9290         {
9291           name[i] = ' ';
9292           if (i+1<len)
9293             name[i+1] = c_toupper (name[i+1]);
9294         }
9295     }
9296   /* fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name); */
9297   ret = [[NSString stringWithUTF8String: name] UTF8String];
9298   xfree (name);
9299   return ret;
9303 void
9304 syms_of_nsterm (void)
9306   NSTRACE ("syms_of_nsterm");
9308   ns_antialias_threshold = 10.0;
9310   /* From 23+ we need to tell emacs what modifiers there are.  */
9311   DEFSYM (Qmodifier_value, "modifier-value");
9312   DEFSYM (Qalt, "alt");
9313   DEFSYM (Qhyper, "hyper");
9314   DEFSYM (Qmeta, "meta");
9315   DEFSYM (Qsuper, "super");
9316   DEFSYM (Qcontrol, "control");
9317   DEFSYM (QUTF8_STRING, "UTF8_STRING");
9319   DEFSYM (Qfile, "file");
9320   DEFSYM (Qurl, "url");
9322   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
9323   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
9324   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
9325   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
9326   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
9328   DEFVAR_LISP ("ns-input-file", ns_input_file,
9329               "The file specified in the last NS event.");
9330   ns_input_file =Qnil;
9332   DEFVAR_LISP ("ns-working-text", ns_working_text,
9333               "String for visualizing working composition sequence.");
9334   ns_working_text =Qnil;
9336   DEFVAR_LISP ("ns-input-font", ns_input_font,
9337               "The font specified in the last NS event.");
9338   ns_input_font =Qnil;
9340   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
9341               "The fontsize specified in the last NS event.");
9342   ns_input_fontsize =Qnil;
9344   DEFVAR_LISP ("ns-input-line", ns_input_line,
9345                "The line specified in the last NS event.");
9346   ns_input_line =Qnil;
9348   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9349                "The service name specified in the last NS event.");
9350   ns_input_spi_name =Qnil;
9352   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9353                "The service argument specified in the last NS event.");
9354   ns_input_spi_arg =Qnil;
9356   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9357                "This variable describes the behavior of the alternate or option key.\n\
9358 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9359 that key.\n\
9360 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9361 at all, allowing it to be used at a lower level for accented character entry.");
9362   ns_alternate_modifier = Qmeta;
9364   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9365                "This variable describes the behavior of the right alternate or option key.\n\
9366 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9367 that key.\n\
9368 Set to left means be the same key as `ns-alternate-modifier'.\n\
9369 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9370 at all, allowing it to be used at a lower level for accented character entry.");
9371   ns_right_alternate_modifier = Qleft;
9373   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9374                "This variable describes the behavior of the command key.\n\
9375 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9376 that key.");
9377   ns_command_modifier = Qsuper;
9379   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9380                "This variable describes the behavior of the right command key.\n\
9381 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9382 that key.\n\
9383 Set to left means be the same key as `ns-command-modifier'.\n\
9384 Set to none means that the command / option key is not interpreted by Emacs\n\
9385 at all, allowing it to be used at a lower level for accented character entry.");
9386   ns_right_command_modifier = Qleft;
9388   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9389                "This variable describes the behavior of the control key.\n\
9390 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9391 that key.");
9392   ns_control_modifier = Qcontrol;
9394   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9395                "This variable describes the behavior of the right control key.\n\
9396 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9397 that key.\n\
9398 Set to left means be the same key as `ns-control-modifier'.\n\
9399 Set to none means that the control / option key is not interpreted by Emacs\n\
9400 at all, allowing it to be used at a lower level for accented character entry.");
9401   ns_right_control_modifier = Qleft;
9403   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9404                "This variable describes the behavior of the function key (on laptops).\n\
9405 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9406 that key.\n\
9407 Set to none means that the function key is not interpreted by Emacs at all,\n\
9408 allowing it to be used at a lower level for accented character entry.");
9409   ns_function_modifier = Qnone;
9411   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9412                "Non-nil (the default) means to render text antialiased.");
9413   ns_antialias_text = Qt;
9415   DEFVAR_LISP ("ns-use-thin-smoothing", ns_use_thin_smoothing,
9416                "Non-nil turns on a font smoothing method that produces thinner strokes.");
9417   ns_use_thin_smoothing = Qnil;
9419   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9420                "Whether to confirm application quit using dialog.");
9421   ns_confirm_quit = Qnil;
9423   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9424                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9425 Only works on Mac OS X.  */);
9426   ns_auto_hide_menu_bar = Qnil;
9428   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9429      doc: /* Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9430 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
9431 multiple monitors, but lacks tool bar.  This variable is ignored on
9432 Mac OS X < 10.7.  Default is t.  */);
9433   ns_use_native_fullscreen = YES;
9434   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9436   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9437      doc: /* Non-nil means use animation on non-native fullscreen.
9438 For native fullscreen, this does nothing.
9439 Default is nil.  */);
9440   ns_use_fullscreen_animation = NO;
9442   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9443      doc: /* Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9444 Note that this does not apply to images.
9445 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
9446   ns_use_srgb_colorspace = YES;
9448   DEFVAR_BOOL ("ns-use-mwheel-acceleration",
9449                ns_use_mwheel_acceleration,
9450      doc: /* Non-nil means use macOS's standard mouse wheel acceleration.
9451 This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
9452   ns_use_mwheel_acceleration = YES;
9454   DEFVAR_LISP ("ns-mwheel-line-height", ns_mwheel_line_height,
9455                doc: /* The number of pixels touchpad scrolling considers one line.
9456 Nil or a non-number means use the default frame line height.
9457 This variable is ignored on macOS < 10.7 and GNUstep.  Default is nil.  */);
9458   ns_mwheel_line_height = Qnil;
9460   DEFVAR_BOOL ("ns-use-mwheel-momentum", ns_use_mwheel_momentum,
9461                doc: /* Non-nil means mouse wheel scrolling uses momentum.
9462 This variable is ignored on macOS < 10.7 and GNUstep.  Default is t.  */);
9463   ns_use_mwheel_momentum = YES;
9465   /* TODO: Move to common code.  */
9466   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9467                doc: /* SKIP: real doc in xterm.c.  */);
9468   Vx_toolkit_scroll_bars = Qt;
9470   DEFVAR_BOOL ("x-use-underline-position-properties",
9471                x_use_underline_position_properties,
9472      doc: /* SKIP: real doc in xterm.c.  */);
9473   x_use_underline_position_properties = 0;
9474   DEFSYM (Qx_use_underline_position_properties,
9475           "x-use-underline-position-properties");
9477   DEFVAR_BOOL ("x-underline-at-descent-line",
9478                x_underline_at_descent_line,
9479      doc: /* SKIP: real doc in xterm.c.  */);
9480   x_underline_at_descent_line = 0;
9481   DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line");
9483   /* Tell Emacs about this window system.  */
9484   Fprovide (Qns, Qnil);
9486   DEFSYM (Qcocoa, "cocoa");
9487   DEFSYM (Qgnustep, "gnustep");
9489 #ifdef NS_IMPL_COCOA
9490   Fprovide (Qcocoa, Qnil);
9491   syms_of_macfont ();
9492 #else
9493   Fprovide (Qgnustep, Qnil);
9494   syms_of_nsfont ();
9495 #endif