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