; * doc/emacs/search.texi (Word Search): Update for changes in bug#27341.
[emacs.git] / src / nsterm.m
bloba3c7031331a2c555d12a41316d2af6f2f83debb6
1 /* NeXT/Open/GNUstep / macOS communication module.      -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2017 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 macOS/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
41 #include <c-ctype.h>
42 #include <c-strcase.h>
43 #include <ftoastr.h>
45 #include "lisp.h"
46 #include "blockinput.h"
47 #include "sysselect.h"
48 #include "nsterm.h"
49 #include "systime.h"
50 #include "character.h"
51 #include "fontset.h"
52 #include "composite.h"
53 #include "ccl.h"
55 #include "termhooks.h"
56 #include "termchar.h"
57 #include "menu.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "buffer.h"
61 #include "font.h"
63 #ifdef NS_IMPL_GNUSTEP
64 #include "process.h"
65 #endif
67 #ifdef NS_IMPL_COCOA
68 #include "macfont.h"
69 #endif
71 static EmacsMenu *dockMenu;
72 #ifdef NS_IMPL_COCOA
73 static EmacsMenu *mainMenu;
74 #endif
76 /* ==========================================================================
78    NSTRACE, Trace support.
80    ========================================================================== */
82 #if NSTRACE_ENABLED
84 /* The following use "volatile" since they can be accessed from
85    parallel threads. */
86 volatile int nstrace_num = 0;
87 volatile int nstrace_depth = 0;
89 /* When 0, no trace is emitted.  This is used by NSTRACE_WHEN and
90    NSTRACE_UNLESS to silence functions called.
92    TODO: This should really be a thread-local variable, to avoid that
93    a function with disabled trace thread silence trace output in
94    another.  However, in practice this seldom is a problem. */
95 volatile int nstrace_enabled_global = 1;
97 /* Called when nstrace_enabled goes out of scope. */
98 void nstrace_leave(int * pointer_to_nstrace_enabled)
100   if (*pointer_to_nstrace_enabled)
101     {
102       --nstrace_depth;
103     }
107 /* Called when nstrace_saved_enabled_global goes out of scope. */
108 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
110   nstrace_enabled_global = *pointer_to_saved_enabled_global;
114 char const * nstrace_fullscreen_type_name (int fs_type)
116   switch (fs_type)
117     {
118     case -1:                   return "-1";
119     case FULLSCREEN_NONE:      return "FULLSCREEN_NONE";
120     case FULLSCREEN_WIDTH:     return "FULLSCREEN_WIDTH";
121     case FULLSCREEN_HEIGHT:    return "FULLSCREEN_HEIGHT";
122     case FULLSCREEN_BOTH:      return "FULLSCREEN_BOTH";
123     case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
124     default:                   return "FULLSCREEN_?????";
125     }
127 #endif
130 /* ==========================================================================
132    NSColor, EmacsColor category.
134    ========================================================================== */
135 @implementation NSColor (EmacsColor)
136 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
137                          blue:(CGFloat)blue alpha:(CGFloat)alpha
139 #ifdef NS_IMPL_COCOA
140 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
141   if (ns_use_srgb_colorspace)
142       return [NSColor colorWithSRGBRed: red
143                                  green: green
144                                   blue: blue
145                                  alpha: alpha];
146 #endif
147 #endif
148   return [NSColor colorWithCalibratedRed: red
149                                    green: green
150                                     blue: blue
151                                    alpha: alpha];
154 - (NSColor *)colorUsingDefaultColorSpace
156 #ifdef NS_IMPL_COCOA
157 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
158   if (ns_use_srgb_colorspace)
159     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
160 #endif
161 #endif
162   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
165 @end
167 /* ==========================================================================
169     Local declarations
171    ========================================================================== */
173 /* Convert a symbol indexed with an NSxxx value to a value as defined
174    in keyboard.c (lispy_function_key). I hope this is a correct way
175    of doing things... */
176 static unsigned convert_ns_to_X_keysym[] =
178   NSHomeFunctionKey,            0x50,
179   NSLeftArrowFunctionKey,       0x51,
180   NSUpArrowFunctionKey,         0x52,
181   NSRightArrowFunctionKey,      0x53,
182   NSDownArrowFunctionKey,       0x54,
183   NSPageUpFunctionKey,          0x55,
184   NSPageDownFunctionKey,        0x56,
185   NSEndFunctionKey,             0x57,
186   NSBeginFunctionKey,           0x58,
187   NSSelectFunctionKey,          0x60,
188   NSPrintFunctionKey,           0x61,
189   NSClearLineFunctionKey,       0x0B,
190   NSExecuteFunctionKey,         0x62,
191   NSInsertFunctionKey,          0x63,
192   NSUndoFunctionKey,            0x65,
193   NSRedoFunctionKey,            0x66,
194   NSMenuFunctionKey,            0x67,
195   NSFindFunctionKey,            0x68,
196   NSHelpFunctionKey,            0x6A,
197   NSBreakFunctionKey,           0x6B,
199   NSF1FunctionKey,              0xBE,
200   NSF2FunctionKey,              0xBF,
201   NSF3FunctionKey,              0xC0,
202   NSF4FunctionKey,              0xC1,
203   NSF5FunctionKey,              0xC2,
204   NSF6FunctionKey,              0xC3,
205   NSF7FunctionKey,              0xC4,
206   NSF8FunctionKey,              0xC5,
207   NSF9FunctionKey,              0xC6,
208   NSF10FunctionKey,             0xC7,
209   NSF11FunctionKey,             0xC8,
210   NSF12FunctionKey,             0xC9,
211   NSF13FunctionKey,             0xCA,
212   NSF14FunctionKey,             0xCB,
213   NSF15FunctionKey,             0xCC,
214   NSF16FunctionKey,             0xCD,
215   NSF17FunctionKey,             0xCE,
216   NSF18FunctionKey,             0xCF,
217   NSF19FunctionKey,             0xD0,
218   NSF20FunctionKey,             0xD1,
219   NSF21FunctionKey,             0xD2,
220   NSF22FunctionKey,             0xD3,
221   NSF23FunctionKey,             0xD4,
222   NSF24FunctionKey,             0xD5,
224   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
225   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
226   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
228   NSTabCharacter,               0x09,
229   0x19,                         0x09,  /* left tab->regular since pass shift */
230   NSCarriageReturnCharacter,    0x0D,
231   NSNewlineCharacter,           0x0D,
232   NSEnterCharacter,             0x8D,
234   0x41|NSEventModifierFlagNumericPad,   0xAE,  /* KP_Decimal */
235   0x43|NSEventModifierFlagNumericPad,   0xAA,  /* KP_Multiply */
236   0x45|NSEventModifierFlagNumericPad,   0xAB,  /* KP_Add */
237   0x4B|NSEventModifierFlagNumericPad,   0xAF,  /* KP_Divide */
238   0x4E|NSEventModifierFlagNumericPad,   0xAD,  /* KP_Subtract */
239   0x51|NSEventModifierFlagNumericPad,   0xBD,  /* KP_Equal */
240   0x52|NSEventModifierFlagNumericPad,   0xB0,  /* KP_0 */
241   0x53|NSEventModifierFlagNumericPad,   0xB1,  /* KP_1 */
242   0x54|NSEventModifierFlagNumericPad,   0xB2,  /* KP_2 */
243   0x55|NSEventModifierFlagNumericPad,   0xB3,  /* KP_3 */
244   0x56|NSEventModifierFlagNumericPad,   0xB4,  /* KP_4 */
245   0x57|NSEventModifierFlagNumericPad,   0xB5,  /* KP_5 */
246   0x58|NSEventModifierFlagNumericPad,   0xB6,  /* KP_6 */
247   0x59|NSEventModifierFlagNumericPad,   0xB7,  /* KP_7 */
248   0x5B|NSEventModifierFlagNumericPad,   0xB8,  /* KP_8 */
249   0x5C|NSEventModifierFlagNumericPad,   0xB9,  /* KP_9 */
251   0x1B,                         0x1B   /* escape */
254 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
255    the maximum font size to NOT antialias.  On GNUstep there is currently
256    no way to control this behavior. */
257 float ns_antialias_threshold;
259 NSArray *ns_send_types = 0, *ns_return_types = 0;
260 static NSArray *ns_drag_types = 0;
261 NSString *ns_app_name = @"Emacs";  /* default changed later */
263 /* Display variables */
264 struct ns_display_info *x_display_list; /* Chain of existing displays */
265 long context_menu_value = 0;
267 /* display update */
268 static struct frame *ns_updating_frame;
269 static NSView *focus_view = NULL;
270 static int ns_window_num = 0;
271 #ifdef NS_IMPL_GNUSTEP
272 static NSRect uRect;            // TODO: This is dead, remove it?
273 #endif
274 static BOOL gsaved = NO;
275 static BOOL ns_fake_keydown = NO;
276 #ifdef NS_IMPL_COCOA
277 static BOOL ns_menu_bar_is_hidden = NO;
278 #endif
279 /*static int debug_lock = 0; */
281 /* event loop */
282 static BOOL send_appdefined = YES;
283 #define NO_APPDEFINED_DATA (-8)
284 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
285 static NSTimer *timed_entry = 0;
286 static NSTimer *scroll_repeat_entry = nil;
287 static fd_set select_readfds, select_writefds;
288 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
289 static int select_nfds = 0, select_valid = 0;
290 static struct timespec select_timeout = { 0, 0 };
291 static int selfds[2] = { -1, -1 };
292 static pthread_mutex_t select_mutex;
293 static NSAutoreleasePool *outerpool;
294 static struct input_event *emacs_event = NULL;
295 static struct input_event *q_event_ptr = NULL;
296 static int n_emacs_events_pending = 0;
297 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
298   *ns_pending_service_args;
299 static BOOL ns_do_open_file = NO;
300 static BOOL ns_last_use_native_fullscreen;
302 /* Non-zero means that a HELP_EVENT has been generated since Emacs
303    start.  */
305 static BOOL any_help_event_p = NO;
307 static struct {
308   struct input_event *q;
309   int nr, cap;
310 } hold_event_q = {
311   NULL, 0, 0
314 static NSString *represented_filename = nil;
315 static struct frame *represented_frame = 0;
317 #ifdef NS_IMPL_COCOA
319  * State for pending menu activation:
320  * MENU_NONE     Normal state
321  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
322  *               run lisp to update the menu.
323  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
324  *               will open.
325  */
326 #define MENU_NONE 0
327 #define MENU_PENDING 1
328 #define MENU_OPENING 2
329 static int menu_will_open_state = MENU_NONE;
331 /* Saved position for menu click.  */
332 static CGPoint menu_mouse_point;
333 #endif
335 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
336 #define NS_FUNCTION_KEY_MASK 0x800000
337 #define NSLeftControlKeyMask    (0x000001 | NSEventModifierFlagControl)
338 #define NSRightControlKeyMask   (0x002000 | NSEventModifierFlagControl)
339 #define NSLeftCommandKeyMask    (0x000008 | NSEventModifierFlagCommand)
340 #define NSRightCommandKeyMask   (0x000010 | NSEventModifierFlagCommand)
341 #define NSLeftAlternateKeyMask  (0x000020 | NSEventModifierFlagOption)
342 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
343 #define EV_MODIFIERS2(flags)                          \
344     (((flags & NSEventModifierFlagHelp) ?           \
345            hyper_modifier : 0)                        \
346      | (!EQ (ns_right_alternate_modifier, Qleft) && \
347         ((flags & NSRightAlternateKeyMask) \
348          == NSRightAlternateKeyMask) ? \
349            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
350      | ((flags & NSEventModifierFlagOption) ?                 \
351            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
352      | ((flags & NSEventModifierFlagShift) ?     \
353            shift_modifier : 0)                        \
354      | (!EQ (ns_right_control_modifier, Qleft) && \
355         ((flags & NSRightControlKeyMask) \
356          == NSRightControlKeyMask) ? \
357            parse_solitary_modifier (ns_right_control_modifier) : 0) \
358      | ((flags & NSEventModifierFlagControl) ?      \
359            parse_solitary_modifier (ns_control_modifier) : 0)     \
360      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
361            parse_solitary_modifier (ns_function_modifier) : 0)    \
362      | (!EQ (ns_right_command_modifier, Qleft) && \
363         ((flags & NSRightCommandKeyMask) \
364          == NSRightCommandKeyMask) ? \
365            parse_solitary_modifier (ns_right_command_modifier) : 0) \
366      | ((flags & NSEventModifierFlagCommand) ?      \
367            parse_solitary_modifier (ns_command_modifier):0))
368 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
370 #define EV_UDMODIFIERS(e)                                      \
371     ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0)       \
372      | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0)    \
373      | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0)    \
374      | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0)  \
375      | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
376      | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
377      | (([e type] == NSEventTypeLeftMouseUp)   ? up_modifier   : 0)     \
378      | (([e type] == NSEventTypeRightMouseUp)   ? up_modifier   : 0)    \
379      | (([e type] == NSEventTypeOtherMouseUp)   ? up_modifier   : 0))
381 #define EV_BUTTON(e)                                                         \
382     ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 :    \
383       (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
384      [e buttonNumber] - 1)
386 /* Convert the time field to a timestamp in milliseconds. */
387 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
389 /* This is a piece of code which is common to all the event handling
390    methods.  Maybe it should even be a function.  */
391 #define EV_TRAILER(e)                                                   \
392   {                                                                     \
393     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
394     EV_TRAILER2 (e);                                                    \
395   }
397 #define EV_TRAILER2(e)                                                  \
398   {                                                                     \
399       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
400       if (q_event_ptr)                                                  \
401         {                                                               \
402           Lisp_Object tem = Vinhibit_quit;                              \
403           Vinhibit_quit = Qt;                                           \
404           n_emacs_events_pending++;                                     \
405           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
406           Vinhibit_quit = tem;                                          \
407         }                                                               \
408       else                                                              \
409         hold_event (emacs_event);                                       \
410       EVENT_INIT (*emacs_event);                                        \
411       ns_send_appdefined (-1);                                          \
412     }
415 /* GNUstep always shows decorations if the window is resizable,
416    miniaturizable or closable, but Cocoa does strange things in native
417    fullscreen mode if you don't have at least resizable enabled.
419    These flags will be OR'd or XOR'd with the NSWindow's styleMask
420    property depending on what we're doing. */
421 #ifdef NS_IMPL_COCOA
422 #define FRAME_DECORATED_FLAGS NSWindowStyleMaskTitled
423 #else
424 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled              \
425                                | NSWindowStyleMaskResizable         \
426                                | NSWindowStyleMaskMiniaturizable    \
427                                | NSWindowStyleMaskClosable)
428 #endif
429 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
431 /* TODO: get rid of need for these forward declarations */
432 static void ns_condemn_scroll_bars (struct frame *f);
433 static void ns_judge_scroll_bars (struct frame *f);
436 /* ==========================================================================
438     Utilities
440    ========================================================================== */
442 void
443 ns_set_represented_filename (NSString *fstr, struct frame *f)
445   represented_filename = [fstr retain];
446   represented_frame = f;
449 void
450 ns_init_events (struct input_event *ev)
452   EVENT_INIT (*ev);
453   emacs_event = ev;
456 void
457 ns_finish_events (void)
459   emacs_event = NULL;
462 static void
463 hold_event (struct input_event *event)
465   if (hold_event_q.nr == hold_event_q.cap)
466     {
467       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
468       else hold_event_q.cap *= 2;
469       hold_event_q.q =
470         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
471     }
473   hold_event_q.q[hold_event_q.nr++] = *event;
474   /* Make sure ns_read_socket is called, i.e. we have input.  */
475   raise (SIGIO);
476   send_appdefined = YES;
479 static Lisp_Object
480 append2 (Lisp_Object list, Lisp_Object item)
481 /* --------------------------------------------------------------------------
482    Utility to append to a list
483    -------------------------------------------------------------------------- */
485   return CALLN (Fnconc, list, list1 (item));
489 const char *
490 ns_etc_directory (void)
491 /* If running as a self-contained app bundle, return as a string the
492    filename of the etc directory, if present; else nil.  */
494   NSBundle *bundle = [NSBundle mainBundle];
495   NSString *resourceDir = [bundle resourcePath];
496   NSString *resourcePath;
497   NSFileManager *fileManager = [NSFileManager defaultManager];
498   BOOL isDir;
500   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
501   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
502     {
503       if (isDir) return [resourcePath UTF8String];
504     }
505   return NULL;
509 const char *
510 ns_exec_path (void)
511 /* If running as a self-contained app bundle, return as a path string
512    the filenames of the libexec and bin directories, ie libexec:bin.
513    Otherwise, return nil.
514    Normally, Emacs does not add its own bin/ directory to the PATH.
515    However, a self-contained NS build has a different layout, with
516    bin/ and libexec/ subdirectories in the directory that contains
517    Emacs.app itself.
518    We put libexec first, because init_callproc_1 uses the first
519    element to initialize exec-directory.  An alternative would be
520    for init_callproc to check for invocation-directory/libexec.
523   NSBundle *bundle = [NSBundle mainBundle];
524   NSString *resourceDir = [bundle resourcePath];
525   NSString *binDir = [bundle bundlePath];
526   NSString *resourcePath, *resourcePaths;
527   NSRange range;
528   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
529   NSFileManager *fileManager = [NSFileManager defaultManager];
530   NSArray *paths;
531   NSEnumerator *pathEnum;
532   BOOL isDir;
534   range = [resourceDir rangeOfString: @"Contents"];
535   if (range.location != NSNotFound)
536     {
537       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
538 #ifdef NS_IMPL_COCOA
539       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
540 #endif
541     }
543   paths = [binDir stringsByAppendingPaths:
544                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
545   pathEnum = [paths objectEnumerator];
546   resourcePaths = @"";
548   while ((resourcePath = [pathEnum nextObject]))
549     {
550       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
551         if (isDir)
552           {
553             if ([resourcePaths length] > 0)
554               resourcePaths
555                 = [resourcePaths stringByAppendingString: pathSeparator];
556             resourcePaths
557               = [resourcePaths stringByAppendingString: resourcePath];
558           }
559     }
560   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
562   return NULL;
566 const char *
567 ns_load_path (void)
568 /* If running as a self-contained app bundle, return as a path string
569    the filenames of the site-lisp and lisp directories.
570    Ie, site-lisp:lisp.  Otherwise, return nil.  */
572   NSBundle *bundle = [NSBundle mainBundle];
573   NSString *resourceDir = [bundle resourcePath];
574   NSString *resourcePath, *resourcePaths;
575   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
576   NSFileManager *fileManager = [NSFileManager defaultManager];
577   BOOL isDir;
578   NSArray *paths = [resourceDir stringsByAppendingPaths:
579                               [NSArray arrayWithObjects:
580                                          @"site-lisp", @"lisp", nil]];
581   NSEnumerator *pathEnum = [paths objectEnumerator];
582   resourcePaths = @"";
584   /* Hack to skip site-lisp.  */
585   if (no_site_lisp) resourcePath = [pathEnum nextObject];
587   while ((resourcePath = [pathEnum nextObject]))
588     {
589       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
590         if (isDir)
591           {
592             if ([resourcePaths length] > 0)
593               resourcePaths
594                 = [resourcePaths stringByAppendingString: pathSeparator];
595             resourcePaths
596               = [resourcePaths stringByAppendingString: resourcePath];
597           }
598     }
599   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
601   return NULL;
605 void
606 ns_init_locale (void)
607 /* macOS doesn't set any environment variables for the locale when run
608    from the GUI. Get the locale from the OS and set LANG. */
610   NSLocale *locale = [NSLocale currentLocale];
612   NSTRACE ("ns_init_locale");
614   @try
615     {
616       /* It seems macOS should probably use UTF-8 everywhere.
617          'localeIdentifier' does not specify the encoding, and I can't
618          find any way to get the OS to tell us which encoding to use,
619          so hard-code '.UTF-8'. */
620       NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
621                                      [locale localeIdentifier]];
623       /* Set LANG to locale, but not if LANG is already set. */
624       setenv("LANG", [localeID UTF8String], 0);
625     }
626   @catch (NSException *e)
627     {
628       NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
629     }
633 void
634 ns_release_object (void *obj)
635 /* --------------------------------------------------------------------------
636     Release an object (callable from C)
637    -------------------------------------------------------------------------- */
639     [(id)obj release];
643 void
644 ns_retain_object (void *obj)
645 /* --------------------------------------------------------------------------
646     Retain an object (callable from C)
647    -------------------------------------------------------------------------- */
649     [(id)obj retain];
653 void *
654 ns_alloc_autorelease_pool (void)
655 /* --------------------------------------------------------------------------
656      Allocate a pool for temporary objects (callable from C)
657    -------------------------------------------------------------------------- */
659   return [[NSAutoreleasePool alloc] init];
663 void
664 ns_release_autorelease_pool (void *pool)
665 /* --------------------------------------------------------------------------
666      Free a pool and temporary objects it refers to (callable from C)
667    -------------------------------------------------------------------------- */
669   ns_release_object (pool);
673 static BOOL
674 ns_menu_bar_should_be_hidden (void)
675 /* True, if the menu bar should be hidden.  */
677   return !NILP (ns_auto_hide_menu_bar)
678     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
682 struct EmacsMargins
684   CGFloat top;
685   CGFloat bottom;
686   CGFloat left;
687   CGFloat right;
691 static struct EmacsMargins
692 ns_screen_margins (NSScreen *screen)
693 /* The parts of SCREEN used by the operating system.  */
695   NSTRACE ("ns_screen_margins");
697   struct EmacsMargins margins;
699   NSRect screenFrame = [screen frame];
700   NSRect screenVisibleFrame = [screen visibleFrame];
702   /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
703      menu bar, check this explicitly.  */
704   if (ns_menu_bar_should_be_hidden())
705     {
706       margins.top = 0;
707     }
708   else
709     {
710       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
711       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
712                                  + screenVisibleFrame.size.height);
714       margins.top = frameTop - visibleFrameTop;
715     }
717   {
718     CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
719     CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
720                                  + screenVisibleFrame.size.width);
721     margins.right = frameRight - visibleFrameRight;
722   }
724   margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
725   margins.left   = screenVisibleFrame.origin.x - screenFrame.origin.x;
727   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
728                margins.left,
729                margins.right,
730                margins.top,
731                margins.bottom);
733   return margins;
737 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
738    assumed to contain a hidden dock.  macOS currently use 4 pixels for
739    this, however, to be future compatible, a larger value is used.  */
740 #define DOCK_IGNORE_LIMIT 6
742 static struct EmacsMargins
743 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
744 /* The parts of SCREEN used by the operating system, excluding the parts
745 reserved for an hidden dock.  */
747   NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
749   struct EmacsMargins margins = ns_screen_margins(screen);
751   /* macOS (currently) reserved 4 pixels along the edge where a hidden
752      dock is located.  Unfortunately, it's not possible to find the
753      location and information about if the dock is hidden.  Instead,
754      it is assumed that if the margin of an edge is less than
755      DOCK_IGNORE_LIMIT, it contains a hidden dock.  */
756   if (margins.left <= DOCK_IGNORE_LIMIT)
757     {
758       margins.left = 0;
759     }
760   if (margins.right <= DOCK_IGNORE_LIMIT)
761     {
762       margins.right = 0;
763     }
764   if (margins.top <= DOCK_IGNORE_LIMIT)
765     {
766       margins.top = 0;
767     }
768   /* Note: This doesn't occur in current versions of macOS, but
769      included for completeness and future compatibility.  */
770   if (margins.bottom <= DOCK_IGNORE_LIMIT)
771     {
772       margins.bottom = 0;
773     }
775   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
776                margins.left,
777                margins.right,
778                margins.top,
779                margins.bottom);
781   return margins;
785 static CGFloat
786 ns_menu_bar_height (NSScreen *screen)
787 /* The height of the menu bar, if visible.
789    Note: Don't use this when fullscreen is enabled -- the screen
790    sometimes includes, sometimes excludes the menu bar area.  */
792   struct EmacsMargins margins = ns_screen_margins(screen);
794   CGFloat res = margins.top;
796   NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
798   return res;
802 /* ==========================================================================
804     Focus (clipping) and screen update
806    ========================================================================== */
809 // Window constraining
810 // -------------------
812 // To ensure that the windows are not placed under the menu bar, they
813 // are typically moved by the call-back constrainFrameRect. However,
814 // by overriding it, it's possible to inhibit this, leaving the window
815 // in it's original position.
817 // It's possible to hide the menu bar. However, technically, it's only
818 // possible to hide it when the application is active. To ensure that
819 // this work properly, the menu bar and window constraining are
820 // deferred until the application becomes active.
822 // Even though it's not possible to manually move a window above the
823 // top of the screen, it is allowed if it's done programmatically,
824 // when the menu is hidden. This allows the editable area to cover the
825 // full screen height.
827 // Test cases
828 // ----------
830 // Use the following extra files:
832 //    init.el:
833 //       ;; Hide menu and place frame slightly above the top of the screen.
834 //       (setq ns-auto-hide-menu-bar t)
835 //       (set-frame-position (selected-frame) 0 -20)
837 // Test 1:
839 //    emacs -Q -l init.el
841 //    Result: No menu bar, and the title bar should be above the screen.
843 // Test 2:
845 //    emacs -Q
847 //    Result: Menu bar visible, frame placed immediately below the menu.
850 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
852   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
853              NSTRACE_ARG_RECT (frameRect));
855   // --------------------
856   // Collect information about the screen the frame is covering.
857   //
859   NSArray *screens = [NSScreen screens];
860   NSUInteger nr_screens = [screens count];
862   int i;
864   // The height of the menu bar, if present in any screen the frame is
865   // displayed in.
866   int menu_bar_height = 0;
868   // A rectangle covering all the screen the frame is displayed in.
869   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
870   for (i = 0; i < nr_screens; ++i )
871     {
872       NSScreen *s = [screens objectAtIndex: i];
873       NSRect scrRect = [s frame];
875       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
876                    i, NSTRACE_ARG_RECT (scrRect));
878       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
879         {
880           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
882           if (!isFullscreen)
883             {
884               CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
885               menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
886             }
887         }
888     }
890   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
892   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
894   if (multiscreenRect.size.width == 0
895       || multiscreenRect.size.height == 0)
896     {
897       // Failed to find any monitor, give up.
898       NSTRACE_MSG ("multiscreenRect empty");
899       NSTRACE_RETURN_RECT (frameRect);
900       return frameRect;
901     }
904   // --------------------
905   // Find a suitable placement.
906   //
908   if (ns_menu_bar_should_be_hidden())
909     {
910       // When the menu bar is hidden, the user may place part of the
911       // frame above the top of the screen, for example to hide the
912       // title bar.
913       //
914       // Hence, keep the original position.
915     }
916   else
917     {
918       // Ensure that the frame is below the menu bar, or below the top
919       // of the screen.
920       //
921       // This assume that the menu bar is placed at the top in the
922       // rectangle that covers the monitors.  (It doesn't have to be,
923       // but if it's not it's hard to do anything useful.)
924       CGFloat topOfWorkArea = (multiscreenRect.origin.y
925                                + multiscreenRect.size.height
926                                - menu_bar_height);
928       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
929       if (topOfFrame > topOfWorkArea)
930         {
931           frameRect.origin.y -= topOfFrame - topOfWorkArea;
932           NSTRACE_RECT ("After placement adjust", frameRect);
933         }
934     }
936   // Include the following section to restrict frame to the screens.
937   // (If so, update it to allow the frame to stretch down below the
938   // screen.)
939 #if 0
940   // --------------------
941   // Ensure frame doesn't stretch below the screens.
942   //
944   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
946   if (diff > 0)
947     {
948       frameRect.origin.y = multiscreenRect.origin.y;
949       frameRect.size.height -= diff;
950     }
951 #endif
953   NSTRACE_RETURN_RECT (frameRect);
954   return frameRect;
958 static void
959 ns_constrain_all_frames (void)
960 /* --------------------------------------------------------------------------
961      Ensure that the menu bar doesn't cover any frames.
962    -------------------------------------------------------------------------- */
964   Lisp_Object tail, frame;
966   NSTRACE ("ns_constrain_all_frames");
968   block_input ();
970   FOR_EACH_FRAME (tail, frame)
971     {
972       struct frame *f = XFRAME (frame);
973       if (FRAME_NS_P (f))
974         {
975           EmacsView *view = FRAME_NS_VIEW (f);
977           if (![view isFullscreen])
978             {
979               [[view window]
980                 setFrame:constrain_frame_rect([[view window] frame], false)
981                  display:NO];
982             }
983         }
984     }
986   unblock_input ();
990 static void
991 ns_update_auto_hide_menu_bar (void)
992 /* --------------------------------------------------------------------------
993      Show or hide the menu bar, based on user setting.
994    -------------------------------------------------------------------------- */
996 #ifdef NS_IMPL_COCOA
997   NSTRACE ("ns_update_auto_hide_menu_bar");
999   block_input ();
1001   if (NSApp != nil && [NSApp isActive])
1002     {
1003       // Note, "setPresentationOptions" triggers an error unless the
1004       // application is active.
1005       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1007       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1008         {
1009           NSApplicationPresentationOptions options
1010             = NSApplicationPresentationDefault;
1012           if (menu_bar_should_be_hidden)
1013             options |= NSApplicationPresentationAutoHideMenuBar
1014               | NSApplicationPresentationAutoHideDock;
1016           [NSApp setPresentationOptions: options];
1018           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1020           if (!ns_menu_bar_is_hidden)
1021             {
1022               ns_constrain_all_frames ();
1023             }
1024         }
1025     }
1027   unblock_input ();
1028 #endif
1032 static void
1033 ns_update_begin (struct frame *f)
1034 /* --------------------------------------------------------------------------
1035    Prepare for a grouped sequence of drawing calls
1036    external (RIF) call; whole frame, called before update_window_begin
1037    -------------------------------------------------------------------------- */
1039   EmacsView *view = FRAME_NS_VIEW (f);
1040   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1042   ns_update_auto_hide_menu_bar ();
1044 #ifdef NS_IMPL_COCOA
1045   if ([view isFullscreen] && [view fsIsNative])
1046   {
1047     // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1048     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1049     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1050     if (! tbar_visible != ! [toolbar isVisible])
1051       [toolbar setVisible: tbar_visible];
1052   }
1053 #endif
1055   ns_updating_frame = f;
1056   [view lockFocus];
1058   /* drawRect may have been called for say the minibuffer, and then clip path
1059      is for the minibuffer.  But the display engine may draw more because
1060      we have set the frame as garbaged.  So reset clip path to the whole
1061      view.  */
1062 #ifdef NS_IMPL_COCOA
1063   {
1064     NSBezierPath *bp;
1065     NSRect r = [view frame];
1066     NSRect cr = [[view window] frame];
1067     /* If a large frame size is set, r may be larger than the window frame
1068        before constrained.  In that case don't change the clip path, as we
1069        will clear in to the tool bar and title bar.  */
1070     if (r.size.height
1071         + FRAME_NS_TITLEBAR_HEIGHT (f)
1072         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1073       {
1074         bp = [[NSBezierPath bezierPathWithRect: r] retain];
1075         [bp setClip];
1076         [bp release];
1077       }
1078   }
1079 #endif
1081 #ifdef NS_IMPL_GNUSTEP
1082   uRect = NSMakeRect (0, 0, 0, 0);
1083 #endif
1087 static void
1088 ns_update_window_begin (struct window *w)
1089 /* --------------------------------------------------------------------------
1090    Prepare for a grouped sequence of drawing calls
1091    external (RIF) call; for one window, called after update_begin
1092    -------------------------------------------------------------------------- */
1094   struct frame *f = XFRAME (WINDOW_FRAME (w));
1095   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1097   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1098   w->output_cursor = w->cursor;
1100   block_input ();
1102   if (f == hlinfo->mouse_face_mouse_frame)
1103     {
1104       /* Don't do highlighting for mouse motion during the update.  */
1105       hlinfo->mouse_face_defer = 1;
1107         /* If the frame needs to be redrawn,
1108            simply forget about any prior mouse highlighting.  */
1109       if (FRAME_GARBAGED_P (f))
1110         hlinfo->mouse_face_window = Qnil;
1112       /* (further code for mouse faces ifdef'd out in other terms elided) */
1113     }
1115   unblock_input ();
1119 static void
1120 ns_update_window_end (struct window *w, bool cursor_on_p,
1121                       bool mouse_face_overwritten_p)
1122 /* --------------------------------------------------------------------------
1123    Finished a grouped sequence of drawing calls
1124    external (RIF) call; for one window called before update_end
1125    -------------------------------------------------------------------------- */
1127   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1129   /* note: this fn is nearly identical in all terms */
1130   if (!w->pseudo_window_p)
1131     {
1132       block_input ();
1134       if (cursor_on_p)
1135         display_and_set_cursor (w, 1,
1136                                 w->output_cursor.hpos, w->output_cursor.vpos,
1137                                 w->output_cursor.x, w->output_cursor.y);
1139       if (draw_window_fringes (w, 1))
1140         {
1141           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1142             x_draw_right_divider (w);
1143           else
1144             x_draw_vertical_border (w);
1145         }
1147       unblock_input ();
1148     }
1150   /* If a row with mouse-face was overwritten, arrange for
1151      frame_up_to_date to redisplay the mouse highlight.  */
1152   if (mouse_face_overwritten_p)
1153     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1157 static void
1158 ns_update_end (struct frame *f)
1159 /* --------------------------------------------------------------------------
1160    Finished a grouped sequence of drawing calls
1161    external (RIF) call; for whole frame, called after update_window_end
1162    -------------------------------------------------------------------------- */
1164   EmacsView *view = FRAME_NS_VIEW (f);
1166   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1168 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1169   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1171   block_input ();
1173   [view unlockFocus];
1174   [[view window] flushWindow];
1176   unblock_input ();
1177   ns_updating_frame = NULL;
1180 static void
1181 ns_focus (struct frame *f, NSRect *r, int n)
1182 /* --------------------------------------------------------------------------
1183    Internal: Focus on given frame.  During small local updates this is used to
1184      draw, however during large updates, ns_update_begin and ns_update_end are
1185      called to wrap the whole thing, in which case these calls are stubbed out.
1186      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1187      the back end won't do this automatically, and will just end up flushing
1188      the entire window.
1189    -------------------------------------------------------------------------- */
1191   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1192   if (r != NULL)
1193     {
1194       NSTRACE_RECT ("r", *r);
1195     }
1197   if (f != ns_updating_frame)
1198     {
1199       NSView *view = FRAME_NS_VIEW (f);
1200       if (view != focus_view)
1201         {
1202           if (focus_view != NULL)
1203             {
1204               [focus_view unlockFocus];
1205               [[focus_view window] flushWindow];
1206 /*debug_lock--; */
1207             }
1209           if (view)
1210             [view lockFocus];
1211           focus_view = view;
1212 /*if (view) debug_lock++; */
1213         }
1214     }
1216   /* clipping */
1217   if (r)
1218     {
1219       [[NSGraphicsContext currentContext] saveGraphicsState];
1220       if (n == 2)
1221         NSRectClipList (r, 2);
1222       else
1223         NSRectClip (*r);
1224       gsaved = YES;
1225     }
1229 static void
1230 ns_unfocus (struct frame *f)
1231 /* --------------------------------------------------------------------------
1232      Internal: Remove focus on given frame
1233    -------------------------------------------------------------------------- */
1235   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1237   if (gsaved)
1238     {
1239       [[NSGraphicsContext currentContext] restoreGraphicsState];
1240       gsaved = NO;
1241     }
1243   if (f != ns_updating_frame)
1244     {
1245       if (focus_view != NULL)
1246         {
1247           [focus_view unlockFocus];
1248           [[focus_view window] flushWindow];
1249           focus_view = NULL;
1250 /*debug_lock--; */
1251         }
1252     }
1256 static void
1257 ns_clip_to_row (struct window *w, struct glyph_row *row,
1258                 enum glyph_row_area area, BOOL gc)
1259 /* --------------------------------------------------------------------------
1260      Internal (but parallels other terms): Focus drawing on given row
1261    -------------------------------------------------------------------------- */
1263   struct frame *f = XFRAME (WINDOW_FRAME (w));
1264   NSRect clip_rect;
1265   int window_x, window_y, window_width;
1267   window_box (w, area, &window_x, &window_y, &window_width, 0);
1269   clip_rect.origin.x = window_x;
1270   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1271   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1272   clip_rect.size.width = window_width;
1273   clip_rect.size.height = row->visible_height;
1275   ns_focus (f, &clip_rect, 1);
1279 /* ==========================================================================
1281     Visible bell and beep.
1283    ========================================================================== */
1286 // This bell implementation shows the visual bell image asynchronously
1287 // from the rest of Emacs. This is done by adding a NSView to the
1288 // superview of the Emacs window and removing it using a timer.
1290 // Unfortunately, some Emacs operations, like scrolling, is done using
1291 // low-level primitives that copy the content of the window, including
1292 // the bell image. To some extent, this is handled by removing the
1293 // image prior to scrolling and marking that the window is in need for
1294 // redisplay.
1296 // To test this code, make sure that there is no artifacts of the bell
1297 // image in the following situations. Use a non-empty buffer (like the
1298 // tutorial) to ensure that a scroll is performed:
1300 // * Single-window: C-g C-v
1302 // * Side-by-windows: C-x 3 C-g C-v
1304 // * Windows above each other: C-x 2 C-g C-v
1306 @interface EmacsBell : NSImageView
1308   // Number of currently active bell:s.
1309   unsigned int nestCount;
1310   NSView * mView;
1311   bool isAttached;
1313 - (void)show:(NSView *)view;
1314 - (void)hide;
1315 - (void)remove;
1316 @end
1318 @implementation EmacsBell
1320 - (id)init
1322   NSTRACE ("[EmacsBell init]");
1323   if ((self = [super init]))
1324     {
1325       nestCount = 0;
1326       isAttached = false;
1327 #ifdef NS_IMPL_GNUSTEP
1328       // GNUstep doesn't provide named images.  This was reported in
1329       // 2011, see https://savannah.gnu.org/bugs/?33396
1330       //
1331       // As a drop in replacement, a semitransparent gray square is used.
1332       self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1333       [self.image lockFocus];
1334       [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1335       NSRectFill(NSMakeRect(0, 0, 32, 32));
1336       [self.image unlockFocus];
1337 #else
1338       self.image = [NSImage imageNamed:NSImageNameCaution];
1339       [self.image setSize:NSMakeSize(self.image.size.width * 5,
1340                                      self.image.size.height * 5)];
1341 #endif
1342     }
1343   return self;
1346 - (void)show:(NSView *)view
1348   NSTRACE ("[EmacsBell show:]");
1349   NSTRACE_MSG ("nestCount: %u", nestCount);
1351   // Show the image, unless it's already shown.
1352   if (nestCount == 0)
1353     {
1354       NSRect rect = [view bounds];
1355       NSPoint pos;
1356       pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
1357       pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1359       [self setFrameOrigin:pos];
1360       [self setFrameSize:self.image.size];
1362       isAttached = true;
1363       mView = view;
1364       [[[view window] contentView] addSubview:self
1365                                    positioned:NSWindowAbove
1366                                    relativeTo:nil];
1367     }
1369   ++nestCount;
1371   [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1375 - (void)hide
1377   // Note: Trace output from this method isn't shown, reason unknown.
1378   // NSTRACE ("[EmacsBell hide]");
1380   if (nestCount > 0)
1381     --nestCount;
1383   // Remove the image once the last bell became inactive.
1384   if (nestCount == 0)
1385     {
1386       [self remove];
1387     }
1391 -(void)remove
1393   NSTRACE ("[EmacsBell remove]");
1394   if (isAttached)
1395     {
1396       NSTRACE_MSG ("removeFromSuperview");
1397       [self removeFromSuperview];
1398       mView.needsDisplay = YES;
1399       isAttached = false;
1400     }
1403 @end
1406 static EmacsBell * bell_view = nil;
1408 static void
1409 ns_ring_bell (struct frame *f)
1410 /* --------------------------------------------------------------------------
1411      "Beep" routine
1412    -------------------------------------------------------------------------- */
1414   NSTRACE ("ns_ring_bell");
1415   if (visible_bell)
1416     {
1417       struct frame *frame = SELECTED_FRAME ();
1418       NSView *view;
1420       if (bell_view == nil)
1421         {
1422           bell_view = [[EmacsBell alloc] init];
1423           [bell_view retain];
1424         }
1426       block_input ();
1428       view = FRAME_NS_VIEW (frame);
1429       if (view != nil)
1430         {
1431           [bell_view show:view];
1432         }
1434       unblock_input ();
1435     }
1436   else
1437     {
1438       NSBeep ();
1439     }
1443 static void
1444 hide_bell (void)
1445 /* --------------------------------------------------------------------------
1446      Ensure the bell is hidden.
1447    -------------------------------------------------------------------------- */
1449   NSTRACE ("hide_bell");
1451   if (bell_view != nil)
1452     {
1453       [bell_view remove];
1454     }
1458 /* ==========================================================================
1460     Frame / window manager related functions
1462    ========================================================================== */
1465 static void
1466 ns_raise_frame (struct frame *f, BOOL make_key)
1467 /* --------------------------------------------------------------------------
1468      Bring window to foreground and if make_key is YES, give it focus.
1469    -------------------------------------------------------------------------- */
1471   NSView *view;
1473   check_window_system (f);
1474   view = FRAME_NS_VIEW (f);
1475   block_input ();
1476   if (FRAME_VISIBLE_P (f))
1477     {
1478       if (make_key)
1479         [[view window] makeKeyAndOrderFront: NSApp];
1480       else
1481         [[view window] orderFront: NSApp];
1482     }
1483   unblock_input ();
1487 static void
1488 ns_lower_frame (struct frame *f)
1489 /* --------------------------------------------------------------------------
1490      Send window to back
1491    -------------------------------------------------------------------------- */
1493   NSView *view;
1495   check_window_system (f);
1496   view = FRAME_NS_VIEW (f);
1497   block_input ();
1498   [[view window] orderBack: NSApp];
1499   unblock_input ();
1503 static void
1504 ns_frame_raise_lower (struct frame *f, bool raise)
1505 /* --------------------------------------------------------------------------
1506      External (hook)
1507    -------------------------------------------------------------------------- */
1509   NSTRACE ("ns_frame_raise_lower");
1511   if (raise)
1512     ns_raise_frame (f, YES);
1513   else
1514     ns_lower_frame (f);
1518 static void
1519 ns_frame_rehighlight (struct frame *frame)
1520 /* --------------------------------------------------------------------------
1521      External (hook): called on things like window switching within frame
1522    -------------------------------------------------------------------------- */
1524   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1525   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1527   NSTRACE ("ns_frame_rehighlight");
1528   if (dpyinfo->x_focus_frame)
1529     {
1530       dpyinfo->x_highlight_frame
1531         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1532            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1533            : dpyinfo->x_focus_frame);
1534       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1535         {
1536           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1537           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1538         }
1539     }
1540   else
1541       dpyinfo->x_highlight_frame = 0;
1543   if (dpyinfo->x_highlight_frame &&
1544          dpyinfo->x_highlight_frame != old_highlight)
1545     {
1546       if (old_highlight)
1547         {
1548           x_update_cursor (old_highlight, 1);
1549           x_set_frame_alpha (old_highlight);
1550         }
1551       if (dpyinfo->x_highlight_frame)
1552         {
1553           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1554           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1555         }
1556     }
1560 void
1561 x_make_frame_visible (struct frame *f)
1562 /* --------------------------------------------------------------------------
1563      External: Show the window (X11 semantics)
1564    -------------------------------------------------------------------------- */
1566   NSTRACE ("x_make_frame_visible");
1567   /* XXX: at some points in past this was not needed, as the only place that
1568      called this (frame.c:Fraise_frame ()) also called raise_lower;
1569      if this ends up the case again, comment this out again. */
1570   if (!FRAME_VISIBLE_P (f))
1571     {
1572       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1573       NSWindow *window = [view window];
1575       SET_FRAME_VISIBLE (f, 1);
1576       ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1578       /* Making a new frame from a fullscreen frame will make the new frame
1579          fullscreen also.  So skip handleFS as this will print an error.  */
1580       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1581           && [view isFullscreen])
1582         return;
1584       if (f->want_fullscreen != FULLSCREEN_NONE)
1585         {
1586           block_input ();
1587           [view handleFS];
1588           unblock_input ();
1589         }
1591       /* Making a frame invisible seems to break the parent->child
1592          relationship, so reinstate it. */
1593       if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1594         {
1595           NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1597           block_input ();
1598           [parent addChildWindow: window
1599                          ordered: NSWindowAbove];
1600           unblock_input ();
1602           /* If the parent frame moved while the child frame was
1603              invisible, the child frame's position won't have been
1604              updated.  Make sure it's in the right place now. */
1605           x_set_offset(f, f->left_pos, f->top_pos, 0);
1606         }
1607     }
1611 void
1612 x_make_frame_invisible (struct frame *f)
1613 /* --------------------------------------------------------------------------
1614      External: Hide the window (X11 semantics)
1615    -------------------------------------------------------------------------- */
1617   NSView *view;
1618   NSTRACE ("x_make_frame_invisible");
1619   check_window_system (f);
1620   view = FRAME_NS_VIEW (f);
1621   [[view window] orderOut: NSApp];
1622   SET_FRAME_VISIBLE (f, 0);
1623   SET_FRAME_ICONIFIED (f, 0);
1627 void
1628 x_iconify_frame (struct frame *f)
1629 /* --------------------------------------------------------------------------
1630      External: Iconify window
1631    -------------------------------------------------------------------------- */
1633   NSView *view;
1634   struct ns_display_info *dpyinfo;
1636   NSTRACE ("x_iconify_frame");
1637   check_window_system (f);
1638   view = FRAME_NS_VIEW (f);
1639   dpyinfo = FRAME_DISPLAY_INFO (f);
1641   if (dpyinfo->x_highlight_frame == f)
1642     dpyinfo->x_highlight_frame = 0;
1644   if ([[view window] windowNumber] <= 0)
1645     {
1646       /* the window is still deferred.  Make it very small, bring it
1647          on screen and order it out. */
1648       NSRect s = { { 100, 100}, {0, 0} };
1649       NSRect t;
1650       t = [[view window] frame];
1651       [[view window] setFrame: s display: NO];
1652       [[view window] orderBack: NSApp];
1653       [[view window] orderOut: NSApp];
1654       [[view window] setFrame: t display: NO];
1655     }
1657   /* Processing input while Emacs is being minimized can cause a
1658      crash, so block it for the duration. */
1659   block_input();
1660   [[view window] miniaturize: NSApp];
1661   unblock_input();
1664 /* Free X resources of frame F.  */
1666 void
1667 x_free_frame_resources (struct frame *f)
1669   NSView *view;
1670   struct ns_display_info *dpyinfo;
1671   Mouse_HLInfo *hlinfo;
1673   NSTRACE ("x_free_frame_resources");
1674   check_window_system (f);
1675   view = FRAME_NS_VIEW (f);
1676   dpyinfo = FRAME_DISPLAY_INFO (f);
1677   hlinfo = MOUSE_HL_INFO (f);
1679   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1681   block_input ();
1683   free_frame_menubar (f);
1684   free_frame_faces (f);
1686   if (f == dpyinfo->x_focus_frame)
1687     dpyinfo->x_focus_frame = 0;
1688   if (f == dpyinfo->x_highlight_frame)
1689     dpyinfo->x_highlight_frame = 0;
1690   if (f == hlinfo->mouse_face_mouse_frame)
1691     reset_mouse_highlight (hlinfo);
1693   if (f->output_data.ns->miniimage != nil)
1694     [f->output_data.ns->miniimage release];
1696   [[view window] close];
1697   [view release];
1699   xfree (f->output_data.ns);
1701   unblock_input ();
1704 void
1705 x_destroy_window (struct frame *f)
1706 /* --------------------------------------------------------------------------
1707      External: Delete the window
1708    -------------------------------------------------------------------------- */
1710   NSTRACE ("x_destroy_window");
1712   /* If this frame has a parent window, detach it as not doing so can
1713      cause a crash in GNUStep. */
1714   if (FRAME_PARENT_FRAME (f) != NULL)
1715     {
1716       NSWindow *child = [FRAME_NS_VIEW (f) window];
1717       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1719       [parent removeChildWindow: child];
1720     }
1722   check_window_system (f);
1723   x_free_frame_resources (f);
1724   ns_window_num--;
1728 void
1729 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1730 /* --------------------------------------------------------------------------
1731      External: Position the window
1732    -------------------------------------------------------------------------- */
1734   NSView *view = FRAME_NS_VIEW (f);
1735   NSArray *screens = [NSScreen screens];
1736   NSScreen *fscreen = [screens objectAtIndex: 0];
1737   NSScreen *screen = [[view window] screen];
1739   NSTRACE ("x_set_offset");
1741   block_input ();
1743   f->left_pos = xoff;
1744   f->top_pos = yoff;
1746   if (view != nil && screen && fscreen)
1747     {
1748       f->left_pos = f->size_hint_flags & XNegative
1749         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1750         : f->left_pos;
1751       /* We use visibleFrame here to take menu bar into account.
1752          Ideally we should also adjust left/top with visibleFrame.origin.  */
1754       f->top_pos = f->size_hint_flags & YNegative
1755         ? ([screen visibleFrame].size.height + f->top_pos
1756            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1757            - FRAME_TOOLBAR_HEIGHT (f))
1758         : f->top_pos;
1759 #ifdef NS_IMPL_GNUSTEP
1760       if (FRAME_PARENT_FRAME (f) == NULL)
1761         {
1762           if (f->left_pos < 100)
1763             f->left_pos = 100;  /* don't overlap menu */
1764         }
1765 #endif
1766       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1767          menu bar.  */
1768       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1769                                                 + NS_PARENT_WINDOW_LEFT_POS (f)),
1770                                 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1771                                                 - f->top_pos));
1772       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1773       [[view window] setFrameTopLeftPoint: pt];
1774       f->size_hint_flags &= ~(XNegative|YNegative);
1775     }
1777   unblock_input ();
1781 void
1782 x_set_window_size (struct frame *f,
1783                    bool change_gravity,
1784                    int width,
1785                    int height,
1786                    bool pixelwise)
1787 /* --------------------------------------------------------------------------
1788      Adjust window pixel size based on given character grid size
1789      Impl is a bit more complex than other terms, need to do some
1790      internal clipping.
1791    -------------------------------------------------------------------------- */
1793   EmacsView *view = FRAME_NS_VIEW (f);
1794   NSWindow *window = [view window];
1795   NSRect wr = [window frame];
1796   int pixelwidth, pixelheight;
1797   int orig_height = wr.size.height;
1799   NSTRACE ("x_set_window_size");
1801   if (view == nil)
1802     return;
1804   NSTRACE_RECT ("current", wr);
1805   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1806   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1808   block_input ();
1810   if (pixelwise)
1811     {
1812       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1813       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1814     }
1815   else
1816     {
1817       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1818       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1819     }
1821   wr.size.width = pixelwidth + f->border_width;
1822   wr.size.height = pixelheight;
1823   if (! [view isFullscreen])
1824     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1825       + FRAME_TOOLBAR_HEIGHT (f);
1827   /* Do not try to constrain to this screen.  We may have multiple
1828      screens, and want Emacs to span those.  Constraining to screen
1829      prevents that, and that is not nice to the user.  */
1830  if (f->output_data.ns->zooming)
1831    f->output_data.ns->zooming = 0;
1832  else
1833    wr.origin.y += orig_height - wr.size.height;
1835  frame_size_history_add
1836    (f, Qx_set_window_size_1, width, height,
1837     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1838            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1839            make_number (f->border_width),
1840            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1841            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1843   [window setFrame: wr display: YES];
1845   [view updateFrameSize: NO];
1846   unblock_input ();
1849 #ifdef NS_IMPL_COCOA
1850 void
1851 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1852 /* --------------------------------------------------------------------------
1853      Set frame F's `undecorated' parameter.  If non-nil, F's window-system
1854      window is drawn without decorations, title, minimize/maximize boxes
1855      and external borders.  This usually means that the window cannot be
1856      dragged, resized, iconified, maximized or deleted with the mouse.  If
1857      nil, draw the frame with all the elements listed above unless these
1858      have been suspended via window manager settings.
1860      GNUStep cannot change an existing window's style.
1861    -------------------------------------------------------------------------- */
1863   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1864   NSWindow *window = [view window];
1866   NSTRACE ("x_set_undecorated");
1868   if (!EQ (new_value, old_value))
1869     {
1870       block_input ();
1872       if (NILP (new_value))
1873         {
1874           FRAME_UNDECORATED (f) = false;
1875           [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1876                                   ^ FRAME_UNDECORATED_FLAGS)];
1878           [view createToolbar: f];
1879         }
1880       else
1881         {
1882           [window setToolbar: nil];
1883           /* Do I need to release the toolbar here? */
1885           FRAME_UNDECORATED (f) = true;
1886           [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1887                                  ^ FRAME_DECORATED_FLAGS)];
1888         }
1890       /* At this point it seems we don't have an active NSResponder,
1891          so some key presses (TAB) are swallowed by the system. */
1892       [window makeFirstResponder: view];
1894       [view updateFrameSize: NO];
1895       unblock_input ();
1896     }
1898 #endif /* NS_IMPL_COCOA */
1900 void
1901 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1902 /* --------------------------------------------------------------------------
1903      Set frame F's `parent-frame' parameter.  If non-nil, make F a child
1904      frame of the frame specified by that parameter.  Technically, this
1905      makes F's window-system window a child window of the parent frame's
1906      window-system window.  If nil, make F's window-system window a
1907      top-level window--a child of its display's root window.
1909      A child frame's `left' and `top' parameters specify positions
1910      relative to the top-left corner of its parent frame's native
1911      rectangle.  On macOS moving a parent frame moves all its child
1912      frames too, keeping their position relative to the parent
1913      unaltered.  When a parent frame is iconified or made invisible, its
1914      child frames are made invisible.  When a parent frame is deleted,
1915      its child frames are deleted too.
1917      Whether a child frame has a tool bar may be window-system or window
1918      manager dependent.  It's advisable to disable it via the frame
1919      parameter settings.
1921      Some window managers may not honor this parameter.
1922    -------------------------------------------------------------------------- */
1924   struct frame *p = NULL;
1925   NSWindow *parent, *child;
1927   NSTRACE ("x_set_parent_frame");
1929   if (!NILP (new_value)
1930       && (!FRAMEP (new_value)
1931           || !FRAME_LIVE_P (p = XFRAME (new_value))
1932           || !FRAME_X_P (p)))
1933     {
1934       store_frame_param (f, Qparent_frame, old_value);
1935       error ("Invalid specification of `parent-frame'");
1936     }
1938   if (p != FRAME_PARENT_FRAME (f))
1939     {
1940       parent = [FRAME_NS_VIEW (p) window];
1941       child = [FRAME_NS_VIEW (f) window];
1943       block_input ();
1944       [parent addChildWindow: child
1945                      ordered: NSWindowAbove];
1946       unblock_input ();
1948       fset_parent_frame (f, new_value);
1949     }
1952 void
1953 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1954 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
1955  * that F's window-system window does not want to receive input focus
1956  * when it is mapped.  (A frame's window is mapped when the frame is
1957  * displayed for the first time and when the frame changes its state
1958  * from `iconified' or `invisible' to `visible'.)
1960  * Some window managers may not honor this parameter. */
1962   NSTRACE ("x_set_no_focus_on_map");
1964   if (!EQ (new_value, old_value))
1965     {
1966       FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1967     }
1970 void
1971 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1972 /*  Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1973  * that F's window-system window does not want to receive input focus
1974  * via mouse clicks or by moving the mouse into it.
1976  * If non-nil, this may have the unwanted side-effect that a user cannot
1977  * scroll a non-selected frame with the mouse.
1979  * Some window managers may not honor this parameter. */
1981   NSTRACE ("x_set_no_accept_focus");
1983   if (!EQ (new_value, old_value))
1984     FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1987 void
1988 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1989 /* Set frame F's `z-group' parameter.  If `above', F's window-system
1990    window is displayed above all windows that do not have the `above'
1991    property set.  If nil, F's window is shown below all windows that
1992    have the `above' property set and above all windows that have the
1993    `below' property set.  If `below', F's window is displayed below
1994    all windows that do.
1996    Some window managers may not honor this parameter. */
1998   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1999   NSWindow *window = [view window];
2001   NSTRACE ("x_set_z_group");
2003   if (NILP (new_value))
2004     {
2005       window.level = NSNormalWindowLevel;
2006       FRAME_Z_GROUP (f) = z_group_none;
2007     }
2008   else if (EQ (new_value, Qabove))
2009     {
2010       window.level = NSNormalWindowLevel + 1;
2011       FRAME_Z_GROUP (f) = z_group_above;
2012     }
2013   else if (EQ (new_value, Qabove_suspended))
2014     {
2015       /* Not sure what level this should be. */
2016       window.level = NSNormalWindowLevel + 1;
2017       FRAME_Z_GROUP (f) = z_group_above_suspended;
2018     }
2019   else if (EQ (new_value, Qbelow))
2020     {
2021       window.level = NSNormalWindowLevel - 1;
2022       FRAME_Z_GROUP (f) = z_group_below;
2023     }
2024   else
2025     error ("Invalid z-group specification");
2028 static void
2029 ns_fullscreen_hook (struct frame *f)
2031   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2033   NSTRACE ("ns_fullscreen_hook");
2035   if (!FRAME_VISIBLE_P (f))
2036     return;
2038    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2039     {
2040       /* Old style fs don't initiate correctly if created from
2041          init/default-frame alist, so use a timer (not nice...).
2042       */
2043       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2044                                      selector: @selector (handleFS)
2045                                      userInfo: nil repeats: NO];
2046       return;
2047     }
2049   block_input ();
2050   [view handleFS];
2051   unblock_input ();
2054 /* ==========================================================================
2056     Color management
2058    ========================================================================== */
2061 NSColor *
2062 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2064   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2065   if (idx < 1 || idx >= color_table->avail)
2066     return nil;
2067   return color_table->colors[idx];
2071 unsigned long
2072 ns_index_color (NSColor *color, struct frame *f)
2074   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2075   ptrdiff_t idx;
2076   ptrdiff_t i;
2078   if (!color_table->colors)
2079     {
2080       color_table->size = NS_COLOR_CAPACITY;
2081       color_table->avail = 1; /* skip idx=0 as marker */
2082       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2083       color_table->colors[0] = nil;
2084       color_table->empty_indices = [[NSMutableSet alloc] init];
2085     }
2087   /* Do we already have this color?  */
2088   for (i = 1; i < color_table->avail; i++)
2089     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2090       return i;
2092   if ([color_table->empty_indices count] > 0)
2093     {
2094       NSNumber *index = [color_table->empty_indices anyObject];
2095       [color_table->empty_indices removeObject: index];
2096       idx = [index unsignedLongValue];
2097     }
2098   else
2099     {
2100       if (color_table->avail == color_table->size)
2101         color_table->colors =
2102           xpalloc (color_table->colors, &color_table->size, 1,
2103                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2104       idx = color_table->avail++;
2105     }
2107   color_table->colors[idx] = color;
2108   [color retain];
2109 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2110   return idx;
2114 static int
2115 ns_get_color (const char *name, NSColor **col)
2116 /* --------------------------------------------------------------------------
2117      Parse a color name
2118    -------------------------------------------------------------------------- */
2119 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2120    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2121    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2123   NSColor *new = nil;
2124   static char hex[20];
2125   int scaling = 0;
2126   float r = -1.0, g, b;
2127   NSString *nsname = [NSString stringWithUTF8String: name];
2129   NSTRACE ("ns_get_color(%s, **)", name);
2131   block_input ();
2133   if ([nsname isEqualToString: @"ns_selection_bg_color"])
2134     {
2135 #ifdef NS_IMPL_COCOA
2136       NSString *defname = [[NSUserDefaults standardUserDefaults]
2137                             stringForKey: @"AppleHighlightColor"];
2138       if (defname != nil)
2139         nsname = defname;
2140       else
2141 #endif
2142       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2143         {
2144           *col = [new colorUsingDefaultColorSpace];
2145           unblock_input ();
2146           return 0;
2147         }
2148       else
2149         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2151       name = [nsname UTF8String];
2152     }
2153   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2154     {
2155       /* NOTE: macOS applications normally don't set foreground
2156          selection, but text may be unreadable if we don't.
2157       */
2158       if ((new = [NSColor selectedTextColor]) != nil)
2159         {
2160           *col = [new colorUsingDefaultColorSpace];
2161           unblock_input ();
2162           return 0;
2163         }
2165       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2166       name = [nsname UTF8String];
2167     }
2169   /* First, check for some sort of numeric specification. */
2170   hex[0] = '\0';
2172   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
2173     {
2174       NSScanner *scanner = [NSScanner scannerWithString: nsname];
2175       [scanner scanFloat: &r];
2176       [scanner scanFloat: &g];
2177       [scanner scanFloat: &b];
2178     }
2179   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
2180     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2181   else if (name[0] == '#')        /* An old X11 format; convert to newer */
2182     {
2183       int len = (strlen(name) - 1);
2184       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2185       int i;
2186       scaling = strlen(name+start) / 3;
2187       for (i = 0; i < 3; i++)
2188         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2189                  name + start + i * scaling);
2190       hex[3 * (scaling + 1) - 1] = '\0';
2191     }
2193   if (hex[0])
2194     {
2195       unsigned int rr, gg, bb;
2196       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2197       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2198         {
2199           r = rr / fscale;
2200           g = gg / fscale;
2201           b = bb / fscale;
2202         }
2203     }
2205   if (r >= 0.0F)
2206     {
2207       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2208       unblock_input ();
2209       return 0;
2210     }
2212   /* Otherwise, color is expected to be from a list */
2213   {
2214     NSEnumerator *lenum, *cenum;
2215     NSString *name;
2216     NSColorList *clist;
2218 #ifdef NS_IMPL_GNUSTEP
2219     /* XXX: who is wrong, the requestor or the implementation? */
2220     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2221         == NSOrderedSame)
2222       nsname = @"highlightColor";
2223 #endif
2225     lenum = [[NSColorList availableColorLists] objectEnumerator];
2226     while ( (clist = [lenum nextObject]) && new == nil)
2227       {
2228         cenum = [[clist allKeys] objectEnumerator];
2229         while ( (name = [cenum nextObject]) && new == nil )
2230           {
2231             if ([name compare: nsname
2232                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
2233               new = [clist colorWithKey: name];
2234           }
2235       }
2236   }
2238   if (new)
2239     *col = [new colorUsingDefaultColorSpace];
2240   unblock_input ();
2241   return new ? 0 : 1;
2246 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2247 /* --------------------------------------------------------------------------
2248      Convert a Lisp string object to a NS color
2249    -------------------------------------------------------------------------- */
2251   NSTRACE ("ns_lisp_to_color");
2252   if (STRINGP (color))
2253     return ns_get_color (SSDATA (color), col);
2254   else if (SYMBOLP (color))
2255     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2256   return 1;
2260 void
2261 ns_query_color(void *col, XColor *color_def, int setPixel)
2262 /* --------------------------------------------------------------------------
2263          Get ARGB values out of NSColor col and put them into color_def.
2264          If setPixel, set the pixel to a concatenated version.
2265          and set color_def pixel to the resulting index.
2266    -------------------------------------------------------------------------- */
2268   EmacsCGFloat r, g, b, a;
2270   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2271   color_def->red   = r * 65535;
2272   color_def->green = g * 65535;
2273   color_def->blue  = b * 65535;
2275   if (setPixel == YES)
2276     color_def->pixel
2277       = ARGB_TO_ULONG((int)(a*255),
2278                       (int)(r*255), (int)(g*255), (int)(b*255));
2282 bool
2283 ns_defined_color (struct frame *f,
2284                   const char *name,
2285                   XColor *color_def,
2286                   bool alloc,
2287                   bool makeIndex)
2288 /* --------------------------------------------------------------------------
2289          Return true if named color found, and set color_def rgb accordingly.
2290          If makeIndex and alloc are nonzero put the color in the color_table,
2291          and set color_def pixel to the resulting index.
2292          If makeIndex is zero, set color_def pixel to ARGB.
2293          Return false if not found
2294    -------------------------------------------------------------------------- */
2296   NSColor *col;
2297   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2299   block_input ();
2300   if (ns_get_color (name, &col) != 0) /* Color not found  */
2301     {
2302       unblock_input ();
2303       return 0;
2304     }
2305   if (makeIndex && alloc)
2306     color_def->pixel = ns_index_color (col, f);
2307   ns_query_color (col, color_def, !makeIndex);
2308   unblock_input ();
2309   return 1;
2313 void
2314 x_set_frame_alpha (struct frame *f)
2315 /* --------------------------------------------------------------------------
2316      change the entire-frame transparency
2317    -------------------------------------------------------------------------- */
2319   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2320   double alpha = 1.0;
2321   double alpha_min = 1.0;
2323   NSTRACE ("x_set_frame_alpha");
2325   if (dpyinfo->x_highlight_frame == f)
2326     alpha = f->alpha[0];
2327   else
2328     alpha = f->alpha[1];
2330   if (FLOATP (Vframe_alpha_lower_limit))
2331     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2332   else if (INTEGERP (Vframe_alpha_lower_limit))
2333     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2335   if (alpha < 0.0)
2336     return;
2337   else if (1.0 < alpha)
2338     alpha = 1.0;
2339   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2340     alpha = alpha_min;
2342 #ifdef NS_IMPL_COCOA
2343   {
2344     EmacsView *view = FRAME_NS_VIEW (f);
2345   [[view window] setAlphaValue: alpha];
2346   }
2347 #endif
2351 /* ==========================================================================
2353     Mouse handling
2355    ========================================================================== */
2358 void
2359 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2360 /* --------------------------------------------------------------------------
2361      Programmatically reposition mouse pointer in pixel coordinates
2362    -------------------------------------------------------------------------- */
2364   NSTRACE ("frame_set_mouse_pixel_position");
2366   /* FIXME: what about GNUstep? */
2367 #ifdef NS_IMPL_COCOA
2368   CGPoint mouse_pos =
2369     CGPointMake(f->left_pos + pix_x,
2370                 f->top_pos + pix_y +
2371                 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2372   CGWarpMouseCursorPosition (mouse_pos);
2373 #endif
2376 static int
2377 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2378 /*   ------------------------------------------------------------------------
2379      Called by EmacsView on mouseMovement events.  Passes on
2380      to emacs mainstream code if we moved off of a rect of interest
2381      known as last_mouse_glyph.
2382      ------------------------------------------------------------------------ */
2384   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2385   NSRect *r;
2387 //  NSTRACE ("note_mouse_movement");
2389   dpyinfo->last_mouse_motion_frame = frame;
2390   r = &dpyinfo->last_mouse_glyph;
2392   /* Note, this doesn't get called for enter/leave, since we don't have a
2393      position.  Those are taken care of in the corresponding NSView methods. */
2395   /* has movement gone beyond last rect we were tracking? */
2396   if (x < r->origin.x || x >= r->origin.x + r->size.width
2397       || y < r->origin.y || y >= r->origin.y + r->size.height)
2398     {
2399       ns_update_begin (frame);
2400       frame->mouse_moved = 1;
2401       note_mouse_highlight (frame, x, y);
2402       remember_mouse_glyph (frame, x, y, r);
2403       ns_update_end (frame);
2404       return 1;
2405     }
2407   return 0;
2411 static void
2412 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2413                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2414                    Time *time)
2415 /* --------------------------------------------------------------------------
2416     External (hook): inform emacs about mouse position and hit parts.
2417     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2418     x & y should be position in the scrollbar (the whole bar, not the handle)
2419     and length of scrollbar respectively
2420    -------------------------------------------------------------------------- */
2422   id view;
2423   NSPoint position;
2424   Lisp_Object frame, tail;
2425   struct frame *f;
2426   struct ns_display_info *dpyinfo;
2428   NSTRACE ("ns_mouse_position");
2430   if (*fp == NULL)
2431     {
2432       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2433       return;
2434     }
2436   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2438   block_input ();
2440   /* Clear the mouse-moved flag for every frame on this display.  */
2441   FOR_EACH_FRAME (tail, frame)
2442     if (FRAME_NS_P (XFRAME (frame))
2443         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2444       XFRAME (frame)->mouse_moved = 0;
2446   dpyinfo->last_mouse_scroll_bar = nil;
2447   if (dpyinfo->last_mouse_frame
2448       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2449     f = dpyinfo->last_mouse_frame;
2450   else
2451     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2453   if (f && FRAME_NS_P (f))
2454     {
2455       view = FRAME_NS_VIEW (*fp);
2457       position = [[view window] mouseLocationOutsideOfEventStream];
2458       position = [view convertPoint: position fromView: nil];
2459       remember_mouse_glyph (f, position.x, position.y,
2460                             &dpyinfo->last_mouse_glyph);
2461       NSTRACE_POINT ("position", position);
2463       if (bar_window) *bar_window = Qnil;
2464       if (part) *part = scroll_bar_above_handle;
2466       if (x) XSETINT (*x, lrint (position.x));
2467       if (y) XSETINT (*y, lrint (position.y));
2468       if (time)
2469         *time = dpyinfo->last_mouse_movement_time;
2470       *fp = f;
2471     }
2473   unblock_input ();
2477 static void
2478 ns_frame_up_to_date (struct frame *f)
2479 /* --------------------------------------------------------------------------
2480     External (hook): Fix up mouse highlighting right after a full update.
2481     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2482    -------------------------------------------------------------------------- */
2484   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2486   if (FRAME_NS_P (f))
2487     {
2488       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2489       if (f == hlinfo->mouse_face_mouse_frame)
2490         {
2491           block_input ();
2492           ns_update_begin(f);
2493           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2494                                 hlinfo->mouse_face_mouse_x,
2495                                 hlinfo->mouse_face_mouse_y);
2496           ns_update_end(f);
2497           unblock_input ();
2498         }
2499     }
2503 static void
2504 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2505 /* --------------------------------------------------------------------------
2506     External (RIF): set frame mouse pointer type.
2507    -------------------------------------------------------------------------- */
2509   NSTRACE ("ns_define_frame_cursor");
2510   if (FRAME_POINTER_TYPE (f) != cursor)
2511     {
2512       EmacsView *view = FRAME_NS_VIEW (f);
2513       FRAME_POINTER_TYPE (f) = cursor;
2514       [[view window] invalidateCursorRectsForView: view];
2515       /* Redisplay assumes this function also draws the changed frame
2516          cursor, but this function doesn't, so do it explicitly.  */
2517       x_update_cursor (f, 1);
2518     }
2523 /* ==========================================================================
2525     Keyboard handling
2527    ========================================================================== */
2530 static unsigned
2531 ns_convert_key (unsigned code)
2532 /* --------------------------------------------------------------------------
2533     Internal call used by NSView-keyDown.
2534    -------------------------------------------------------------------------- */
2536   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2537   unsigned keysym;
2538   /* An array would be faster, but less easy to read. */
2539   for (keysym = 0; keysym < last_keysym; keysym += 2)
2540     if (code == convert_ns_to_X_keysym[keysym])
2541       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2542   return 0;
2543 /* if decide to use keyCode and Carbon table, use this line:
2544      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2548 char *
2549 x_get_keysym_name (int keysym)
2550 /* --------------------------------------------------------------------------
2551     Called by keyboard.c.  Not sure if the return val is important, except
2552     that it be unique.
2553    -------------------------------------------------------------------------- */
2555   static char value[16];
2556   NSTRACE ("x_get_keysym_name");
2557   sprintf (value, "%d", keysym);
2558   return value;
2563 /* ==========================================================================
2565     Block drawing operations
2567    ========================================================================== */
2570 static void
2571 ns_redraw_scroll_bars (struct frame *f)
2573   int i;
2574   id view;
2575   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2576   NSTRACE ("ns_redraw_scroll_bars");
2577   for (i =[subviews count]-1; i >= 0; i--)
2578     {
2579       view = [subviews objectAtIndex: i];
2580       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2581       [view display];
2582     }
2586 void
2587 ns_clear_frame (struct frame *f)
2588 /* --------------------------------------------------------------------------
2589       External (hook): Erase the entire frame
2590    -------------------------------------------------------------------------- */
2592   NSView *view = FRAME_NS_VIEW (f);
2593   NSRect r;
2595   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2597  /* comes on initial frame because we have
2598     after-make-frame-functions = select-frame */
2599  if (!FRAME_DEFAULT_FACE (f))
2600    return;
2602   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2604   r = [view bounds];
2606   block_input ();
2607   ns_focus (f, &r, 1);
2608   [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2609                             (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2610   NSRectFill (r);
2611   ns_unfocus (f);
2613   /* as of 2006/11 or so this is now needed */
2614   ns_redraw_scroll_bars (f);
2615   unblock_input ();
2619 static void
2620 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2621 /* --------------------------------------------------------------------------
2622     External (RIF):  Clear section of frame
2623    -------------------------------------------------------------------------- */
2625   NSRect r = NSMakeRect (x, y, width, height);
2626   NSView *view = FRAME_NS_VIEW (f);
2627   struct face *face = FRAME_DEFAULT_FACE (f);
2629   if (!view || !face)
2630     return;
2632   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2634   r = NSIntersectionRect (r, [view frame]);
2635   ns_focus (f, &r, 1);
2636   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2638   NSRectFill (r);
2640   ns_unfocus (f);
2641   return;
2644 static void
2645 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2647   NSTRACE ("ns_copy_bits");
2649   if (FRAME_NS_VIEW (f))
2650     {
2651       hide_bell();              // Ensure the bell image isn't scrolled.
2653       ns_focus (f, &dest, 1);
2654       [FRAME_NS_VIEW (f) scrollRect: src
2655                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2656                                                  dest.origin.y - src.origin.y)];
2657       ns_unfocus (f);
2658     }
2661 static void
2662 ns_scroll_run (struct window *w, struct run *run)
2663 /* --------------------------------------------------------------------------
2664     External (RIF):  Insert or delete n lines at line vpos
2665    -------------------------------------------------------------------------- */
2667   struct frame *f = XFRAME (w->frame);
2668   int x, y, width, height, from_y, to_y, bottom_y;
2670   NSTRACE ("ns_scroll_run");
2672   /* begin copy from other terms */
2673   /* Get frame-relative bounding box of the text display area of W,
2674      without mode lines.  Include in this box the left and right
2675      fringe of W.  */
2676   window_box (w, ANY_AREA, &x, &y, &width, &height);
2678   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2679   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2680   bottom_y = y + height;
2682   if (to_y < from_y)
2683     {
2684       /* Scrolling up.  Make sure we don't copy part of the mode
2685          line at the bottom.  */
2686       if (from_y + run->height > bottom_y)
2687         height = bottom_y - from_y;
2688       else
2689         height = run->height;
2690     }
2691   else
2692     {
2693       /* Scrolling down.  Make sure we don't copy over the mode line.
2694          at the bottom.  */
2695       if (to_y + run->height > bottom_y)
2696         height = bottom_y - to_y;
2697       else
2698         height = run->height;
2699     }
2700   /* end copy from other terms */
2702   if (height == 0)
2703       return;
2705   block_input ();
2707   x_clear_cursor (w);
2709   {
2710     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2711     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2713     ns_copy_bits (f, srcRect , dstRect);
2714   }
2716   unblock_input ();
2720 static void
2721 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2722 /* --------------------------------------------------------------------------
2723     External (RIF): preparatory to fringe update after text was updated
2724    -------------------------------------------------------------------------- */
2726   struct frame *f;
2727   int width, height;
2729   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2731   /* begin copy from other terms */
2732   eassert (w);
2734   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2735     desired_row->redraw_fringe_bitmaps_p = 1;
2737   /* When a window has disappeared, make sure that no rest of
2738      full-width rows stays visible in the internal border.  */
2739   if (windows_or_buffers_changed
2740       && desired_row->full_width_p
2741       && (f = XFRAME (w->frame),
2742           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2743           width != 0)
2744       && (height = desired_row->visible_height,
2745           height > 0))
2746     {
2747       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2749       block_input ();
2750       ns_clear_frame_area (f, 0, y, width, height);
2751       ns_clear_frame_area (f,
2752                            FRAME_PIXEL_WIDTH (f) - width,
2753                            y, width, height);
2754       unblock_input ();
2755     }
2759 static void
2760 ns_shift_glyphs_for_insert (struct frame *f,
2761                            int x, int y, int width, int height,
2762                            int shift_by)
2763 /* --------------------------------------------------------------------------
2764     External (RIF): copy an area horizontally, don't worry about clearing src
2765    -------------------------------------------------------------------------- */
2767   NSRect srcRect = NSMakeRect (x, y, width, height);
2768   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2770   NSTRACE ("ns_shift_glyphs_for_insert");
2772   ns_copy_bits (f, srcRect, dstRect);
2777 /* ==========================================================================
2779     Character encoding and metrics
2781    ========================================================================== */
2784 static void
2785 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2786 /* --------------------------------------------------------------------------
2787      External (RIF); compute left/right overhang of whole string and set in s
2788    -------------------------------------------------------------------------- */
2790   struct font *font = s->font;
2792   if (s->char2b)
2793     {
2794       struct font_metrics metrics;
2795       unsigned int codes[2];
2796       codes[0] = *(s->char2b);
2797       codes[1] = *(s->char2b + s->nchars - 1);
2799       font->driver->text_extents (font, codes, 2, &metrics);
2800       s->left_overhang = -metrics.lbearing;
2801       s->right_overhang
2802         = metrics.rbearing > metrics.width
2803         ? metrics.rbearing - metrics.width : 0;
2804     }
2805   else
2806     {
2807       s->left_overhang = 0;
2808       if (EQ (font->driver->type, Qns))
2809         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2810           FONT_HEIGHT (font) * 0.2 : 0;
2811       else
2812         s->right_overhang = 0;
2813     }
2818 /* ==========================================================================
2820     Fringe and cursor drawing
2822    ========================================================================== */
2825 extern int max_used_fringe_bitmap;
2826 static void
2827 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2828                       struct draw_fringe_bitmap_params *p)
2829 /* --------------------------------------------------------------------------
2830     External (RIF); fringe-related
2831    -------------------------------------------------------------------------- */
2833   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2834      periodic bitmap is used to create a continuous pattern.  Since a
2835      bitmap is rendered one text line at a time, the start offset (dh)
2836      of the bitmap varies.  Concretely, this is used for the empty
2837      line indicator.
2839      For a bitmap, "h + dh" is the full height and is always
2840      invariant.  For a normal bitmap "dh" is zero.
2842      For example, when the period is three and the full height is 72
2843      the following combinations exists:
2845        h=72 dh=0
2846        h=71 dh=1
2847        h=70 dh=2 */
2849   struct frame *f = XFRAME (WINDOW_FRAME (w));
2850   struct face *face = p->face;
2851   static EmacsImage **bimgs = NULL;
2852   static int nBimgs = 0;
2854   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2855   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2856                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2858   /* grow bimgs if needed */
2859   if (nBimgs < max_used_fringe_bitmap)
2860     {
2861       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2862       memset (bimgs + nBimgs, 0,
2863               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2864       nBimgs = max_used_fringe_bitmap;
2865     }
2867   /* Must clip because of partially visible lines.  */
2868   ns_clip_to_row (w, row, ANY_AREA, YES);
2870   if (!p->overlay_p)
2871     {
2872       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2874       if (bx >= 0 && nx > 0)
2875         {
2876           NSRect r = NSMakeRect (bx, by, nx, ny);
2877           NSRectClip (r);
2878           [ns_lookup_indexed_color (face->background, f) set];
2879           NSRectFill (r);
2880         }
2881     }
2883   if (p->which)
2884     {
2885       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2886       EmacsImage *img = bimgs[p->which - 1];
2888       if (!img)
2889         {
2890           // Note: For "periodic" images, allocate one EmacsImage for
2891           // the base image, and use it for all dh:s.
2892           unsigned short *bits = p->bits;
2893           int full_height = p->h + p->dh;
2894           int i;
2895           unsigned char *cbits = xmalloc (full_height);
2897           for (i = 0; i < full_height; i++)
2898             cbits[i] = bits[i];
2899           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2900                                          height: full_height
2901                                              fg: 0 bg: 0];
2902           bimgs[p->which - 1] = img;
2903           xfree (cbits);
2904         }
2906       NSTRACE_RECT ("r", r);
2908       NSRectClip (r);
2909       /* Since we composite the bitmap instead of just blitting it, we need
2910          to erase the whole background. */
2911       [ns_lookup_indexed_color(face->background, f) set];
2912       NSRectFill (r);
2914       {
2915         NSColor *bm_color;
2916         if (!p->cursor_p)
2917           bm_color = ns_lookup_indexed_color(face->foreground, f);
2918         else if (p->overlay_p)
2919           bm_color = ns_lookup_indexed_color(face->background, f);
2920         else
2921           bm_color = f->output_data.ns->cursor_color;
2922         [img setXBMColor: bm_color];
2923       }
2925 #ifdef NS_IMPL_COCOA
2926       // Note: For periodic images, the full image height is "h + hd".
2927       // By using the height h, a suitable part of the image is used.
2928       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2930       NSTRACE_RECT ("fromRect", fromRect);
2932       [img drawInRect: r
2933               fromRect: fromRect
2934              operation: NSCompositingOperationSourceOver
2935               fraction: 1.0
2936            respectFlipped: YES
2937                 hints: nil];
2938 #else
2939       {
2940         NSPoint pt = r.origin;
2941         pt.y += p->h;
2942         [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
2943       }
2944 #endif
2945     }
2946   ns_unfocus (f);
2950 static void
2951 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2952                        int x, int y, enum text_cursor_kinds cursor_type,
2953                        int cursor_width, bool on_p, bool active_p)
2954 /* --------------------------------------------------------------------------
2955      External call (RIF): draw cursor.
2956      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2957    -------------------------------------------------------------------------- */
2959   NSRect r, s;
2960   int fx, fy, h, cursor_height;
2961   struct frame *f = WINDOW_XFRAME (w);
2962   struct glyph *phys_cursor_glyph;
2963   struct glyph *cursor_glyph;
2964   struct face *face;
2965   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2967   /* If cursor is out of bounds, don't draw garbage.  This can happen
2968      in mini-buffer windows when switching between echo area glyphs
2969      and mini-buffer.  */
2971   NSTRACE ("ns_draw_window_cursor");
2973   if (!on_p)
2974     return;
2976   w->phys_cursor_type = cursor_type;
2977   w->phys_cursor_on_p = on_p;
2979   if (cursor_type == NO_CURSOR)
2980     {
2981       w->phys_cursor_width = 0;
2982       return;
2983     }
2985   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2986     {
2987       if (glyph_row->exact_window_width_line_p
2988           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2989         {
2990           glyph_row->cursor_in_fringe_p = 1;
2991           draw_fringe_bitmap (w, glyph_row, 0);
2992         }
2993       return;
2994     }
2996   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2997      (other terminals do it the other way round).  We must set
2998      w->phys_cursor_width to the cursor width.  For bar cursors, that
2999      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
3000   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3002   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3003      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3004   if (cursor_type == BAR_CURSOR)
3005     {
3006       if (cursor_width < 1)
3007         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3009       /* The bar cursor should never be wider than the glyph. */
3010       if (cursor_width < w->phys_cursor_width)
3011         w->phys_cursor_width = cursor_width;
3012     }
3013   /* If we have an HBAR, "cursor_width" MAY specify height. */
3014   else if (cursor_type == HBAR_CURSOR)
3015     {
3016       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3017       if (cursor_height > glyph_row->height)
3018         cursor_height = glyph_row->height;
3019       if (h > cursor_height) // Cursor smaller than line height, move down
3020         fy += h - cursor_height;
3021       h = cursor_height;
3022     }
3024   r.origin.x = fx, r.origin.y = fy;
3025   r.size.height = h;
3026   r.size.width = w->phys_cursor_width;
3028   /* Prevent the cursor from being drawn outside the text area. */
3029   ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3032   face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3033   if (face && NS_FACE_BACKGROUND (face)
3034       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3035     {
3036       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3037       hollow_color = FRAME_CURSOR_COLOR (f);
3038     }
3039   else
3040     [FRAME_CURSOR_COLOR (f) set];
3042 #ifdef NS_IMPL_COCOA
3043   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3044            atomic.  Cleaner ways of doing this should be investigated.
3045            One way would be to set a global variable DRAWING_CURSOR
3046            when making the call to draw_phys..(), don't focus in that
3047            case, then move the ns_unfocus() here after that call. */
3048   NSDisableScreenUpdates ();
3049 #endif
3051   switch (cursor_type)
3052     {
3053     case DEFAULT_CURSOR:
3054     case NO_CURSOR:
3055       break;
3056     case FILLED_BOX_CURSOR:
3057       NSRectFill (r);
3058       break;
3059     case HOLLOW_BOX_CURSOR:
3060       NSRectFill (r);
3061       [hollow_color set];
3062       NSRectFill (NSInsetRect (r, 1, 1));
3063       [FRAME_CURSOR_COLOR (f) set];
3064       break;
3065     case HBAR_CURSOR:
3066       NSRectFill (r);
3067       break;
3068     case BAR_CURSOR:
3069       s = r;
3070       /* If the character under cursor is R2L, draw the bar cursor
3071          on the right of its glyph, rather than on the left.  */
3072       cursor_glyph = get_phys_cursor_glyph (w);
3073       if ((cursor_glyph->resolved_level & 1) != 0)
3074         s.origin.x += cursor_glyph->pixel_width - s.size.width;
3076       NSRectFill (s);
3077       break;
3078     }
3079   ns_unfocus (f);
3081   /* draw the character under the cursor */
3082   if (cursor_type != NO_CURSOR)
3083     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3085 #ifdef NS_IMPL_COCOA
3086   NSEnableScreenUpdates ();
3087 #endif
3092 static void
3093 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3094 /* --------------------------------------------------------------------------
3095      External (RIF): Draw a vertical line.
3096    -------------------------------------------------------------------------- */
3098   struct frame *f = XFRAME (WINDOW_FRAME (w));
3099   struct face *face;
3100   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3102   NSTRACE ("ns_draw_vertical_window_border");
3104   face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3106   ns_focus (f, &r, 1);
3107   if (face)
3108     [ns_lookup_indexed_color(face->foreground, f) set];
3110   NSRectFill(r);
3111   ns_unfocus (f);
3115 static void
3116 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3117 /* --------------------------------------------------------------------------
3118      External (RIF): Draw a window divider.
3119    -------------------------------------------------------------------------- */
3121   struct frame *f = XFRAME (WINDOW_FRAME (w));
3122   struct face *face;
3123   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
3125   NSTRACE ("ns_draw_window_divider");
3127   face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3129   ns_focus (f, &r, 1);
3130   if (face)
3131     [ns_lookup_indexed_color(face->foreground, f) set];
3133   NSRectFill(r);
3134   ns_unfocus (f);
3137 static void
3138 ns_show_hourglass (struct frame *f)
3140   /* TODO: add NSProgressIndicator to all frames.  */
3143 static void
3144 ns_hide_hourglass (struct frame *f)
3146   /* TODO: remove NSProgressIndicator from all frames.  */
3149 /* ==========================================================================
3151     Glyph drawing operations
3153    ========================================================================== */
3155 static int
3156 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3157 /* --------------------------------------------------------------------------
3158     Wrapper utility to account for internal border width on full-width lines,
3159     and allow top full-width rows to hit the frame top.  nr should be pointer
3160     to two successive NSRects.  Number of rects actually used is returned.
3161    -------------------------------------------------------------------------- */
3163   int n = get_glyph_string_clip_rects (s, nr, 2);
3164   return n;
3167 /* --------------------------------------------------------------------
3168    Draw a wavy line under glyph string s. The wave fills wave_height
3169    pixels from y.
3171                     x          wave_length = 2
3172                                  --
3173                 y    *   *   *   *   *
3174                      |* * * * * * * * *
3175     wave_height = 3  | *   *   *   *
3176   --------------------------------------------------------------------- */
3178 static void
3179 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3181   int wave_height = 3, wave_length = 2;
3182   int y, dx, dy, odd, xmax;
3183   NSPoint a, b;
3184   NSRect waveClip;
3186   dx = wave_length;
3187   dy = wave_height - 1;
3188   y =  s->ybase - wave_height + 3;
3189   xmax = x + width;
3191   /* Find and set clipping rectangle */
3192   waveClip = NSMakeRect (x, y, width, wave_height);
3193   [[NSGraphicsContext currentContext] saveGraphicsState];
3194   NSRectClip (waveClip);
3196   /* Draw the waves */
3197   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3198   b.x = a.x + dx;
3199   odd = (int)(a.x/dx) % 2;
3200   a.y = b.y = y + 0.5;
3202   if (odd)
3203     a.y += dy;
3204   else
3205     b.y += dy;
3207   while (a.x <= xmax)
3208     {
3209       [NSBezierPath strokeLineFromPoint:a toPoint:b];
3210       a.x = b.x, a.y = b.y;
3211       b.x += dx, b.y = y + 0.5 + odd*dy;
3212       odd = !odd;
3213     }
3215   /* Restore previous clipping rectangle(s) */
3216   [[NSGraphicsContext currentContext] restoreGraphicsState];
3221 static void
3222 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3223                          NSColor *defaultCol, CGFloat width, CGFloat x)
3224 /* --------------------------------------------------------------------------
3225    Draw underline, overline, and strike-through on glyph string s.
3226    -------------------------------------------------------------------------- */
3228   if (s->for_overlaps)
3229     return;
3231   /* Do underline. */
3232   if (face->underline_p)
3233     {
3234       if (s->face->underline_type == FACE_UNDER_WAVE)
3235         {
3236           if (face->underline_defaulted_p)
3237             [defaultCol set];
3238           else
3239             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3241           ns_draw_underwave (s, width, x);
3242         }
3243       else if (s->face->underline_type == FACE_UNDER_LINE)
3244         {
3246           NSRect r;
3247           unsigned long thickness, position;
3249           /* If the prev was underlined, match its appearance. */
3250           if (s->prev && s->prev->face->underline_p
3251               && s->prev->face->underline_type == FACE_UNDER_LINE
3252               && s->prev->underline_thickness > 0)
3253             {
3254               thickness = s->prev->underline_thickness;
3255               position = s->prev->underline_position;
3256             }
3257           else
3258             {
3259               struct font *font = font_for_underline_metrics (s);
3260               unsigned long descent = s->y + s->height - s->ybase;
3262               /* Use underline thickness of font, defaulting to 1. */
3263               thickness = (font && font->underline_thickness > 0)
3264                 ? font->underline_thickness : 1;
3266               /* Determine the offset of underlining from the baseline. */
3267               if (x_underline_at_descent_line)
3268                 position = descent - thickness;
3269               else if (x_use_underline_position_properties
3270                        && font && font->underline_position >= 0)
3271                 position = font->underline_position;
3272               else if (font)
3273                 position = lround (font->descent / 2);
3274               else
3275                 position = underline_minimum_offset;
3277               position = max (position, underline_minimum_offset);
3279               /* Ensure underlining is not cropped. */
3280               if (descent <= position)
3281                 {
3282                   position = descent - 1;
3283                   thickness = 1;
3284                 }
3285               else if (descent < position + thickness)
3286                 thickness = 1;
3287             }
3289           s->underline_thickness = thickness;
3290           s->underline_position = position;
3292           r = NSMakeRect (x, s->ybase + position, width, thickness);
3294           if (face->underline_defaulted_p)
3295             [defaultCol set];
3296           else
3297             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3298           NSRectFill (r);
3299         }
3300     }
3301   /* Do overline. We follow other terms in using a thickness of 1
3302      and ignoring overline_margin. */
3303   if (face->overline_p)
3304     {
3305       NSRect r;
3306       r = NSMakeRect (x, s->y, width, 1);
3308       if (face->overline_color_defaulted_p)
3309         [defaultCol set];
3310       else
3311         [ns_lookup_indexed_color (face->overline_color, s->f) set];
3312       NSRectFill (r);
3313     }
3315   /* Do strike-through.  We follow other terms for thickness and
3316      vertical position.*/
3317   if (face->strike_through_p)
3318     {
3319       NSRect r;
3320       /* Y-coordinate and height of the glyph string's first glyph.
3321          We cannot use s->y and s->height because those could be
3322          larger if there are taller display elements (e.g., characters
3323          displayed with a larger font) in the same glyph row.  */
3324       int glyph_y = s->ybase - s->first_glyph->ascent;
3325       int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3326       /* Strike-through width and offset from the glyph string's
3327          top edge.  */
3328       unsigned long h = 1;
3329       unsigned long dy;
3331       dy = lrint ((glyph_height - h) / 2);
3332       r = NSMakeRect (x, glyph_y + dy, width, 1);
3334       if (face->strike_through_color_defaulted_p)
3335         [defaultCol set];
3336       else
3337         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3338       NSRectFill (r);
3339     }
3342 static void
3343 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3344              char left_p, char right_p)
3345 /* --------------------------------------------------------------------------
3346     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3347     Note we can't just use an NSDrawRect command, because of the possibility
3348     of some sides not being drawn, and because the rect will be filled.
3349    -------------------------------------------------------------------------- */
3351   NSRect s = r;
3352   [col set];
3354   /* top, bottom */
3355   s.size.height = thickness;
3356   NSRectFill (s);
3357   s.origin.y += r.size.height - thickness;
3358   NSRectFill (s);
3360   s.size.height = r.size.height;
3361   s.origin.y = r.origin.y;
3363   /* left, right (optional) */
3364   s.size.width = thickness;
3365   if (left_p)
3366     NSRectFill (s);
3367   if (right_p)
3368     {
3369       s.origin.x += r.size.width - thickness;
3370       NSRectFill (s);
3371     }
3375 static void
3376 ns_draw_relief (NSRect r, int thickness, char raised_p,
3377                char top_p, char bottom_p, char left_p, char right_p,
3378                struct glyph_string *s)
3379 /* --------------------------------------------------------------------------
3380     Draw a relief rect inside r, optionally leaving some sides open.
3381     Note we can't just use an NSDrawBezel command, because of the possibility
3382     of some sides not being drawn, and because the rect will be filled.
3383    -------------------------------------------------------------------------- */
3385   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3386   NSColor *newBaseCol = nil;
3387   NSRect sr = r;
3389   NSTRACE ("ns_draw_relief");
3391   /* set up colors */
3393   if (s->face->use_box_color_for_shadows_p)
3394     {
3395       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3396     }
3397 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3398            && s->img->pixmap
3399            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3400        {
3401          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3402        } */
3403   else
3404     {
3405       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3406     }
3408   if (newBaseCol == nil)
3409     newBaseCol = [NSColor grayColor];
3411   if (newBaseCol != baseCol)  /* TODO: better check */
3412     {
3413       [baseCol release];
3414       baseCol = [newBaseCol retain];
3415       [lightCol release];
3416       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3417       [darkCol release];
3418       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3419     }
3421   [(raised_p ? lightCol : darkCol) set];
3423   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3425   /* top */
3426   sr.size.height = thickness;
3427   if (top_p) NSRectFill (sr);
3429   /* left */
3430   sr.size.height = r.size.height;
3431   sr.size.width = thickness;
3432   if (left_p) NSRectFill (sr);
3434   [(raised_p ? darkCol : lightCol) set];
3436   /* bottom */
3437   sr.size.width = r.size.width;
3438   sr.size.height = thickness;
3439   sr.origin.y += r.size.height - thickness;
3440   if (bottom_p) NSRectFill (sr);
3442   /* right */
3443   sr.size.height = r.size.height;
3444   sr.origin.y = r.origin.y;
3445   sr.size.width = thickness;
3446   sr.origin.x += r.size.width - thickness;
3447   if (right_p) NSRectFill (sr);
3451 static void
3452 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3453 /* --------------------------------------------------------------------------
3454       Function modeled after x_draw_glyph_string_box ().
3455       Sets up parameters for drawing.
3456    -------------------------------------------------------------------------- */
3458   int right_x, last_x;
3459   char left_p, right_p;
3460   struct glyph *last_glyph;
3461   NSRect r;
3462   int thickness;
3463   struct face *face;
3465   if (s->hl == DRAW_MOUSE_FACE)
3466     {
3467       face = FACE_FROM_ID_OR_NULL (s->f,
3468                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3469       if (!face)
3470         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3471     }
3472   else
3473     face = s->face;
3475   thickness = face->box_line_width;
3477   NSTRACE ("ns_dumpglyphs_box_or_relief");
3479   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3480             ? WINDOW_RIGHT_EDGE_X (s->w)
3481             : window_box_right (s->w, s->area));
3482   last_glyph = (s->cmp || s->img
3483                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3485   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3486               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3488   left_p = (s->first_glyph->left_box_line_p
3489             || (s->hl == DRAW_MOUSE_FACE
3490                 && (s->prev == NULL || s->prev->hl != s->hl)));
3491   right_p = (last_glyph->right_box_line_p
3492              || (s->hl == DRAW_MOUSE_FACE
3493                  && (s->next == NULL || s->next->hl != s->hl)));
3495   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3497   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3498   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3499     {
3500       ns_draw_box (r, abs (thickness),
3501                    ns_lookup_indexed_color (face->box_color, s->f),
3502                   left_p, right_p);
3503     }
3504   else
3505     {
3506       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3507                      1, 1, left_p, right_p, s);
3508     }
3512 static void
3513 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3514 /* --------------------------------------------------------------------------
3515       Modeled after x_draw_glyph_string_background, which draws BG in
3516       certain cases.  Others are left to the text rendering routine.
3517    -------------------------------------------------------------------------- */
3519   NSTRACE ("ns_maybe_dumpglyphs_background");
3521   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3522     {
3523       int box_line_width = max (s->face->box_line_width, 0);
3524       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3525           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3526              dimensions, since the actual glyphs might be much
3527              smaller.  So in that case we always clear the rectangle
3528              with background color.  */
3529           || FONT_TOO_HIGH (s->font)
3530           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3531         {
3532           struct face *face;
3533           if (s->hl == DRAW_MOUSE_FACE)
3534             {
3535               face
3536                 = FACE_FROM_ID_OR_NULL (s->f,
3537                                         MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3538               if (!face)
3539                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3540             }
3541           else
3542             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3543           if (!face->stipple)
3544             [(NS_FACE_BACKGROUND (face) != 0
3545               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3546               : FRAME_BACKGROUND_COLOR (s->f)) set];
3547           else
3548             {
3549               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3550               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3551             }
3553           if (s->hl != DRAW_CURSOR)
3554             {
3555               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3556                                     s->background_width,
3557                                     s->height-2*box_line_width);
3558               NSRectFill (r);
3559             }
3561           s->background_filled_p = 1;
3562         }
3563     }
3567 static void
3568 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3569 /* --------------------------------------------------------------------------
3570       Renders an image and associated borders.
3571    -------------------------------------------------------------------------- */
3573   EmacsImage *img = s->img->pixmap;
3574   int box_line_vwidth = max (s->face->box_line_width, 0);
3575   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3576   int bg_x, bg_y, bg_height;
3577   int th;
3578   char raised_p;
3579   NSRect br;
3580   struct face *face;
3581   NSColor *tdCol;
3583   NSTRACE ("ns_dumpglyphs_image");
3585   if (s->face->box != FACE_NO_BOX
3586       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3587     x += abs (s->face->box_line_width);
3589   bg_x = x;
3590   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3591   bg_height = s->height;
3592   /* other terms have this, but was causing problems w/tabbar mode */
3593   /* - 2 * box_line_vwidth; */
3595   if (s->slice.x == 0) x += s->img->hmargin;
3596   if (s->slice.y == 0) y += s->img->vmargin;
3598   /* Draw BG: if we need larger area than image itself cleared, do that,
3599      otherwise, since we composite the image under NS (instead of mucking
3600      with its background color), we must clear just the image area. */
3601   if (s->hl == DRAW_MOUSE_FACE)
3602     {
3603       face = FACE_FROM_ID_OR_NULL (s->f,
3604                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3605       if (!face)
3606        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3607     }
3608   else
3609     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3611   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3613   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3614       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3615     {
3616       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3617       s->background_filled_p = 1;
3618     }
3619   else
3620     {
3621       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3622     }
3624   NSRectFill (br);
3626   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3627   if (img != nil)
3628     {
3629 #ifdef NS_IMPL_COCOA
3630       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3631       NSRect ir = NSMakeRect (s->slice.x,
3632                               s->img->height - s->slice.y - s->slice.height,
3633                               s->slice.width, s->slice.height);
3634       [img drawInRect: dr
3635              fromRect: ir
3636              operation: NSCompositingOperationSourceOver
3637               fraction: 1.0
3638            respectFlipped: YES
3639                 hints: nil];
3640 #else
3641       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3642                   operation: NSCompositingOperationSourceOver];
3643 #endif
3644     }
3646   if (s->hl == DRAW_CURSOR)
3647     {
3648     [FRAME_CURSOR_COLOR (s->f) set];
3649     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3650       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3651     else
3652       /* Currently on NS img->mask is always 0. Since
3653          get_window_cursor_type specifies a hollow box cursor when on
3654          a non-masked image we never reach this clause. But we put it
3655          in in anticipation of better support for image masks on
3656          NS. */
3657       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3658     }
3659   else
3660     {
3661       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3662     }
3664   /* Draw underline, overline, strike-through. */
3665   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3667   /* Draw relief, if requested */
3668   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3669     {
3670       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3671         {
3672           th = tool_bar_button_relief >= 0 ?
3673             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3674           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3675         }
3676       else
3677         {
3678           th = abs (s->img->relief);
3679           raised_p = (s->img->relief > 0);
3680         }
3682       r.origin.x = x - th;
3683       r.origin.y = y - th;
3684       r.size.width = s->slice.width + 2*th-1;
3685       r.size.height = s->slice.height + 2*th-1;
3686       ns_draw_relief (r, th, raised_p,
3687                       s->slice.y == 0,
3688                       s->slice.y + s->slice.height == s->img->height,
3689                       s->slice.x == 0,
3690                       s->slice.x + s->slice.width == s->img->width, s);
3691     }
3693   /* If there is no mask, the background won't be seen,
3694      so draw a rectangle on the image for the cursor.
3695      Do this for all images, getting transparency right is not reliable.  */
3696   if (s->hl == DRAW_CURSOR)
3697     {
3698       int thickness = abs (s->img->relief);
3699       if (thickness == 0) thickness = 1;
3700       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3701     }
3705 static void
3706 ns_dumpglyphs_stretch (struct glyph_string *s)
3708   NSRect r[2];
3709   int n, i;
3710   struct face *face;
3711   NSColor *fgCol, *bgCol;
3713   if (!s->background_filled_p)
3714     {
3715       n = ns_get_glyph_string_clip_rect (s, r);
3716       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3718       ns_focus (s->f, r, n);
3720       if (s->hl == DRAW_MOUSE_FACE)
3721        {
3722          face = FACE_FROM_ID_OR_NULL (s->f,
3723                                       MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3724          if (!face)
3725            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3726        }
3727       else
3728        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3730       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3731       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3733       for (i = 0; i < n; ++i)
3734         {
3735           if (!s->row->full_width_p)
3736             {
3737               int overrun, leftoverrun;
3739               /* truncate to avoid overwriting fringe and/or scrollbar */
3740               overrun = max (0, (s->x + s->background_width)
3741                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3742                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3743               r[i].size.width -= overrun;
3745               /* truncate to avoid overwriting to left of the window box */
3746               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3747                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3749               if (leftoverrun > 0)
3750                 {
3751                   r[i].origin.x += leftoverrun;
3752                   r[i].size.width -= leftoverrun;
3753                 }
3755               /* XXX: Try to work between problem where a stretch glyph on
3756                  a partially-visible bottom row will clear part of the
3757                  modeline, and another where list-buffers headers and similar
3758                  rows erroneously have visible_height set to 0.  Not sure
3759                  where this is coming from as other terms seem not to show. */
3760               r[i].size.height = min (s->height, s->row->visible_height);
3761             }
3763           [bgCol set];
3765           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3766              overwriting cursor (usually when cursor on a tab) */
3767           if (s->hl == DRAW_CURSOR)
3768             {
3769               CGFloat x, width;
3771               x = r[i].origin.x;
3772               width = s->w->phys_cursor_width;
3773               r[i].size.width -= width;
3774               r[i].origin.x += width;
3776               NSRectFill (r[i]);
3778               /* Draw overlining, etc. on the cursor. */
3779               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3780                 ns_draw_text_decoration (s, face, bgCol, width, x);
3781               else
3782                 ns_draw_text_decoration (s, face, fgCol, width, x);
3783             }
3784           else
3785             {
3786               NSRectFill (r[i]);
3787             }
3789           /* Draw overlining, etc. on the stretch glyph (or the part
3790              of the stretch glyph after the cursor). */
3791           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3792                                    r[i].origin.x);
3793         }
3794       ns_unfocus (s->f);
3795       s->background_filled_p = 1;
3796     }
3800 static void
3801 ns_draw_glyph_string_foreground (struct glyph_string *s)
3803   int x, flags;
3804   struct font *font = s->font;
3806   /* If first glyph of S has a left box line, start drawing the text
3807      of S to the right of that box line.  */
3808   if (s->face && s->face->box != FACE_NO_BOX
3809       && s->first_glyph->left_box_line_p)
3810     x = s->x + eabs (s->face->box_line_width);
3811   else
3812     x = s->x;
3814   flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3815     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3816      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3817       NS_DUMPGLYPH_NORMAL));
3819   font->driver->draw
3820     (s, s->cmp_from, s->nchars, x, s->ybase,
3821      (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3822      || flags == NS_DUMPGLYPH_MOUSEFACE);
3826 static void
3827 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3829   int i, j, x;
3830   struct font *font = s->font;
3832   /* If first glyph of S has a left box line, start drawing the text
3833      of S to the right of that box line.  */
3834   if (s->face && s->face->box != FACE_NO_BOX
3835       && s->first_glyph->left_box_line_p)
3836     x = s->x + eabs (s->face->box_line_width);
3837   else
3838     x = s->x;
3840   /* S is a glyph string for a composition.  S->cmp_from is the index
3841      of the first character drawn for glyphs of this composition.
3842      S->cmp_from == 0 means we are drawing the very first character of
3843      this composition.  */
3845   /* Draw a rectangle for the composition if the font for the very
3846      first character of the composition could not be loaded.  */
3847   if (s->font_not_found_p)
3848     {
3849       if (s->cmp_from == 0)
3850         {
3851           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3852           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3853         }
3854     }
3855   else if (! s->first_glyph->u.cmp.automatic)
3856     {
3857       int y = s->ybase;
3859       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3860         /* TAB in a composition means display glyphs with padding
3861            space on the left or right.  */
3862         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3863           {
3864             int xx = x + s->cmp->offsets[j * 2];
3865             int yy = y - s->cmp->offsets[j * 2 + 1];
3867             font->driver->draw (s, j, j + 1, xx, yy, false);
3868             if (s->face->overstrike)
3869               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3870           }
3871     }
3872   else
3873     {
3874       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3875       Lisp_Object glyph;
3876       int y = s->ybase;
3877       int width = 0;
3879       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3880         {
3881           glyph = LGSTRING_GLYPH (gstring, i);
3882           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3883             width += LGLYPH_WIDTH (glyph);
3884           else
3885             {
3886               int xoff, yoff, wadjust;
3888               if (j < i)
3889                 {
3890                   font->driver->draw (s, j, i, x, y, false);
3891                   if (s->face->overstrike)
3892                     font->driver->draw (s, j, i, x + 1, y, false);
3893                   x += width;
3894                 }
3895               xoff = LGLYPH_XOFF (glyph);
3896               yoff = LGLYPH_YOFF (glyph);
3897               wadjust = LGLYPH_WADJUST (glyph);
3898               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3899               if (s->face->overstrike)
3900                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3901                                     false);
3902               x += wadjust;
3903               j = i + 1;
3904               width = 0;
3905             }
3906         }
3907       if (j < i)
3908         {
3909           font->driver->draw (s, j, i, x, y, false);
3910           if (s->face->overstrike)
3911             font->driver->draw (s, j, i, x + 1, y, false);
3912         }
3913     }
3916 static void
3917 ns_draw_glyph_string (struct glyph_string *s)
3918 /* --------------------------------------------------------------------------
3919       External (RIF): Main draw-text call.
3920    -------------------------------------------------------------------------- */
3922   /* TODO (optimize): focus for box and contents draw */
3923   NSRect r[2];
3924   int n;
3925   char box_drawn_p = 0;
3926   struct font *font = s->face->font;
3927   if (! font) font = FRAME_FONT (s->f);
3929   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3931   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3932     {
3933       int width;
3934       struct glyph_string *next;
3936       for (width = 0, next = s->next;
3937            next && width < s->right_overhang;
3938            width += next->width, next = next->next)
3939         if (next->first_glyph->type != IMAGE_GLYPH)
3940           {
3941             if (next->first_glyph->type != STRETCH_GLYPH)
3942               {
3943                 n = ns_get_glyph_string_clip_rect (s->next, r);
3944                 ns_focus (s->f, r, n);
3945                 ns_maybe_dumpglyphs_background (s->next, 1);
3946                 ns_unfocus (s->f);
3947               }
3948             else
3949               {
3950                 ns_dumpglyphs_stretch (s->next);
3951               }
3952             next->num_clips = 0;
3953           }
3954     }
3956   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3957         && (s->first_glyph->type == CHAR_GLYPH
3958             || s->first_glyph->type == COMPOSITE_GLYPH))
3959     {
3960       n = ns_get_glyph_string_clip_rect (s, r);
3961       ns_focus (s->f, r, n);
3962       ns_maybe_dumpglyphs_background (s, 1);
3963       ns_dumpglyphs_box_or_relief (s);
3964       ns_unfocus (s->f);
3965       box_drawn_p = 1;
3966     }
3968   switch (s->first_glyph->type)
3969     {
3971     case IMAGE_GLYPH:
3972       n = ns_get_glyph_string_clip_rect (s, r);
3973       ns_focus (s->f, r, n);
3974       ns_dumpglyphs_image (s, r[0]);
3975       ns_unfocus (s->f);
3976       break;
3978     case STRETCH_GLYPH:
3979       ns_dumpglyphs_stretch (s);
3980       break;
3982     case CHAR_GLYPH:
3983     case COMPOSITE_GLYPH:
3984       n = ns_get_glyph_string_clip_rect (s, r);
3985       ns_focus (s->f, r, n);
3987       if (s->for_overlaps || (s->cmp_from > 0
3988                               && ! s->first_glyph->u.cmp.automatic))
3989         s->background_filled_p = 1;
3990       else
3991         ns_maybe_dumpglyphs_background
3992           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3994       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3995         {
3996           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3997           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3998           NS_FACE_FOREGROUND (s->face) = tmp;
3999         }
4001       {
4002         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4004         if (isComposite)
4005           ns_draw_composite_glyph_string_foreground (s);
4006         else
4007           ns_draw_glyph_string_foreground (s);
4008       }
4010       {
4011         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4012                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4013                                                    s->f)
4014                         : FRAME_FOREGROUND_COLOR (s->f));
4015         [col set];
4017         /* Draw underline, overline, strike-through. */
4018         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4019       }
4021       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4022         {
4023           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4024           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4025           NS_FACE_FOREGROUND (s->face) = tmp;
4026         }
4028       ns_unfocus (s->f);
4029       break;
4031     case GLYPHLESS_GLYPH:
4032       n = ns_get_glyph_string_clip_rect (s, r);
4033       ns_focus (s->f, r, n);
4035       if (s->for_overlaps || (s->cmp_from > 0
4036                               && ! s->first_glyph->u.cmp.automatic))
4037         s->background_filled_p = 1;
4038       else
4039         ns_maybe_dumpglyphs_background
4040           (s, s->first_glyph->type == COMPOSITE_GLYPH);
4041       /* ... */
4042       /* Not yet implemented.  */
4043       /* ... */
4044       ns_unfocus (s->f);
4045       break;
4047     default:
4048       emacs_abort ();
4049     }
4051   /* Draw box if not done already. */
4052   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4053     {
4054       n = ns_get_glyph_string_clip_rect (s, r);
4055       ns_focus (s->f, r, n);
4056       ns_dumpglyphs_box_or_relief (s);
4057       ns_unfocus (s->f);
4058     }
4060   s->num_clips = 0;
4065 /* ==========================================================================
4067     Event loop
4069    ========================================================================== */
4072 static void
4073 ns_send_appdefined (int value)
4074 /* --------------------------------------------------------------------------
4075     Internal: post an appdefined event which EmacsApp-sendEvent will
4076               recognize and take as a command to halt the event loop.
4077    -------------------------------------------------------------------------- */
4079   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4081   // GNUstep needs postEvent to happen on the main thread.
4082   // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4083   if (! [[NSThread currentThread] isMainThread])
4084     {
4085       EmacsApp *app = (EmacsApp *)NSApp;
4086       app->nextappdefined = value;
4087       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4088                             withObject:nil
4089                          waitUntilDone:NO];
4090       return;
4091     }
4093   /* Only post this event if we haven't already posted one.  This will end
4094        the [NXApp run] main loop after having processed all events queued at
4095        this moment.  */
4097 #ifdef NS_IMPL_COCOA
4098   if (! send_appdefined)
4099     {
4100       /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4101          in certain situations (rapid incoming events).
4102          So check if we have one, if not add one.  */
4103       NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4104                                           untilDate:[NSDate distantPast]
4105                                              inMode:NSDefaultRunLoopMode
4106                                             dequeue:NO];
4107       if (! appev) send_appdefined = YES;
4108     }
4109 #endif
4111   if (send_appdefined)
4112     {
4113       NSEvent *nxev;
4115       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
4116       send_appdefined = NO;
4118       /* Don't need wakeup timer any more */
4119       if (timed_entry)
4120         {
4121           [timed_entry invalidate];
4122           [timed_entry release];
4123           timed_entry = nil;
4124         }
4126       nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4127                                 location: NSMakePoint (0, 0)
4128                            modifierFlags: 0
4129                                timestamp: 0
4130                             windowNumber: [[NSApp mainWindow] windowNumber]
4131                                  context: [NSApp context]
4132                                  subtype: 0
4133                                    data1: value
4134                                    data2: 0];
4136       /* Post an application defined event on the event queue.  When this is
4137          received the [NXApp run] will return, thus having processed all
4138          events which are currently queued.  */
4139       [NSApp postEvent: nxev atStart: NO];
4140     }
4143 #ifdef HAVE_NATIVE_FS
4144 static void
4145 check_native_fs ()
4147   Lisp_Object frame, tail;
4149   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4150     return;
4152   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4154   FOR_EACH_FRAME (tail, frame)
4155     {
4156       struct frame *f = XFRAME (frame);
4157       if (FRAME_NS_P (f))
4158         {
4159           EmacsView *view = FRAME_NS_VIEW (f);
4160           [view updateCollectionBehavior];
4161         }
4162     }
4164 #endif
4166 /* GNUstep does not have cancelTracking.  */
4167 #ifdef NS_IMPL_COCOA
4168 /* Check if menu open should be canceled or continued as normal.  */
4169 void
4170 ns_check_menu_open (NSMenu *menu)
4172   /* Click in menu bar? */
4173   NSArray *a = [[NSApp mainMenu] itemArray];
4174   int i;
4175   BOOL found = NO;
4177   if (menu == nil) // Menu tracking ended.
4178     {
4179       if (menu_will_open_state == MENU_OPENING)
4180         menu_will_open_state = MENU_NONE;
4181       return;
4182     }
4184   for (i = 0; ! found && i < [a count]; i++)
4185     found = menu == [[a objectAtIndex:i] submenu];
4186   if (found)
4187     {
4188       if (menu_will_open_state == MENU_NONE && emacs_event)
4189         {
4190           NSEvent *theEvent = [NSApp currentEvent];
4191           struct frame *emacsframe = SELECTED_FRAME ();
4193           [menu cancelTracking];
4194           menu_will_open_state = MENU_PENDING;
4195           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4196           EV_TRAILER (theEvent);
4198           CGEventRef ourEvent = CGEventCreate (NULL);
4199           menu_mouse_point = CGEventGetLocation (ourEvent);
4200           CFRelease (ourEvent);
4201         }
4202       else if (menu_will_open_state == MENU_OPENING)
4203         {
4204           menu_will_open_state = MENU_NONE;
4205         }
4206     }
4209 /* Redo saved menu click if state is MENU_PENDING.  */
4210 void
4211 ns_check_pending_open_menu ()
4213   if (menu_will_open_state == MENU_PENDING)
4214     {
4215       CGEventSourceRef source
4216         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4218       CGEventRef event = CGEventCreateMouseEvent (source,
4219                                                   kCGEventLeftMouseDown,
4220                                                   menu_mouse_point,
4221                                                   kCGMouseButtonLeft);
4222       CGEventSetType (event, kCGEventLeftMouseDown);
4223       CGEventPost (kCGHIDEventTap, event);
4224       CFRelease (event);
4225       CFRelease (source);
4227       menu_will_open_state = MENU_OPENING;
4228     }
4230 #endif /* NS_IMPL_COCOA */
4232 static int
4233 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4234 /* --------------------------------------------------------------------------
4235      External (hook): Post an event to ourself and keep reading events until
4236      we read it back again.  In effect process all events which were waiting.
4237      From 21+ we have to manage the event buffer ourselves.
4238    -------------------------------------------------------------------------- */
4240   struct input_event ev;
4241   int nevents;
4243   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4245 #ifdef HAVE_NATIVE_FS
4246   check_native_fs ();
4247 #endif
4249   if ([NSApp modalWindow] != nil)
4250     return -1;
4252   if (hold_event_q.nr > 0)
4253     {
4254       int i;
4255       for (i = 0; i < hold_event_q.nr; ++i)
4256         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4257       hold_event_q.nr = 0;
4258       return i;
4259     }
4261   if ([NSThread isMainThread])
4262     {
4263       block_input ();
4264       n_emacs_events_pending = 0;
4265       ns_init_events (&ev);
4266       q_event_ptr = hold_quit;
4268       /* we manage autorelease pools by allocate/reallocate each time around
4269          the loop; strict nesting is occasionally violated but seems not to
4270          matter.. earlier methods using full nesting caused major memory leaks */
4271       [outerpool release];
4272       outerpool = [[NSAutoreleasePool alloc] init];
4274       /* If have pending open-file requests, attend to the next one of those. */
4275       if (ns_pending_files && [ns_pending_files count] != 0
4276           && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4277         {
4278           [ns_pending_files removeObjectAtIndex: 0];
4279         }
4280       /* Deal with pending service requests. */
4281       else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4282                && [(EmacsApp *)
4283                     NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4284                                  withArg: [ns_pending_service_args objectAtIndex: 0]])
4285         {
4286           [ns_pending_service_names removeObjectAtIndex: 0];
4287           [ns_pending_service_args removeObjectAtIndex: 0];
4288         }
4289       else
4290         {
4291           /* Run and wait for events.  We must always send one NX_APPDEFINED event
4292              to ourself, otherwise [NXApp run] will never exit.  */
4293           send_appdefined = YES;
4294           ns_send_appdefined (-1);
4296           [NSApp run];
4297         }
4299       nevents = n_emacs_events_pending;
4300       n_emacs_events_pending = 0;
4301       ns_finish_events ();
4302       q_event_ptr = NULL;
4303       unblock_input ();
4304     }
4305   else
4306     return -1;
4308   return nevents;
4313 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4314            fd_set *exceptfds, struct timespec *timeout,
4315            sigset_t *sigmask)
4316 /* --------------------------------------------------------------------------
4317      Replacement for select, checking for events
4318    -------------------------------------------------------------------------- */
4320   int result;
4321   int t, k, nr = 0;
4322   struct input_event event;
4323   char c;
4325   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4327 #ifdef HAVE_NATIVE_FS
4328   check_native_fs ();
4329 #endif
4331   if (hold_event_q.nr > 0)
4332     {
4333       /* We already have events pending. */
4334       raise (SIGIO);
4335       errno = EINTR;
4336       return -1;
4337     }
4339   for (k = 0; k < nfds+1; k++)
4340     {
4341       if (readfds && FD_ISSET(k, readfds)) ++nr;
4342       if (writefds && FD_ISSET(k, writefds)) ++nr;
4343     }
4345   if (NSApp == nil
4346       || ![NSThread isMainThread]
4347       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4348     return thread_select(pselect, nfds, readfds, writefds,
4349                          exceptfds, timeout, sigmask);
4350   else
4351     {
4352       struct timespec t = {0, 0};
4353       thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4354     }
4356   [outerpool release];
4357   outerpool = [[NSAutoreleasePool alloc] init];
4360   send_appdefined = YES;
4361   if (nr > 0)
4362     {
4363       pthread_mutex_lock (&select_mutex);
4364       select_nfds = nfds;
4365       select_valid = 0;
4366       if (readfds)
4367         {
4368           select_readfds = *readfds;
4369           select_valid += SELECT_HAVE_READ;
4370         }
4371       if (writefds)
4372         {
4373           select_writefds = *writefds;
4374           select_valid += SELECT_HAVE_WRITE;
4375         }
4377       if (timeout)
4378         {
4379           select_timeout = *timeout;
4380           select_valid += SELECT_HAVE_TMO;
4381         }
4383       pthread_mutex_unlock (&select_mutex);
4385       /* Inform fd_handler that select should be called */
4386       c = 'g';
4387       emacs_write_sig (selfds[1], &c, 1);
4388     }
4389   else if (nr == 0 && timeout)
4390     {
4391       /* No file descriptor, just a timeout, no need to wake fd_handler  */
4392       double time = timespectod (*timeout);
4393       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4394                                                       target: NSApp
4395                                                     selector:
4396                                   @selector (timeout_handler:)
4397                                                     userInfo: 0
4398                                                      repeats: NO]
4399                       retain];
4400     }
4401   else /* No timeout and no file descriptors, can this happen?  */
4402     {
4403       /* Send appdefined so we exit from the loop */
4404       ns_send_appdefined (-1);
4405     }
4407   block_input ();
4408   ns_init_events (&event);
4410   [NSApp run];
4412   ns_finish_events ();
4413   if (nr > 0 && readfds)
4414     {
4415       c = 's';
4416       emacs_write_sig (selfds[1], &c, 1);
4417     }
4418   unblock_input ();
4420   t = last_appdefined_event_data;
4422   if (t != NO_APPDEFINED_DATA)
4423     {
4424       last_appdefined_event_data = NO_APPDEFINED_DATA;
4426       if (t == -2)
4427         {
4428           /* The NX_APPDEFINED event we received was a timeout. */
4429           result = 0;
4430         }
4431       else if (t == -1)
4432         {
4433           /* The NX_APPDEFINED event we received was the result of
4434              at least one real input event arriving.  */
4435           errno = EINTR;
4436           result = -1;
4437         }
4438       else
4439         {
4440           /* Received back from select () in fd_handler; copy the results */
4441           pthread_mutex_lock (&select_mutex);
4442           if (readfds) *readfds = select_readfds;
4443           if (writefds) *writefds = select_writefds;
4444           pthread_mutex_unlock (&select_mutex);
4445           result = t;
4446         }
4447     }
4448   else
4449     {
4450       errno = EINTR;
4451       result = -1;
4452     }
4454   return result;
4457 #ifdef HAVE_PTHREAD
4458 void
4459 ns_run_loop_break ()
4460 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4462   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4464   /* If we don't have a GUI, don't send the event. */
4465   if (NSApp != NULL)
4466     ns_send_appdefined(-1);
4468 #endif
4471 /* ==========================================================================
4473     Scrollbar handling
4475    ========================================================================== */
4478 static void
4479 ns_set_vertical_scroll_bar (struct window *window,
4480                            int portion, int whole, int position)
4481 /* --------------------------------------------------------------------------
4482       External (hook): Update or add scrollbar
4483    -------------------------------------------------------------------------- */
4485   Lisp_Object win;
4486   NSRect r, v;
4487   struct frame *f = XFRAME (WINDOW_FRAME (window));
4488   EmacsView *view = FRAME_NS_VIEW (f);
4489   EmacsScroller *bar;
4490   int window_y, window_height;
4491   int top, left, height, width;
4492   BOOL update_p = YES;
4494   /* optimization; display engine sends WAY too many of these.. */
4495   if (!NILP (window->vertical_scroll_bar))
4496     {
4497       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4498       if ([bar checkSamePosition: position portion: portion whole: whole])
4499         {
4500           if (view->scrollbarsNeedingUpdate == 0)
4501             {
4502               if (!windows_or_buffers_changed)
4503                   return;
4504             }
4505           else
4506             view->scrollbarsNeedingUpdate--;
4507           update_p = NO;
4508         }
4509     }
4511   NSTRACE ("ns_set_vertical_scroll_bar");
4513   /* Get dimensions.  */
4514   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4515   top = window_y;
4516   height = window_height;
4517   width = NS_SCROLL_BAR_WIDTH (f);
4518   left = WINDOW_SCROLL_BAR_AREA_X (window);
4520   r = NSMakeRect (left, top, width, height);
4521   /* the parent view is flipped, so we need to flip y value */
4522   v = [view frame];
4523   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4525   XSETWINDOW (win, window);
4526   block_input ();
4528   /* we want at least 5 lines to display a scrollbar */
4529   if (WINDOW_TOTAL_LINES (window) < 5)
4530     {
4531       if (!NILP (window->vertical_scroll_bar))
4532         {
4533           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4534           [bar removeFromSuperview];
4535           wset_vertical_scroll_bar (window, Qnil);
4536           [bar release];
4537         }
4538       ns_clear_frame_area (f, left, top, width, height);
4539       unblock_input ();
4540       return;
4541     }
4543   if (NILP (window->vertical_scroll_bar))
4544     {
4545       if (width > 0 && height > 0)
4546         ns_clear_frame_area (f, left, top, width, height);
4548       bar = [[EmacsScroller alloc] initFrame: r window: win];
4549       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4550       update_p = YES;
4551     }
4552   else
4553     {
4554       NSRect oldRect;
4555       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4556       oldRect = [bar frame];
4557       r.size.width = oldRect.size.width;
4558       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4559         {
4560           if (oldRect.origin.x != r.origin.x)
4561               ns_clear_frame_area (f, left, top, width, height);
4562           [bar setFrame: r];
4563         }
4564     }
4566   if (update_p)
4567     [bar setPosition: position portion: portion whole: whole];
4568   unblock_input ();
4572 static void
4573 ns_set_horizontal_scroll_bar (struct window *window,
4574                               int portion, int whole, int position)
4575 /* --------------------------------------------------------------------------
4576       External (hook): Update or add scrollbar
4577    -------------------------------------------------------------------------- */
4579   Lisp_Object win;
4580   NSRect r, v;
4581   struct frame *f = XFRAME (WINDOW_FRAME (window));
4582   EmacsView *view = FRAME_NS_VIEW (f);
4583   EmacsScroller *bar;
4584   int top, height, left, width;
4585   int window_x, window_width;
4586   BOOL update_p = YES;
4588   /* optimization; display engine sends WAY too many of these.. */
4589   if (!NILP (window->horizontal_scroll_bar))
4590     {
4591       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4592       if ([bar checkSamePosition: position portion: portion whole: whole])
4593         {
4594           if (view->scrollbarsNeedingUpdate == 0)
4595             {
4596               if (!windows_or_buffers_changed)
4597                   return;
4598             }
4599           else
4600             view->scrollbarsNeedingUpdate--;
4601           update_p = NO;
4602         }
4603     }
4605   NSTRACE ("ns_set_horizontal_scroll_bar");
4607   /* Get dimensions.  */
4608   window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4609   left = window_x;
4610   width = window_width;
4611   height = NS_SCROLL_BAR_HEIGHT (f);
4612   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4614   r = NSMakeRect (left, top, width, height);
4615   /* the parent view is flipped, so we need to flip y value */
4616   v = [view frame];
4617   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4619   XSETWINDOW (win, window);
4620   block_input ();
4622   if (NILP (window->horizontal_scroll_bar))
4623     {
4624       if (width > 0 && height > 0)
4625         ns_clear_frame_area (f, left, top, width, height);
4627       bar = [[EmacsScroller alloc] initFrame: r window: win];
4628       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4629       update_p = YES;
4630     }
4631   else
4632     {
4633       NSRect oldRect;
4634       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4635       oldRect = [bar frame];
4636       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4637         {
4638           if (oldRect.origin.y != r.origin.y)
4639             ns_clear_frame_area (f, left, top, width, height);
4640           [bar setFrame: r];
4641           update_p = YES;
4642         }
4643     }
4645   /* If there are both horizontal and vertical scroll-bars they leave
4646      a square that belongs to neither. We need to clear it otherwise
4647      it fills with junk. */
4648   if (!NILP (window->vertical_scroll_bar))
4649     ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4650                          NS_SCROLL_BAR_HEIGHT (f), height);
4652   if (update_p)
4653     [bar setPosition: position portion: portion whole: whole];
4654   unblock_input ();
4658 static void
4659 ns_condemn_scroll_bars (struct frame *f)
4660 /* --------------------------------------------------------------------------
4661      External (hook): arrange for all frame's scrollbars to be removed
4662      at next call to judge_scroll_bars, except for those redeemed.
4663    -------------------------------------------------------------------------- */
4665   int i;
4666   id view;
4667   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4669   NSTRACE ("ns_condemn_scroll_bars");
4671   for (i =[subviews count]-1; i >= 0; i--)
4672     {
4673       view = [subviews objectAtIndex: i];
4674       if ([view isKindOfClass: [EmacsScroller class]])
4675         [view condemn];
4676     }
4680 static void
4681 ns_redeem_scroll_bar (struct window *window)
4682 /* --------------------------------------------------------------------------
4683      External (hook): arrange to spare this window's scrollbar
4684      at next call to judge_scroll_bars.
4685    -------------------------------------------------------------------------- */
4687   id bar;
4688   NSTRACE ("ns_redeem_scroll_bar");
4689   if (!NILP (window->vertical_scroll_bar)
4690       && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4691     {
4692       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4693       [bar reprieve];
4694     }
4696   if (!NILP (window->horizontal_scroll_bar)
4697       && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4698     {
4699       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4700       [bar reprieve];
4701     }
4705 static void
4706 ns_judge_scroll_bars (struct frame *f)
4707 /* --------------------------------------------------------------------------
4708      External (hook): destroy all scrollbars on frame that weren't
4709      redeemed after call to condemn_scroll_bars.
4710    -------------------------------------------------------------------------- */
4712   int i;
4713   id view;
4714   EmacsView *eview = FRAME_NS_VIEW (f);
4715   NSArray *subviews = [[eview superview] subviews];
4716   BOOL removed = NO;
4718   NSTRACE ("ns_judge_scroll_bars");
4719   for (i = [subviews count]-1; i >= 0; --i)
4720     {
4721       view = [subviews objectAtIndex: i];
4722       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4723       if ([view judge])
4724         removed = YES;
4725     }
4727   if (removed)
4728     [eview updateFrameSize: NO];
4731 /* ==========================================================================
4733     Initialization
4735    ========================================================================== */
4738 x_display_pixel_height (struct ns_display_info *dpyinfo)
4740   NSArray *screens = [NSScreen screens];
4741   NSEnumerator *enumerator = [screens objectEnumerator];
4742   NSScreen *screen;
4743   NSRect frame;
4745   frame = NSZeroRect;
4746   while ((screen = [enumerator nextObject]) != nil)
4747     frame = NSUnionRect (frame, [screen frame]);
4749   return NSHeight (frame);
4753 x_display_pixel_width (struct ns_display_info *dpyinfo)
4755   NSArray *screens = [NSScreen screens];
4756   NSEnumerator *enumerator = [screens objectEnumerator];
4757   NSScreen *screen;
4758   NSRect frame;
4760   frame = NSZeroRect;
4761   while ((screen = [enumerator nextObject]) != nil)
4762     frame = NSUnionRect (frame, [screen frame]);
4764   return NSWidth (frame);
4768 static Lisp_Object ns_string_to_lispmod (const char *s)
4769 /* --------------------------------------------------------------------------
4770      Convert modifier name to lisp symbol
4771    -------------------------------------------------------------------------- */
4773   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4774     return Qmeta;
4775   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4776     return Qsuper;
4777   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4778     return Qcontrol;
4779   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4780     return Qalt;
4781   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4782     return Qhyper;
4783   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4784     return Qnone;
4785   else
4786     return Qnil;
4790 static void
4791 ns_default (const char *parameter, Lisp_Object *result,
4792            Lisp_Object yesval, Lisp_Object noval,
4793            BOOL is_float, BOOL is_modstring)
4794 /* --------------------------------------------------------------------------
4795       Check a parameter value in user's preferences
4796    -------------------------------------------------------------------------- */
4798   const char *value = ns_get_defaults_value (parameter);
4800   if (value)
4801     {
4802       double f;
4803       char *pos;
4804       if (c_strcasecmp (value, "YES") == 0)
4805         *result = yesval;
4806       else if (c_strcasecmp (value, "NO") == 0)
4807         *result = noval;
4808       else if (is_float && (f = strtod (value, &pos), pos != value))
4809         *result = make_float (f);
4810       else if (is_modstring && value)
4811         *result = ns_string_to_lispmod (value);
4812       else fprintf (stderr,
4813                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4814     }
4818 static void
4819 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4820 /* --------------------------------------------------------------------------
4821       Initialize global info and storage for display.
4822    -------------------------------------------------------------------------- */
4824     NSScreen *screen = [NSScreen mainScreen];
4825     NSWindowDepth depth = [screen depth];
4827     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4828     dpyinfo->resy = 72.27;
4829     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4830                                                   NSColorSpaceFromDepth (depth)]
4831                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4832                                                  NSColorSpaceFromDepth (depth)];
4833     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4834     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4835     dpyinfo->color_table->colors = NULL;
4836     dpyinfo->root_window = 42; /* a placeholder.. */
4837     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4838     dpyinfo->n_fonts = 0;
4839     dpyinfo->smallest_font_height = 1;
4840     dpyinfo->smallest_char_width = 1;
4842     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4846 /* This and next define (many of the) public functions in this file. */
4847 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4848          with using despite presence in the "system dependent" redisplay
4849          interface.  In addition, many of the ns_ methods have code that is
4850          shared with all terms, indicating need for further refactoring. */
4851 extern frame_parm_handler ns_frame_parm_handlers[];
4852 static struct redisplay_interface ns_redisplay_interface =
4854   ns_frame_parm_handlers,
4855   x_produce_glyphs,
4856   x_write_glyphs,
4857   x_insert_glyphs,
4858   x_clear_end_of_line,
4859   ns_scroll_run,
4860   ns_after_update_window_line,
4861   ns_update_window_begin,
4862   ns_update_window_end,
4863   0, /* flush_display */
4864   x_clear_window_mouse_face,
4865   x_get_glyph_overhangs,
4866   x_fix_overlapping_area,
4867   ns_draw_fringe_bitmap,
4868   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4869   0, /* destroy_fringe_bitmap */
4870   ns_compute_glyph_string_overhangs,
4871   ns_draw_glyph_string,
4872   ns_define_frame_cursor,
4873   ns_clear_frame_area,
4874   ns_draw_window_cursor,
4875   ns_draw_vertical_window_border,
4876   ns_draw_window_divider,
4877   ns_shift_glyphs_for_insert,
4878   ns_show_hourglass,
4879   ns_hide_hourglass
4883 static void
4884 ns_delete_display (struct ns_display_info *dpyinfo)
4886   /* TODO... */
4890 /* This function is called when the last frame on a display is deleted. */
4891 static void
4892 ns_delete_terminal (struct terminal *terminal)
4894   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4896   NSTRACE ("ns_delete_terminal");
4898   /* Protect against recursive calls.  delete_frame in
4899      delete_terminal calls us back when it deletes our last frame.  */
4900   if (!terminal->name)
4901     return;
4903   block_input ();
4905   x_destroy_all_bitmaps (dpyinfo);
4906   ns_delete_display (dpyinfo);
4907   unblock_input ();
4911 static struct terminal *
4912 ns_create_terminal (struct ns_display_info *dpyinfo)
4913 /* --------------------------------------------------------------------------
4914       Set up use of NS before we make the first connection.
4915    -------------------------------------------------------------------------- */
4917   struct terminal *terminal;
4919   NSTRACE ("ns_create_terminal");
4921   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4923   terminal->display_info.ns = dpyinfo;
4924   dpyinfo->terminal = terminal;
4926   terminal->clear_frame_hook = ns_clear_frame;
4927   terminal->ring_bell_hook = ns_ring_bell;
4928   terminal->update_begin_hook = ns_update_begin;
4929   terminal->update_end_hook = ns_update_end;
4930   terminal->read_socket_hook = ns_read_socket;
4931   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4932   terminal->mouse_position_hook = ns_mouse_position;
4933   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4934   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4935   terminal->fullscreen_hook = ns_fullscreen_hook;
4936   terminal->menu_show_hook = ns_menu_show;
4937   terminal->popup_dialog_hook = ns_popup_dialog;
4938   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4939   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4940   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4941   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4942   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4943   terminal->delete_frame_hook = x_destroy_window;
4944   terminal->delete_terminal_hook = ns_delete_terminal;
4945   /* Other hooks are NULL by default.  */
4947   return terminal;
4951 struct ns_display_info *
4952 ns_term_init (Lisp_Object display_name)
4953 /* --------------------------------------------------------------------------
4954      Start the Application and get things rolling.
4955    -------------------------------------------------------------------------- */
4957   struct terminal *terminal;
4958   struct ns_display_info *dpyinfo;
4959   static int ns_initialized = 0;
4960   Lisp_Object tmp;
4962   if (ns_initialized) return x_display_list;
4963   ns_initialized = 1;
4965   block_input ();
4967   NSTRACE ("ns_term_init");
4969   [outerpool release];
4970   outerpool = [[NSAutoreleasePool alloc] init];
4972   /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
4973   /*GSDebugAllocationActive (YES); */
4974   block_input ();
4976   baud_rate = 38400;
4977   Fset_input_interrupt_mode (Qnil);
4979   if (selfds[0] == -1)
4980     {
4981       if (emacs_pipe (selfds) != 0)
4982         {
4983           fprintf (stderr, "Failed to create pipe: %s\n",
4984                    emacs_strerror (errno));
4985           emacs_abort ();
4986         }
4988       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4989       FD_ZERO (&select_readfds);
4990       FD_ZERO (&select_writefds);
4991       pthread_mutex_init (&select_mutex, NULL);
4992     }
4994   ns_pending_files = [[NSMutableArray alloc] init];
4995   ns_pending_service_names = [[NSMutableArray alloc] init];
4996   ns_pending_service_args = [[NSMutableArray alloc] init];
4998 /* Start app and create the main menu, window, view.
4999      Needs to be here because ns_initialize_display_info () uses AppKit classes.
5000      The view will then ask the NSApp to stop and return to Emacs. */
5001   [EmacsApp sharedApplication];
5002   if (NSApp == nil)
5003     return NULL;
5004   [NSApp setDelegate: NSApp];
5006   /* Start the select thread.  */
5007   [NSThread detachNewThreadSelector:@selector (fd_handler:)
5008                            toTarget:NSApp
5009                          withObject:nil];
5011   /* debugging: log all notifications */
5012   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
5013                                          selector: @selector (logNotification:)
5014                                              name: nil object: nil]; */
5016   dpyinfo = xzalloc (sizeof *dpyinfo);
5018   ns_initialize_display_info (dpyinfo);
5019   terminal = ns_create_terminal (dpyinfo);
5021   terminal->kboard = allocate_kboard (Qns);
5022   /* Don't let the initial kboard remain current longer than necessary.
5023      That would cause problems if a file loaded on startup tries to
5024      prompt in the mini-buffer.  */
5025   if (current_kboard == initial_kboard)
5026     current_kboard = terminal->kboard;
5027   terminal->kboard->reference_count++;
5029   dpyinfo->next = x_display_list;
5030   x_display_list = dpyinfo;
5032   dpyinfo->name_list_element = Fcons (display_name, Qnil);
5034   terminal->name = xlispstrdup (display_name);
5036   unblock_input ();
5038   if (!inhibit_x_resources)
5039     {
5040       ns_default ("GSFontAntiAlias", &ns_antialias_text,
5041                  Qt, Qnil, NO, NO);
5042       tmp = Qnil;
5043       /* this is a standard variable */
5044       ns_default ("AppleAntiAliasingThreshold", &tmp,
5045                  make_float (10.0), make_float (6.0), YES, NO);
5046       ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5047     }
5049   NSTRACE_MSG ("Colors");
5051   {
5052     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5054     if ( cl == nil )
5055       {
5056         Lisp_Object color_file, color_map, color;
5057         unsigned long c;
5058         char *name;
5060         color_file = Fexpand_file_name (build_string ("rgb.txt"),
5061                          Fsymbol_value (intern ("data-directory")));
5063         color_map = Fx_load_color_file (color_file);
5064         if (NILP (color_map))
5065           fatal ("Could not read %s.\n", SDATA (color_file));
5067         cl = [[NSColorList alloc] initWithName: @"Emacs"];
5068         for ( ; CONSP (color_map); color_map = XCDR (color_map))
5069           {
5070             color = XCAR (color_map);
5071             name = SSDATA (XCAR (color));
5072             c = XINT (XCDR (color));
5073             [cl setColor:
5074                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5075                                       green: GREEN_FROM_ULONG (c) / 255.0
5076                                        blue: BLUE_FROM_ULONG (c) / 255.0
5077                                       alpha: 1.0]
5078                   forKey: [NSString stringWithUTF8String: name]];
5079           }
5080         [cl writeToFile: nil];
5081       }
5082   }
5084   NSTRACE_MSG ("Versions");
5086   {
5087 #ifdef NS_IMPL_GNUSTEP
5088     Vwindow_system_version = build_string (gnustep_base_version);
5089 #else
5090     /*PSnextrelease (128, c); */
5091     char c[DBL_BUFSIZE_BOUND];
5092     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5093     Vwindow_system_version = make_unibyte_string (c, len);
5094 #endif
5095   }
5097   delete_keyboard_wait_descriptor (0);
5099   ns_app_name = [[NSProcessInfo processInfo] processName];
5101   /* Set up macOS app menu */
5103   NSTRACE_MSG ("Menu init");
5105 #ifdef NS_IMPL_COCOA
5106   {
5107     NSMenu *appMenu;
5108     NSMenuItem *item;
5109     /* set up the application menu */
5110     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5111     [svcsMenu setAutoenablesItems: NO];
5112     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5113     [appMenu setAutoenablesItems: NO];
5114     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5115     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5117     [appMenu insertItemWithTitle: @"About Emacs"
5118                           action: @selector (orderFrontStandardAboutPanel:)
5119                    keyEquivalent: @""
5120                          atIndex: 0];
5121     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5122     [appMenu insertItemWithTitle: @"Preferences..."
5123                           action: @selector (showPreferencesWindow:)
5124                    keyEquivalent: @","
5125                          atIndex: 2];
5126     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5127     item = [appMenu insertItemWithTitle: @"Services"
5128                                  action: @selector (menuDown:)
5129                           keyEquivalent: @""
5130                                 atIndex: 4];
5131     [appMenu setSubmenu: svcsMenu forItem: item];
5132     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5133     [appMenu insertItemWithTitle: @"Hide Emacs"
5134                           action: @selector (hide:)
5135                    keyEquivalent: @"h"
5136                          atIndex: 6];
5137     item =  [appMenu insertItemWithTitle: @"Hide Others"
5138                           action: @selector (hideOtherApplications:)
5139                    keyEquivalent: @"h"
5140                          atIndex: 7];
5141     [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5142     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5143     [appMenu insertItemWithTitle: @"Quit Emacs"
5144                           action: @selector (terminate:)
5145                    keyEquivalent: @"q"
5146                          atIndex: 9];
5148     item = [mainMenu insertItemWithTitle: ns_app_name
5149                                   action: @selector (menuDown:)
5150                            keyEquivalent: @""
5151                                  atIndex: 0];
5152     [mainMenu setSubmenu: appMenu forItem: item];
5153     [dockMenu insertItemWithTitle: @"New Frame"
5154                            action: @selector (newFrame:)
5155                     keyEquivalent: @""
5156                           atIndex: 0];
5158     [NSApp setMainMenu: mainMenu];
5159     [NSApp setAppleMenu: appMenu];
5160     [NSApp setServicesMenu: svcsMenu];
5161     /* Needed at least on Cocoa, to get dock menu to show windows */
5162     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5164     [[NSNotificationCenter defaultCenter]
5165       addObserver: mainMenu
5166          selector: @selector (trackingNotification:)
5167              name: NSMenuDidBeginTrackingNotification object: mainMenu];
5168     [[NSNotificationCenter defaultCenter]
5169       addObserver: mainMenu
5170          selector: @selector (trackingNotification:)
5171              name: NSMenuDidEndTrackingNotification object: mainMenu];
5172   }
5173 #endif /* macOS menu setup */
5175   /* Register our external input/output types, used for determining
5176      applicable services and also drag/drop eligibility. */
5178   NSTRACE_MSG ("Input/output types");
5180   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5181   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5182                       retain];
5183   ns_drag_types = [[NSArray arrayWithObjects:
5184                             NSStringPboardType,
5185                             NSTabularTextPboardType,
5186                             NSFilenamesPboardType,
5187                             NSURLPboardType, nil] retain];
5189   /* If fullscreen is in init/default-frame-alist, focus isn't set
5190      right for fullscreen windows, so set this.  */
5191   [NSApp activateIgnoringOtherApps:YES];
5193   NSTRACE_MSG ("Call NSApp run");
5195   [NSApp run];
5196   ns_do_open_file = YES;
5198 #ifdef NS_IMPL_GNUSTEP
5199   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5200      We must re-catch it so subprocess works.  */
5201   catch_child_signal ();
5202 #endif
5204   NSTRACE_MSG ("ns_term_init done");
5206   unblock_input ();
5208   return dpyinfo;
5212 void
5213 ns_term_shutdown (int sig)
5215   [[NSUserDefaults standardUserDefaults] synchronize];
5217   /* code not reached in emacs.c after this is called by shut_down_emacs: */
5218   if (STRINGP (Vauto_save_list_file_name))
5219     unlink (SSDATA (Vauto_save_list_file_name));
5221   if (sig == 0 || sig == SIGTERM)
5222     {
5223       [NSApp terminate: NSApp];
5224     }
5225   else // force a stack trace to happen
5226     {
5227       emacs_abort ();
5228     }
5232 /* ==========================================================================
5234     EmacsApp implementation
5236    ========================================================================== */
5239 @implementation EmacsApp
5241 - (id)init
5243   NSTRACE ("[EmacsApp init]");
5245   if ((self = [super init]))
5246     {
5247 #ifdef NS_IMPL_COCOA
5248       self->isFirst = YES;
5249 #endif
5250 #ifdef NS_IMPL_GNUSTEP
5251       self->applicationDidFinishLaunchingCalled = NO;
5252 #endif
5253     }
5255   return self;
5258 #ifdef NS_IMPL_COCOA
5259 - (void)run
5261   NSTRACE ("[EmacsApp run]");
5263 #ifndef NSAppKitVersionNumber10_9
5264 #define NSAppKitVersionNumber10_9 1265
5265 #endif
5267     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5268       {
5269         [super run];
5270         return;
5271       }
5273   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5275   if (isFirst) [self finishLaunching];
5276   isFirst = NO;
5278   shouldKeepRunning = YES;
5279   do
5280     {
5281       [pool release];
5282       pool = [[NSAutoreleasePool alloc] init];
5284       NSEvent *event =
5285         [self nextEventMatchingMask:NSEventMaskAny
5286                           untilDate:[NSDate distantFuture]
5287                              inMode:NSDefaultRunLoopMode
5288                             dequeue:YES];
5290       [self sendEvent:event];
5291       [self updateWindows];
5292     } while (shouldKeepRunning);
5294   [pool release];
5297 - (void)stop: (id)sender
5299   NSTRACE ("[EmacsApp stop:]");
5301     shouldKeepRunning = NO;
5302     // Stop possible dialog also.  Noop if no dialog present.
5303     // The file dialog still leaks 7k - 10k on 10.9 though.
5304     [super stop:sender];
5306 #endif /* NS_IMPL_COCOA */
5308 - (void)logNotification: (NSNotification *)notification
5310   NSTRACE ("[EmacsApp logNotification:]");
5312   const char *name = [[notification name] UTF8String];
5313   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5314       && !strstr (name, "WindowNumber"))
5315     NSLog (@"notification: '%@'", [notification name]);
5319 - (void)sendEvent: (NSEvent *)theEvent
5320 /* --------------------------------------------------------------------------
5321      Called when NSApp is running for each event received.  Used to stop
5322      the loop when we choose, since there's no way to just run one iteration.
5323    -------------------------------------------------------------------------- */
5325   int type = [theEvent type];
5326   NSWindow *window = [theEvent window];
5328   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5329   NSTRACE_MSG ("Type: %d", type);
5331 #ifdef NS_IMPL_GNUSTEP
5332   // Keyboard events aren't propagated to file dialogs for some reason.
5333   if ([NSApp modalWindow] != nil &&
5334       (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5335     {
5336       [[NSApp modalWindow] sendEvent: theEvent];
5337       return;
5338     }
5339 #endif
5341   if (represented_filename != nil && represented_frame)
5342     {
5343       NSString *fstr = represented_filename;
5344       NSView *view = FRAME_NS_VIEW (represented_frame);
5345 #ifdef NS_IMPL_COCOA
5346       /* work around a bug observed on 10.3 and later where
5347          setTitleWithRepresentedFilename does not clear out previous state
5348          if given filename does not exist */
5349       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5350         [[view window] setRepresentedFilename: @""];
5351 #endif
5352       [[view window] setRepresentedFilename: fstr];
5353       [represented_filename release];
5354       represented_filename = nil;
5355       represented_frame = NULL;
5356     }
5358   if (type == NSEventTypeApplicationDefined)
5359     {
5360       switch ([theEvent data2])
5361         {
5362 #ifdef NS_IMPL_COCOA
5363         case NSAPP_DATA2_RUNASSCRIPT:
5364           ns_run_ascript ();
5365           [self stop: self];
5366           return;
5367 #endif
5368         case NSAPP_DATA2_RUNFILEDIALOG:
5369           ns_run_file_dialog ();
5370           [self stop: self];
5371           return;
5372         }
5373     }
5375   if (type == NSEventTypeCursorUpdate && window == nil)
5376     {
5377       fprintf (stderr, "Dropping external cursor update event.\n");
5378       return;
5379     }
5381   if (type == NSEventTypeApplicationDefined)
5382     {
5383       /* Events posted by ns_send_appdefined interrupt the run loop here.
5384          But, if a modal window is up, an appdefined can still come through,
5385          (e.g., from a makeKeyWindow event) but stopping self also stops the
5386          modal loop. Just defer it until later. */
5387       if ([NSApp modalWindow] == nil)
5388         {
5389           last_appdefined_event_data = [theEvent data1];
5390           [self stop: self];
5391         }
5392       else
5393         {
5394           send_appdefined = YES;
5395         }
5396     }
5399 #ifdef NS_IMPL_COCOA
5400   /* If no dialog and none of our frames have focus and it is a move, skip it.
5401      It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5402      such as Wifi, sound, date or similar.
5403      This prevents "spooky" highlighting in the frame under the menu.  */
5404   if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5405     {
5406       struct ns_display_info *di;
5407       BOOL has_focus = NO;
5408       for (di = x_display_list; ! has_focus && di; di = di->next)
5409         has_focus = di->x_focus_frame != 0;
5410       if (! has_focus)
5411         return;
5412     }
5413 #endif
5415   NSTRACE_UNSILENCE();
5417   [super sendEvent: theEvent];
5421 - (void)showPreferencesWindow: (id)sender
5423   struct frame *emacsframe = SELECTED_FRAME ();
5424   NSEvent *theEvent = [NSApp currentEvent];
5426   if (!emacs_event)
5427     return;
5428   emacs_event->kind = NS_NONKEY_EVENT;
5429   emacs_event->code = KEY_NS_SHOW_PREFS;
5430   emacs_event->modifiers = 0;
5431   EV_TRAILER (theEvent);
5435 - (void)newFrame: (id)sender
5437   NSTRACE ("[EmacsApp newFrame:]");
5439   struct frame *emacsframe = SELECTED_FRAME ();
5440   NSEvent *theEvent = [NSApp currentEvent];
5442   if (!emacs_event)
5443     return;
5444   emacs_event->kind = NS_NONKEY_EVENT;
5445   emacs_event->code = KEY_NS_NEW_FRAME;
5446   emacs_event->modifiers = 0;
5447   EV_TRAILER (theEvent);
5451 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5452 - (BOOL) openFile: (NSString *)fileName
5454   NSTRACE ("[EmacsApp openFile:]");
5456   struct frame *emacsframe = SELECTED_FRAME ();
5457   NSEvent *theEvent = [NSApp currentEvent];
5459   if (!emacs_event)
5460     return NO;
5462   emacs_event->kind = NS_NONKEY_EVENT;
5463   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5464   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5465   ns_input_line = Qnil; /* can be start or cons start,end */
5466   emacs_event->modifiers =0;
5467   EV_TRAILER (theEvent);
5469   return YES;
5473 /* **************************************************************************
5475       EmacsApp delegate implementation
5477    ************************************************************************** */
5479 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5480 /* --------------------------------------------------------------------------
5481      When application is loaded, terminate event loop in ns_term_init
5482    -------------------------------------------------------------------------- */
5484   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5486 #ifdef NS_IMPL_GNUSTEP
5487   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5488 #endif
5489   [NSApp setServicesProvider: NSApp];
5491   [self antialiasThresholdDidChange:nil];
5492 #ifdef NS_IMPL_COCOA
5493   [[NSNotificationCenter defaultCenter]
5494     addObserver:self
5495        selector:@selector(antialiasThresholdDidChange:)
5496            name:NSAntialiasThresholdChangedNotification
5497          object:nil];
5498 #endif
5500   ns_send_appdefined (-2);
5503 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5505 #ifdef NS_IMPL_COCOA
5506   macfont_update_antialias_threshold ();
5507 #endif
5511 /* Termination sequences:
5512     C-x C-c:
5513     Cmd-Q:
5514     MenuBar | File | Exit:
5515     Select Quit from App menubar:
5516         -terminate
5517         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5518         ns_term_shutdown()
5520     Select Quit from Dock menu:
5521     Logout attempt:
5522         -appShouldTerminate
5523           Cancel -> Nothing else
5524           Accept ->
5526           -terminate
5527           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5528           ns_term_shutdown()
5532 - (void) terminate: (id)sender
5534   NSTRACE ("[EmacsApp terminate:]");
5536   struct frame *emacsframe = SELECTED_FRAME ();
5538   if (!emacs_event)
5539     return;
5541   emacs_event->kind = NS_NONKEY_EVENT;
5542   emacs_event->code = KEY_NS_POWER_OFF;
5543   emacs_event->arg = Qt; /* mark as non-key event */
5544   EV_TRAILER ((id)nil);
5547 static bool
5548 runAlertPanel(NSString *title,
5549               NSString *msgFormat,
5550               NSString *defaultButton,
5551               NSString *alternateButton)
5553 #if !defined (NS_IMPL_COCOA) || \
5554   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5555   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5556     == NSAlertDefaultReturn;
5557 #else
5558   NSAlert *alert = [[NSAlert alloc] init];
5559   [alert setAlertStyle: NSAlertStyleCritical];
5560   [alert setMessageText: msgFormat];
5561   [alert addButtonWithTitle: defaultButton];
5562   [alert addButtonWithTitle: alternateButton];
5563   NSInteger ret = [alert runModal];
5564   [alert release];
5565   return ret == NSAlertFirstButtonReturn;
5566 #endif
5570 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5572   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5574   bool ret;
5576   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5577     return NSTerminateNow;
5579   ret = runAlertPanel(ns_app_name,
5580                       @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5581                       @"Save Buffers and Exit", @"Cancel");
5583   return ret ? NSTerminateNow : NSTerminateCancel;
5586 static int
5587 not_in_argv (NSString *arg)
5589   int k;
5590   const char *a = [arg UTF8String];
5591   for (k = 1; k < initial_argc; ++k)
5592     if (strcmp (a, initial_argv[k]) == 0) return 0;
5593   return 1;
5596 /*   Notification from the Workspace to open a file */
5597 - (BOOL)application: sender openFile: (NSString *)file
5599   if (ns_do_open_file || not_in_argv (file))
5600     [ns_pending_files addObject: file];
5601   return YES;
5605 /*   Open a file as a temporary file */
5606 - (BOOL)application: sender openTempFile: (NSString *)file
5608   if (ns_do_open_file || not_in_argv (file))
5609     [ns_pending_files addObject: file];
5610   return YES;
5614 /*   Notification from the Workspace to open a file noninteractively (?) */
5615 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5617   if (ns_do_open_file || not_in_argv (file))
5618     [ns_pending_files addObject: file];
5619   return YES;
5622 /*   Notification from the Workspace to open multiple files */
5623 - (void)application: sender openFiles: (NSArray *)fileList
5625   NSEnumerator *files = [fileList objectEnumerator];
5626   NSString *file;
5627   /* Don't open files from the command line unconditionally,
5628      Cocoa parses the command line wrong, --option value tries to open value
5629      if --option is the last option.  */
5630   while ((file = [files nextObject]) != nil)
5631     if (ns_do_open_file || not_in_argv (file))
5632       [ns_pending_files addObject: file];
5634   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5639 /* Handle dock menu requests.  */
5640 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5642   return dockMenu;
5646 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5647 - (void)applicationWillBecomeActive: (NSNotification *)notification
5649   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5650   //ns_app_active=YES;
5653 - (void)applicationDidBecomeActive: (NSNotification *)notification
5655   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5657 #ifdef NS_IMPL_GNUSTEP
5658   if (! applicationDidFinishLaunchingCalled)
5659     [self applicationDidFinishLaunching:notification];
5660 #endif
5661   //ns_app_active=YES;
5663   ns_update_auto_hide_menu_bar ();
5664   // No constraining takes place when the application is not active.
5665   ns_constrain_all_frames ();
5667 - (void)applicationDidResignActive: (NSNotification *)notification
5669   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5671   //ns_app_active=NO;
5672   ns_send_appdefined (-1);
5677 /* ==========================================================================
5679     EmacsApp aux handlers for managing event loop
5681    ========================================================================== */
5684 - (void)timeout_handler: (NSTimer *)timedEntry
5685 /* --------------------------------------------------------------------------
5686      The timeout specified to ns_select has passed.
5687    -------------------------------------------------------------------------- */
5689   /*NSTRACE ("timeout_handler"); */
5690   ns_send_appdefined (-2);
5693 - (void)sendFromMainThread:(id)unused
5695   ns_send_appdefined (nextappdefined);
5698 - (void)fd_handler:(id)unused
5699 /* --------------------------------------------------------------------------
5700      Check data waiting on file descriptors and terminate if so
5701    -------------------------------------------------------------------------- */
5703   int result;
5704   int waiting = 1, nfds;
5705   char c;
5707   fd_set readfds, writefds, *wfds;
5708   struct timespec timeout, *tmo;
5709   NSAutoreleasePool *pool = nil;
5711   /* NSTRACE ("fd_handler"); */
5713   for (;;)
5714     {
5715       [pool release];
5716       pool = [[NSAutoreleasePool alloc] init];
5718       if (waiting)
5719         {
5720           fd_set fds;
5721           FD_ZERO (&fds);
5722           FD_SET (selfds[0], &fds);
5723           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5724           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5725             waiting = 0;
5726         }
5727       else
5728         {
5729           pthread_mutex_lock (&select_mutex);
5730           nfds = select_nfds;
5732           if (select_valid & SELECT_HAVE_READ)
5733             readfds = select_readfds;
5734           else
5735             FD_ZERO (&readfds);
5737           if (select_valid & SELECT_HAVE_WRITE)
5738             {
5739               writefds = select_writefds;
5740               wfds = &writefds;
5741             }
5742           else
5743             wfds = NULL;
5744           if (select_valid & SELECT_HAVE_TMO)
5745             {
5746               timeout = select_timeout;
5747               tmo = &timeout;
5748             }
5749           else
5750             tmo = NULL;
5752           pthread_mutex_unlock (&select_mutex);
5754           FD_SET (selfds[0], &readfds);
5755           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5757           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5759           if (result == 0)
5760             ns_send_appdefined (-2);
5761           else if (result > 0)
5762             {
5763               if (FD_ISSET (selfds[0], &readfds))
5764                 {
5765                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5766                     waiting = 1;
5767                 }
5768               else
5769                 {
5770                   pthread_mutex_lock (&select_mutex);
5771                   if (select_valid & SELECT_HAVE_READ)
5772                     select_readfds = readfds;
5773                   if (select_valid & SELECT_HAVE_WRITE)
5774                     select_writefds = writefds;
5775                   if (select_valid & SELECT_HAVE_TMO)
5776                     select_timeout = timeout;
5777                   pthread_mutex_unlock (&select_mutex);
5779                   ns_send_appdefined (result);
5780                 }
5781             }
5782           waiting = 1;
5783         }
5784     }
5789 /* ==========================================================================
5791     Service provision
5793    ========================================================================== */
5795 /* called from system: queue for next pass through event loop */
5796 - (void)requestService: (NSPasteboard *)pboard
5797               userData: (NSString *)userData
5798                  error: (NSString **)error
5800   [ns_pending_service_names addObject: userData];
5801   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5802       SSDATA (ns_string_from_pasteboard (pboard))]];
5806 /* called from ns_read_socket to clear queue */
5807 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5809   struct frame *emacsframe = SELECTED_FRAME ();
5810   NSEvent *theEvent = [NSApp currentEvent];
5812   NSTRACE ("[EmacsApp fulfillService:withArg:]");
5814   if (!emacs_event)
5815     return NO;
5817   emacs_event->kind = NS_NONKEY_EVENT;
5818   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5819   ns_input_spi_name = build_string ([name UTF8String]);
5820   ns_input_spi_arg = build_string ([arg UTF8String]);
5821   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5822   EV_TRAILER (theEvent);
5824   return YES;
5828 @end  /* EmacsApp */
5832 /* ==========================================================================
5834     EmacsView implementation
5836    ========================================================================== */
5839 @implementation EmacsView
5841 /* needed to inform when window closed from LISP */
5842 - (void) setWindowClosing: (BOOL)closing
5844   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5846   windowClosing = closing;
5850 - (void)dealloc
5852   NSTRACE ("[EmacsView dealloc]");
5853   [toolbar release];
5854   if (fs_state == FULLSCREEN_BOTH)
5855     [nonfs_window release];
5856   [super dealloc];
5860 /* called on font panel selection */
5861 - (void)changeFont: (id)sender
5863   NSEvent *e = [[self window] currentEvent];
5864   struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5865   struct font *font = face->font;
5866   id newFont;
5867   CGFloat size;
5868   NSFont *nsfont;
5870   NSTRACE ("[EmacsView changeFont:]");
5872   if (!emacs_event)
5873     return;
5875 #ifdef NS_IMPL_GNUSTEP
5876   nsfont = ((struct nsfont_info *)font)->nsfont;
5877 #endif
5878 #ifdef NS_IMPL_COCOA
5879   nsfont = (NSFont *) macfont_get_nsctfont (font);
5880 #endif
5882   if ((newFont = [sender convertFont: nsfont]))
5883     {
5884       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5886       emacs_event->kind = NS_NONKEY_EVENT;
5887       emacs_event->modifiers = 0;
5888       emacs_event->code = KEY_NS_CHANGE_FONT;
5890       size = [newFont pointSize];
5891       ns_input_fontsize = make_number (lrint (size));
5892       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5893       EV_TRAILER (e);
5894     }
5898 - (BOOL)acceptsFirstResponder
5900   NSTRACE ("[EmacsView acceptsFirstResponder]");
5901   return YES;
5905 - (void)resetCursorRects
5907   NSRect visible = [self visibleRect];
5908   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5909   NSTRACE ("[EmacsView resetCursorRects]");
5911   if (currentCursor == nil)
5912     currentCursor = [NSCursor arrowCursor];
5914   if (!NSIsEmptyRect (visible))
5915     [self addCursorRect: visible cursor: currentCursor];
5916   [currentCursor setOnMouseEntered: YES];
5921 /*****************************************************************************/
5922 /* Keyboard handling. */
5923 #define NS_KEYLOG 0
5925 - (void)keyDown: (NSEvent *)theEvent
5927   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5928   int code;
5929   unsigned fnKeysym = 0;
5930   static NSMutableArray *nsEvArray;
5931   int left_is_none;
5932   unsigned int flags = [theEvent modifierFlags];
5934   NSTRACE ("[EmacsView keyDown:]");
5936   /* Rhapsody and macOS give up and down events for the arrow keys */
5937   if (ns_fake_keydown == YES)
5938     ns_fake_keydown = NO;
5939   else if ([theEvent type] != NSEventTypeKeyDown)
5940     return;
5942   if (!emacs_event)
5943     return;
5945  if (![[self window] isKeyWindow]
5946      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5947      /* we must avoid an infinite loop here. */
5948      && (EmacsView *)[[theEvent window] delegate] != self)
5949    {
5950      /* XXX: There is an occasional condition in which, when Emacs display
5951          updates a different frame from the current one, and temporarily
5952          selects it, then processes some interrupt-driven input
5953          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5954          for some reason that window has its first responder set to the NSView
5955          most recently updated (I guess), which is not the correct one. */
5956      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5957      return;
5958    }
5960   if (nsEvArray == nil)
5961     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5963   [NSCursor setHiddenUntilMouseMoves: YES];
5965   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5966     {
5967       clear_mouse_face (hlinfo);
5968       hlinfo->mouse_face_hidden = 1;
5969     }
5971   if (!processingCompose)
5972     {
5973       /* When using screen sharing, no left or right information is sent,
5974          so use Left key in those cases.  */
5975       int is_left_key, is_right_key;
5977       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5978         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5980       /* (Carbon way: [theEvent keyCode]) */
5982       /* is it a "function key"? */
5983       /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
5984          flag set (this is probably a bug in the OS).
5985       */
5986       if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
5987         {
5988           fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
5989         }
5990       if (fnKeysym == 0)
5991         {
5992           fnKeysym = ns_convert_key (code);
5993         }
5995       if (fnKeysym)
5996         {
5997           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5998              because Emacs treats Delete and KP-Delete same (in simple.el). */
5999           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6000 #ifdef NS_IMPL_GNUSTEP
6001               /*  GNUstep uses incompatible keycodes, even for those that are
6002                   supposed to be hardware independent.  Just check for delete.
6003                   Keypad delete does not have keysym 0xFFFF.
6004                   See http://savannah.gnu.org/bugs/?25395
6005               */
6006               || (fnKeysym == 0xFFFF && code == 127)
6007 #endif
6008             )
6009             code = 0xFF08; /* backspace */
6010           else
6011             code = fnKeysym;
6012         }
6014       /* are there modifiers? */
6015       emacs_event->modifiers = 0;
6017       if (flags & NSEventModifierFlagHelp)
6018           emacs_event->modifiers |= hyper_modifier;
6020       if (flags & NSEventModifierFlagShift)
6021         emacs_event->modifiers |= shift_modifier;
6023       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
6024       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
6025         || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
6027       if (is_right_key)
6028         emacs_event->modifiers |= parse_solitary_modifier
6029           (EQ (ns_right_command_modifier, Qleft)
6030            ? ns_command_modifier
6031            : ns_right_command_modifier);
6033       if (is_left_key)
6034         {
6035           emacs_event->modifiers |= parse_solitary_modifier
6036             (ns_command_modifier);
6038           /* if super (default), take input manager's word so things like
6039              dvorak / qwerty layout work */
6040           if (EQ (ns_command_modifier, Qsuper)
6041               && !fnKeysym
6042               && [[theEvent characters] length] != 0)
6043             {
6044               /* XXX: the code we get will be unshifted, so if we have
6045                  a shift modifier, must convert ourselves */
6046               if (!(flags & NSEventModifierFlagShift))
6047                 code = [[theEvent characters] characterAtIndex: 0];
6048 #if 0
6049               /* this is ugly and also requires linking w/Carbon framework
6050                  (for LMGetKbdType) so for now leave this rare (?) case
6051                  undealt with.. in future look into CGEvent methods */
6052               else
6053                 {
6054                   long smv = GetScriptManagerVariable (smKeyScript);
6055                   Handle uchrHandle = GetResource
6056                     ('uchr', GetScriptVariable (smv, smScriptKeys));
6057                   UInt32 dummy = 0;
6058                   UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6059                                  [[theEvent characters] characterAtIndex: 0],
6060                                  kUCKeyActionDisplay,
6061                                  (flags & ~NSEventModifierFlagCommand) >> 8,
6062                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6063                                  &dummy, 1, &dummy, &code);
6064                   code &= 0xFF;
6065                 }
6066 #endif
6067             }
6068         }
6070       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6071       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6072         || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6074       if (is_right_key)
6075           emacs_event->modifiers |= parse_solitary_modifier
6076               (EQ (ns_right_control_modifier, Qleft)
6077                ? ns_control_modifier
6078                : ns_right_control_modifier);
6080       if (is_left_key)
6081         emacs_event->modifiers |= parse_solitary_modifier
6082           (ns_control_modifier);
6084       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6085           emacs_event->modifiers |=
6086             parse_solitary_modifier (ns_function_modifier);
6088       left_is_none = NILP (ns_alternate_modifier)
6089         || EQ (ns_alternate_modifier, Qnone);
6091       is_right_key = (flags & NSRightAlternateKeyMask)
6092         == NSRightAlternateKeyMask;
6093       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6094         || (! is_right_key
6095             && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6097       if (is_right_key)
6098         {
6099           if ((NILP (ns_right_alternate_modifier)
6100                || EQ (ns_right_alternate_modifier, Qnone)
6101                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6102               && !fnKeysym)
6103             {   /* accept pre-interp alt comb */
6104               if ([[theEvent characters] length] > 0)
6105                 code = [[theEvent characters] characterAtIndex: 0];
6106               /*HACK: clear lone shift modifier to stop next if from firing */
6107               if (emacs_event->modifiers == shift_modifier)
6108                 emacs_event->modifiers = 0;
6109             }
6110           else
6111             emacs_event->modifiers |= parse_solitary_modifier
6112               (EQ (ns_right_alternate_modifier, Qleft)
6113                ? ns_alternate_modifier
6114                : ns_right_alternate_modifier);
6115         }
6117       if (is_left_key) /* default = meta */
6118         {
6119           if (left_is_none && !fnKeysym)
6120             {   /* accept pre-interp alt comb */
6121               if ([[theEvent characters] length] > 0)
6122                 code = [[theEvent characters] characterAtIndex: 0];
6123               /*HACK: clear lone shift modifier to stop next if from firing */
6124               if (emacs_event->modifiers == shift_modifier)
6125                 emacs_event->modifiers = 0;
6126             }
6127           else
6128               emacs_event->modifiers |=
6129                 parse_solitary_modifier (ns_alternate_modifier);
6130         }
6132   if (NS_KEYLOG)
6133     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6134              (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6136       /* if it was a function key or had modifiers, pass it directly to emacs */
6137       if (fnKeysym || (emacs_event->modifiers
6138                        && (emacs_event->modifiers != shift_modifier)
6139                        && [[theEvent charactersIgnoringModifiers] length] > 0))
6140 /*[[theEvent characters] length] */
6141         {
6142           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6143           if (code < 0x20)
6144             code |= (1<<28)|(3<<16);
6145           else if (code == 0x7f)
6146             code |= (1<<28)|(3<<16);
6147           else if (!fnKeysym)
6148             emacs_event->kind = code > 0xFF
6149               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6151           emacs_event->code = code;
6152           EV_TRAILER (theEvent);
6153           processingCompose = NO;
6154           return;
6155         }
6156     }
6159   if (NS_KEYLOG && !processingCompose)
6160     fprintf (stderr, "keyDown: Begin compose sequence.\n");
6162   processingCompose = YES;
6163   [nsEvArray addObject: theEvent];
6164   [self interpretKeyEvents: nsEvArray];
6165   [nsEvArray removeObject: theEvent];
6169 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6172 /* <NSTextInput>: called when done composing;
6173    NOTE: also called when we delete over working text, followed immed.
6174          by doCommandBySelector: deleteBackward: */
6175 - (void)insertText: (id)aString
6177   int code;
6178   int len = [(NSString *)aString length];
6179   int i;
6181   NSTRACE ("[EmacsView insertText:]");
6183   if (NS_KEYLOG)
6184     NSLog (@"insertText '%@'\tlen = %d", aString, len);
6185   processingCompose = NO;
6187   if (!emacs_event)
6188     return;
6190   /* first, clear any working text */
6191   if (workingText != nil)
6192     [self deleteWorkingText];
6194   /* now insert the string as keystrokes */
6195   for (i =0; i<len; i++)
6196     {
6197       code = [aString characterAtIndex: i];
6198       /* TODO: still need this? */
6199       if (code == 0x2DC)
6200         code = '~'; /* 0x7E */
6201       if (code != 32) /* Space */
6202         emacs_event->modifiers = 0;
6203       emacs_event->kind
6204         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6205       emacs_event->code = code;
6206       EV_TRAILER ((id)nil);
6207     }
6211 /* <NSTextInput>: inserts display of composing characters */
6212 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6214   NSString *str = [aString respondsToSelector: @selector (string)] ?
6215     [aString string] : aString;
6217   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6219   if (NS_KEYLOG)
6220     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6221            str, (unsigned long)[str length],
6222            (unsigned long)selRange.length,
6223            (unsigned long)selRange.location);
6225   if (workingText != nil)
6226     [self deleteWorkingText];
6227   if ([str length] == 0)
6228     return;
6230   if (!emacs_event)
6231     return;
6233   processingCompose = YES;
6234   workingText = [str copy];
6235   ns_working_text = build_string ([workingText UTF8String]);
6237   emacs_event->kind = NS_TEXT_EVENT;
6238   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6239   EV_TRAILER ((id)nil);
6243 /* delete display of composing characters [not in <NSTextInput>] */
6244 - (void)deleteWorkingText
6246   NSTRACE ("[EmacsView deleteWorkingText]");
6248   if (workingText == nil)
6249     return;
6250   if (NS_KEYLOG)
6251     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6252   [workingText release];
6253   workingText = nil;
6254   processingCompose = NO;
6256   if (!emacs_event)
6257     return;
6259   emacs_event->kind = NS_TEXT_EVENT;
6260   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6261   EV_TRAILER ((id)nil);
6265 - (BOOL)hasMarkedText
6267   NSTRACE ("[EmacsView hasMarkedText]");
6269   return workingText != nil;
6273 - (NSRange)markedRange
6275   NSTRACE ("[EmacsView markedRange]");
6277   NSRange rng = workingText != nil
6278     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6279   if (NS_KEYLOG)
6280     NSLog (@"markedRange request");
6281   return rng;
6285 - (void)unmarkText
6287   NSTRACE ("[EmacsView unmarkText]");
6289   if (NS_KEYLOG)
6290     NSLog (@"unmark (accept) text");
6291   [self deleteWorkingText];
6292   processingCompose = NO;
6296 /* used to position char selection windows, etc. */
6297 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6299   NSRect rect;
6300   NSPoint pt;
6301   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6303   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6305   if (NS_KEYLOG)
6306     NSLog (@"firstRectForCharRange request");
6308   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6309   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6310   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6311   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6312                                        +FRAME_LINE_HEIGHT (emacsframe));
6314   pt = [self convertPoint: pt toView: nil];
6315 #if !defined (NS_IMPL_COCOA) || \
6316   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
6317   pt = [[self window] convertBaseToScreen: pt];
6318   rect.origin = pt;
6319 #else
6320   rect.origin = pt;
6321   rect = [[self window] convertRectToScreen: rect];
6322 #endif
6323   return rect;
6327 - (NSInteger)conversationIdentifier
6329   return (NSInteger)self;
6333 - (void)doCommandBySelector: (SEL)aSelector
6335   NSTRACE ("[EmacsView doCommandBySelector:]");
6337   if (NS_KEYLOG)
6338     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6340   processingCompose = NO;
6341   if (aSelector == @selector (deleteBackward:))
6342     {
6343       /* happens when user backspaces over an ongoing composition:
6344          throw a 'delete' into the event queue */
6345       if (!emacs_event)
6346         return;
6347       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6348       emacs_event->code = 0xFF08;
6349       EV_TRAILER ((id)nil);
6350     }
6353 - (NSArray *)validAttributesForMarkedText
6355   static NSArray *arr = nil;
6356   if (arr == nil) arr = [NSArray new];
6357  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6358   return arr;
6361 - (NSRange)selectedRange
6363   if (NS_KEYLOG)
6364     NSLog (@"selectedRange request");
6365   return NSMakeRange (NSNotFound, 0);
6368 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6369     GNUSTEP_GUI_MINOR_VERSION > 22
6370 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6371 #else
6372 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6373 #endif
6375   if (NS_KEYLOG)
6376     NSLog (@"characterIndexForPoint request");
6377   return 0;
6380 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6382   static NSAttributedString *str = nil;
6383   if (str == nil) str = [NSAttributedString new];
6384   if (NS_KEYLOG)
6385     NSLog (@"attributedSubstringFromRange request");
6386   return str;
6389 /* End <NSTextInput> impl. */
6390 /*****************************************************************************/
6393 /* This is what happens when the user presses a mouse button.  */
6394 - (void)mouseDown: (NSEvent *)theEvent
6396   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6397   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6399   NSTRACE ("[EmacsView mouseDown:]");
6401   [self deleteWorkingText];
6403   if (!emacs_event)
6404     return;
6406   dpyinfo->last_mouse_frame = emacsframe;
6407   /* appears to be needed to prevent spurious movement events generated on
6408      button clicks */
6409   emacsframe->mouse_moved = 0;
6411   if ([theEvent type] == NSEventTypeScrollWheel)
6412     {
6413       CGFloat delta = [theEvent deltaY];
6414       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6415       if (delta == 0)
6416         {
6417           delta = [theEvent deltaX];
6418           if (delta == 0)
6419             {
6420               NSTRACE_MSG ("deltaIsZero");
6421               return;
6422             }
6423           emacs_event->kind = HORIZ_WHEEL_EVENT;
6424         }
6425       else
6426         emacs_event->kind = WHEEL_EVENT;
6428       emacs_event->code = 0;
6429       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6430         ((delta > 0) ? up_modifier : down_modifier);
6431     }
6432   else
6433     {
6434       emacs_event->kind = MOUSE_CLICK_EVENT;
6435       emacs_event->code = EV_BUTTON (theEvent);
6436       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6437                              | EV_UDMODIFIERS (theEvent);
6438     }
6439   XSETINT (emacs_event->x, lrint (p.x));
6440   XSETINT (emacs_event->y, lrint (p.y));
6441   EV_TRAILER (theEvent);
6445 - (void)rightMouseDown: (NSEvent *)theEvent
6447   NSTRACE ("[EmacsView rightMouseDown:]");
6448   [self mouseDown: theEvent];
6452 - (void)otherMouseDown: (NSEvent *)theEvent
6454   NSTRACE ("[EmacsView otherMouseDown:]");
6455   [self mouseDown: theEvent];
6459 - (void)mouseUp: (NSEvent *)theEvent
6461   NSTRACE ("[EmacsView mouseUp:]");
6462   [self mouseDown: theEvent];
6466 - (void)rightMouseUp: (NSEvent *)theEvent
6468   NSTRACE ("[EmacsView rightMouseUp:]");
6469   [self mouseDown: theEvent];
6473 - (void)otherMouseUp: (NSEvent *)theEvent
6475   NSTRACE ("[EmacsView otherMouseUp:]");
6476   [self mouseDown: theEvent];
6480 - (void) scrollWheel: (NSEvent *)theEvent
6482   NSTRACE ("[EmacsView scrollWheel:]");
6483   [self mouseDown: theEvent];
6487 /* Tell emacs the mouse has moved. */
6488 - (void)mouseMoved: (NSEvent *)e
6490   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6491   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6492   Lisp_Object frame;
6493   NSPoint pt;
6495   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6497   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6498   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6499   dpyinfo->last_mouse_motion_x = pt.x;
6500   dpyinfo->last_mouse_motion_y = pt.y;
6502   /* update any mouse face */
6503   if (hlinfo->mouse_face_hidden)
6504     {
6505       hlinfo->mouse_face_hidden = 0;
6506       clear_mouse_face (hlinfo);
6507     }
6509   /* tooltip handling */
6510   previous_help_echo_string = help_echo_string;
6511   help_echo_string = Qnil;
6513   if (!NILP (Vmouse_autoselect_window))
6514     {
6515       NSTRACE_MSG ("mouse_autoselect_window");
6516       static Lisp_Object last_mouse_window;
6517       Lisp_Object window
6518         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6520       if (WINDOWP (window)
6521           && !EQ (window, last_mouse_window)
6522           && !EQ (window, selected_window)
6523           && (!NILP (focus_follows_mouse)
6524               || (EQ (XWINDOW (window)->frame,
6525                       XWINDOW (selected_window)->frame))))
6526         {
6527           NSTRACE_MSG ("in_window");
6528           emacs_event->kind = SELECT_WINDOW_EVENT;
6529           emacs_event->frame_or_window = window;
6530           EV_TRAILER2 (e);
6531         }
6532       /* Remember the last window where we saw the mouse.  */
6533       last_mouse_window = window;
6534     }
6536   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6537     help_echo_string = previous_help_echo_string;
6539   XSETFRAME (frame, emacsframe);
6540   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6541     {
6542       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6543          (note_mouse_highlight), which is called through the
6544          note_mouse_movement () call above */
6545       any_help_event_p = YES;
6546       gen_help_event (help_echo_string, frame, help_echo_window,
6547                       help_echo_object, help_echo_pos);
6548     }
6550   if (emacsframe->mouse_moved && send_appdefined)
6551     ns_send_appdefined (-1);
6555 - (void)mouseDragged: (NSEvent *)e
6557   NSTRACE ("[EmacsView mouseDragged:]");
6558   [self mouseMoved: e];
6562 - (void)rightMouseDragged: (NSEvent *)e
6564   NSTRACE ("[EmacsView rightMouseDragged:]");
6565   [self mouseMoved: e];
6569 - (void)otherMouseDragged: (NSEvent *)e
6571   NSTRACE ("[EmacsView otherMouseDragged:]");
6572   [self mouseMoved: e];
6576 - (BOOL)windowShouldClose: (id)sender
6578   NSEvent *e =[[self window] currentEvent];
6580   NSTRACE ("[EmacsView windowShouldClose:]");
6581   windowClosing = YES;
6582   if (!emacs_event)
6583     return NO;
6584   emacs_event->kind = DELETE_WINDOW_EVENT;
6585   emacs_event->modifiers = 0;
6586   emacs_event->code = 0;
6587   EV_TRAILER (e);
6588   /* Don't close this window, let this be done from lisp code.  */
6589   return NO;
6592 - (void) updateFrameSize: (BOOL) delay
6594   NSWindow *window = [self window];
6595   NSRect wr = [window frame];
6596   int extra = 0;
6597   int oldc = cols, oldr = rows;
6598   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6599   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6600   int neww, newh;
6602   NSTRACE ("[EmacsView updateFrameSize:]");
6603   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6604   NSTRACE_RECT ("Original frame", wr);
6605   NSTRACE_MSG  ("Original columns: %d", cols);
6606   NSTRACE_MSG  ("Original rows: %d", rows);
6608   if (! [self isFullscreen])
6609     {
6610 #ifdef NS_IMPL_GNUSTEP
6611       // GNUstep does not always update the tool bar height.  Force it.
6612       if (toolbar && [toolbar isVisible])
6613           update_frame_tool_bar (emacsframe);
6614 #endif
6616       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6617         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6618     }
6620   if (wait_for_tool_bar)
6621     {
6622       /* The toolbar height is always 0 in fullscreen, so don't wait
6623          for it to become available. */
6624       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6625           && ! [self isFullscreen])
6626         {
6627           NSTRACE_MSG ("Waiting for toolbar");
6628           return;
6629         }
6630       wait_for_tool_bar = NO;
6631     }
6633   neww = (int)wr.size.width - emacsframe->border_width;
6634   newh = (int)wr.size.height - extra;
6636   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6637   NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6638   NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6640   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6641   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6643   if (cols < MINWIDTH)
6644     cols = MINWIDTH;
6646   if (rows < MINHEIGHT)
6647     rows = MINHEIGHT;
6649   NSTRACE_MSG ("New columns: %d", cols);
6650   NSTRACE_MSG ("New rows: %d", rows);
6652   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6653     {
6654       NSView *view = FRAME_NS_VIEW (emacsframe);
6656       change_frame_size (emacsframe,
6657                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6658                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6659                          0, delay, 0, 1);
6660       SET_FRAME_GARBAGED (emacsframe);
6661       cancel_mouse_face (emacsframe);
6663       /* The next two lines appear to be setting the frame to the same
6664          size as it already is.  Why are they there? */
6665       // wr = NSMakeRect (0, 0, neww, newh);
6667       // [view setFrame: wr];
6669       // to do: consider using [NSNotificationCenter postNotificationName:].
6670       [self windowDidMove: // Update top/left.
6671               [NSNotification notificationWithName:NSWindowDidMoveNotification
6672                                             object:[view window]]];
6673     }
6674   else
6675     {
6676       NSTRACE_MSG ("No change");
6677     }
6680 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6681 /* normalize frame to gridded text size */
6683   int extra = 0;
6685   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6686            NSTRACE_ARG_SIZE (frameSize));
6687   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6688   NSTRACE_FSTYPE ("fs_state", fs_state);
6690   if (fs_state == FULLSCREEN_MAXIMIZED
6691       && (maximized_width != (int)frameSize.width
6692           || maximized_height != (int)frameSize.height))
6693     [self setFSValue: FULLSCREEN_NONE];
6694   else if (fs_state == FULLSCREEN_WIDTH
6695            && maximized_width != (int)frameSize.width)
6696     [self setFSValue: FULLSCREEN_NONE];
6697   else if (fs_state == FULLSCREEN_HEIGHT
6698            && maximized_height != (int)frameSize.height)
6699     [self setFSValue: FULLSCREEN_NONE];
6701   if (fs_state == FULLSCREEN_NONE)
6702     maximized_width = maximized_height = -1;
6704   if (! [self isFullscreen])
6705     {
6706       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6707         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6708     }
6710   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6711   if (cols < MINWIDTH)
6712     cols = MINWIDTH;
6714   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6715                                            frameSize.height - extra);
6716   if (rows < MINHEIGHT)
6717     rows = MINHEIGHT;
6718 #ifdef NS_IMPL_COCOA
6719   {
6720     /* this sets window title to have size in it; the wm does this under GS */
6721     NSRect r = [[self window] frame];
6722     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6723       {
6724         if (old_title != 0)
6725           {
6726             xfree (old_title);
6727             old_title = 0;
6728           }
6729       }
6730     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6731              && [[self window] title] != NULL)
6732       {
6733         char *size_title;
6734         NSWindow *window = [self window];
6735         if (old_title == 0)
6736           {
6737             char *t = strdup ([[[self window] title] UTF8String]);
6738             char *pos = strstr (t, "  â€”  ");
6739             if (pos)
6740               *pos = '\0';
6741             old_title = t;
6742           }
6743         size_title = xmalloc (strlen (old_title) + 40);
6744         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6745         [window setTitle: [NSString stringWithUTF8String: size_title]];
6746         [window display];
6747         xfree (size_title);
6748       }
6749   }
6750 #endif /* NS_IMPL_COCOA */
6752   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6754   /* Restrict the new size to the text gird.
6756      Don't restrict the width if the user only adjusted the height, and
6757      vice versa.  (Without this, the frame would shrink, and move
6758      slightly, if the window was resized by dragging one of its
6759      borders.) */
6760   if (!frame_resize_pixelwise)
6761     {
6762       NSRect r = [[self window] frame];
6764       if (r.size.width != frameSize.width)
6765         {
6766           frameSize.width =
6767             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6768         }
6770       if (r.size.height != frameSize.height)
6771         {
6772           frameSize.height =
6773             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6774         }
6775     }
6777   NSTRACE_RETURN_SIZE (frameSize);
6779   return frameSize;
6783 - (void)windowDidResize: (NSNotification *)notification
6785   NSTRACE ("[EmacsView windowDidResize:]");
6786   if (!FRAME_LIVE_P (emacsframe))
6787     {
6788       NSTRACE_MSG ("Ignored (frame dead)");
6789       return;
6790     }
6791   if (emacsframe->output_data.ns->in_animation)
6792     {
6793       NSTRACE_MSG ("Ignored (in animation)");
6794       return;
6795     }
6797   if (! [self fsIsNative])
6798     {
6799       NSWindow *theWindow = [notification object];
6800       /* We can get notification on the non-FS window when in
6801          fullscreen mode.  */
6802       if ([self window] != theWindow) return;
6803     }
6805   NSTRACE_RECT ("frame", [[notification object] frame]);
6807 #ifdef NS_IMPL_GNUSTEP
6808   NSWindow *theWindow = [notification object];
6810    /* In GNUstep, at least currently, it's possible to get a didResize
6811       without getting a willResize.. therefore we need to act as if we got
6812       the willResize now */
6813   NSSize sz = [theWindow frame].size;
6814   sz = [self windowWillResize: theWindow toSize: sz];
6815 #endif /* NS_IMPL_GNUSTEP */
6817   if (cols > 0 && rows > 0)
6818     {
6819       [self updateFrameSize: YES];
6820     }
6822   ns_send_appdefined (-1);
6825 #ifdef NS_IMPL_COCOA
6826 - (void)viewDidEndLiveResize
6828   NSTRACE ("[EmacsView viewDidEndLiveResize]");
6830   [super viewDidEndLiveResize];
6831   if (old_title != 0)
6832     {
6833       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6834       xfree (old_title);
6835       old_title = 0;
6836     }
6837   maximizing_resize = NO;
6839 #endif /* NS_IMPL_COCOA */
6842 - (void)windowDidBecomeKey: (NSNotification *)notification
6843 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6845   [self windowDidBecomeKey];
6849 - (void)windowDidBecomeKey      /* for direct calls */
6851   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6852   struct frame *old_focus = dpyinfo->x_focus_frame;
6854   NSTRACE ("[EmacsView windowDidBecomeKey]");
6856   if (emacsframe != old_focus)
6857     dpyinfo->x_focus_frame = emacsframe;
6859   ns_frame_rehighlight (emacsframe);
6861   if (emacs_event)
6862     {
6863       emacs_event->kind = FOCUS_IN_EVENT;
6864       EV_TRAILER ((id)nil);
6865     }
6869 - (void)windowDidResignKey: (NSNotification *)notification
6870 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6872   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6873   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6874   NSTRACE ("[EmacsView windowDidResignKey:]");
6876   if (is_focus_frame)
6877     dpyinfo->x_focus_frame = 0;
6879   emacsframe->mouse_moved = 0;
6880   ns_frame_rehighlight (emacsframe);
6882   /* FIXME: for some reason needed on second and subsequent clicks away
6883             from sole-frame Emacs to get hollow box to show */
6884   if (!windowClosing && [[self window] isVisible] == YES)
6885     {
6886       x_update_cursor (emacsframe, 1);
6887       x_set_frame_alpha (emacsframe);
6888     }
6890   if (any_help_event_p)
6891     {
6892       Lisp_Object frame;
6893       XSETFRAME (frame, emacsframe);
6894       help_echo_string = Qnil;
6895       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6896     }
6898   if (emacs_event && is_focus_frame)
6899     {
6900       [self deleteWorkingText];
6901       emacs_event->kind = FOCUS_OUT_EVENT;
6902       EV_TRAILER ((id)nil);
6903     }
6907 - (void)windowWillMiniaturize: sender
6909   NSTRACE ("[EmacsView windowWillMiniaturize:]");
6913 - (void)setFrame:(NSRect)frameRect
6915   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6916            NSTRACE_ARG_RECT (frameRect));
6918   [super setFrame:(NSRect)frameRect];
6922 - (BOOL)isFlipped
6924   return YES;
6928 - (BOOL)isOpaque
6930   return NO;
6934 - (void)createToolbar: (struct frame *)f
6936   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
6937   NSWindow *window = [view window];
6939   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6940                    [NSString stringWithFormat: @"Emacs Frame %d",
6941                              ns_window_num]];
6942   [toolbar setVisible: NO];
6943   [window setToolbar: toolbar];
6945   /* Don't set frame garbaged until tool bar is up to date?
6946      This avoids an extra clear and redraw (flicker) at frame creation.  */
6947   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6948   else wait_for_tool_bar = NO;
6951 #ifdef NS_IMPL_COCOA
6952   {
6953     NSButton *toggleButton;
6954     toggleButton = [window standardWindowButton: NSWindowToolbarButton];
6955     [toggleButton setTarget: self];
6956     [toggleButton setAction: @selector (toggleToolbar: )];
6957   }
6958 #endif
6962 - (instancetype) initFrameFromEmacs: (struct frame *)f
6964   NSRect r, wr;
6965   Lisp_Object tem;
6966   NSWindow *win;
6967   NSColor *col;
6968   NSString *name;
6970   NSTRACE ("[EmacsView initFrameFromEmacs:]");
6971   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6973   windowClosing = NO;
6974   processingCompose = NO;
6975   scrollbarsNeedingUpdate = 0;
6976   fs_state = FULLSCREEN_NONE;
6977   fs_before_fs = next_maximized = -1;
6978 #ifdef HAVE_NATIVE_FS
6979   fs_is_native = ns_use_native_fullscreen;
6980 #else
6981   fs_is_native = NO;
6982 #endif
6983   maximized_width = maximized_height = -1;
6984   nonfs_window = nil;
6986   ns_userRect = NSMakeRect (0, 0, 0, 0);
6987   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6988                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6989   [self initWithFrame: r];
6990   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6992   FRAME_NS_VIEW (f) = self;
6993   emacsframe = f;
6994 #ifdef NS_IMPL_COCOA
6995   old_title = 0;
6996   maximizing_resize = NO;
6997 #endif
6999   win = [[EmacsWindow alloc]
7000             initWithContentRect: r
7001                       styleMask: (FRAME_UNDECORATED (f)
7002                                   ? FRAME_UNDECORATED_FLAGS
7003                                   : FRAME_DECORATED_FLAGS
7004 #ifdef NS_IMPL_COCOA
7005                                   | NSWindowStyleMaskResizable
7006                                   | NSWindowStyleMaskMiniaturizable
7007                                   | NSWindowStyleMaskClosable
7008 #endif
7009                                   )
7010                         backing: NSBackingStoreBuffered
7011                           defer: YES];
7013 #ifdef HAVE_NATIVE_FS
7014     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7015 #endif
7017   wr = [win frame];
7018   bwidth = f->border_width = wr.size.width - r.size.width;
7020   [win setAcceptsMouseMovedEvents: YES];
7021   [win setDelegate: self];
7022 #if !defined (NS_IMPL_COCOA) || \
7023   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7024   [win useOptimizedDrawing: YES];
7025 #endif
7027   [[win contentView] addSubview: self];
7029   if (ns_drag_types)
7030     [self registerForDraggedTypes: ns_drag_types];
7032   tem = f->name;
7033   name = [NSString stringWithUTF8String:
7034                    NILP (tem) ? "Emacs" : SSDATA (tem)];
7035   [win setTitle: name];
7037   /* toolbar support */
7038   if (! FRAME_UNDECORATED (f))
7039     [self createToolbar: f];
7041   tem = f->icon_name;
7042   if (!NILP (tem))
7043     [win setMiniwindowTitle:
7044            [NSString stringWithUTF8String: SSDATA (tem)]];
7046   if (FRAME_PARENT_FRAME (f) != NULL)
7047     {
7048       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7049       [parent addChildWindow: win
7050                      ordered: NSWindowAbove];
7051     }
7053   if (FRAME_Z_GROUP (f) != z_group_none)
7054       win.level = NSNormalWindowLevel
7055         + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7057   {
7058     NSScreen *screen = [win screen];
7060     if (screen != 0)
7061       {
7062         NSPoint pt = NSMakePoint
7063           (IN_BOUND (-SCREENMAX, f->left_pos
7064                      + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7065            IN_BOUND (-SCREENMAX,
7066                      NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7067                      SCREENMAX));
7069         [win setFrameTopLeftPoint: pt];
7071         NSTRACE_RECT ("new frame", [win frame]);
7072       }
7073   }
7075   [win makeFirstResponder: self];
7077   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7078                                  (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7079                                  emacsframe);
7080   [win setBackgroundColor: col];
7081   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7082     [win setOpaque: NO];
7084 #if !defined (NS_IMPL_COCOA) || \
7085   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7086   [self allocateGState];
7087 #endif
7088   [NSApp registerServicesMenuSendTypes: ns_send_types
7089                            returnTypes: [NSArray array]];
7091   /* macOS Sierra automatically enables tabbed windows.  We can't
7092      allow this to be enabled until it's available on a Free system.
7093      Currently it only happens by accident and is buggy anyway. */
7094 #if defined (NS_IMPL_COCOA) && \
7095   MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
7096   [win setTabbingMode: NSWindowTabbingModeDisallowed];
7097 #endif
7099   ns_window_num++;
7100   return self;
7104 - (void)windowDidMove: sender
7106   NSWindow *win = [self window];
7107   NSRect r = [win frame];
7108   NSArray *screens = [NSScreen screens];
7109   NSScreen *screen = [screens objectAtIndex: 0];
7111   NSTRACE ("[EmacsView windowDidMove:]");
7113   if (!emacsframe->output_data.ns)
7114     return;
7115   if (screen != nil)
7116     {
7117       emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7118       emacsframe->top_pos =
7119         NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7121       if (emacs_event)
7122         {
7123           emacs_event->kind = MOVE_FRAME_EVENT;
7124           EV_TRAILER ((id)nil);
7125         }
7126     }
7130 /* Called AFTER method below, but before our windowWillResize call there leads
7131    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
7132    location so set_window_size moves the frame. */
7133 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7135   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7136             NSTRACE_FMT_RETURN "YES"),
7137            NSTRACE_ARG_RECT (newFrame));
7139   emacsframe->output_data.ns->zooming = 1;
7140   return YES;
7144 /* Override to do something slightly nonstandard, but nice.  First click on
7145    zoom button will zoom vertically.  Second will zoom completely.  Third
7146    returns to original. */
7147 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7148                         defaultFrame:(NSRect)defaultFrame
7150   // TODO: Rename to "currentFrame" and assign "result" properly in
7151   // all paths.
7152   NSRect result = [sender frame];
7154   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7155             NSTRACE_FMT_RECT "]"),
7156            NSTRACE_ARG_RECT (defaultFrame));
7157   NSTRACE_FSTYPE ("fs_state", fs_state);
7158   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7159   NSTRACE_FSTYPE ("next_maximized", next_maximized);
7160   NSTRACE_RECT   ("ns_userRect", ns_userRect);
7161   NSTRACE_RECT   ("[sender frame]", [sender frame]);
7163   if (fs_before_fs != -1) /* Entering fullscreen */
7164     {
7165       NSTRACE_MSG ("Entering fullscreen");
7166       result = defaultFrame;
7167     }
7168   else
7169     {
7170       // Save the window size and position (frame) before the resize.
7171       if (fs_state != FULLSCREEN_MAXIMIZED
7172           && fs_state != FULLSCREEN_WIDTH)
7173         {
7174           ns_userRect.size.width = result.size.width;
7175           ns_userRect.origin.x   = result.origin.x;
7176         }
7178       if (fs_state != FULLSCREEN_MAXIMIZED
7179           && fs_state != FULLSCREEN_HEIGHT)
7180         {
7181           ns_userRect.size.height = result.size.height;
7182           ns_userRect.origin.y    = result.origin.y;
7183         }
7185       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7187       if (next_maximized == FULLSCREEN_HEIGHT
7188           || (next_maximized == -1
7189               && abs ((int)(defaultFrame.size.height - result.size.height))
7190               > FRAME_LINE_HEIGHT (emacsframe)))
7191         {
7192           /* first click */
7193           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7194           maximized_height = result.size.height = defaultFrame.size.height;
7195           maximized_width = -1;
7196           result.origin.y = defaultFrame.origin.y;
7197           if (ns_userRect.size.height != 0)
7198             {
7199               result.origin.x = ns_userRect.origin.x;
7200               result.size.width = ns_userRect.size.width;
7201             }
7202           [self setFSValue: FULLSCREEN_HEIGHT];
7203 #ifdef NS_IMPL_COCOA
7204           maximizing_resize = YES;
7205 #endif
7206         }
7207       else if (next_maximized == FULLSCREEN_WIDTH)
7208         {
7209           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7210           maximized_width = result.size.width = defaultFrame.size.width;
7211           maximized_height = -1;
7212           result.origin.x = defaultFrame.origin.x;
7213           if (ns_userRect.size.width != 0)
7214             {
7215               result.origin.y = ns_userRect.origin.y;
7216               result.size.height = ns_userRect.size.height;
7217             }
7218           [self setFSValue: FULLSCREEN_WIDTH];
7219         }
7220       else if (next_maximized == FULLSCREEN_MAXIMIZED
7221                || (next_maximized == -1
7222                    && abs ((int)(defaultFrame.size.width - result.size.width))
7223                    > FRAME_COLUMN_WIDTH (emacsframe)))
7224         {
7225           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7227           result = defaultFrame;  /* second click */
7228           maximized_width = result.size.width;
7229           maximized_height = result.size.height;
7230           [self setFSValue: FULLSCREEN_MAXIMIZED];
7231 #ifdef NS_IMPL_COCOA
7232           maximizing_resize = YES;
7233 #endif
7234         }
7235       else
7236         {
7237           /* restore */
7238           NSTRACE_MSG ("Restore");
7239           result = ns_userRect.size.height ? ns_userRect : result;
7240           NSTRACE_RECT ("restore (2)", result);
7241           ns_userRect = NSMakeRect (0, 0, 0, 0);
7242 #ifdef NS_IMPL_COCOA
7243           maximizing_resize = fs_state != FULLSCREEN_NONE;
7244 #endif
7245           [self setFSValue: FULLSCREEN_NONE];
7246           maximized_width = maximized_height = -1;
7247         }
7248     }
7250   if (fs_before_fs == -1) next_maximized = -1;
7252   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
7253   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
7254   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
7255   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7257   [self windowWillResize: sender toSize: result.size];
7259   NSTRACE_RETURN_RECT (result);
7261   return result;
7265 - (void)windowDidDeminiaturize: sender
7267   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7268   if (!emacsframe->output_data.ns)
7269     return;
7271   SET_FRAME_ICONIFIED (emacsframe, 0);
7272   SET_FRAME_VISIBLE (emacsframe, 1);
7273   windows_or_buffers_changed = 63;
7275   if (emacs_event)
7276     {
7277       emacs_event->kind = DEICONIFY_EVENT;
7278       EV_TRAILER ((id)nil);
7279     }
7283 - (void)windowDidExpose: sender
7285   NSTRACE ("[EmacsView windowDidExpose:]");
7286   if (!emacsframe->output_data.ns)
7287     return;
7289   SET_FRAME_VISIBLE (emacsframe, 1);
7290   SET_FRAME_GARBAGED (emacsframe);
7292   if (send_appdefined)
7293     ns_send_appdefined (-1);
7297 - (void)windowDidMiniaturize: sender
7299   NSTRACE ("[EmacsView windowDidMiniaturize:]");
7300   if (!emacsframe->output_data.ns)
7301     return;
7303   SET_FRAME_ICONIFIED (emacsframe, 1);
7304   SET_FRAME_VISIBLE (emacsframe, 0);
7306   if (emacs_event)
7307     {
7308       emacs_event->kind = ICONIFY_EVENT;
7309       EV_TRAILER ((id)nil);
7310     }
7313 #ifdef HAVE_NATIVE_FS
7314 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7315       willUseFullScreenPresentationOptions:
7316   (NSApplicationPresentationOptions)proposedOptions
7318   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7320 #endif
7322 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7324   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7325   [self windowWillEnterFullScreen];
7327 - (void)windowWillEnterFullScreen /* provided for direct calls */
7329   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7330   fs_before_fs = fs_state;
7333 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7335   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7336   [self windowDidEnterFullScreen];
7339 - (void)windowDidEnterFullScreen /* provided for direct calls */
7341   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7342   [self setFSValue: FULLSCREEN_BOTH];
7343   if (! [self fsIsNative])
7344     {
7345       [self windowDidBecomeKey];
7346       [nonfs_window orderOut:self];
7347     }
7348   else
7349     {
7350       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7351 #ifdef NS_IMPL_COCOA
7352 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7353       unsigned val = (unsigned)[NSApp presentationOptions];
7355       // Mac OS X 10.7 bug fix, the menu won't appear without this.
7356       // val is non-zero on other macOS versions.
7357       if (val == 0)
7358         {
7359           NSApplicationPresentationOptions options
7360             = NSApplicationPresentationAutoHideDock
7361             | NSApplicationPresentationAutoHideMenuBar
7362             | NSApplicationPresentationFullScreen
7363             | NSApplicationPresentationAutoHideToolbar;
7365           [NSApp setPresentationOptions: options];
7366         }
7367 #endif
7368 #endif
7369       [toolbar setVisible:tbar_visible];
7370     }
7373 - (void)windowWillExitFullScreen:(NSNotification *)notification
7375   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7376   [self windowWillExitFullScreen];
7379 - (void)windowWillExitFullScreen /* provided for direct calls */
7381   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7382   if (!FRAME_LIVE_P (emacsframe))
7383     {
7384       NSTRACE_MSG ("Ignored (frame dead)");
7385       return;
7386     }
7387   if (next_maximized != -1)
7388     fs_before_fs = next_maximized;
7391 - (void)windowDidExitFullScreen:(NSNotification *)notification
7393   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7394   [self windowDidExitFullScreen];
7397 - (void)windowDidExitFullScreen /* provided for direct calls */
7399   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7400   if (!FRAME_LIVE_P (emacsframe))
7401     {
7402       NSTRACE_MSG ("Ignored (frame dead)");
7403       return;
7404     }
7405   [self setFSValue: fs_before_fs];
7406   fs_before_fs = -1;
7407 #ifdef HAVE_NATIVE_FS
7408   [self updateCollectionBehavior];
7409 #endif
7410   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7411     {
7412       [toolbar setVisible:YES];
7413       update_frame_tool_bar (emacsframe);
7414       [self updateFrameSize:YES];
7415       [[self window] display];
7416     }
7417   else
7418     [toolbar setVisible:NO];
7420   if (next_maximized != -1)
7421     [[self window] performZoom:self];
7424 - (BOOL)fsIsNative
7426   return fs_is_native;
7429 - (BOOL)isFullscreen
7431   BOOL res;
7433   if (! fs_is_native)
7434     {
7435       res = (nonfs_window != nil);
7436     }
7437   else
7438     {
7439 #ifdef HAVE_NATIVE_FS
7440       res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7441 #else
7442       res = NO;
7443 #endif
7444     }
7446   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7447            (int) res);
7449   return res;
7452 #ifdef HAVE_NATIVE_FS
7453 - (void)updateCollectionBehavior
7455   NSTRACE ("[EmacsView updateCollectionBehavior]");
7457   if (! [self isFullscreen])
7458     {
7459       NSWindow *win = [self window];
7460       NSWindowCollectionBehavior b = [win collectionBehavior];
7461       if (ns_use_native_fullscreen)
7462         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7463       else
7464         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7466       [win setCollectionBehavior: b];
7467       fs_is_native = ns_use_native_fullscreen;
7468     }
7470 #endif
7472 - (void)toggleFullScreen: (id)sender
7474   NSWindow *w, *fw;
7475   BOOL onFirstScreen;
7476   struct frame *f;
7477   NSRect r, wr;
7478   NSColor *col;
7480   NSTRACE ("[EmacsView toggleFullScreen:]");
7482   if (fs_is_native)
7483     {
7484 #ifdef HAVE_NATIVE_FS
7485       [[self window] toggleFullScreen:sender];
7486 #endif
7487       return;
7488     }
7490   w = [self window];
7491   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7492   f = emacsframe;
7493   wr = [w frame];
7494   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7495                                  (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7496                                  f);
7498   if (fs_state != FULLSCREEN_BOTH)
7499     {
7500       NSScreen *screen = [w screen];
7502 #if defined (NS_IMPL_COCOA) && \
7503   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7504       /* Hide ghost menu bar on secondary monitor? */
7505       if (! onFirstScreen)
7506         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7507 #endif
7508       /* Hide dock and menubar if we are on the primary screen.  */
7509       if (onFirstScreen)
7510         {
7511 #ifdef NS_IMPL_COCOA
7512           NSApplicationPresentationOptions options
7513             = NSApplicationPresentationAutoHideDock
7514             | NSApplicationPresentationAutoHideMenuBar;
7516           [NSApp setPresentationOptions: options];
7517 #else
7518           [NSMenu setMenuBarVisible:NO];
7519 #endif
7520         }
7522       fw = [[EmacsFSWindow alloc]
7523                        initWithContentRect:[w contentRectForFrameRect:wr]
7524                                  styleMask:NSWindowStyleMaskBorderless
7525                                    backing:NSBackingStoreBuffered
7526                                      defer:YES
7527                                     screen:screen];
7529       [fw setContentView:[w contentView]];
7530       [fw setTitle:[w title]];
7531       [fw setDelegate:self];
7532       [fw setAcceptsMouseMovedEvents: YES];
7533 #if !defined (NS_IMPL_COCOA) || \
7534   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7535       [fw useOptimizedDrawing: YES];
7536 #endif
7537       [fw setBackgroundColor: col];
7538       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7539         [fw setOpaque: NO];
7541       f->border_width = 0;
7543       nonfs_window = w;
7545       [self windowWillEnterFullScreen];
7546       [fw makeKeyAndOrderFront:NSApp];
7547       [fw makeFirstResponder:self];
7548       [w orderOut:self];
7549       r = [fw frameRectForContentRect:[screen frame]];
7550       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7551       [self windowDidEnterFullScreen];
7552       [fw display];
7553     }
7554   else
7555     {
7556       fw = w;
7557       w = nonfs_window;
7558       nonfs_window = nil;
7560       if (onFirstScreen)
7561         {
7562 #ifdef NS_IMPL_COCOA
7563           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7564 #else
7565           [NSMenu setMenuBarVisible:YES];
7566 #endif
7567         }
7569       [w setContentView:[fw contentView]];
7570       [w setBackgroundColor: col];
7571       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7572         [w setOpaque: NO];
7574       f->border_width = bwidth;
7576       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7578       [self windowWillExitFullScreen];
7579       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7580       [fw close];
7581       [w makeKeyAndOrderFront:NSApp];
7582       [self windowDidExitFullScreen];
7583       [self updateFrameSize:YES];
7584     }
7587 - (void)handleFS
7589   NSTRACE ("[EmacsView handleFS]");
7591   if (fs_state != emacsframe->want_fullscreen)
7592     {
7593       if (fs_state == FULLSCREEN_BOTH)
7594         {
7595           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7596           [self toggleFullScreen:self];
7597         }
7599       switch (emacsframe->want_fullscreen)
7600         {
7601         case FULLSCREEN_BOTH:
7602           NSTRACE_MSG ("FULLSCREEN_BOTH");
7603           [self toggleFullScreen:self];
7604           break;
7605         case FULLSCREEN_WIDTH:
7606           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7607           next_maximized = FULLSCREEN_WIDTH;
7608           if (fs_state != FULLSCREEN_BOTH)
7609             [[self window] performZoom:self];
7610           break;
7611         case FULLSCREEN_HEIGHT:
7612           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7613           next_maximized = FULLSCREEN_HEIGHT;
7614           if (fs_state != FULLSCREEN_BOTH)
7615             [[self window] performZoom:self];
7616           break;
7617         case FULLSCREEN_MAXIMIZED:
7618           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7619           next_maximized = FULLSCREEN_MAXIMIZED;
7620           if (fs_state != FULLSCREEN_BOTH)
7621             [[self window] performZoom:self];
7622           break;
7623         case FULLSCREEN_NONE:
7624           NSTRACE_MSG ("FULLSCREEN_NONE");
7625           if (fs_state != FULLSCREEN_BOTH)
7626             {
7627               next_maximized = FULLSCREEN_NONE;
7628               [[self window] performZoom:self];
7629             }
7630           break;
7631         }
7633       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7634     }
7638 - (void) setFSValue: (int)value
7640   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7641            NSTRACE_ARG_FSTYPE(value));
7643   Lisp_Object lval = Qnil;
7644   switch (value)
7645     {
7646     case FULLSCREEN_BOTH:
7647       lval = Qfullboth;
7648       break;
7649     case FULLSCREEN_WIDTH:
7650       lval = Qfullwidth;
7651       break;
7652     case FULLSCREEN_HEIGHT:
7653       lval = Qfullheight;
7654       break;
7655     case FULLSCREEN_MAXIMIZED:
7656       lval = Qmaximized;
7657       break;
7658     }
7659   store_frame_param (emacsframe, Qfullscreen, lval);
7660   fs_state = value;
7663 - (void)mouseEntered: (NSEvent *)theEvent
7665   NSTRACE ("[EmacsView mouseEntered:]");
7666   if (emacsframe)
7667     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7668       = EV_TIMESTAMP (theEvent);
7672 - (void)mouseExited: (NSEvent *)theEvent
7674   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7676   NSTRACE ("[EmacsView mouseExited:]");
7678   if (!hlinfo)
7679     return;
7681   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7682     = EV_TIMESTAMP (theEvent);
7684   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7685     {
7686       clear_mouse_face (hlinfo);
7687       hlinfo->mouse_face_mouse_frame = 0;
7688     }
7692 - (instancetype)menuDown: sender
7694   NSTRACE ("[EmacsView menuDown:]");
7695   if (context_menu_value == -1)
7696     context_menu_value = [sender tag];
7697   else
7698     {
7699       NSInteger tag = [sender tag];
7700       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7701                                     emacsframe->menu_bar_vector,
7702                                     (void *)tag);
7703     }
7705   ns_send_appdefined (-1);
7706   return self;
7710 - (EmacsToolbar *)toolbar
7712   return toolbar;
7716 /* this gets called on toolbar button click */
7717 - (instancetype)toolbarClicked: (id)item
7719   NSEvent *theEvent;
7720   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7722   NSTRACE ("[EmacsView toolbarClicked:]");
7724   if (!emacs_event)
7725     return self;
7727   /* send first event (for some reason two needed) */
7728   theEvent = [[self window] currentEvent];
7729   emacs_event->kind = TOOL_BAR_EVENT;
7730   XSETFRAME (emacs_event->arg, emacsframe);
7731   EV_TRAILER (theEvent);
7733   emacs_event->kind = TOOL_BAR_EVENT;
7734 /*   XSETINT (emacs_event->code, 0); */
7735   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7736                            idx + TOOL_BAR_ITEM_KEY);
7737   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7738   EV_TRAILER (theEvent);
7739   return self;
7743 - (instancetype)toggleToolbar: (id)sender
7745   NSTRACE ("[EmacsView toggleToolbar:]");
7747   if (!emacs_event)
7748     return self;
7750   emacs_event->kind = NS_NONKEY_EVENT;
7751   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7752   EV_TRAILER ((id)nil);
7753   return self;
7757 - (void)drawRect: (NSRect)rect
7759   int x = NSMinX (rect), y = NSMinY (rect);
7760   int width = NSWidth (rect), height = NSHeight (rect);
7762   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7763            NSTRACE_ARG_RECT(rect));
7765   if (!emacsframe || !emacsframe->output_data.ns)
7766     return;
7768   ns_clear_frame_area (emacsframe, x, y, width, height);
7769   block_input ();
7770   expose_frame (emacsframe, x, y, width, height);
7771   unblock_input ();
7773   /*
7774     drawRect: may be called (at least in Mac OS X 10.5) for invisible
7775     views as well for some reason.  Thus, do not infer visibility
7776     here.
7778     emacsframe->async_visible = 1;
7779     emacsframe->async_iconified = 0;
7780   */
7784 /* NSDraggingDestination protocol methods.  Actually this is not really a
7785    protocol, but a category of Object.  O well...  */
7787 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7789   NSTRACE ("[EmacsView draggingEntered:]");
7790   return NSDragOperationGeneric;
7794 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7796   return YES;
7800 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7802   id pb;
7803   int x, y;
7804   NSString *type;
7805   NSEvent *theEvent = [[self window] currentEvent];
7806   NSPoint position;
7807   NSDragOperation op = [sender draggingSourceOperationMask];
7808   int modifiers = 0;
7810   NSTRACE ("[EmacsView performDragOperation:]");
7812   if (!emacs_event)
7813     return NO;
7815   position = [self convertPoint: [sender draggingLocation] fromView: nil];
7816   x = lrint (position.x);  y = lrint (position.y);
7818   pb = [sender draggingPasteboard];
7819   type = [pb availableTypeFromArray: ns_drag_types];
7821   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7822       // URL drags contain all operations (0xf), don't allow all to be set.
7823       (op & 0xf) != 0xf)
7824     {
7825       if (op & NSDragOperationLink)
7826         modifiers |= NSEventModifierFlagControl;
7827       if (op & NSDragOperationCopy)
7828         modifiers |= NSEventModifierFlagOption;
7829       if (op & NSDragOperationGeneric)
7830         modifiers |= NSEventModifierFlagCommand;
7831     }
7833   modifiers = EV_MODIFIERS2 (modifiers);
7834   if (type == 0)
7835     {
7836       return NO;
7837     }
7838   else if ([type isEqualToString: NSFilenamesPboardType])
7839     {
7840       NSArray *files;
7841       NSEnumerator *fenum;
7842       NSString *file;
7844       if (!(files = [pb propertyListForType: type]))
7845         return NO;
7847       fenum = [files objectEnumerator];
7848       while ( (file = [fenum nextObject]) )
7849         {
7850           emacs_event->kind = DRAG_N_DROP_EVENT;
7851           XSETINT (emacs_event->x, x);
7852           XSETINT (emacs_event->y, y);
7853           ns_input_file = append2 (ns_input_file,
7854                                    build_string ([file UTF8String]));
7855           emacs_event->modifiers = modifiers;
7856           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
7857           EV_TRAILER (theEvent);
7858         }
7859       return YES;
7860     }
7861   else if ([type isEqualToString: NSURLPboardType])
7862     {
7863       NSURL *url = [NSURL URLFromPasteboard: pb];
7864       if (url == nil) return NO;
7866       emacs_event->kind = DRAG_N_DROP_EVENT;
7867       XSETINT (emacs_event->x, x);
7868       XSETINT (emacs_event->y, y);
7869       emacs_event->modifiers = modifiers;
7870       emacs_event->arg =  list2 (Qurl,
7871                                  build_string ([[url absoluteString]
7872                                                  UTF8String]));
7873       EV_TRAILER (theEvent);
7875       if ([url isFileURL] != NO)
7876         {
7877           NSString *file = [url path];
7878           ns_input_file = append2 (ns_input_file,
7879                                    build_string ([file UTF8String]));
7880         }
7881       return YES;
7882     }
7883   else if ([type isEqualToString: NSStringPboardType]
7884            || [type isEqualToString: NSTabularTextPboardType])
7885     {
7886       NSString *data;
7888       if (! (data = [pb stringForType: type]))
7889         return NO;
7891       emacs_event->kind = DRAG_N_DROP_EVENT;
7892       XSETINT (emacs_event->x, x);
7893       XSETINT (emacs_event->y, y);
7894       emacs_event->modifiers = modifiers;
7895       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
7896       EV_TRAILER (theEvent);
7897       return YES;
7898     }
7899   else
7900     {
7901       fprintf (stderr, "Invalid data type in dragging pasteboard");
7902       return NO;
7903     }
7907 - (id) validRequestorForSendType: (NSString *)typeSent
7908                       returnType: (NSString *)typeReturned
7910   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7911   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7912       && typeReturned == nil)
7913     {
7914       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7915         return self;
7916     }
7918   return [super validRequestorForSendType: typeSent
7919                                returnType: typeReturned];
7923 /* The next two methods are part of NSServicesRequests informal protocol,
7924    supposedly called when a services menu item is chosen from this app.
7925    But this should not happen because we override the services menu with our
7926    own entries which call ns-perform-service.
7927    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7928    So let's at least stub them out until further investigation can be done. */
7930 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7932   /* we could call ns_string_from_pasteboard(pboard) here but then it should
7933      be written into the buffer in place of the existing selection..
7934      ordinary service calls go through functions defined in ns-win.el */
7935   return NO;
7938 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7940   NSArray *typesDeclared;
7941   Lisp_Object val;
7943   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7945   /* We only support NSStringPboardType */
7946   if ([types containsObject:NSStringPboardType] == NO) {
7947     return NO;
7948   }
7950   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7951   if (CONSP (val) && SYMBOLP (XCAR (val)))
7952     {
7953       val = XCDR (val);
7954       if (CONSP (val) && NILP (XCDR (val)))
7955         val = XCAR (val);
7956     }
7957   if (! STRINGP (val))
7958     return NO;
7960   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7961   [pb declareTypes:typesDeclared owner:nil];
7962   ns_string_to_pasteboard (pb, val);
7963   return YES;
7967 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7968    (gives a miniaturized version of the window); currently we use the latter for
7969    frames whose active buffer doesn't correspond to any file
7970    (e.g., '*scratch*') */
7971 - (instancetype)setMiniwindowImage: (BOOL) setMini
7973   id image = [[self window] miniwindowImage];
7974   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7976   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7977      about "AppleDockIconEnabled" notwithstanding, however the set message
7978      below has its effect nonetheless. */
7979   if (image != emacsframe->output_data.ns->miniimage)
7980     {
7981       if (image && [image isKindOfClass: [EmacsImage class]])
7982         [image release];
7983       [[self window] setMiniwindowImage:
7984                        setMini ? emacsframe->output_data.ns->miniimage : nil];
7985     }
7987   return self;
7991 - (void) setRows: (int) r andColumns: (int) c
7993   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7994   rows = r;
7995   cols = c;
7998 - (int) fullscreenState
8000   return fs_state;
8003 @end  /* EmacsView */
8007 /* ==========================================================================
8009     EmacsWindow implementation
8011    ========================================================================== */
8013 @implementation EmacsWindow
8015 #ifdef NS_IMPL_COCOA
8016 - (id)accessibilityAttributeValue:(NSString *)attribute
8018   Lisp_Object str = Qnil;
8019   struct frame *f = SELECTED_FRAME ();
8020   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8022   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8024   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8025     return NSAccessibilityTextFieldRole;
8027   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8028       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8029     {
8030       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8031     }
8032   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8033     {
8034       if (! NILP (BVAR (curbuf, mark_active)))
8035           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8037       if (NILP (str))
8038         {
8039           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8040           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8041           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8043           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8044             str = make_uninit_multibyte_string (range, byte_range);
8045           else
8046             str = make_uninit_string (range);
8047           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8048              Is this a problem?  */
8049           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8050         }
8051     }
8054   if (! NILP (str))
8055     {
8056       if (CONSP (str) && SYMBOLP (XCAR (str)))
8057         {
8058           str = XCDR (str);
8059           if (CONSP (str) && NILP (XCDR (str)))
8060             str = XCAR (str);
8061         }
8062       if (STRINGP (str))
8063         {
8064           const char *utfStr = SSDATA (str);
8065           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8066           return nsStr;
8067         }
8068     }
8070   return [super accessibilityAttributeValue:attribute];
8072 #endif /* NS_IMPL_COCOA */
8074 /* Constrain size and placement of a frame.
8076    By returning the original "frameRect", the frame is not
8077    constrained. This can lead to unwanted situations where, for
8078    example, the menu bar covers the frame.
8080    The default implementation (accessed using "super") constrains the
8081    frame to the visible area of SCREEN, minus the menu bar (if
8082    present) and the Dock.  Note that default implementation also calls
8083    windowWillResize, with the frame it thinks should have.  (This can
8084    make the frame exit maximized mode.)
8086    Note that this should work in situations where multiple monitors
8087    are present.  Common configurations are side-by-side monitors and a
8088    monitor on top of another (e.g. when a laptop is placed under a
8089    large screen). */
8090 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8092   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8093              NSTRACE_ARG_RECT (frameRect));
8095 #ifdef NS_IMPL_COCOA
8096 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
8097   // If separate spaces is on, it is like each screen is independent.  There is
8098   // no spanning of frames across screens.
8099   if ([NSScreen screensHaveSeparateSpaces])
8100     {
8101       NSTRACE_MSG ("Screens have separate spaces");
8102       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8103       NSTRACE_RETURN_RECT (frameRect);
8104       return frameRect;
8105     }
8106   else
8107 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 */
8108     // Check that the proposed frameRect is visible in at least one
8109     // screen.  If it is not, ask the system to reposition it (only
8110     // for non-child windows).
8112     if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8113     {
8114       NSArray *screens = [NSScreen screens];
8115       NSUInteger nr_screens = [screens count];
8117       int i;
8118       BOOL frame_on_screen = NO;
8120       for (i = 0; i < nr_screens; ++i)
8121         {
8122           NSScreen *s = [screens objectAtIndex: i];
8123           NSRect scrRect = [s frame];
8125           if (NSIntersectsRect(frameRect, scrRect))
8126             {
8127               frame_on_screen = YES;
8128               break;
8129             }
8130         }
8132       if (!frame_on_screen)
8133         {
8134           NSTRACE_MSG ("Frame outside screens; constraining");
8135           frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8136           NSTRACE_RETURN_RECT (frameRect);
8137           return frameRect;
8138         }
8139     }
8140 #endif
8142   return constrain_frame_rect(frameRect,
8143                               [(EmacsView *)[self delegate] isFullscreen]);
8147 - (void)performZoom:(id)sender
8149   NSTRACE ("[EmacsWindow performZoom:]");
8151   return [super performZoom:sender];
8154 - (void)zoom:(id)sender
8156   NSTRACE ("[EmacsWindow zoom:]");
8158   ns_update_auto_hide_menu_bar();
8160   // Below are three zoom implementations.  In the final commit, the
8161   // idea is that the last should be included.
8163 #if 0
8164   // Native zoom done using the standard zoom animation.  Size of the
8165   // resulting frame reduced to accommodate the Dock and, if present,
8166   // the menu-bar.
8167   [super zoom:sender];
8169 #elif 0
8170   // Native zoom done using the standard zoom animation, plus an
8171   // explicit resize to cover the full screen, except the menu-bar and
8172   // dock, if present.
8173   [super zoom:sender];
8175   // After the native zoom, resize the resulting frame to fill the
8176   // entire screen, except the menu-bar.
8177   //
8178   // This works for all practical purposes.  (The only minor oddity is
8179   // when transiting from full-height frame to a maximized, the
8180   // animation reduces the height of the frame slightly (to the 4
8181   // pixels needed to accommodate the Doc) before it snaps back into
8182   // full height.  The user would need a very trained eye to spot
8183   // this.)
8184   NSScreen * screen = [self screen];
8185   if (screen != nil)
8186     {
8187       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8189       NSTRACE_FSTYPE ("fullscreenState", fs_state);
8191       NSRect sr = [screen frame];
8192       struct EmacsMargins margins
8193         = ns_screen_margins_ignoring_hidden_dock(screen);
8195       NSRect wr = [self frame];
8196       NSTRACE_RECT ("Rect after zoom", wr);
8198       NSRect newWr = wr;
8200       if (fs_state == FULLSCREEN_MAXIMIZED
8201           || fs_state == FULLSCREEN_HEIGHT)
8202         {
8203           newWr.origin.y = sr.origin.y + margins.bottom;
8204           newWr.size.height = sr.size.height - margins.top - margins.bottom;
8205         }
8207       if (fs_state == FULLSCREEN_MAXIMIZED
8208           || fs_state == FULLSCREEN_WIDTH)
8209         {
8210           newWr.origin.x = sr.origin.x + margins.left;
8211           newWr.size.width = sr.size.width - margins.right - margins.left;
8212         }
8214       if (newWr.size.width     != wr.size.width
8215           || newWr.size.height != wr.size.height
8216           || newWr.origin.x    != wr.origin.x
8217           || newWr.origin.y    != wr.origin.y)
8218         {
8219           NSTRACE_MSG ("New frame different");
8220           [self setFrame: newWr display: NO];
8221         }
8222     }
8223 #else
8224   // Non-native zoom which is done instantaneously.  The resulting
8225   // frame covers the entire screen, except the menu-bar and dock, if
8226   // present.
8227   NSScreen * screen = [self screen];
8228   if (screen != nil)
8229     {
8230       NSRect sr = [screen frame];
8231       struct EmacsMargins margins
8232         = ns_screen_margins_ignoring_hidden_dock(screen);
8234       sr.size.height -= (margins.top + margins.bottom);
8235       sr.size.width  -= (margins.left + margins.right);
8236       sr.origin.x += margins.left;
8237       sr.origin.y += margins.bottom;
8239       sr = [[self delegate] windowWillUseStandardFrame:self
8240                                           defaultFrame:sr];
8241       [self setFrame: sr display: NO];
8242     }
8243 #endif
8246 - (void)setFrame:(NSRect)windowFrame
8247          display:(BOOL)displayViews
8249   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8250            NSTRACE_ARG_RECT (windowFrame), displayViews);
8252   [super setFrame:windowFrame display:displayViews];
8255 - (void)setFrame:(NSRect)windowFrame
8256          display:(BOOL)displayViews
8257          animate:(BOOL)performAnimation
8259   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8260            " display:%d performAnimation:%d]",
8261            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8263   [super setFrame:windowFrame display:displayViews animate:performAnimation];
8266 - (void)setFrameTopLeftPoint:(NSPoint)point
8268   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8269            NSTRACE_ARG_POINT (point));
8271   [super setFrameTopLeftPoint:point];
8274 - (BOOL)canBecomeKeyWindow
8276   return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8278 @end /* EmacsWindow */
8281 @implementation EmacsFSWindow
8283 - (BOOL)canBecomeKeyWindow
8285   return YES;
8288 - (BOOL)canBecomeMainWindow
8290   return YES;
8293 @end
8295 /* ==========================================================================
8297     EmacsScroller implementation
8299    ========================================================================== */
8302 @implementation EmacsScroller
8304 /* for repeat button push */
8305 #define SCROLL_BAR_FIRST_DELAY 0.5
8306 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8308 + (CGFloat) scrollerWidth
8310   /* TODO: if we want to allow variable widths, this is the place to do it,
8311            however neither GNUstep nor Cocoa support it very well */
8312   CGFloat r;
8313 #if !defined (NS_IMPL_COCOA) || \
8314   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
8315   r = [NSScroller scrollerWidth];
8316 #else
8317   r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8318                                 scrollerStyle: NSScrollerStyleLegacy];
8319 #endif
8320   return r;
8323 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8325   NSTRACE ("[EmacsScroller initFrame: window:]");
8327   if (r.size.width > r.size.height)
8328       horizontal = YES;
8329   else
8330       horizontal = NO;
8332   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8333   [self setContinuous: YES];
8334   [self setEnabled: YES];
8336   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8337      locked against the top and bottom edges, and right edge on macOS, where
8338      scrollers are on right. */
8339 #ifdef NS_IMPL_GNUSTEP
8340   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8341 #else
8342   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8343 #endif
8345   window = XWINDOW (nwin);
8346   condemned = NO;
8347   if (horizontal)
8348     pixel_length = NSWidth (r);
8349   else
8350     pixel_length = NSHeight (r);
8351   if (pixel_length == 0) pixel_length = 1;
8352   min_portion = 20 / pixel_length;
8354   frame = XFRAME (window->frame);
8355   if (FRAME_LIVE_P (frame))
8356     {
8357       int i;
8358       EmacsView *view = FRAME_NS_VIEW (frame);
8359       NSView *sview = [[view window] contentView];
8360       NSArray *subs = [sview subviews];
8362       /* disable optimization stopping redraw of other scrollbars */
8363       view->scrollbarsNeedingUpdate = 0;
8364       for (i =[subs count]-1; i >= 0; i--)
8365         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8366           view->scrollbarsNeedingUpdate++;
8367       [sview addSubview: self];
8368     }
8370 /*  [self setFrame: r]; */
8372   return self;
8376 - (void)setFrame: (NSRect)newRect
8378   NSTRACE ("[EmacsScroller setFrame:]");
8380 /*  block_input (); */
8381   if (horizontal)
8382     pixel_length = NSWidth (newRect);
8383   else
8384     pixel_length = NSHeight (newRect);
8385   if (pixel_length == 0) pixel_length = 1;
8386   min_portion = 20 / pixel_length;
8387   [super setFrame: newRect];
8388 /*  unblock_input (); */
8392 - (void)dealloc
8394   NSTRACE ("[EmacsScroller dealloc]");
8395   if (window)
8396     {
8397       if (horizontal)
8398         wset_horizontal_scroll_bar (window, Qnil);
8399       else
8400         wset_vertical_scroll_bar (window, Qnil);
8401     }
8402   window = 0;
8403   [super dealloc];
8407 - (instancetype)condemn
8409   NSTRACE ("[EmacsScroller condemn]");
8410   condemned =YES;
8411   return self;
8415 - (instancetype)reprieve
8417   NSTRACE ("[EmacsScroller reprieve]");
8418   condemned =NO;
8419   return self;
8423 -(bool)judge
8425   NSTRACE ("[EmacsScroller judge]");
8426   bool ret = condemned;
8427   if (condemned)
8428     {
8429       EmacsView *view;
8430       block_input ();
8431       /* ensure other scrollbar updates after deletion */
8432       view = (EmacsView *)FRAME_NS_VIEW (frame);
8433       if (view != nil)
8434         view->scrollbarsNeedingUpdate++;
8435       if (window)
8436         {
8437           if (horizontal)
8438             wset_horizontal_scroll_bar (window, Qnil);
8439           else
8440             wset_vertical_scroll_bar (window, Qnil);
8441         }
8442       window = 0;
8443       [self removeFromSuperview];
8444       [self release];
8445       unblock_input ();
8446     }
8447   return ret;
8451 - (void)resetCursorRects
8453   NSRect visible = [self visibleRect];
8454   NSTRACE ("[EmacsScroller resetCursorRects]");
8456   if (!NSIsEmptyRect (visible))
8457     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8458   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8462 - (int) checkSamePosition: (int) position portion: (int) portion
8463                     whole: (int) whole
8465   return em_position ==position && em_portion ==portion && em_whole ==whole
8466     && portion != whole; /* needed for resize empty buf */
8470 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8472   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8474   em_position = position;
8475   em_portion = portion;
8476   em_whole = whole;
8478   if (portion >= whole)
8479     {
8480 #ifdef NS_IMPL_COCOA
8481       [self setKnobProportion: 1.0];
8482       [self setDoubleValue: 1.0];
8483 #else
8484       [self setFloatValue: 0.0 knobProportion: 1.0];
8485 #endif
8486     }
8487   else
8488     {
8489       float pos;
8490       CGFloat por;
8491       portion = max ((float)whole*min_portion/pixel_length, portion);
8492       pos = (float)position / (whole - portion);
8493       por = (CGFloat)portion/whole;
8494 #ifdef NS_IMPL_COCOA
8495       [self setKnobProportion: por];
8496       [self setDoubleValue: pos];
8497 #else
8498       [self setFloatValue: pos knobProportion: por];
8499 #endif
8500     }
8502   return self;
8505 /* set up emacs_event */
8506 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8508   Lisp_Object win;
8510   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8512   if (!emacs_event)
8513     return;
8515   emacs_event->part = last_hit_part;
8516   emacs_event->code = 0;
8517   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8518   XSETWINDOW (win, window);
8519   emacs_event->frame_or_window = win;
8520   emacs_event->timestamp = EV_TIMESTAMP (e);
8521   emacs_event->arg = Qnil;
8523   if (horizontal)
8524     {
8525       emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8526       XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8527       XSETINT (emacs_event->y, em_whole);
8528     }
8529   else
8530     {
8531       emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8532       XSETINT (emacs_event->x, loc);
8533       XSETINT (emacs_event->y, pixel_length-20);
8534     }
8536   if (q_event_ptr)
8537     {
8538       n_emacs_events_pending++;
8539       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8540     }
8541   else
8542     hold_event (emacs_event);
8543   EVENT_INIT (*emacs_event);
8544   ns_send_appdefined (-1);
8548 /* called manually thru timer to implement repeated button action w/hold-down */
8549 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8551   NSEvent *e = [[self window] currentEvent];
8552   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8553   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8555   NSTRACE ("[EmacsScroller repeatScroll:]");
8557   /* clear timer if need be */
8558   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8559     {
8560         [scroll_repeat_entry invalidate];
8561         [scroll_repeat_entry release];
8562         scroll_repeat_entry = nil;
8564         if (inKnob)
8565           return self;
8567         scroll_repeat_entry
8568           = [[NSTimer scheduledTimerWithTimeInterval:
8569                         SCROLL_BAR_CONTINUOUS_DELAY
8570                                             target: self
8571                                           selector: @selector (repeatScroll:)
8572                                           userInfo: 0
8573                                            repeats: YES]
8574               retain];
8575     }
8577   [self sendScrollEventAtLoc: 0 fromEvent: e];
8578   return self;
8582 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8583    mouseDragged events without going into a modal loop. */
8584 - (void)mouseDown: (NSEvent *)e
8586   NSRect sr, kr;
8587   /* hitPart is only updated AFTER event is passed on */
8588   NSScrollerPart part = [self testPart: [e locationInWindow]];
8589   CGFloat loc, kloc, pos UNINIT;
8590   int edge = 0;
8592   NSTRACE ("[EmacsScroller mouseDown:]");
8594   switch (part)
8595     {
8596     case NSScrollerDecrementPage:
8597       last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8598     case NSScrollerIncrementPage:
8599       last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8600     case NSScrollerDecrementLine:
8601       last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8602     case NSScrollerIncrementLine:
8603       last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8604     case NSScrollerKnob:
8605       last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8606     case NSScrollerKnobSlot:  /* GNUstep-only */
8607       last_hit_part = scroll_bar_move_ratio; break;
8608     default:  /* NSScrollerNoPart? */
8609       fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8610                (long) part);
8611       return;
8612     }
8614   if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8615     {
8616       /* handle, or on GNUstep possibly slot */
8617       NSEvent *fake_event;
8618       int length;
8620       /* compute float loc in slot and mouse offset on knob */
8621       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8622                       toView: nil];
8623       if (horizontal)
8624         {
8625           length = NSWidth (sr);
8626           loc = ([e locationInWindow].x - NSMinX (sr));
8627         }
8628       else
8629         {
8630           length = NSHeight (sr);
8631           loc = length - ([e locationInWindow].y - NSMinY (sr));
8632         }
8634       if (loc <= 0.0)
8635         {
8636           loc = 0.0;
8637           edge = -1;
8638         }
8639       else if (loc >= length)
8640         {
8641           loc = length;
8642           edge = 1;
8643         }
8645       if (edge)
8646         kloc = 0.5 * edge;
8647       else
8648         {
8649           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8650                           toView: nil];
8651           if (horizontal)
8652             kloc = ([e locationInWindow].x - NSMinX (kr));
8653           else
8654             kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8655         }
8656       last_mouse_offset = kloc;
8658       if (part != NSScrollerKnob)
8659         /* this is a slot click on GNUstep: go straight there */
8660         pos = loc;
8662       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8663       fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8664                                       location: [e locationInWindow]
8665                                  modifierFlags: [e modifierFlags]
8666                                      timestamp: [e timestamp]
8667                                   windowNumber: [e windowNumber]
8668                                        context: nil
8669                                    eventNumber: [e eventNumber]
8670                                     clickCount: [e clickCount]
8671                                       pressure: [e pressure]];
8672       [super mouseUp: fake_event];
8673     }
8674   else
8675     {
8676       pos = 0;      /* ignored */
8678       /* set a timer to repeat, as we can't let superclass do this modally */
8679       scroll_repeat_entry
8680         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8681                                             target: self
8682                                           selector: @selector (repeatScroll:)
8683                                           userInfo: 0
8684                                            repeats: YES]
8685             retain];
8686     }
8688   if (part != NSScrollerKnob)
8689     [self sendScrollEventAtLoc: pos fromEvent: e];
8693 /* Called as we manually track scroller drags, rather than superclass. */
8694 - (void)mouseDragged: (NSEvent *)e
8696     NSRect sr;
8697     double loc, pos;
8698     int length;
8700     NSTRACE ("[EmacsScroller mouseDragged:]");
8702       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8703                       toView: nil];
8705       if (horizontal)
8706         {
8707           length = NSWidth (sr);
8708           loc = ([e locationInWindow].x - NSMinX (sr));
8709         }
8710       else
8711         {
8712           length = NSHeight (sr);
8713           loc = length - ([e locationInWindow].y - NSMinY (sr));
8714         }
8716       if (loc <= 0.0)
8717         {
8718           loc = 0.0;
8719         }
8720       else if (loc >= length + last_mouse_offset)
8721         {
8722           loc = length + last_mouse_offset;
8723         }
8725       pos = (loc - last_mouse_offset);
8726       [self sendScrollEventAtLoc: pos fromEvent: e];
8730 - (void)mouseUp: (NSEvent *)e
8732   NSTRACE ("[EmacsScroller mouseUp:]");
8734   if (scroll_repeat_entry)
8735     {
8736       [scroll_repeat_entry invalidate];
8737       [scroll_repeat_entry release];
8738       scroll_repeat_entry = nil;
8739     }
8740   last_hit_part = scroll_bar_above_handle;
8744 /* treat scrollwheel events in the bar as though they were in the main window */
8745 - (void) scrollWheel: (NSEvent *)theEvent
8747   NSTRACE ("[EmacsScroller scrollWheel:]");
8749   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8750   [view mouseDown: theEvent];
8753 @end  /* EmacsScroller */
8756 #ifdef NS_IMPL_GNUSTEP
8757 /* Dummy class to get rid of startup warnings.  */
8758 @implementation EmacsDocument
8760 @end
8761 #endif
8764 /* ==========================================================================
8766    Font-related functions; these used to be in nsfaces.m
8768    ========================================================================== */
8771 Lisp_Object
8772 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8774   struct font *font = XFONT_OBJECT (font_object);
8775   EmacsView *view = FRAME_NS_VIEW (f);
8776   int font_ascent, font_descent;
8778   if (fontset < 0)
8779     fontset = fontset_from_font (font_object);
8780   FRAME_FONTSET (f) = fontset;
8782   if (FRAME_FONT (f) == font)
8783     /* This font is already set in frame F.  There's nothing more to
8784        do.  */
8785     return font_object;
8787   FRAME_FONT (f) = font;
8789   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8790   FRAME_COLUMN_WIDTH (f) = font->average_width;
8791   get_font_ascent_descent (font, &font_ascent, &font_descent);
8792   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8794   /* Compute the scroll bar width in character columns.  */
8795   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8796     {
8797       int wid = FRAME_COLUMN_WIDTH (f);
8798       FRAME_CONFIG_SCROLL_BAR_COLS (f)
8799         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8800     }
8801   else
8802     {
8803       int wid = FRAME_COLUMN_WIDTH (f);
8804       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8805     }
8807   /* Compute the scroll bar height in character lines.  */
8808   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8809     {
8810       int height = FRAME_LINE_HEIGHT (f);
8811       FRAME_CONFIG_SCROLL_BAR_LINES (f)
8812         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8813     }
8814   else
8815     {
8816       int height = FRAME_LINE_HEIGHT (f);
8817       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8818     }
8820   /* Now make the frame display the given font.  */
8821   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8822     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8823                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8824                        false, Qfont);
8826   return font_object;
8830 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8831 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8832          in 1.43. */
8834 const char *
8835 ns_xlfd_to_fontname (const char *xlfd)
8836 /* --------------------------------------------------------------------------
8837     Convert an X font name (XLFD) to an NS font name.
8838     Only family is used.
8839     The string returned is temporarily allocated.
8840    -------------------------------------------------------------------------- */
8842   char *name = xmalloc (180);
8843   int i, len;
8844   const char *ret;
8846   if (!strncmp (xlfd, "--", 2))
8847     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8848   else
8849     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8851   /* stopgap for malformed XLFD input */
8852   if (strlen (name) == 0)
8853     strcpy (name, "Monaco");
8855   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8856      also uppercase after '-' or ' ' */
8857   name[0] = c_toupper (name[0]);
8858   for (len =strlen (name), i =0; i<len; i++)
8859     {
8860       if (name[i] == '$')
8861         {
8862           name[i] = '-';
8863           if (i+1<len)
8864             name[i+1] = c_toupper (name[i+1]);
8865         }
8866       else if (name[i] == '_')
8867         {
8868           name[i] = ' ';
8869           if (i+1<len)
8870             name[i+1] = c_toupper (name[i+1]);
8871         }
8872     }
8873 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
8874   ret = [[NSString stringWithUTF8String: name] UTF8String];
8875   xfree (name);
8876   return ret;
8880 void
8881 syms_of_nsterm (void)
8883   NSTRACE ("syms_of_nsterm");
8885   ns_antialias_threshold = 10.0;
8887   /* from 23+ we need to tell emacs what modifiers there are.. */
8888   DEFSYM (Qmodifier_value, "modifier-value");
8889   DEFSYM (Qalt, "alt");
8890   DEFSYM (Qhyper, "hyper");
8891   DEFSYM (Qmeta, "meta");
8892   DEFSYM (Qsuper, "super");
8893   DEFSYM (Qcontrol, "control");
8894   DEFSYM (QUTF8_STRING, "UTF8_STRING");
8896   DEFSYM (Qfile, "file");
8897   DEFSYM (Qurl, "url");
8899   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8900   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8901   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8902   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8903   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8905   DEFVAR_LISP ("ns-input-file", ns_input_file,
8906               "The file specified in the last NS event.");
8907   ns_input_file =Qnil;
8909   DEFVAR_LISP ("ns-working-text", ns_working_text,
8910               "String for visualizing working composition sequence.");
8911   ns_working_text =Qnil;
8913   DEFVAR_LISP ("ns-input-font", ns_input_font,
8914               "The font specified in the last NS event.");
8915   ns_input_font =Qnil;
8917   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8918               "The fontsize specified in the last NS event.");
8919   ns_input_fontsize =Qnil;
8921   DEFVAR_LISP ("ns-input-line", ns_input_line,
8922                "The line specified in the last NS event.");
8923   ns_input_line =Qnil;
8925   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8926                "The service name specified in the last NS event.");
8927   ns_input_spi_name =Qnil;
8929   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8930                "The service argument specified in the last NS event.");
8931   ns_input_spi_arg =Qnil;
8933   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8934                "This variable describes the behavior of the alternate or option key.\n\
8935 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8936 that key.\n\
8937 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8938 at all, allowing it to be used at a lower level for accented character entry.");
8939   ns_alternate_modifier = Qmeta;
8941   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8942                "This variable describes the behavior of the right alternate or option key.\n\
8943 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8944 that key.\n\
8945 Set to left means be the same key as `ns-alternate-modifier'.\n\
8946 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8947 at all, allowing it to be used at a lower level for accented character entry.");
8948   ns_right_alternate_modifier = Qleft;
8950   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8951                "This variable describes the behavior of the command key.\n\
8952 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8953 that key.");
8954   ns_command_modifier = Qsuper;
8956   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8957                "This variable describes the behavior of the right command key.\n\
8958 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8959 that key.\n\
8960 Set to left means be the same key as `ns-command-modifier'.\n\
8961 Set to none means that the command / option key is not interpreted by Emacs\n\
8962 at all, allowing it to be used at a lower level for accented character entry.");
8963   ns_right_command_modifier = Qleft;
8965   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8966                "This variable describes the behavior of the control key.\n\
8967 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8968 that key.");
8969   ns_control_modifier = Qcontrol;
8971   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8972                "This variable describes the behavior of the right control key.\n\
8973 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8974 that key.\n\
8975 Set to left means be the same key as `ns-control-modifier'.\n\
8976 Set to none means that the control / option key is not interpreted by Emacs\n\
8977 at all, allowing it to be used at a lower level for accented character entry.");
8978   ns_right_control_modifier = Qleft;
8980   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8981                "This variable describes the behavior of the function key (on laptops).\n\
8982 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8983 that key.\n\
8984 Set to none means that the function key is not interpreted by Emacs at all,\n\
8985 allowing it to be used at a lower level for accented character entry.");
8986   ns_function_modifier = Qnone;
8988   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8989                "Non-nil (the default) means to render text antialiased.");
8990   ns_antialias_text = Qt;
8992   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8993                "Whether to confirm application quit using dialog.");
8994   ns_confirm_quit = Qnil;
8996   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8997                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8998 Only works on Mac OS X 10.6 or later.  */);
8999   ns_auto_hide_menu_bar = Qnil;
9001   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9002      doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9003 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
9004 multiple monitors, but lacks tool bar.  This variable is ignored on
9005 Mac OS X < 10.7.  Default is t for 10.7 and later, nil otherwise.  */);
9006 #ifdef HAVE_NATIVE_FS
9007   ns_use_native_fullscreen = YES;
9008 #else
9009   ns_use_native_fullscreen = NO;
9010 #endif
9011   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9013   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9014      doc: /*Non-nil means use animation on non-native fullscreen.
9015 For native fullscreen, this does nothing.
9016 Default is nil.  */);
9017   ns_use_fullscreen_animation = NO;
9019   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9020      doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9021 Note that this does not apply to images.
9022 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
9023   ns_use_srgb_colorspace = YES;
9025   /* TODO: move to common code */
9026   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9027                doc: /* Which toolkit scroll bars Emacs uses, if any.
9028 A value of nil means Emacs doesn't use toolkit scroll bars.
9029 With the X Window system, the value is a symbol describing the
9030 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
9031 With MS Windows or Nextstep, the value is t.  */);
9032   Vx_toolkit_scroll_bars = Qt;
9034   DEFVAR_BOOL ("x-use-underline-position-properties",
9035                x_use_underline_position_properties,
9036      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9037 A value of nil means ignore them.  If you encounter fonts with bogus
9038 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9039 to 4.1, set this to nil. */);
9040   x_use_underline_position_properties = 0;
9042   DEFVAR_BOOL ("x-underline-at-descent-line",
9043                x_underline_at_descent_line,
9044      doc: /* Non-nil means to draw the underline at the same place as the descent line.
9045 A value of nil means to draw the underline according to the value of the
9046 variable `x-use-underline-position-properties', which is usually at the
9047 baseline level.  The default value is nil.  */);
9048   x_underline_at_descent_line = 0;
9050   /* Tell Emacs about this window system.  */
9051   Fprovide (Qns, Qnil);
9053   DEFSYM (Qcocoa, "cocoa");
9054   DEFSYM (Qgnustep, "gnustep");
9056 #ifdef NS_IMPL_COCOA
9057   Fprovide (Qcocoa, Qnil);
9058   syms_of_macfont ();
9059 #else
9060   Fprovide (Qgnustep, Qnil);
9061   syms_of_nsfont ();
9062 #endif