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