Make CC Mode load cl-lib rather than cl in Emacs 26.
[emacs.git] / src / nsterm.m
blobe05dbf45fbc8b64cfbf2a1431a9f91aa14a93715
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);
1574       SET_FRAME_VISIBLE (f, 1);
1575       ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1577       /* Making a new frame from a fullscreen frame will make the new frame
1578          fullscreen also.  So skip handleFS as this will print an error.  */
1579       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1580           && [view isFullscreen])
1581         return;
1583       if (f->want_fullscreen != FULLSCREEN_NONE)
1584         {
1585           block_input ();
1586           [view handleFS];
1587           unblock_input ();
1588         }
1589     }
1593 void
1594 x_make_frame_invisible (struct frame *f)
1595 /* --------------------------------------------------------------------------
1596      External: Hide the window (X11 semantics)
1597    -------------------------------------------------------------------------- */
1599   NSView *view;
1600   NSTRACE ("x_make_frame_invisible");
1601   check_window_system (f);
1602   view = FRAME_NS_VIEW (f);
1603   [[view window] orderOut: NSApp];
1604   SET_FRAME_VISIBLE (f, 0);
1605   SET_FRAME_ICONIFIED (f, 0);
1609 void
1610 x_iconify_frame (struct frame *f)
1611 /* --------------------------------------------------------------------------
1612      External: Iconify window
1613    -------------------------------------------------------------------------- */
1615   NSView *view;
1616   struct ns_display_info *dpyinfo;
1618   NSTRACE ("x_iconify_frame");
1619   check_window_system (f);
1620   view = FRAME_NS_VIEW (f);
1621   dpyinfo = FRAME_DISPLAY_INFO (f);
1623   if (dpyinfo->x_highlight_frame == f)
1624     dpyinfo->x_highlight_frame = 0;
1626   if ([[view window] windowNumber] <= 0)
1627     {
1628       /* the window is still deferred.  Make it very small, bring it
1629          on screen and order it out. */
1630       NSRect s = { { 100, 100}, {0, 0} };
1631       NSRect t;
1632       t = [[view window] frame];
1633       [[view window] setFrame: s display: NO];
1634       [[view window] orderBack: NSApp];
1635       [[view window] orderOut: NSApp];
1636       [[view window] setFrame: t display: NO];
1637     }
1639   /* Processing input while Emacs is being minimized can cause a
1640      crash, so block it for the duration. */
1641   block_input();
1642   [[view window] miniaturize: NSApp];
1643   unblock_input();
1646 /* Free X resources of frame F.  */
1648 void
1649 x_free_frame_resources (struct frame *f)
1651   NSView *view;
1652   struct ns_display_info *dpyinfo;
1653   Mouse_HLInfo *hlinfo;
1655   NSTRACE ("x_free_frame_resources");
1656   check_window_system (f);
1657   view = FRAME_NS_VIEW (f);
1658   dpyinfo = FRAME_DISPLAY_INFO (f);
1659   hlinfo = MOUSE_HL_INFO (f);
1661   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1663   block_input ();
1665   free_frame_menubar (f);
1666   free_frame_faces (f);
1668   if (f == dpyinfo->x_focus_frame)
1669     dpyinfo->x_focus_frame = 0;
1670   if (f == dpyinfo->x_highlight_frame)
1671     dpyinfo->x_highlight_frame = 0;
1672   if (f == hlinfo->mouse_face_mouse_frame)
1673     reset_mouse_highlight (hlinfo);
1675   if (f->output_data.ns->miniimage != nil)
1676     [f->output_data.ns->miniimage release];
1678   [[view window] close];
1679   [view release];
1681   xfree (f->output_data.ns);
1683   unblock_input ();
1686 void
1687 x_destroy_window (struct frame *f)
1688 /* --------------------------------------------------------------------------
1689      External: Delete the window
1690    -------------------------------------------------------------------------- */
1692   NSTRACE ("x_destroy_window");
1694   /* If this frame has a parent window, detach it as not doing so can
1695      cause a crash in GNUStep. */
1696   if (FRAME_PARENT_FRAME (f) != NULL)
1697     {
1698       NSWindow *child = [FRAME_NS_VIEW (f) window];
1699       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1701       [parent removeChildWindow: child];
1702     }
1704   check_window_system (f);
1705   x_free_frame_resources (f);
1706   ns_window_num--;
1710 void
1711 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1712 /* --------------------------------------------------------------------------
1713      External: Position the window
1714    -------------------------------------------------------------------------- */
1716   NSView *view = FRAME_NS_VIEW (f);
1717   NSArray *screens = [NSScreen screens];
1718   NSScreen *fscreen = [screens objectAtIndex: 0];
1719   NSScreen *screen = [[view window] screen];
1721   NSTRACE ("x_set_offset");
1723   block_input ();
1725   f->left_pos = xoff;
1726   f->top_pos = yoff;
1728   if (view != nil && screen && fscreen)
1729     {
1730       f->left_pos = f->size_hint_flags & XNegative
1731         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1732         : f->left_pos;
1733       /* We use visibleFrame here to take menu bar into account.
1734          Ideally we should also adjust left/top with visibleFrame.origin.  */
1736       f->top_pos = f->size_hint_flags & YNegative
1737         ? ([screen visibleFrame].size.height + f->top_pos
1738            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1739            - FRAME_TOOLBAR_HEIGHT (f))
1740         : f->top_pos;
1741 #ifdef NS_IMPL_GNUSTEP
1742       if (FRAME_PARENT_FRAME (f) == NULL)
1743         {
1744           if (f->left_pos < 100)
1745             f->left_pos = 100;  /* don't overlap menu */
1746         }
1747 #endif
1748       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1749          menu bar.  */
1750       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1751                                                 + NS_PARENT_WINDOW_LEFT_POS (f)),
1752                                 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1753                                                 - f->top_pos));
1754       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1755       [[view window] setFrameTopLeftPoint: pt];
1756       f->size_hint_flags &= ~(XNegative|YNegative);
1757     }
1759   unblock_input ();
1763 void
1764 x_set_window_size (struct frame *f,
1765                    bool change_gravity,
1766                    int width,
1767                    int height,
1768                    bool pixelwise)
1769 /* --------------------------------------------------------------------------
1770      Adjust window pixel size based on given character grid size
1771      Impl is a bit more complex than other terms, need to do some
1772      internal clipping.
1773    -------------------------------------------------------------------------- */
1775   EmacsView *view = FRAME_NS_VIEW (f);
1776   NSWindow *window = [view window];
1777   NSRect wr = [window frame];
1778   int pixelwidth, pixelheight;
1779   int orig_height = wr.size.height;
1781   NSTRACE ("x_set_window_size");
1783   if (view == nil)
1784     return;
1786   NSTRACE_RECT ("current", wr);
1787   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1788   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1790   block_input ();
1792   if (pixelwise)
1793     {
1794       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1795       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1796     }
1797   else
1798     {
1799       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1800       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1801     }
1803   wr.size.width = pixelwidth + f->border_width;
1804   wr.size.height = pixelheight;
1805   if (! [view isFullscreen])
1806     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1807       + FRAME_TOOLBAR_HEIGHT (f);
1809   /* Do not try to constrain to this screen.  We may have multiple
1810      screens, and want Emacs to span those.  Constraining to screen
1811      prevents that, and that is not nice to the user.  */
1812  if (f->output_data.ns->zooming)
1813    f->output_data.ns->zooming = 0;
1814  else
1815    wr.origin.y += orig_height - wr.size.height;
1817  frame_size_history_add
1818    (f, Qx_set_window_size_1, width, height,
1819     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1820            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1821            make_number (f->border_width),
1822            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1823            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1825   [window setFrame: wr display: YES];
1827   [view updateFrameSize: NO];
1828   unblock_input ();
1831 #ifdef NS_IMPL_COCOA
1832 void
1833 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1834 /* --------------------------------------------------------------------------
1835      Set frame F's `undecorated' parameter.  If non-nil, F's window-system
1836      window is drawn without decorations, title, minimize/maximize boxes
1837      and external borders.  This usually means that the window cannot be
1838      dragged, resized, iconified, maximized or deleted with the mouse.  If
1839      nil, draw the frame with all the elements listed above unless these
1840      have been suspended via window manager settings.
1842      GNUStep cannot change an existing window's style.
1843    -------------------------------------------------------------------------- */
1845   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1846   NSWindow *window = [view window];
1848   NSTRACE ("x_set_undecorated");
1850   if (!EQ (new_value, old_value))
1851     {
1852       block_input ();
1854       if (NILP (new_value))
1855         {
1856           FRAME_UNDECORATED (f) = false;
1857           [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1858                                   ^ FRAME_UNDECORATED_FLAGS)];
1860           [view createToolbar: f];
1861         }
1862       else
1863         {
1864           [window setToolbar: nil];
1865           /* Do I need to release the toolbar here? */
1867           FRAME_UNDECORATED (f) = true;
1868           [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1869                                  ^ FRAME_DECORATED_FLAGS)];
1870         }
1872       /* At this point it seems we don't have an active NSResponder,
1873          so some key presses (TAB) are swallowed by the system. */
1874       [window makeFirstResponder: view];
1876       [view updateFrameSize: NO];
1877       unblock_input ();
1878     }
1880 #endif /* NS_IMPL_COCOA */
1882 void
1883 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1884 /* --------------------------------------------------------------------------
1885      Set frame F's `parent-frame' parameter.  If non-nil, make F a child
1886      frame of the frame specified by that parameter.  Technically, this
1887      makes F's window-system window a child window of the parent frame's
1888      window-system window.  If nil, make F's window-system window a
1889      top-level window--a child of its display's root window.
1891      A child frame's `left' and `top' parameters specify positions
1892      relative to the top-left corner of its parent frame's native
1893      rectangle.  On macOS moving a parent frame moves all its child
1894      frames too, keeping their position relative to the parent
1895      unaltered.  When a parent frame is iconified or made invisible, its
1896      child frames are made invisible.  When a parent frame is deleted,
1897      its child frames are deleted too.
1899      Whether a child frame has a tool bar may be window-system or window
1900      manager dependent.  It's advisable to disable it via the frame
1901      parameter settings.
1903      Some window managers may not honor this parameter.
1904    -------------------------------------------------------------------------- */
1906   struct frame *p = NULL;
1907   NSWindow *parent, *child;
1909   NSTRACE ("x_set_parent_frame");
1911   if (!NILP (new_value)
1912       && (!FRAMEP (new_value)
1913           || !FRAME_LIVE_P (p = XFRAME (new_value))
1914           || !FRAME_X_P (p)))
1915     {
1916       store_frame_param (f, Qparent_frame, old_value);
1917       error ("Invalid specification of `parent-frame'");
1918     }
1920   if (p != FRAME_PARENT_FRAME (f))
1921     {
1922       parent = [FRAME_NS_VIEW (p) window];
1923       child = [FRAME_NS_VIEW (f) window];
1925       block_input ();
1926       [parent addChildWindow: child
1927                      ordered: NSWindowAbove];
1928       unblock_input ();
1930       fset_parent_frame (f, new_value);
1931     }
1934 void
1935 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1936 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
1937  * that F's window-system window does not want to receive input focus
1938  * when it is mapped.  (A frame's window is mapped when the frame is
1939  * displayed for the first time and when the frame changes its state
1940  * from `iconified' or `invisible' to `visible'.)
1942  * Some window managers may not honor this parameter. */
1944   NSTRACE ("x_set_no_focus_on_map");
1946   if (!EQ (new_value, old_value))
1947     {
1948       FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1949     }
1952 void
1953 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1954 /*  Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1955  * that F's window-system window does not want to receive input focus
1956  * via mouse clicks or by moving the mouse into it.
1958  * If non-nil, this may have the unwanted side-effect that a user cannot
1959  * scroll a non-selected frame with the mouse.
1961  * Some window managers may not honor this parameter. */
1963   NSTRACE ("x_set_no_accept_focus");
1965   if (!EQ (new_value, old_value))
1966     FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1969 void
1970 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1971 /* Set frame F's `z-group' parameter.  If `above', F's window-system
1972    window is displayed above all windows that do not have the `above'
1973    property set.  If nil, F's window is shown below all windows that
1974    have the `above' property set and above all windows that have the
1975    `below' property set.  If `below', F's window is displayed below
1976    all windows that do.
1978    Some window managers may not honor this parameter. */
1980   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1981   NSWindow *window = [view window];
1983   NSTRACE ("x_set_z_group");
1985   if (NILP (new_value))
1986     {
1987       window.level = NSNormalWindowLevel;
1988       FRAME_Z_GROUP (f) = z_group_none;
1989     }
1990   else if (EQ (new_value, Qabove))
1991     {
1992       window.level = NSNormalWindowLevel + 1;
1993       FRAME_Z_GROUP (f) = z_group_above;
1994     }
1995   else if (EQ (new_value, Qabove_suspended))
1996     {
1997       /* Not sure what level this should be. */
1998       window.level = NSNormalWindowLevel + 1;
1999       FRAME_Z_GROUP (f) = z_group_above_suspended;
2000     }
2001   else if (EQ (new_value, Qbelow))
2002     {
2003       window.level = NSNormalWindowLevel - 1;
2004       FRAME_Z_GROUP (f) = z_group_below;
2005     }
2006   else
2007     error ("Invalid z-group specification");
2010 static void
2011 ns_fullscreen_hook (struct frame *f)
2013   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2015   NSTRACE ("ns_fullscreen_hook");
2017   if (!FRAME_VISIBLE_P (f))
2018     return;
2020    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2021     {
2022       /* Old style fs don't initiate correctly if created from
2023          init/default-frame alist, so use a timer (not nice...).
2024       */
2025       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2026                                      selector: @selector (handleFS)
2027                                      userInfo: nil repeats: NO];
2028       return;
2029     }
2031   block_input ();
2032   [view handleFS];
2033   unblock_input ();
2036 /* ==========================================================================
2038     Color management
2040    ========================================================================== */
2043 NSColor *
2044 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2046   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2047   if (idx < 1 || idx >= color_table->avail)
2048     return nil;
2049   return color_table->colors[idx];
2053 unsigned long
2054 ns_index_color (NSColor *color, struct frame *f)
2056   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2057   ptrdiff_t idx;
2058   ptrdiff_t i;
2060   if (!color_table->colors)
2061     {
2062       color_table->size = NS_COLOR_CAPACITY;
2063       color_table->avail = 1; /* skip idx=0 as marker */
2064       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2065       color_table->colors[0] = nil;
2066       color_table->empty_indices = [[NSMutableSet alloc] init];
2067     }
2069   /* Do we already have this color?  */
2070   for (i = 1; i < color_table->avail; i++)
2071     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2072       return i;
2074   if ([color_table->empty_indices count] > 0)
2075     {
2076       NSNumber *index = [color_table->empty_indices anyObject];
2077       [color_table->empty_indices removeObject: index];
2078       idx = [index unsignedLongValue];
2079     }
2080   else
2081     {
2082       if (color_table->avail == color_table->size)
2083         color_table->colors =
2084           xpalloc (color_table->colors, &color_table->size, 1,
2085                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2086       idx = color_table->avail++;
2087     }
2089   color_table->colors[idx] = color;
2090   [color retain];
2091 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2092   return idx;
2096 static int
2097 ns_get_color (const char *name, NSColor **col)
2098 /* --------------------------------------------------------------------------
2099      Parse a color name
2100    -------------------------------------------------------------------------- */
2101 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2102    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2103    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2105   NSColor *new = nil;
2106   static char hex[20];
2107   int scaling = 0;
2108   float r = -1.0, g, b;
2109   NSString *nsname = [NSString stringWithUTF8String: name];
2111   NSTRACE ("ns_get_color(%s, **)", name);
2113   block_input ();
2115   if ([nsname isEqualToString: @"ns_selection_bg_color"])
2116     {
2117 #ifdef NS_IMPL_COCOA
2118       NSString *defname = [[NSUserDefaults standardUserDefaults]
2119                             stringForKey: @"AppleHighlightColor"];
2120       if (defname != nil)
2121         nsname = defname;
2122       else
2123 #endif
2124       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2125         {
2126           *col = [new colorUsingDefaultColorSpace];
2127           unblock_input ();
2128           return 0;
2129         }
2130       else
2131         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2133       name = [nsname UTF8String];
2134     }
2135   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2136     {
2137       /* NOTE: macOS applications normally don't set foreground
2138          selection, but text may be unreadable if we don't.
2139       */
2140       if ((new = [NSColor selectedTextColor]) != nil)
2141         {
2142           *col = [new colorUsingDefaultColorSpace];
2143           unblock_input ();
2144           return 0;
2145         }
2147       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2148       name = [nsname UTF8String];
2149     }
2151   /* First, check for some sort of numeric specification. */
2152   hex[0] = '\0';
2154   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
2155     {
2156       NSScanner *scanner = [NSScanner scannerWithString: nsname];
2157       [scanner scanFloat: &r];
2158       [scanner scanFloat: &g];
2159       [scanner scanFloat: &b];
2160     }
2161   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
2162     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2163   else if (name[0] == '#')        /* An old X11 format; convert to newer */
2164     {
2165       int len = (strlen(name) - 1);
2166       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2167       int i;
2168       scaling = strlen(name+start) / 3;
2169       for (i = 0; i < 3; i++)
2170         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2171                  name + start + i * scaling);
2172       hex[3 * (scaling + 1) - 1] = '\0';
2173     }
2175   if (hex[0])
2176     {
2177       unsigned int rr, gg, bb;
2178       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2179       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2180         {
2181           r = rr / fscale;
2182           g = gg / fscale;
2183           b = bb / fscale;
2184         }
2185     }
2187   if (r >= 0.0F)
2188     {
2189       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2190       unblock_input ();
2191       return 0;
2192     }
2194   /* Otherwise, color is expected to be from a list */
2195   {
2196     NSEnumerator *lenum, *cenum;
2197     NSString *name;
2198     NSColorList *clist;
2200 #ifdef NS_IMPL_GNUSTEP
2201     /* XXX: who is wrong, the requestor or the implementation? */
2202     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2203         == NSOrderedSame)
2204       nsname = @"highlightColor";
2205 #endif
2207     lenum = [[NSColorList availableColorLists] objectEnumerator];
2208     while ( (clist = [lenum nextObject]) && new == nil)
2209       {
2210         cenum = [[clist allKeys] objectEnumerator];
2211         while ( (name = [cenum nextObject]) && new == nil )
2212           {
2213             if ([name compare: nsname
2214                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
2215               new = [clist colorWithKey: name];
2216           }
2217       }
2218   }
2220   if (new)
2221     *col = [new colorUsingDefaultColorSpace];
2222   unblock_input ();
2223   return new ? 0 : 1;
2228 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2229 /* --------------------------------------------------------------------------
2230      Convert a Lisp string object to a NS color
2231    -------------------------------------------------------------------------- */
2233   NSTRACE ("ns_lisp_to_color");
2234   if (STRINGP (color))
2235     return ns_get_color (SSDATA (color), col);
2236   else if (SYMBOLP (color))
2237     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2238   return 1;
2242 void
2243 ns_query_color(void *col, XColor *color_def, int setPixel)
2244 /* --------------------------------------------------------------------------
2245          Get ARGB values out of NSColor col and put them into color_def.
2246          If setPixel, set the pixel to a concatenated version.
2247          and set color_def pixel to the resulting index.
2248    -------------------------------------------------------------------------- */
2250   EmacsCGFloat r, g, b, a;
2252   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2253   color_def->red   = r * 65535;
2254   color_def->green = g * 65535;
2255   color_def->blue  = b * 65535;
2257   if (setPixel == YES)
2258     color_def->pixel
2259       = ARGB_TO_ULONG((int)(a*255),
2260                       (int)(r*255), (int)(g*255), (int)(b*255));
2264 bool
2265 ns_defined_color (struct frame *f,
2266                   const char *name,
2267                   XColor *color_def,
2268                   bool alloc,
2269                   bool makeIndex)
2270 /* --------------------------------------------------------------------------
2271          Return true if named color found, and set color_def rgb accordingly.
2272          If makeIndex and alloc are nonzero put the color in the color_table,
2273          and set color_def pixel to the resulting index.
2274          If makeIndex is zero, set color_def pixel to ARGB.
2275          Return false if not found
2276    -------------------------------------------------------------------------- */
2278   NSColor *col;
2279   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2281   block_input ();
2282   if (ns_get_color (name, &col) != 0) /* Color not found  */
2283     {
2284       unblock_input ();
2285       return 0;
2286     }
2287   if (makeIndex && alloc)
2288     color_def->pixel = ns_index_color (col, f);
2289   ns_query_color (col, color_def, !makeIndex);
2290   unblock_input ();
2291   return 1;
2295 void
2296 x_set_frame_alpha (struct frame *f)
2297 /* --------------------------------------------------------------------------
2298      change the entire-frame transparency
2299    -------------------------------------------------------------------------- */
2301   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2302   double alpha = 1.0;
2303   double alpha_min = 1.0;
2305   NSTRACE ("x_set_frame_alpha");
2307   if (dpyinfo->x_highlight_frame == f)
2308     alpha = f->alpha[0];
2309   else
2310     alpha = f->alpha[1];
2312   if (FLOATP (Vframe_alpha_lower_limit))
2313     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2314   else if (INTEGERP (Vframe_alpha_lower_limit))
2315     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2317   if (alpha < 0.0)
2318     return;
2319   else if (1.0 < alpha)
2320     alpha = 1.0;
2321   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2322     alpha = alpha_min;
2324 #ifdef NS_IMPL_COCOA
2325   {
2326     EmacsView *view = FRAME_NS_VIEW (f);
2327   [[view window] setAlphaValue: alpha];
2328   }
2329 #endif
2333 /* ==========================================================================
2335     Mouse handling
2337    ========================================================================== */
2340 void
2341 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2342 /* --------------------------------------------------------------------------
2343      Programmatically reposition mouse pointer in pixel coordinates
2344    -------------------------------------------------------------------------- */
2346   NSTRACE ("frame_set_mouse_pixel_position");
2348   /* FIXME: what about GNUstep? */
2349 #ifdef NS_IMPL_COCOA
2350   CGPoint mouse_pos =
2351     CGPointMake(f->left_pos + pix_x,
2352                 f->top_pos + pix_y +
2353                 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2354   CGWarpMouseCursorPosition (mouse_pos);
2355 #endif
2358 static int
2359 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2360 /*   ------------------------------------------------------------------------
2361      Called by EmacsView on mouseMovement events.  Passes on
2362      to emacs mainstream code if we moved off of a rect of interest
2363      known as last_mouse_glyph.
2364      ------------------------------------------------------------------------ */
2366   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2367   NSRect *r;
2369 //  NSTRACE ("note_mouse_movement");
2371   dpyinfo->last_mouse_motion_frame = frame;
2372   r = &dpyinfo->last_mouse_glyph;
2374   /* Note, this doesn't get called for enter/leave, since we don't have a
2375      position.  Those are taken care of in the corresponding NSView methods. */
2377   /* has movement gone beyond last rect we were tracking? */
2378   if (x < r->origin.x || x >= r->origin.x + r->size.width
2379       || y < r->origin.y || y >= r->origin.y + r->size.height)
2380     {
2381       ns_update_begin (frame);
2382       frame->mouse_moved = 1;
2383       note_mouse_highlight (frame, x, y);
2384       remember_mouse_glyph (frame, x, y, r);
2385       ns_update_end (frame);
2386       return 1;
2387     }
2389   return 0;
2393 static void
2394 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2395                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2396                    Time *time)
2397 /* --------------------------------------------------------------------------
2398     External (hook): inform emacs about mouse position and hit parts.
2399     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2400     x & y should be position in the scrollbar (the whole bar, not the handle)
2401     and length of scrollbar respectively
2402    -------------------------------------------------------------------------- */
2404   id view;
2405   NSPoint position;
2406   Lisp_Object frame, tail;
2407   struct frame *f;
2408   struct ns_display_info *dpyinfo;
2410   NSTRACE ("ns_mouse_position");
2412   if (*fp == NULL)
2413     {
2414       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2415       return;
2416     }
2418   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2420   block_input ();
2422   /* Clear the mouse-moved flag for every frame on this display.  */
2423   FOR_EACH_FRAME (tail, frame)
2424     if (FRAME_NS_P (XFRAME (frame))
2425         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2426       XFRAME (frame)->mouse_moved = 0;
2428   dpyinfo->last_mouse_scroll_bar = nil;
2429   if (dpyinfo->last_mouse_frame
2430       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2431     f = dpyinfo->last_mouse_frame;
2432   else
2433     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2435   if (f && FRAME_NS_P (f))
2436     {
2437       view = FRAME_NS_VIEW (*fp);
2439       position = [[view window] mouseLocationOutsideOfEventStream];
2440       position = [view convertPoint: position fromView: nil];
2441       remember_mouse_glyph (f, position.x, position.y,
2442                             &dpyinfo->last_mouse_glyph);
2443       NSTRACE_POINT ("position", position);
2445       if (bar_window) *bar_window = Qnil;
2446       if (part) *part = scroll_bar_above_handle;
2448       if (x) XSETINT (*x, lrint (position.x));
2449       if (y) XSETINT (*y, lrint (position.y));
2450       if (time)
2451         *time = dpyinfo->last_mouse_movement_time;
2452       *fp = f;
2453     }
2455   unblock_input ();
2459 static void
2460 ns_frame_up_to_date (struct frame *f)
2461 /* --------------------------------------------------------------------------
2462     External (hook): Fix up mouse highlighting right after a full update.
2463     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2464    -------------------------------------------------------------------------- */
2466   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2468   if (FRAME_NS_P (f))
2469     {
2470       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2471       if (f == hlinfo->mouse_face_mouse_frame)
2472         {
2473           block_input ();
2474           ns_update_begin(f);
2475           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2476                                 hlinfo->mouse_face_mouse_x,
2477                                 hlinfo->mouse_face_mouse_y);
2478           ns_update_end(f);
2479           unblock_input ();
2480         }
2481     }
2485 static void
2486 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2487 /* --------------------------------------------------------------------------
2488     External (RIF): set frame mouse pointer type.
2489    -------------------------------------------------------------------------- */
2491   NSTRACE ("ns_define_frame_cursor");
2492   if (FRAME_POINTER_TYPE (f) != cursor)
2493     {
2494       EmacsView *view = FRAME_NS_VIEW (f);
2495       FRAME_POINTER_TYPE (f) = cursor;
2496       [[view window] invalidateCursorRectsForView: view];
2497       /* Redisplay assumes this function also draws the changed frame
2498          cursor, but this function doesn't, so do it explicitly.  */
2499       x_update_cursor (f, 1);
2500     }
2505 /* ==========================================================================
2507     Keyboard handling
2509    ========================================================================== */
2512 static unsigned
2513 ns_convert_key (unsigned code)
2514 /* --------------------------------------------------------------------------
2515     Internal call used by NSView-keyDown.
2516    -------------------------------------------------------------------------- */
2518   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2519   unsigned keysym;
2520   /* An array would be faster, but less easy to read. */
2521   for (keysym = 0; keysym < last_keysym; keysym += 2)
2522     if (code == convert_ns_to_X_keysym[keysym])
2523       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2524   return 0;
2525 /* if decide to use keyCode and Carbon table, use this line:
2526      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2530 char *
2531 x_get_keysym_name (int keysym)
2532 /* --------------------------------------------------------------------------
2533     Called by keyboard.c.  Not sure if the return val is important, except
2534     that it be unique.
2535    -------------------------------------------------------------------------- */
2537   static char value[16];
2538   NSTRACE ("x_get_keysym_name");
2539   sprintf (value, "%d", keysym);
2540   return value;
2545 /* ==========================================================================
2547     Block drawing operations
2549    ========================================================================== */
2552 static void
2553 ns_redraw_scroll_bars (struct frame *f)
2555   int i;
2556   id view;
2557   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2558   NSTRACE ("ns_redraw_scroll_bars");
2559   for (i =[subviews count]-1; i >= 0; i--)
2560     {
2561       view = [subviews objectAtIndex: i];
2562       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2563       [view display];
2564     }
2568 void
2569 ns_clear_frame (struct frame *f)
2570 /* --------------------------------------------------------------------------
2571       External (hook): Erase the entire frame
2572    -------------------------------------------------------------------------- */
2574   NSView *view = FRAME_NS_VIEW (f);
2575   NSRect r;
2577   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2579  /* comes on initial frame because we have
2580     after-make-frame-functions = select-frame */
2581  if (!FRAME_DEFAULT_FACE (f))
2582    return;
2584   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2586   r = [view bounds];
2588   block_input ();
2589   ns_focus (f, &r, 1);
2590   [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2591                             (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2592   NSRectFill (r);
2593   ns_unfocus (f);
2595   /* as of 2006/11 or so this is now needed */
2596   ns_redraw_scroll_bars (f);
2597   unblock_input ();
2601 static void
2602 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2603 /* --------------------------------------------------------------------------
2604     External (RIF):  Clear section of frame
2605    -------------------------------------------------------------------------- */
2607   NSRect r = NSMakeRect (x, y, width, height);
2608   NSView *view = FRAME_NS_VIEW (f);
2609   struct face *face = FRAME_DEFAULT_FACE (f);
2611   if (!view || !face)
2612     return;
2614   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2616   r = NSIntersectionRect (r, [view frame]);
2617   ns_focus (f, &r, 1);
2618   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2620   NSRectFill (r);
2622   ns_unfocus (f);
2623   return;
2626 static void
2627 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2629   NSTRACE ("ns_copy_bits");
2631   if (FRAME_NS_VIEW (f))
2632     {
2633       hide_bell();              // Ensure the bell image isn't scrolled.
2635       ns_focus (f, &dest, 1);
2636       [FRAME_NS_VIEW (f) scrollRect: src
2637                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2638                                                  dest.origin.y - src.origin.y)];
2639       ns_unfocus (f);
2640     }
2643 static void
2644 ns_scroll_run (struct window *w, struct run *run)
2645 /* --------------------------------------------------------------------------
2646     External (RIF):  Insert or delete n lines at line vpos
2647    -------------------------------------------------------------------------- */
2649   struct frame *f = XFRAME (w->frame);
2650   int x, y, width, height, from_y, to_y, bottom_y;
2652   NSTRACE ("ns_scroll_run");
2654   /* begin copy from other terms */
2655   /* Get frame-relative bounding box of the text display area of W,
2656      without mode lines.  Include in this box the left and right
2657      fringe of W.  */
2658   window_box (w, ANY_AREA, &x, &y, &width, &height);
2660   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2661   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2662   bottom_y = y + height;
2664   if (to_y < from_y)
2665     {
2666       /* Scrolling up.  Make sure we don't copy part of the mode
2667          line at the bottom.  */
2668       if (from_y + run->height > bottom_y)
2669         height = bottom_y - from_y;
2670       else
2671         height = run->height;
2672     }
2673   else
2674     {
2675       /* Scrolling down.  Make sure we don't copy over the mode line.
2676          at the bottom.  */
2677       if (to_y + run->height > bottom_y)
2678         height = bottom_y - to_y;
2679       else
2680         height = run->height;
2681     }
2682   /* end copy from other terms */
2684   if (height == 0)
2685       return;
2687   block_input ();
2689   x_clear_cursor (w);
2691   {
2692     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2693     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2695     ns_copy_bits (f, srcRect , dstRect);
2696   }
2698   unblock_input ();
2702 static void
2703 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2704 /* --------------------------------------------------------------------------
2705     External (RIF): preparatory to fringe update after text was updated
2706    -------------------------------------------------------------------------- */
2708   struct frame *f;
2709   int width, height;
2711   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2713   /* begin copy from other terms */
2714   eassert (w);
2716   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2717     desired_row->redraw_fringe_bitmaps_p = 1;
2719   /* When a window has disappeared, make sure that no rest of
2720      full-width rows stays visible in the internal border.  */
2721   if (windows_or_buffers_changed
2722       && desired_row->full_width_p
2723       && (f = XFRAME (w->frame),
2724           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2725           width != 0)
2726       && (height = desired_row->visible_height,
2727           height > 0))
2728     {
2729       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2731       block_input ();
2732       ns_clear_frame_area (f, 0, y, width, height);
2733       ns_clear_frame_area (f,
2734                            FRAME_PIXEL_WIDTH (f) - width,
2735                            y, width, height);
2736       unblock_input ();
2737     }
2741 static void
2742 ns_shift_glyphs_for_insert (struct frame *f,
2743                            int x, int y, int width, int height,
2744                            int shift_by)
2745 /* --------------------------------------------------------------------------
2746     External (RIF): copy an area horizontally, don't worry about clearing src
2747    -------------------------------------------------------------------------- */
2749   NSRect srcRect = NSMakeRect (x, y, width, height);
2750   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2752   NSTRACE ("ns_shift_glyphs_for_insert");
2754   ns_copy_bits (f, srcRect, dstRect);
2759 /* ==========================================================================
2761     Character encoding and metrics
2763    ========================================================================== */
2766 static void
2767 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2768 /* --------------------------------------------------------------------------
2769      External (RIF); compute left/right overhang of whole string and set in s
2770    -------------------------------------------------------------------------- */
2772   struct font *font = s->font;
2774   if (s->char2b)
2775     {
2776       struct font_metrics metrics;
2777       unsigned int codes[2];
2778       codes[0] = *(s->char2b);
2779       codes[1] = *(s->char2b + s->nchars - 1);
2781       font->driver->text_extents (font, codes, 2, &metrics);
2782       s->left_overhang = -metrics.lbearing;
2783       s->right_overhang
2784         = metrics.rbearing > metrics.width
2785         ? metrics.rbearing - metrics.width : 0;
2786     }
2787   else
2788     {
2789       s->left_overhang = 0;
2790       if (EQ (font->driver->type, Qns))
2791         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2792           FONT_HEIGHT (font) * 0.2 : 0;
2793       else
2794         s->right_overhang = 0;
2795     }
2800 /* ==========================================================================
2802     Fringe and cursor drawing
2804    ========================================================================== */
2807 extern int max_used_fringe_bitmap;
2808 static void
2809 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2810                       struct draw_fringe_bitmap_params *p)
2811 /* --------------------------------------------------------------------------
2812     External (RIF); fringe-related
2813    -------------------------------------------------------------------------- */
2815   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2816      periodic bitmap is used to create a continuous pattern.  Since a
2817      bitmap is rendered one text line at a time, the start offset (dh)
2818      of the bitmap varies.  Concretely, this is used for the empty
2819      line indicator.
2821      For a bitmap, "h + dh" is the full height and is always
2822      invariant.  For a normal bitmap "dh" is zero.
2824      For example, when the period is three and the full height is 72
2825      the following combinations exists:
2827        h=72 dh=0
2828        h=71 dh=1
2829        h=70 dh=2 */
2831   struct frame *f = XFRAME (WINDOW_FRAME (w));
2832   struct face *face = p->face;
2833   static EmacsImage **bimgs = NULL;
2834   static int nBimgs = 0;
2836   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2837   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2838                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2840   /* grow bimgs if needed */
2841   if (nBimgs < max_used_fringe_bitmap)
2842     {
2843       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2844       memset (bimgs + nBimgs, 0,
2845               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2846       nBimgs = max_used_fringe_bitmap;
2847     }
2849   /* Must clip because of partially visible lines.  */
2850   ns_clip_to_row (w, row, ANY_AREA, YES);
2852   if (!p->overlay_p)
2853     {
2854       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2856       if (bx >= 0 && nx > 0)
2857         {
2858           NSRect r = NSMakeRect (bx, by, nx, ny);
2859           NSRectClip (r);
2860           [ns_lookup_indexed_color (face->background, f) set];
2861           NSRectFill (r);
2862         }
2863     }
2865   if (p->which)
2866     {
2867       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2868       EmacsImage *img = bimgs[p->which - 1];
2870       if (!img)
2871         {
2872           // Note: For "periodic" images, allocate one EmacsImage for
2873           // the base image, and use it for all dh:s.
2874           unsigned short *bits = p->bits;
2875           int full_height = p->h + p->dh;
2876           int i;
2877           unsigned char *cbits = xmalloc (full_height);
2879           for (i = 0; i < full_height; i++)
2880             cbits[i] = bits[i];
2881           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2882                                          height: full_height
2883                                              fg: 0 bg: 0];
2884           bimgs[p->which - 1] = img;
2885           xfree (cbits);
2886         }
2888       NSTRACE_RECT ("r", r);
2890       NSRectClip (r);
2891       /* Since we composite the bitmap instead of just blitting it, we need
2892          to erase the whole background. */
2893       [ns_lookup_indexed_color(face->background, f) set];
2894       NSRectFill (r);
2896       {
2897         NSColor *bm_color;
2898         if (!p->cursor_p)
2899           bm_color = ns_lookup_indexed_color(face->foreground, f);
2900         else if (p->overlay_p)
2901           bm_color = ns_lookup_indexed_color(face->background, f);
2902         else
2903           bm_color = f->output_data.ns->cursor_color;
2904         [img setXBMColor: bm_color];
2905       }
2907 #ifdef NS_IMPL_COCOA
2908       // Note: For periodic images, the full image height is "h + hd".
2909       // By using the height h, a suitable part of the image is used.
2910       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2912       NSTRACE_RECT ("fromRect", fromRect);
2914       [img drawInRect: r
2915               fromRect: fromRect
2916              operation: NSCompositingOperationSourceOver
2917               fraction: 1.0
2918            respectFlipped: YES
2919                 hints: nil];
2920 #else
2921       {
2922         NSPoint pt = r.origin;
2923         pt.y += p->h;
2924         [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
2925       }
2926 #endif
2927     }
2928   ns_unfocus (f);
2932 static void
2933 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2934                        int x, int y, enum text_cursor_kinds cursor_type,
2935                        int cursor_width, bool on_p, bool active_p)
2936 /* --------------------------------------------------------------------------
2937      External call (RIF): draw cursor.
2938      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2939    -------------------------------------------------------------------------- */
2941   NSRect r, s;
2942   int fx, fy, h, cursor_height;
2943   struct frame *f = WINDOW_XFRAME (w);
2944   struct glyph *phys_cursor_glyph;
2945   struct glyph *cursor_glyph;
2946   struct face *face;
2947   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2949   /* If cursor is out of bounds, don't draw garbage.  This can happen
2950      in mini-buffer windows when switching between echo area glyphs
2951      and mini-buffer.  */
2953   NSTRACE ("ns_draw_window_cursor");
2955   if (!on_p)
2956     return;
2958   w->phys_cursor_type = cursor_type;
2959   w->phys_cursor_on_p = on_p;
2961   if (cursor_type == NO_CURSOR)
2962     {
2963       w->phys_cursor_width = 0;
2964       return;
2965     }
2967   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2968     {
2969       if (glyph_row->exact_window_width_line_p
2970           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2971         {
2972           glyph_row->cursor_in_fringe_p = 1;
2973           draw_fringe_bitmap (w, glyph_row, 0);
2974         }
2975       return;
2976     }
2978   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2979      (other terminals do it the other way round).  We must set
2980      w->phys_cursor_width to the cursor width.  For bar cursors, that
2981      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2982   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2984   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2985      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2986   if (cursor_type == BAR_CURSOR)
2987     {
2988       if (cursor_width < 1)
2989         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2991       /* The bar cursor should never be wider than the glyph. */
2992       if (cursor_width < w->phys_cursor_width)
2993         w->phys_cursor_width = cursor_width;
2994     }
2995   /* If we have an HBAR, "cursor_width" MAY specify height. */
2996   else if (cursor_type == HBAR_CURSOR)
2997     {
2998       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2999       if (cursor_height > glyph_row->height)
3000         cursor_height = glyph_row->height;
3001       if (h > cursor_height) // Cursor smaller than line height, move down
3002         fy += h - cursor_height;
3003       h = cursor_height;
3004     }
3006   r.origin.x = fx, r.origin.y = fy;
3007   r.size.height = h;
3008   r.size.width = w->phys_cursor_width;
3010   /* Prevent the cursor from being drawn outside the text area. */
3011   ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3014   face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3015   if (face && NS_FACE_BACKGROUND (face)
3016       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3017     {
3018       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3019       hollow_color = FRAME_CURSOR_COLOR (f);
3020     }
3021   else
3022     [FRAME_CURSOR_COLOR (f) set];
3024 #ifdef NS_IMPL_COCOA
3025   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3026            atomic.  Cleaner ways of doing this should be investigated.
3027            One way would be to set a global variable DRAWING_CURSOR
3028            when making the call to draw_phys..(), don't focus in that
3029            case, then move the ns_unfocus() here after that call. */
3030   NSDisableScreenUpdates ();
3031 #endif
3033   switch (cursor_type)
3034     {
3035     case DEFAULT_CURSOR:
3036     case NO_CURSOR:
3037       break;
3038     case FILLED_BOX_CURSOR:
3039       NSRectFill (r);
3040       break;
3041     case HOLLOW_BOX_CURSOR:
3042       NSRectFill (r);
3043       [hollow_color set];
3044       NSRectFill (NSInsetRect (r, 1, 1));
3045       [FRAME_CURSOR_COLOR (f) set];
3046       break;
3047     case HBAR_CURSOR:
3048       NSRectFill (r);
3049       break;
3050     case BAR_CURSOR:
3051       s = r;
3052       /* If the character under cursor is R2L, draw the bar cursor
3053          on the right of its glyph, rather than on the left.  */
3054       cursor_glyph = get_phys_cursor_glyph (w);
3055       if ((cursor_glyph->resolved_level & 1) != 0)
3056         s.origin.x += cursor_glyph->pixel_width - s.size.width;
3058       NSRectFill (s);
3059       break;
3060     }
3061   ns_unfocus (f);
3063   /* draw the character under the cursor */
3064   if (cursor_type != NO_CURSOR)
3065     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3067 #ifdef NS_IMPL_COCOA
3068   NSEnableScreenUpdates ();
3069 #endif
3074 static void
3075 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3076 /* --------------------------------------------------------------------------
3077      External (RIF): Draw a vertical line.
3078    -------------------------------------------------------------------------- */
3080   struct frame *f = XFRAME (WINDOW_FRAME (w));
3081   struct face *face;
3082   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3084   NSTRACE ("ns_draw_vertical_window_border");
3086   face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3088   ns_focus (f, &r, 1);
3089   if (face)
3090     [ns_lookup_indexed_color(face->foreground, f) set];
3092   NSRectFill(r);
3093   ns_unfocus (f);
3097 static void
3098 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3099 /* --------------------------------------------------------------------------
3100      External (RIF): Draw a window divider.
3101    -------------------------------------------------------------------------- */
3103   struct frame *f = XFRAME (WINDOW_FRAME (w));
3104   struct face *face;
3105   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
3107   NSTRACE ("ns_draw_window_divider");
3109   face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3111   ns_focus (f, &r, 1);
3112   if (face)
3113     [ns_lookup_indexed_color(face->foreground, f) set];
3115   NSRectFill(r);
3116   ns_unfocus (f);
3119 static void
3120 ns_show_hourglass (struct frame *f)
3122   /* TODO: add NSProgressIndicator to all frames.  */
3125 static void
3126 ns_hide_hourglass (struct frame *f)
3128   /* TODO: remove NSProgressIndicator from all frames.  */
3131 /* ==========================================================================
3133     Glyph drawing operations
3135    ========================================================================== */
3137 static int
3138 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3139 /* --------------------------------------------------------------------------
3140     Wrapper utility to account for internal border width on full-width lines,
3141     and allow top full-width rows to hit the frame top.  nr should be pointer
3142     to two successive NSRects.  Number of rects actually used is returned.
3143    -------------------------------------------------------------------------- */
3145   int n = get_glyph_string_clip_rects (s, nr, 2);
3146   return n;
3149 /* --------------------------------------------------------------------
3150    Draw a wavy line under glyph string s. The wave fills wave_height
3151    pixels from y.
3153                     x          wave_length = 2
3154                                  --
3155                 y    *   *   *   *   *
3156                      |* * * * * * * * *
3157     wave_height = 3  | *   *   *   *
3158   --------------------------------------------------------------------- */
3160 static void
3161 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3163   int wave_height = 3, wave_length = 2;
3164   int y, dx, dy, odd, xmax;
3165   NSPoint a, b;
3166   NSRect waveClip;
3168   dx = wave_length;
3169   dy = wave_height - 1;
3170   y =  s->ybase - wave_height + 3;
3171   xmax = x + width;
3173   /* Find and set clipping rectangle */
3174   waveClip = NSMakeRect (x, y, width, wave_height);
3175   [[NSGraphicsContext currentContext] saveGraphicsState];
3176   NSRectClip (waveClip);
3178   /* Draw the waves */
3179   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3180   b.x = a.x + dx;
3181   odd = (int)(a.x/dx) % 2;
3182   a.y = b.y = y + 0.5;
3184   if (odd)
3185     a.y += dy;
3186   else
3187     b.y += dy;
3189   while (a.x <= xmax)
3190     {
3191       [NSBezierPath strokeLineFromPoint:a toPoint:b];
3192       a.x = b.x, a.y = b.y;
3193       b.x += dx, b.y = y + 0.5 + odd*dy;
3194       odd = !odd;
3195     }
3197   /* Restore previous clipping rectangle(s) */
3198   [[NSGraphicsContext currentContext] restoreGraphicsState];
3203 static void
3204 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3205                          NSColor *defaultCol, CGFloat width, CGFloat x)
3206 /* --------------------------------------------------------------------------
3207    Draw underline, overline, and strike-through on glyph string s.
3208    -------------------------------------------------------------------------- */
3210   if (s->for_overlaps)
3211     return;
3213   /* Do underline. */
3214   if (face->underline_p)
3215     {
3216       if (s->face->underline_type == FACE_UNDER_WAVE)
3217         {
3218           if (face->underline_defaulted_p)
3219             [defaultCol set];
3220           else
3221             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3223           ns_draw_underwave (s, width, x);
3224         }
3225       else if (s->face->underline_type == FACE_UNDER_LINE)
3226         {
3228           NSRect r;
3229           unsigned long thickness, position;
3231           /* If the prev was underlined, match its appearance. */
3232           if (s->prev && s->prev->face->underline_p
3233               && s->prev->face->underline_type == FACE_UNDER_LINE
3234               && s->prev->underline_thickness > 0)
3235             {
3236               thickness = s->prev->underline_thickness;
3237               position = s->prev->underline_position;
3238             }
3239           else
3240             {
3241               struct font *font = font_for_underline_metrics (s);
3242               unsigned long descent = s->y + s->height - s->ybase;
3244               /* Use underline thickness of font, defaulting to 1. */
3245               thickness = (font && font->underline_thickness > 0)
3246                 ? font->underline_thickness : 1;
3248               /* Determine the offset of underlining from the baseline. */
3249               if (x_underline_at_descent_line)
3250                 position = descent - thickness;
3251               else if (x_use_underline_position_properties
3252                        && font && font->underline_position >= 0)
3253                 position = font->underline_position;
3254               else if (font)
3255                 position = lround (font->descent / 2);
3256               else
3257                 position = underline_minimum_offset;
3259               position = max (position, underline_minimum_offset);
3261               /* Ensure underlining is not cropped. */
3262               if (descent <= position)
3263                 {
3264                   position = descent - 1;
3265                   thickness = 1;
3266                 }
3267               else if (descent < position + thickness)
3268                 thickness = 1;
3269             }
3271           s->underline_thickness = thickness;
3272           s->underline_position = position;
3274           r = NSMakeRect (x, s->ybase + position, width, thickness);
3276           if (face->underline_defaulted_p)
3277             [defaultCol set];
3278           else
3279             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3280           NSRectFill (r);
3281         }
3282     }
3283   /* Do overline. We follow other terms in using a thickness of 1
3284      and ignoring overline_margin. */
3285   if (face->overline_p)
3286     {
3287       NSRect r;
3288       r = NSMakeRect (x, s->y, width, 1);
3290       if (face->overline_color_defaulted_p)
3291         [defaultCol set];
3292       else
3293         [ns_lookup_indexed_color (face->overline_color, s->f) set];
3294       NSRectFill (r);
3295     }
3297   /* Do strike-through.  We follow other terms for thickness and
3298      vertical position.*/
3299   if (face->strike_through_p)
3300     {
3301       NSRect r;
3302       /* Y-coordinate and height of the glyph string's first glyph.
3303          We cannot use s->y and s->height because those could be
3304          larger if there are taller display elements (e.g., characters
3305          displayed with a larger font) in the same glyph row.  */
3306       int glyph_y = s->ybase - s->first_glyph->ascent;
3307       int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3308       /* Strike-through width and offset from the glyph string's
3309          top edge.  */
3310       unsigned long h = 1;
3311       unsigned long dy;
3313       dy = lrint ((glyph_height - h) / 2);
3314       r = NSMakeRect (x, glyph_y + dy, width, 1);
3316       if (face->strike_through_color_defaulted_p)
3317         [defaultCol set];
3318       else
3319         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3320       NSRectFill (r);
3321     }
3324 static void
3325 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3326              char left_p, char right_p)
3327 /* --------------------------------------------------------------------------
3328     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3329     Note we can't just use an NSDrawRect command, because of the possibility
3330     of some sides not being drawn, and because the rect will be filled.
3331    -------------------------------------------------------------------------- */
3333   NSRect s = r;
3334   [col set];
3336   /* top, bottom */
3337   s.size.height = thickness;
3338   NSRectFill (s);
3339   s.origin.y += r.size.height - thickness;
3340   NSRectFill (s);
3342   s.size.height = r.size.height;
3343   s.origin.y = r.origin.y;
3345   /* left, right (optional) */
3346   s.size.width = thickness;
3347   if (left_p)
3348     NSRectFill (s);
3349   if (right_p)
3350     {
3351       s.origin.x += r.size.width - thickness;
3352       NSRectFill (s);
3353     }
3357 static void
3358 ns_draw_relief (NSRect r, int thickness, char raised_p,
3359                char top_p, char bottom_p, char left_p, char right_p,
3360                struct glyph_string *s)
3361 /* --------------------------------------------------------------------------
3362     Draw a relief rect inside r, optionally leaving some sides open.
3363     Note we can't just use an NSDrawBezel command, because of the possibility
3364     of some sides not being drawn, and because the rect will be filled.
3365    -------------------------------------------------------------------------- */
3367   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3368   NSColor *newBaseCol = nil;
3369   NSRect sr = r;
3371   NSTRACE ("ns_draw_relief");
3373   /* set up colors */
3375   if (s->face->use_box_color_for_shadows_p)
3376     {
3377       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3378     }
3379 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3380            && s->img->pixmap
3381            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3382        {
3383          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3384        } */
3385   else
3386     {
3387       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3388     }
3390   if (newBaseCol == nil)
3391     newBaseCol = [NSColor grayColor];
3393   if (newBaseCol != baseCol)  /* TODO: better check */
3394     {
3395       [baseCol release];
3396       baseCol = [newBaseCol retain];
3397       [lightCol release];
3398       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3399       [darkCol release];
3400       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3401     }
3403   [(raised_p ? lightCol : darkCol) set];
3405   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3407   /* top */
3408   sr.size.height = thickness;
3409   if (top_p) NSRectFill (sr);
3411   /* left */
3412   sr.size.height = r.size.height;
3413   sr.size.width = thickness;
3414   if (left_p) NSRectFill (sr);
3416   [(raised_p ? darkCol : lightCol) set];
3418   /* bottom */
3419   sr.size.width = r.size.width;
3420   sr.size.height = thickness;
3421   sr.origin.y += r.size.height - thickness;
3422   if (bottom_p) NSRectFill (sr);
3424   /* right */
3425   sr.size.height = r.size.height;
3426   sr.origin.y = r.origin.y;
3427   sr.size.width = thickness;
3428   sr.origin.x += r.size.width - thickness;
3429   if (right_p) NSRectFill (sr);
3433 static void
3434 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3435 /* --------------------------------------------------------------------------
3436       Function modeled after x_draw_glyph_string_box ().
3437       Sets up parameters for drawing.
3438    -------------------------------------------------------------------------- */
3440   int right_x, last_x;
3441   char left_p, right_p;
3442   struct glyph *last_glyph;
3443   NSRect r;
3444   int thickness;
3445   struct face *face;
3447   if (s->hl == DRAW_MOUSE_FACE)
3448     {
3449       face = FACE_FROM_ID_OR_NULL (s->f,
3450                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3451       if (!face)
3452         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3453     }
3454   else
3455     face = s->face;
3457   thickness = face->box_line_width;
3459   NSTRACE ("ns_dumpglyphs_box_or_relief");
3461   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3462             ? WINDOW_RIGHT_EDGE_X (s->w)
3463             : window_box_right (s->w, s->area));
3464   last_glyph = (s->cmp || s->img
3465                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3467   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3468               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3470   left_p = (s->first_glyph->left_box_line_p
3471             || (s->hl == DRAW_MOUSE_FACE
3472                 && (s->prev == NULL || s->prev->hl != s->hl)));
3473   right_p = (last_glyph->right_box_line_p
3474              || (s->hl == DRAW_MOUSE_FACE
3475                  && (s->next == NULL || s->next->hl != s->hl)));
3477   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3479   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3480   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3481     {
3482       ns_draw_box (r, abs (thickness),
3483                    ns_lookup_indexed_color (face->box_color, s->f),
3484                   left_p, right_p);
3485     }
3486   else
3487     {
3488       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3489                      1, 1, left_p, right_p, s);
3490     }
3494 static void
3495 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3496 /* --------------------------------------------------------------------------
3497       Modeled after x_draw_glyph_string_background, which draws BG in
3498       certain cases.  Others are left to the text rendering routine.
3499    -------------------------------------------------------------------------- */
3501   NSTRACE ("ns_maybe_dumpglyphs_background");
3503   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3504     {
3505       int box_line_width = max (s->face->box_line_width, 0);
3506       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3507           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3508              dimensions, since the actual glyphs might be much
3509              smaller.  So in that case we always clear the rectangle
3510              with background color.  */
3511           || FONT_TOO_HIGH (s->font)
3512           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3513         {
3514           struct face *face;
3515           if (s->hl == DRAW_MOUSE_FACE)
3516             {
3517               face
3518                 = FACE_FROM_ID_OR_NULL (s->f,
3519                                         MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3520               if (!face)
3521                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3522             }
3523           else
3524             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3525           if (!face->stipple)
3526             [(NS_FACE_BACKGROUND (face) != 0
3527               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3528               : FRAME_BACKGROUND_COLOR (s->f)) set];
3529           else
3530             {
3531               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3532               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3533             }
3535           if (s->hl != DRAW_CURSOR)
3536             {
3537               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3538                                     s->background_width,
3539                                     s->height-2*box_line_width);
3540               NSRectFill (r);
3541             }
3543           s->background_filled_p = 1;
3544         }
3545     }
3549 static void
3550 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3551 /* --------------------------------------------------------------------------
3552       Renders an image and associated borders.
3553    -------------------------------------------------------------------------- */
3555   EmacsImage *img = s->img->pixmap;
3556   int box_line_vwidth = max (s->face->box_line_width, 0);
3557   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3558   int bg_x, bg_y, bg_height;
3559   int th;
3560   char raised_p;
3561   NSRect br;
3562   struct face *face;
3563   NSColor *tdCol;
3565   NSTRACE ("ns_dumpglyphs_image");
3567   if (s->face->box != FACE_NO_BOX
3568       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3569     x += abs (s->face->box_line_width);
3571   bg_x = x;
3572   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3573   bg_height = s->height;
3574   /* other terms have this, but was causing problems w/tabbar mode */
3575   /* - 2 * box_line_vwidth; */
3577   if (s->slice.x == 0) x += s->img->hmargin;
3578   if (s->slice.y == 0) y += s->img->vmargin;
3580   /* Draw BG: if we need larger area than image itself cleared, do that,
3581      otherwise, since we composite the image under NS (instead of mucking
3582      with its background color), we must clear just the image area. */
3583   if (s->hl == DRAW_MOUSE_FACE)
3584     {
3585       face = FACE_FROM_ID_OR_NULL (s->f,
3586                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3587       if (!face)
3588        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3589     }
3590   else
3591     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3593   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3595   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3596       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3597     {
3598       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3599       s->background_filled_p = 1;
3600     }
3601   else
3602     {
3603       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3604     }
3606   NSRectFill (br);
3608   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3609   if (img != nil)
3610     {
3611 #ifdef NS_IMPL_COCOA
3612       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3613       NSRect ir = NSMakeRect (s->slice.x,
3614                               s->img->height - s->slice.y - s->slice.height,
3615                               s->slice.width, s->slice.height);
3616       [img drawInRect: dr
3617              fromRect: ir
3618              operation: NSCompositingOperationSourceOver
3619               fraction: 1.0
3620            respectFlipped: YES
3621                 hints: nil];
3622 #else
3623       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3624                   operation: NSCompositingOperationSourceOver];
3625 #endif
3626     }
3628   if (s->hl == DRAW_CURSOR)
3629     {
3630     [FRAME_CURSOR_COLOR (s->f) set];
3631     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3632       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3633     else
3634       /* Currently on NS img->mask is always 0. Since
3635          get_window_cursor_type specifies a hollow box cursor when on
3636          a non-masked image we never reach this clause. But we put it
3637          in in anticipation of better support for image masks on
3638          NS. */
3639       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3640     }
3641   else
3642     {
3643       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3644     }
3646   /* Draw underline, overline, strike-through. */
3647   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3649   /* Draw relief, if requested */
3650   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3651     {
3652       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3653         {
3654           th = tool_bar_button_relief >= 0 ?
3655             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3656           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3657         }
3658       else
3659         {
3660           th = abs (s->img->relief);
3661           raised_p = (s->img->relief > 0);
3662         }
3664       r.origin.x = x - th;
3665       r.origin.y = y - th;
3666       r.size.width = s->slice.width + 2*th-1;
3667       r.size.height = s->slice.height + 2*th-1;
3668       ns_draw_relief (r, th, raised_p,
3669                       s->slice.y == 0,
3670                       s->slice.y + s->slice.height == s->img->height,
3671                       s->slice.x == 0,
3672                       s->slice.x + s->slice.width == s->img->width, s);
3673     }
3675   /* If there is no mask, the background won't be seen,
3676      so draw a rectangle on the image for the cursor.
3677      Do this for all images, getting transparency right is not reliable.  */
3678   if (s->hl == DRAW_CURSOR)
3679     {
3680       int thickness = abs (s->img->relief);
3681       if (thickness == 0) thickness = 1;
3682       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3683     }
3687 static void
3688 ns_dumpglyphs_stretch (struct glyph_string *s)
3690   NSRect r[2];
3691   int n, i;
3692   struct face *face;
3693   NSColor *fgCol, *bgCol;
3695   if (!s->background_filled_p)
3696     {
3697       n = ns_get_glyph_string_clip_rect (s, r);
3698       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3700       ns_focus (s->f, r, n);
3702       if (s->hl == DRAW_MOUSE_FACE)
3703        {
3704          face = FACE_FROM_ID_OR_NULL (s->f,
3705                                       MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3706          if (!face)
3707            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3708        }
3709       else
3710        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3712       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3713       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3715       for (i = 0; i < n; ++i)
3716         {
3717           if (!s->row->full_width_p)
3718             {
3719               int overrun, leftoverrun;
3721               /* truncate to avoid overwriting fringe and/or scrollbar */
3722               overrun = max (0, (s->x + s->background_width)
3723                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3724                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3725               r[i].size.width -= overrun;
3727               /* truncate to avoid overwriting to left of the window box */
3728               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3729                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3731               if (leftoverrun > 0)
3732                 {
3733                   r[i].origin.x += leftoverrun;
3734                   r[i].size.width -= leftoverrun;
3735                 }
3737               /* XXX: Try to work between problem where a stretch glyph on
3738                  a partially-visible bottom row will clear part of the
3739                  modeline, and another where list-buffers headers and similar
3740                  rows erroneously have visible_height set to 0.  Not sure
3741                  where this is coming from as other terms seem not to show. */
3742               r[i].size.height = min (s->height, s->row->visible_height);
3743             }
3745           [bgCol set];
3747           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3748              overwriting cursor (usually when cursor on a tab) */
3749           if (s->hl == DRAW_CURSOR)
3750             {
3751               CGFloat x, width;
3753               x = r[i].origin.x;
3754               width = s->w->phys_cursor_width;
3755               r[i].size.width -= width;
3756               r[i].origin.x += width;
3758               NSRectFill (r[i]);
3760               /* Draw overlining, etc. on the cursor. */
3761               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3762                 ns_draw_text_decoration (s, face, bgCol, width, x);
3763               else
3764                 ns_draw_text_decoration (s, face, fgCol, width, x);
3765             }
3766           else
3767             {
3768               NSRectFill (r[i]);
3769             }
3771           /* Draw overlining, etc. on the stretch glyph (or the part
3772              of the stretch glyph after the cursor). */
3773           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3774                                    r[i].origin.x);
3775         }
3776       ns_unfocus (s->f);
3777       s->background_filled_p = 1;
3778     }
3782 static void
3783 ns_draw_glyph_string_foreground (struct glyph_string *s)
3785   int x, flags;
3786   struct font *font = s->font;
3788   /* If first glyph of S has a left box line, start drawing the text
3789      of S to the right of that box line.  */
3790   if (s->face && s->face->box != FACE_NO_BOX
3791       && s->first_glyph->left_box_line_p)
3792     x = s->x + eabs (s->face->box_line_width);
3793   else
3794     x = s->x;
3796   flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3797     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3798      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3799       NS_DUMPGLYPH_NORMAL));
3801   font->driver->draw
3802     (s, s->cmp_from, s->nchars, x, s->ybase,
3803      (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3804      || flags == NS_DUMPGLYPH_MOUSEFACE);
3808 static void
3809 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3811   int i, j, x;
3812   struct font *font = s->font;
3814   /* If first glyph of S has a left box line, start drawing the text
3815      of S to the right of that box line.  */
3816   if (s->face && s->face->box != FACE_NO_BOX
3817       && s->first_glyph->left_box_line_p)
3818     x = s->x + eabs (s->face->box_line_width);
3819   else
3820     x = s->x;
3822   /* S is a glyph string for a composition.  S->cmp_from is the index
3823      of the first character drawn for glyphs of this composition.
3824      S->cmp_from == 0 means we are drawing the very first character of
3825      this composition.  */
3827   /* Draw a rectangle for the composition if the font for the very
3828      first character of the composition could not be loaded.  */
3829   if (s->font_not_found_p)
3830     {
3831       if (s->cmp_from == 0)
3832         {
3833           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3834           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3835         }
3836     }
3837   else if (! s->first_glyph->u.cmp.automatic)
3838     {
3839       int y = s->ybase;
3841       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3842         /* TAB in a composition means display glyphs with padding
3843            space on the left or right.  */
3844         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3845           {
3846             int xx = x + s->cmp->offsets[j * 2];
3847             int yy = y - s->cmp->offsets[j * 2 + 1];
3849             font->driver->draw (s, j, j + 1, xx, yy, false);
3850             if (s->face->overstrike)
3851               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3852           }
3853     }
3854   else
3855     {
3856       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3857       Lisp_Object glyph;
3858       int y = s->ybase;
3859       int width = 0;
3861       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3862         {
3863           glyph = LGSTRING_GLYPH (gstring, i);
3864           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3865             width += LGLYPH_WIDTH (glyph);
3866           else
3867             {
3868               int xoff, yoff, wadjust;
3870               if (j < i)
3871                 {
3872                   font->driver->draw (s, j, i, x, y, false);
3873                   if (s->face->overstrike)
3874                     font->driver->draw (s, j, i, x + 1, y, false);
3875                   x += width;
3876                 }
3877               xoff = LGLYPH_XOFF (glyph);
3878               yoff = LGLYPH_YOFF (glyph);
3879               wadjust = LGLYPH_WADJUST (glyph);
3880               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3881               if (s->face->overstrike)
3882                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3883                                     false);
3884               x += wadjust;
3885               j = i + 1;
3886               width = 0;
3887             }
3888         }
3889       if (j < i)
3890         {
3891           font->driver->draw (s, j, i, x, y, false);
3892           if (s->face->overstrike)
3893             font->driver->draw (s, j, i, x + 1, y, false);
3894         }
3895     }
3898 static void
3899 ns_draw_glyph_string (struct glyph_string *s)
3900 /* --------------------------------------------------------------------------
3901       External (RIF): Main draw-text call.
3902    -------------------------------------------------------------------------- */
3904   /* TODO (optimize): focus for box and contents draw */
3905   NSRect r[2];
3906   int n;
3907   char box_drawn_p = 0;
3908   struct font *font = s->face->font;
3909   if (! font) font = FRAME_FONT (s->f);
3911   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3913   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3914     {
3915       int width;
3916       struct glyph_string *next;
3918       for (width = 0, next = s->next;
3919            next && width < s->right_overhang;
3920            width += next->width, next = next->next)
3921         if (next->first_glyph->type != IMAGE_GLYPH)
3922           {
3923             if (next->first_glyph->type != STRETCH_GLYPH)
3924               {
3925                 n = ns_get_glyph_string_clip_rect (s->next, r);
3926                 ns_focus (s->f, r, n);
3927                 ns_maybe_dumpglyphs_background (s->next, 1);
3928                 ns_unfocus (s->f);
3929               }
3930             else
3931               {
3932                 ns_dumpglyphs_stretch (s->next);
3933               }
3934             next->num_clips = 0;
3935           }
3936     }
3938   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3939         && (s->first_glyph->type == CHAR_GLYPH
3940             || s->first_glyph->type == COMPOSITE_GLYPH))
3941     {
3942       n = ns_get_glyph_string_clip_rect (s, r);
3943       ns_focus (s->f, r, n);
3944       ns_maybe_dumpglyphs_background (s, 1);
3945       ns_dumpglyphs_box_or_relief (s);
3946       ns_unfocus (s->f);
3947       box_drawn_p = 1;
3948     }
3950   switch (s->first_glyph->type)
3951     {
3953     case IMAGE_GLYPH:
3954       n = ns_get_glyph_string_clip_rect (s, r);
3955       ns_focus (s->f, r, n);
3956       ns_dumpglyphs_image (s, r[0]);
3957       ns_unfocus (s->f);
3958       break;
3960     case STRETCH_GLYPH:
3961       ns_dumpglyphs_stretch (s);
3962       break;
3964     case CHAR_GLYPH:
3965     case COMPOSITE_GLYPH:
3966       n = ns_get_glyph_string_clip_rect (s, r);
3967       ns_focus (s->f, r, n);
3969       if (s->for_overlaps || (s->cmp_from > 0
3970                               && ! s->first_glyph->u.cmp.automatic))
3971         s->background_filled_p = 1;
3972       else
3973         ns_maybe_dumpglyphs_background
3974           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3976       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3977         {
3978           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3979           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3980           NS_FACE_FOREGROUND (s->face) = tmp;
3981         }
3983       {
3984         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3986         if (isComposite)
3987           ns_draw_composite_glyph_string_foreground (s);
3988         else
3989           ns_draw_glyph_string_foreground (s);
3990       }
3992       {
3993         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3994                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3995                                                    s->f)
3996                         : FRAME_FOREGROUND_COLOR (s->f));
3997         [col set];
3999         /* Draw underline, overline, strike-through. */
4000         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4001       }
4003       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4004         {
4005           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4006           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4007           NS_FACE_FOREGROUND (s->face) = tmp;
4008         }
4010       ns_unfocus (s->f);
4011       break;
4013     case GLYPHLESS_GLYPH:
4014       n = ns_get_glyph_string_clip_rect (s, r);
4015       ns_focus (s->f, r, n);
4017       if (s->for_overlaps || (s->cmp_from > 0
4018                               && ! s->first_glyph->u.cmp.automatic))
4019         s->background_filled_p = 1;
4020       else
4021         ns_maybe_dumpglyphs_background
4022           (s, s->first_glyph->type == COMPOSITE_GLYPH);
4023       /* ... */
4024       /* Not yet implemented.  */
4025       /* ... */
4026       ns_unfocus (s->f);
4027       break;
4029     default:
4030       emacs_abort ();
4031     }
4033   /* Draw box if not done already. */
4034   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4035     {
4036       n = ns_get_glyph_string_clip_rect (s, r);
4037       ns_focus (s->f, r, n);
4038       ns_dumpglyphs_box_or_relief (s);
4039       ns_unfocus (s->f);
4040     }
4042   s->num_clips = 0;
4047 /* ==========================================================================
4049     Event loop
4051    ========================================================================== */
4054 static void
4055 ns_send_appdefined (int value)
4056 /* --------------------------------------------------------------------------
4057     Internal: post an appdefined event which EmacsApp-sendEvent will
4058               recognize and take as a command to halt the event loop.
4059    -------------------------------------------------------------------------- */
4061   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4063   // GNUstep needs postEvent to happen on the main thread.
4064   // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4065   if (! [[NSThread currentThread] isMainThread])
4066     {
4067       EmacsApp *app = (EmacsApp *)NSApp;
4068       app->nextappdefined = value;
4069       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4070                             withObject:nil
4071                          waitUntilDone:YES];
4072       return;
4073     }
4075   /* Only post this event if we haven't already posted one.  This will end
4076        the [NXApp run] main loop after having processed all events queued at
4077        this moment.  */
4079 #ifdef NS_IMPL_COCOA
4080   if (! send_appdefined)
4081     {
4082       /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4083          in certain situations (rapid incoming events).
4084          So check if we have one, if not add one.  */
4085       NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4086                                           untilDate:[NSDate distantPast]
4087                                              inMode:NSDefaultRunLoopMode
4088                                             dequeue:NO];
4089       if (! appev) send_appdefined = YES;
4090     }
4091 #endif
4093   if (send_appdefined)
4094     {
4095       NSEvent *nxev;
4097       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
4098       send_appdefined = NO;
4100       /* Don't need wakeup timer any more */
4101       if (timed_entry)
4102         {
4103           [timed_entry invalidate];
4104           [timed_entry release];
4105           timed_entry = nil;
4106         }
4108       nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4109                                 location: NSMakePoint (0, 0)
4110                            modifierFlags: 0
4111                                timestamp: 0
4112                             windowNumber: [[NSApp mainWindow] windowNumber]
4113                                  context: [NSApp context]
4114                                  subtype: 0
4115                                    data1: value
4116                                    data2: 0];
4118       /* Post an application defined event on the event queue.  When this is
4119          received the [NXApp run] will return, thus having processed all
4120          events which are currently queued.  */
4121       [NSApp postEvent: nxev atStart: NO];
4122     }
4125 #ifdef HAVE_NATIVE_FS
4126 static void
4127 check_native_fs ()
4129   Lisp_Object frame, tail;
4131   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4132     return;
4134   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4136   FOR_EACH_FRAME (tail, frame)
4137     {
4138       struct frame *f = XFRAME (frame);
4139       if (FRAME_NS_P (f))
4140         {
4141           EmacsView *view = FRAME_NS_VIEW (f);
4142           [view updateCollectionBehavior];
4143         }
4144     }
4146 #endif
4148 /* GNUstep does not have cancelTracking.  */
4149 #ifdef NS_IMPL_COCOA
4150 /* Check if menu open should be canceled or continued as normal.  */
4151 void
4152 ns_check_menu_open (NSMenu *menu)
4154   /* Click in menu bar? */
4155   NSArray *a = [[NSApp mainMenu] itemArray];
4156   int i;
4157   BOOL found = NO;
4159   if (menu == nil) // Menu tracking ended.
4160     {
4161       if (menu_will_open_state == MENU_OPENING)
4162         menu_will_open_state = MENU_NONE;
4163       return;
4164     }
4166   for (i = 0; ! found && i < [a count]; i++)
4167     found = menu == [[a objectAtIndex:i] submenu];
4168   if (found)
4169     {
4170       if (menu_will_open_state == MENU_NONE && emacs_event)
4171         {
4172           NSEvent *theEvent = [NSApp currentEvent];
4173           struct frame *emacsframe = SELECTED_FRAME ();
4175           [menu cancelTracking];
4176           menu_will_open_state = MENU_PENDING;
4177           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4178           EV_TRAILER (theEvent);
4180           CGEventRef ourEvent = CGEventCreate (NULL);
4181           menu_mouse_point = CGEventGetLocation (ourEvent);
4182           CFRelease (ourEvent);
4183         }
4184       else if (menu_will_open_state == MENU_OPENING)
4185         {
4186           menu_will_open_state = MENU_NONE;
4187         }
4188     }
4191 /* Redo saved menu click if state is MENU_PENDING.  */
4192 void
4193 ns_check_pending_open_menu ()
4195   if (menu_will_open_state == MENU_PENDING)
4196     {
4197       CGEventSourceRef source
4198         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4200       CGEventRef event = CGEventCreateMouseEvent (source,
4201                                                   kCGEventLeftMouseDown,
4202                                                   menu_mouse_point,
4203                                                   kCGMouseButtonLeft);
4204       CGEventSetType (event, kCGEventLeftMouseDown);
4205       CGEventPost (kCGHIDEventTap, event);
4206       CFRelease (event);
4207       CFRelease (source);
4209       menu_will_open_state = MENU_OPENING;
4210     }
4212 #endif /* NS_IMPL_COCOA */
4214 static int
4215 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4216 /* --------------------------------------------------------------------------
4217      External (hook): Post an event to ourself and keep reading events until
4218      we read it back again.  In effect process all events which were waiting.
4219      From 21+ we have to manage the event buffer ourselves.
4220    -------------------------------------------------------------------------- */
4222   struct input_event ev;
4223   int nevents;
4225   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4227 #ifdef HAVE_NATIVE_FS
4228   check_native_fs ();
4229 #endif
4231   if ([NSApp modalWindow] != nil)
4232     return -1;
4234   if (hold_event_q.nr > 0)
4235     {
4236       int i;
4237       for (i = 0; i < hold_event_q.nr; ++i)
4238         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4239       hold_event_q.nr = 0;
4240       return i;
4241     }
4243   if ([NSThread isMainThread])
4244     {
4245       block_input ();
4246       n_emacs_events_pending = 0;
4247       ns_init_events (&ev);
4248       q_event_ptr = hold_quit;
4250       /* we manage autorelease pools by allocate/reallocate each time around
4251          the loop; strict nesting is occasionally violated but seems not to
4252          matter.. earlier methods using full nesting caused major memory leaks */
4253       [outerpool release];
4254       outerpool = [[NSAutoreleasePool alloc] init];
4256       /* If have pending open-file requests, attend to the next one of those. */
4257       if (ns_pending_files && [ns_pending_files count] != 0
4258           && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4259         {
4260           [ns_pending_files removeObjectAtIndex: 0];
4261         }
4262       /* Deal with pending service requests. */
4263       else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4264                && [(EmacsApp *)
4265                     NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4266                                  withArg: [ns_pending_service_args objectAtIndex: 0]])
4267         {
4268           [ns_pending_service_names removeObjectAtIndex: 0];
4269           [ns_pending_service_args removeObjectAtIndex: 0];
4270         }
4271       else
4272         {
4273           /* Run and wait for events.  We must always send one NX_APPDEFINED event
4274              to ourself, otherwise [NXApp run] will never exit.  */
4275           send_appdefined = YES;
4276           ns_send_appdefined (-1);
4278           [NSApp run];
4279         }
4281       nevents = n_emacs_events_pending;
4282       n_emacs_events_pending = 0;
4283       ns_finish_events ();
4284       q_event_ptr = NULL;
4285       unblock_input ();
4286     }
4287   else
4288     return -1;
4290   return nevents;
4295 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4296            fd_set *exceptfds, struct timespec const *timeout,
4297            sigset_t const *sigmask)
4298 /* --------------------------------------------------------------------------
4299      Replacement for select, checking for events
4300    -------------------------------------------------------------------------- */
4302   int result;
4303   int t, k, nr = 0;
4304   struct input_event event;
4305   char c;
4307   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4309 #ifdef HAVE_NATIVE_FS
4310   check_native_fs ();
4311 #endif
4313   if (hold_event_q.nr > 0)
4314     {
4315       /* We already have events pending. */
4316       raise (SIGIO);
4317       errno = EINTR;
4318       return -1;
4319     }
4321   for (k = 0; k < nfds+1; k++)
4322     {
4323       if (readfds && FD_ISSET(k, readfds)) ++nr;
4324       if (writefds && FD_ISSET(k, writefds)) ++nr;
4325     }
4327   if (NSApp == nil
4328       || ![NSThread isMainThread]
4329       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4330     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
4332   [outerpool release];
4333   outerpool = [[NSAutoreleasePool alloc] init];
4336   send_appdefined = YES;
4337   if (nr > 0)
4338     {
4339       pthread_mutex_lock (&select_mutex);
4340       select_nfds = nfds;
4341       select_valid = 0;
4342       if (readfds)
4343         {
4344           select_readfds = *readfds;
4345           select_valid += SELECT_HAVE_READ;
4346         }
4347       if (writefds)
4348         {
4349           select_writefds = *writefds;
4350           select_valid += SELECT_HAVE_WRITE;
4351         }
4353       if (timeout)
4354         {
4355           select_timeout = *timeout;
4356           select_valid += SELECT_HAVE_TMO;
4357         }
4359       pthread_mutex_unlock (&select_mutex);
4361       /* Inform fd_handler that select should be called */
4362       c = 'g';
4363       emacs_write_sig (selfds[1], &c, 1);
4364     }
4365   else if (nr == 0 && timeout)
4366     {
4367       /* No file descriptor, just a timeout, no need to wake fd_handler  */
4368       double time = timespectod (*timeout);
4369       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4370                                                       target: NSApp
4371                                                     selector:
4372                                   @selector (timeout_handler:)
4373                                                     userInfo: 0
4374                                                      repeats: NO]
4375                       retain];
4376     }
4377   else /* No timeout and no file descriptors, can this happen?  */
4378     {
4379       /* Send appdefined so we exit from the loop */
4380       ns_send_appdefined (-1);
4381     }
4383   block_input ();
4384   ns_init_events (&event);
4386   [NSApp run];
4388   ns_finish_events ();
4389   if (nr > 0 && readfds)
4390     {
4391       c = 's';
4392       emacs_write_sig (selfds[1], &c, 1);
4393     }
4394   unblock_input ();
4396   t = last_appdefined_event_data;
4398   if (t != NO_APPDEFINED_DATA)
4399     {
4400       last_appdefined_event_data = NO_APPDEFINED_DATA;
4402       if (t == -2)
4403         {
4404           /* The NX_APPDEFINED event we received was a timeout. */
4405           result = 0;
4406         }
4407       else if (t == -1)
4408         {
4409           /* The NX_APPDEFINED event we received was the result of
4410              at least one real input event arriving.  */
4411           errno = EINTR;
4412           result = -1;
4413         }
4414       else
4415         {
4416           /* Received back from select () in fd_handler; copy the results */
4417           pthread_mutex_lock (&select_mutex);
4418           if (readfds) *readfds = select_readfds;
4419           if (writefds) *writefds = select_writefds;
4420           pthread_mutex_unlock (&select_mutex);
4421           result = t;
4422         }
4423     }
4424   else
4425     {
4426       errno = EINTR;
4427       result = -1;
4428     }
4430   return result;
4435 /* ==========================================================================
4437     Scrollbar handling
4439    ========================================================================== */
4442 static void
4443 ns_set_vertical_scroll_bar (struct window *window,
4444                            int portion, int whole, int position)
4445 /* --------------------------------------------------------------------------
4446       External (hook): Update or add scrollbar
4447    -------------------------------------------------------------------------- */
4449   Lisp_Object win;
4450   NSRect r, v;
4451   struct frame *f = XFRAME (WINDOW_FRAME (window));
4452   EmacsView *view = FRAME_NS_VIEW (f);
4453   EmacsScroller *bar;
4454   int window_y, window_height;
4455   int top, left, height, width;
4456   BOOL update_p = YES;
4458   /* optimization; display engine sends WAY too many of these.. */
4459   if (!NILP (window->vertical_scroll_bar))
4460     {
4461       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4462       if ([bar checkSamePosition: position portion: portion whole: whole])
4463         {
4464           if (view->scrollbarsNeedingUpdate == 0)
4465             {
4466               if (!windows_or_buffers_changed)
4467                   return;
4468             }
4469           else
4470             view->scrollbarsNeedingUpdate--;
4471           update_p = NO;
4472         }
4473     }
4475   NSTRACE ("ns_set_vertical_scroll_bar");
4477   /* Get dimensions.  */
4478   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4479   top = window_y;
4480   height = window_height;
4481   width = NS_SCROLL_BAR_WIDTH (f);
4482   left = WINDOW_SCROLL_BAR_AREA_X (window);
4484   r = NSMakeRect (left, top, width, height);
4485   /* the parent view is flipped, so we need to flip y value */
4486   v = [view frame];
4487   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4489   XSETWINDOW (win, window);
4490   block_input ();
4492   /* we want at least 5 lines to display a scrollbar */
4493   if (WINDOW_TOTAL_LINES (window) < 5)
4494     {
4495       if (!NILP (window->vertical_scroll_bar))
4496         {
4497           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4498           [bar removeFromSuperview];
4499           wset_vertical_scroll_bar (window, Qnil);
4500           [bar release];
4501         }
4502       ns_clear_frame_area (f, left, top, width, height);
4503       unblock_input ();
4504       return;
4505     }
4507   if (NILP (window->vertical_scroll_bar))
4508     {
4509       if (width > 0 && height > 0)
4510         ns_clear_frame_area (f, left, top, width, height);
4512       bar = [[EmacsScroller alloc] initFrame: r window: win];
4513       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4514       update_p = YES;
4515     }
4516   else
4517     {
4518       NSRect oldRect;
4519       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4520       oldRect = [bar frame];
4521       r.size.width = oldRect.size.width;
4522       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4523         {
4524           if (oldRect.origin.x != r.origin.x)
4525               ns_clear_frame_area (f, left, top, width, height);
4526           [bar setFrame: r];
4527         }
4528     }
4530   if (update_p)
4531     [bar setPosition: position portion: portion whole: whole];
4532   unblock_input ();
4536 static void
4537 ns_set_horizontal_scroll_bar (struct window *window,
4538                               int portion, int whole, int position)
4539 /* --------------------------------------------------------------------------
4540       External (hook): Update or add scrollbar
4541    -------------------------------------------------------------------------- */
4543   Lisp_Object win;
4544   NSRect r, v;
4545   struct frame *f = XFRAME (WINDOW_FRAME (window));
4546   EmacsView *view = FRAME_NS_VIEW (f);
4547   EmacsScroller *bar;
4548   int top, height, left, width;
4549   int window_x, window_width;
4550   BOOL update_p = YES;
4552   /* optimization; display engine sends WAY too many of these.. */
4553   if (!NILP (window->horizontal_scroll_bar))
4554     {
4555       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4556       if ([bar checkSamePosition: position portion: portion whole: whole])
4557         {
4558           if (view->scrollbarsNeedingUpdate == 0)
4559             {
4560               if (!windows_or_buffers_changed)
4561                   return;
4562             }
4563           else
4564             view->scrollbarsNeedingUpdate--;
4565           update_p = NO;
4566         }
4567     }
4569   NSTRACE ("ns_set_horizontal_scroll_bar");
4571   /* Get dimensions.  */
4572   window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4573   left = window_x;
4574   width = window_width;
4575   height = NS_SCROLL_BAR_HEIGHT (f);
4576   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4578   r = NSMakeRect (left, top, width, height);
4579   /* the parent view is flipped, so we need to flip y value */
4580   v = [view frame];
4581   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4583   XSETWINDOW (win, window);
4584   block_input ();
4586   if (NILP (window->horizontal_scroll_bar))
4587     {
4588       if (width > 0 && height > 0)
4589         ns_clear_frame_area (f, left, top, width, height);
4591       bar = [[EmacsScroller alloc] initFrame: r window: win];
4592       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4593       update_p = YES;
4594     }
4595   else
4596     {
4597       NSRect oldRect;
4598       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4599       oldRect = [bar frame];
4600       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4601         {
4602           if (oldRect.origin.y != r.origin.y)
4603             ns_clear_frame_area (f, left, top, width, height);
4604           [bar setFrame: r];
4605           update_p = YES;
4606         }
4607     }
4609   /* If there are both horizontal and vertical scroll-bars they leave
4610      a square that belongs to neither. We need to clear it otherwise
4611      it fills with junk. */
4612   if (!NILP (window->vertical_scroll_bar))
4613     ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4614                          NS_SCROLL_BAR_HEIGHT (f), height);
4616   if (update_p)
4617     [bar setPosition: position portion: portion whole: whole];
4618   unblock_input ();
4622 static void
4623 ns_condemn_scroll_bars (struct frame *f)
4624 /* --------------------------------------------------------------------------
4625      External (hook): arrange for all frame's scrollbars to be removed
4626      at next call to judge_scroll_bars, except for those redeemed.
4627    -------------------------------------------------------------------------- */
4629   int i;
4630   id view;
4631   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4633   NSTRACE ("ns_condemn_scroll_bars");
4635   for (i =[subviews count]-1; i >= 0; i--)
4636     {
4637       view = [subviews objectAtIndex: i];
4638       if ([view isKindOfClass: [EmacsScroller class]])
4639         [view condemn];
4640     }
4644 static void
4645 ns_redeem_scroll_bar (struct window *window)
4646 /* --------------------------------------------------------------------------
4647      External (hook): arrange to spare this window's scrollbar
4648      at next call to judge_scroll_bars.
4649    -------------------------------------------------------------------------- */
4651   id bar;
4652   NSTRACE ("ns_redeem_scroll_bar");
4653   if (!NILP (window->vertical_scroll_bar)
4654       && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4655     {
4656       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4657       [bar reprieve];
4658     }
4660   if (!NILP (window->horizontal_scroll_bar)
4661       && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4662     {
4663       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4664       [bar reprieve];
4665     }
4669 static void
4670 ns_judge_scroll_bars (struct frame *f)
4671 /* --------------------------------------------------------------------------
4672      External (hook): destroy all scrollbars on frame that weren't
4673      redeemed after call to condemn_scroll_bars.
4674    -------------------------------------------------------------------------- */
4676   int i;
4677   id view;
4678   EmacsView *eview = FRAME_NS_VIEW (f);
4679   NSArray *subviews = [[eview superview] subviews];
4680   BOOL removed = NO;
4682   NSTRACE ("ns_judge_scroll_bars");
4683   for (i = [subviews count]-1; i >= 0; --i)
4684     {
4685       view = [subviews objectAtIndex: i];
4686       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4687       if ([view judge])
4688         removed = YES;
4689     }
4691   if (removed)
4692     [eview updateFrameSize: NO];
4695 /* ==========================================================================
4697     Initialization
4699    ========================================================================== */
4702 x_display_pixel_height (struct ns_display_info *dpyinfo)
4704   NSArray *screens = [NSScreen screens];
4705   NSEnumerator *enumerator = [screens objectEnumerator];
4706   NSScreen *screen;
4707   NSRect frame;
4709   frame = NSZeroRect;
4710   while ((screen = [enumerator nextObject]) != nil)
4711     frame = NSUnionRect (frame, [screen frame]);
4713   return NSHeight (frame);
4717 x_display_pixel_width (struct ns_display_info *dpyinfo)
4719   NSArray *screens = [NSScreen screens];
4720   NSEnumerator *enumerator = [screens objectEnumerator];
4721   NSScreen *screen;
4722   NSRect frame;
4724   frame = NSZeroRect;
4725   while ((screen = [enumerator nextObject]) != nil)
4726     frame = NSUnionRect (frame, [screen frame]);
4728   return NSWidth (frame);
4732 static Lisp_Object ns_string_to_lispmod (const char *s)
4733 /* --------------------------------------------------------------------------
4734      Convert modifier name to lisp symbol
4735    -------------------------------------------------------------------------- */
4737   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4738     return Qmeta;
4739   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4740     return Qsuper;
4741   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4742     return Qcontrol;
4743   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4744     return Qalt;
4745   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4746     return Qhyper;
4747   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4748     return Qnone;
4749   else
4750     return Qnil;
4754 static void
4755 ns_default (const char *parameter, Lisp_Object *result,
4756            Lisp_Object yesval, Lisp_Object noval,
4757            BOOL is_float, BOOL is_modstring)
4758 /* --------------------------------------------------------------------------
4759       Check a parameter value in user's preferences
4760    -------------------------------------------------------------------------- */
4762   const char *value = ns_get_defaults_value (parameter);
4764   if (value)
4765     {
4766       double f;
4767       char *pos;
4768       if (c_strcasecmp (value, "YES") == 0)
4769         *result = yesval;
4770       else if (c_strcasecmp (value, "NO") == 0)
4771         *result = noval;
4772       else if (is_float && (f = strtod (value, &pos), pos != value))
4773         *result = make_float (f);
4774       else if (is_modstring && value)
4775         *result = ns_string_to_lispmod (value);
4776       else fprintf (stderr,
4777                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4778     }
4782 static void
4783 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4784 /* --------------------------------------------------------------------------
4785       Initialize global info and storage for display.
4786    -------------------------------------------------------------------------- */
4788     NSScreen *screen = [NSScreen mainScreen];
4789     NSWindowDepth depth = [screen depth];
4791     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4792     dpyinfo->resy = 72.27;
4793     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4794                                                   NSColorSpaceFromDepth (depth)]
4795                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4796                                                  NSColorSpaceFromDepth (depth)];
4797     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4798     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4799     dpyinfo->color_table->colors = NULL;
4800     dpyinfo->root_window = 42; /* a placeholder.. */
4801     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4802     dpyinfo->n_fonts = 0;
4803     dpyinfo->smallest_font_height = 1;
4804     dpyinfo->smallest_char_width = 1;
4806     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4810 /* This and next define (many of the) public functions in this file. */
4811 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4812          with using despite presence in the "system dependent" redisplay
4813          interface.  In addition, many of the ns_ methods have code that is
4814          shared with all terms, indicating need for further refactoring. */
4815 extern frame_parm_handler ns_frame_parm_handlers[];
4816 static struct redisplay_interface ns_redisplay_interface =
4818   ns_frame_parm_handlers,
4819   x_produce_glyphs,
4820   x_write_glyphs,
4821   x_insert_glyphs,
4822   x_clear_end_of_line,
4823   ns_scroll_run,
4824   ns_after_update_window_line,
4825   ns_update_window_begin,
4826   ns_update_window_end,
4827   0, /* flush_display */
4828   x_clear_window_mouse_face,
4829   x_get_glyph_overhangs,
4830   x_fix_overlapping_area,
4831   ns_draw_fringe_bitmap,
4832   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4833   0, /* destroy_fringe_bitmap */
4834   ns_compute_glyph_string_overhangs,
4835   ns_draw_glyph_string,
4836   ns_define_frame_cursor,
4837   ns_clear_frame_area,
4838   ns_draw_window_cursor,
4839   ns_draw_vertical_window_border,
4840   ns_draw_window_divider,
4841   ns_shift_glyphs_for_insert,
4842   ns_show_hourglass,
4843   ns_hide_hourglass
4847 static void
4848 ns_delete_display (struct ns_display_info *dpyinfo)
4850   /* TODO... */
4854 /* This function is called when the last frame on a display is deleted. */
4855 static void
4856 ns_delete_terminal (struct terminal *terminal)
4858   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4860   NSTRACE ("ns_delete_terminal");
4862   /* Protect against recursive calls.  delete_frame in
4863      delete_terminal calls us back when it deletes our last frame.  */
4864   if (!terminal->name)
4865     return;
4867   block_input ();
4869   x_destroy_all_bitmaps (dpyinfo);
4870   ns_delete_display (dpyinfo);
4871   unblock_input ();
4875 static struct terminal *
4876 ns_create_terminal (struct ns_display_info *dpyinfo)
4877 /* --------------------------------------------------------------------------
4878       Set up use of NS before we make the first connection.
4879    -------------------------------------------------------------------------- */
4881   struct terminal *terminal;
4883   NSTRACE ("ns_create_terminal");
4885   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4887   terminal->display_info.ns = dpyinfo;
4888   dpyinfo->terminal = terminal;
4890   terminal->clear_frame_hook = ns_clear_frame;
4891   terminal->ring_bell_hook = ns_ring_bell;
4892   terminal->update_begin_hook = ns_update_begin;
4893   terminal->update_end_hook = ns_update_end;
4894   terminal->read_socket_hook = ns_read_socket;
4895   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4896   terminal->mouse_position_hook = ns_mouse_position;
4897   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4898   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4899   terminal->fullscreen_hook = ns_fullscreen_hook;
4900   terminal->menu_show_hook = ns_menu_show;
4901   terminal->popup_dialog_hook = ns_popup_dialog;
4902   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4903   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4904   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4905   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4906   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4907   terminal->delete_frame_hook = x_destroy_window;
4908   terminal->delete_terminal_hook = ns_delete_terminal;
4909   /* Other hooks are NULL by default.  */
4911   return terminal;
4915 struct ns_display_info *
4916 ns_term_init (Lisp_Object display_name)
4917 /* --------------------------------------------------------------------------
4918      Start the Application and get things rolling.
4919    -------------------------------------------------------------------------- */
4921   struct terminal *terminal;
4922   struct ns_display_info *dpyinfo;
4923   static int ns_initialized = 0;
4924   Lisp_Object tmp;
4926   if (ns_initialized) return x_display_list;
4927   ns_initialized = 1;
4929   block_input ();
4931   NSTRACE ("ns_term_init");
4933   [outerpool release];
4934   outerpool = [[NSAutoreleasePool alloc] init];
4936   /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
4937   /*GSDebugAllocationActive (YES); */
4938   block_input ();
4940   baud_rate = 38400;
4941   Fset_input_interrupt_mode (Qnil);
4943   if (selfds[0] == -1)
4944     {
4945       if (emacs_pipe (selfds) != 0)
4946         {
4947           fprintf (stderr, "Failed to create pipe: %s\n",
4948                    emacs_strerror (errno));
4949           emacs_abort ();
4950         }
4952       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4953       FD_ZERO (&select_readfds);
4954       FD_ZERO (&select_writefds);
4955       pthread_mutex_init (&select_mutex, NULL);
4956     }
4958   ns_pending_files = [[NSMutableArray alloc] init];
4959   ns_pending_service_names = [[NSMutableArray alloc] init];
4960   ns_pending_service_args = [[NSMutableArray alloc] init];
4962 /* Start app and create the main menu, window, view.
4963      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4964      The view will then ask the NSApp to stop and return to Emacs. */
4965   [EmacsApp sharedApplication];
4966   if (NSApp == nil)
4967     return NULL;
4968   [NSApp setDelegate: NSApp];
4970   /* Start the select thread.  */
4971   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4972                            toTarget:NSApp
4973                          withObject:nil];
4975   /* debugging: log all notifications */
4976   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4977                                          selector: @selector (logNotification:)
4978                                              name: nil object: nil]; */
4980   dpyinfo = xzalloc (sizeof *dpyinfo);
4982   ns_initialize_display_info (dpyinfo);
4983   terminal = ns_create_terminal (dpyinfo);
4985   terminal->kboard = allocate_kboard (Qns);
4986   /* Don't let the initial kboard remain current longer than necessary.
4987      That would cause problems if a file loaded on startup tries to
4988      prompt in the mini-buffer.  */
4989   if (current_kboard == initial_kboard)
4990     current_kboard = terminal->kboard;
4991   terminal->kboard->reference_count++;
4993   dpyinfo->next = x_display_list;
4994   x_display_list = dpyinfo;
4996   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4998   terminal->name = xlispstrdup (display_name);
5000   unblock_input ();
5002   if (!inhibit_x_resources)
5003     {
5004       ns_default ("GSFontAntiAlias", &ns_antialias_text,
5005                  Qt, Qnil, NO, NO);
5006       tmp = Qnil;
5007       /* this is a standard variable */
5008       ns_default ("AppleAntiAliasingThreshold", &tmp,
5009                  make_float (10.0), make_float (6.0), YES, NO);
5010       ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5011     }
5013   NSTRACE_MSG ("Colors");
5015   {
5016     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5018     if ( cl == nil )
5019       {
5020         Lisp_Object color_file, color_map, color;
5021         unsigned long c;
5022         char *name;
5024         color_file = Fexpand_file_name (build_string ("rgb.txt"),
5025                          Fsymbol_value (intern ("data-directory")));
5027         color_map = Fx_load_color_file (color_file);
5028         if (NILP (color_map))
5029           fatal ("Could not read %s.\n", SDATA (color_file));
5031         cl = [[NSColorList alloc] initWithName: @"Emacs"];
5032         for ( ; CONSP (color_map); color_map = XCDR (color_map))
5033           {
5034             color = XCAR (color_map);
5035             name = SSDATA (XCAR (color));
5036             c = XINT (XCDR (color));
5037             [cl setColor:
5038                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5039                                       green: GREEN_FROM_ULONG (c) / 255.0
5040                                        blue: BLUE_FROM_ULONG (c) / 255.0
5041                                       alpha: 1.0]
5042                   forKey: [NSString stringWithUTF8String: name]];
5043           }
5044         [cl writeToFile: nil];
5045       }
5046   }
5048   NSTRACE_MSG ("Versions");
5050   {
5051 #ifdef NS_IMPL_GNUSTEP
5052     Vwindow_system_version = build_string (gnustep_base_version);
5053 #else
5054     /*PSnextrelease (128, c); */
5055     char c[DBL_BUFSIZE_BOUND];
5056     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5057     Vwindow_system_version = make_unibyte_string (c, len);
5058 #endif
5059   }
5061   delete_keyboard_wait_descriptor (0);
5063   ns_app_name = [[NSProcessInfo processInfo] processName];
5065   /* Set up macOS app menu */
5067   NSTRACE_MSG ("Menu init");
5069 #ifdef NS_IMPL_COCOA
5070   {
5071     NSMenu *appMenu;
5072     NSMenuItem *item;
5073     /* set up the application menu */
5074     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5075     [svcsMenu setAutoenablesItems: NO];
5076     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5077     [appMenu setAutoenablesItems: NO];
5078     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5079     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5081     [appMenu insertItemWithTitle: @"About Emacs"
5082                           action: @selector (orderFrontStandardAboutPanel:)
5083                    keyEquivalent: @""
5084                          atIndex: 0];
5085     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5086     [appMenu insertItemWithTitle: @"Preferences..."
5087                           action: @selector (showPreferencesWindow:)
5088                    keyEquivalent: @","
5089                          atIndex: 2];
5090     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5091     item = [appMenu insertItemWithTitle: @"Services"
5092                                  action: @selector (menuDown:)
5093                           keyEquivalent: @""
5094                                 atIndex: 4];
5095     [appMenu setSubmenu: svcsMenu forItem: item];
5096     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5097     [appMenu insertItemWithTitle: @"Hide Emacs"
5098                           action: @selector (hide:)
5099                    keyEquivalent: @"h"
5100                          atIndex: 6];
5101     item =  [appMenu insertItemWithTitle: @"Hide Others"
5102                           action: @selector (hideOtherApplications:)
5103                    keyEquivalent: @"h"
5104                          atIndex: 7];
5105     [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5106     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5107     [appMenu insertItemWithTitle: @"Quit Emacs"
5108                           action: @selector (terminate:)
5109                    keyEquivalent: @"q"
5110                          atIndex: 9];
5112     item = [mainMenu insertItemWithTitle: ns_app_name
5113                                   action: @selector (menuDown:)
5114                            keyEquivalent: @""
5115                                  atIndex: 0];
5116     [mainMenu setSubmenu: appMenu forItem: item];
5117     [dockMenu insertItemWithTitle: @"New Frame"
5118                            action: @selector (newFrame:)
5119                     keyEquivalent: @""
5120                           atIndex: 0];
5122     [NSApp setMainMenu: mainMenu];
5123     [NSApp setAppleMenu: appMenu];
5124     [NSApp setServicesMenu: svcsMenu];
5125     /* Needed at least on Cocoa, to get dock menu to show windows */
5126     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5128     [[NSNotificationCenter defaultCenter]
5129       addObserver: mainMenu
5130          selector: @selector (trackingNotification:)
5131              name: NSMenuDidBeginTrackingNotification object: mainMenu];
5132     [[NSNotificationCenter defaultCenter]
5133       addObserver: mainMenu
5134          selector: @selector (trackingNotification:)
5135              name: NSMenuDidEndTrackingNotification object: mainMenu];
5136   }
5137 #endif /* macOS menu setup */
5139   /* Register our external input/output types, used for determining
5140      applicable services and also drag/drop eligibility. */
5142   NSTRACE_MSG ("Input/output types");
5144   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5145   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5146                       retain];
5147   ns_drag_types = [[NSArray arrayWithObjects:
5148                             NSStringPboardType,
5149                             NSTabularTextPboardType,
5150                             NSFilenamesPboardType,
5151                             NSURLPboardType, nil] retain];
5153   /* If fullscreen is in init/default-frame-alist, focus isn't set
5154      right for fullscreen windows, so set this.  */
5155   [NSApp activateIgnoringOtherApps:YES];
5157   NSTRACE_MSG ("Call NSApp run");
5159   [NSApp run];
5160   ns_do_open_file = YES;
5162 #ifdef NS_IMPL_GNUSTEP
5163   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5164      We must re-catch it so subprocess works.  */
5165   catch_child_signal ();
5166 #endif
5168   NSTRACE_MSG ("ns_term_init done");
5170   unblock_input ();
5172   return dpyinfo;
5176 void
5177 ns_term_shutdown (int sig)
5179   [[NSUserDefaults standardUserDefaults] synchronize];
5181   /* code not reached in emacs.c after this is called by shut_down_emacs: */
5182   if (STRINGP (Vauto_save_list_file_name))
5183     unlink (SSDATA (Vauto_save_list_file_name));
5185   if (sig == 0 || sig == SIGTERM)
5186     {
5187       [NSApp terminate: NSApp];
5188     }
5189   else // force a stack trace to happen
5190     {
5191       emacs_abort ();
5192     }
5196 /* ==========================================================================
5198     EmacsApp implementation
5200    ========================================================================== */
5203 @implementation EmacsApp
5205 - (id)init
5207   NSTRACE ("[EmacsApp init]");
5209   if ((self = [super init]))
5210     {
5211 #ifdef NS_IMPL_COCOA
5212       self->isFirst = YES;
5213 #endif
5214 #ifdef NS_IMPL_GNUSTEP
5215       self->applicationDidFinishLaunchingCalled = NO;
5216 #endif
5217     }
5219   return self;
5222 #ifdef NS_IMPL_COCOA
5223 - (void)run
5225   NSTRACE ("[EmacsApp run]");
5227 #ifndef NSAppKitVersionNumber10_9
5228 #define NSAppKitVersionNumber10_9 1265
5229 #endif
5231     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5232       {
5233         [super run];
5234         return;
5235       }
5237   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5239   if (isFirst) [self finishLaunching];
5240   isFirst = NO;
5242   shouldKeepRunning = YES;
5243   do
5244     {
5245       [pool release];
5246       pool = [[NSAutoreleasePool alloc] init];
5248       NSEvent *event =
5249         [self nextEventMatchingMask:NSEventMaskAny
5250                           untilDate:[NSDate distantFuture]
5251                              inMode:NSDefaultRunLoopMode
5252                             dequeue:YES];
5254       [self sendEvent:event];
5255       [self updateWindows];
5256     } while (shouldKeepRunning);
5258   [pool release];
5261 - (void)stop: (id)sender
5263   NSTRACE ("[EmacsApp stop:]");
5265     shouldKeepRunning = NO;
5266     // Stop possible dialog also.  Noop if no dialog present.
5267     // The file dialog still leaks 7k - 10k on 10.9 though.
5268     [super stop:sender];
5270 #endif /* NS_IMPL_COCOA */
5272 - (void)logNotification: (NSNotification *)notification
5274   NSTRACE ("[EmacsApp logNotification:]");
5276   const char *name = [[notification name] UTF8String];
5277   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5278       && !strstr (name, "WindowNumber"))
5279     NSLog (@"notification: '%@'", [notification name]);
5283 - (void)sendEvent: (NSEvent *)theEvent
5284 /* --------------------------------------------------------------------------
5285      Called when NSApp is running for each event received.  Used to stop
5286      the loop when we choose, since there's no way to just run one iteration.
5287    -------------------------------------------------------------------------- */
5289   int type = [theEvent type];
5290   NSWindow *window = [theEvent window];
5292   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5293   NSTRACE_MSG ("Type: %d", type);
5295 #ifdef NS_IMPL_GNUSTEP
5296   // Keyboard events aren't propagated to file dialogs for some reason.
5297   if ([NSApp modalWindow] != nil &&
5298       (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5299     {
5300       [[NSApp modalWindow] sendEvent: theEvent];
5301       return;
5302     }
5303 #endif
5305   if (represented_filename != nil && represented_frame)
5306     {
5307       NSString *fstr = represented_filename;
5308       NSView *view = FRAME_NS_VIEW (represented_frame);
5309 #ifdef NS_IMPL_COCOA
5310       /* work around a bug observed on 10.3 and later where
5311          setTitleWithRepresentedFilename does not clear out previous state
5312          if given filename does not exist */
5313       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5314         [[view window] setRepresentedFilename: @""];
5315 #endif
5316       [[view window] setRepresentedFilename: fstr];
5317       [represented_filename release];
5318       represented_filename = nil;
5319       represented_frame = NULL;
5320     }
5322   if (type == NSEventTypeApplicationDefined)
5323     {
5324       switch ([theEvent data2])
5325         {
5326 #ifdef NS_IMPL_COCOA
5327         case NSAPP_DATA2_RUNASSCRIPT:
5328           ns_run_ascript ();
5329           [self stop: self];
5330           return;
5331 #endif
5332         case NSAPP_DATA2_RUNFILEDIALOG:
5333           ns_run_file_dialog ();
5334           [self stop: self];
5335           return;
5336         }
5337     }
5339   if (type == NSEventTypeCursorUpdate && window == nil)
5340     {
5341       fprintf (stderr, "Dropping external cursor update event.\n");
5342       return;
5343     }
5345   if (type == NSEventTypeApplicationDefined)
5346     {
5347       /* Events posted by ns_send_appdefined interrupt the run loop here.
5348          But, if a modal window is up, an appdefined can still come through,
5349          (e.g., from a makeKeyWindow event) but stopping self also stops the
5350          modal loop. Just defer it until later. */
5351       if ([NSApp modalWindow] == nil)
5352         {
5353           last_appdefined_event_data = [theEvent data1];
5354           [self stop: self];
5355         }
5356       else
5357         {
5358           send_appdefined = YES;
5359         }
5360     }
5363 #ifdef NS_IMPL_COCOA
5364   /* If no dialog and none of our frames have focus and it is a move, skip it.
5365      It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5366      such as Wifi, sound, date or similar.
5367      This prevents "spooky" highlighting in the frame under the menu.  */
5368   if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5369     {
5370       struct ns_display_info *di;
5371       BOOL has_focus = NO;
5372       for (di = x_display_list; ! has_focus && di; di = di->next)
5373         has_focus = di->x_focus_frame != 0;
5374       if (! has_focus)
5375         return;
5376     }
5377 #endif
5379   NSTRACE_UNSILENCE();
5381   [super sendEvent: theEvent];
5385 - (void)showPreferencesWindow: (id)sender
5387   struct frame *emacsframe = SELECTED_FRAME ();
5388   NSEvent *theEvent = [NSApp currentEvent];
5390   if (!emacs_event)
5391     return;
5392   emacs_event->kind = NS_NONKEY_EVENT;
5393   emacs_event->code = KEY_NS_SHOW_PREFS;
5394   emacs_event->modifiers = 0;
5395   EV_TRAILER (theEvent);
5399 - (void)newFrame: (id)sender
5401   NSTRACE ("[EmacsApp newFrame:]");
5403   struct frame *emacsframe = SELECTED_FRAME ();
5404   NSEvent *theEvent = [NSApp currentEvent];
5406   if (!emacs_event)
5407     return;
5408   emacs_event->kind = NS_NONKEY_EVENT;
5409   emacs_event->code = KEY_NS_NEW_FRAME;
5410   emacs_event->modifiers = 0;
5411   EV_TRAILER (theEvent);
5415 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5416 - (BOOL) openFile: (NSString *)fileName
5418   NSTRACE ("[EmacsApp openFile:]");
5420   struct frame *emacsframe = SELECTED_FRAME ();
5421   NSEvent *theEvent = [NSApp currentEvent];
5423   if (!emacs_event)
5424     return NO;
5426   emacs_event->kind = NS_NONKEY_EVENT;
5427   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5428   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5429   ns_input_line = Qnil; /* can be start or cons start,end */
5430   emacs_event->modifiers =0;
5431   EV_TRAILER (theEvent);
5433   return YES;
5437 /* **************************************************************************
5439       EmacsApp delegate implementation
5441    ************************************************************************** */
5443 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5444 /* --------------------------------------------------------------------------
5445      When application is loaded, terminate event loop in ns_term_init
5446    -------------------------------------------------------------------------- */
5448   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5450 #ifdef NS_IMPL_GNUSTEP
5451   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5452 #endif
5453   [NSApp setServicesProvider: NSApp];
5455   [self antialiasThresholdDidChange:nil];
5456 #ifdef NS_IMPL_COCOA
5457   [[NSNotificationCenter defaultCenter]
5458     addObserver:self
5459        selector:@selector(antialiasThresholdDidChange:)
5460            name:NSAntialiasThresholdChangedNotification
5461          object:nil];
5462 #endif
5464   ns_send_appdefined (-2);
5467 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5469 #ifdef NS_IMPL_COCOA
5470   macfont_update_antialias_threshold ();
5471 #endif
5475 /* Termination sequences:
5476     C-x C-c:
5477     Cmd-Q:
5478     MenuBar | File | Exit:
5479     Select Quit from App menubar:
5480         -terminate
5481         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5482         ns_term_shutdown()
5484     Select Quit from Dock menu:
5485     Logout attempt:
5486         -appShouldTerminate
5487           Cancel -> Nothing else
5488           Accept ->
5490           -terminate
5491           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5492           ns_term_shutdown()
5496 - (void) terminate: (id)sender
5498   NSTRACE ("[EmacsApp terminate:]");
5500   struct frame *emacsframe = SELECTED_FRAME ();
5502   if (!emacs_event)
5503     return;
5505   emacs_event->kind = NS_NONKEY_EVENT;
5506   emacs_event->code = KEY_NS_POWER_OFF;
5507   emacs_event->arg = Qt; /* mark as non-key event */
5508   EV_TRAILER ((id)nil);
5511 static bool
5512 runAlertPanel(NSString *title,
5513               NSString *msgFormat,
5514               NSString *defaultButton,
5515               NSString *alternateButton)
5517 #if !defined (NS_IMPL_COCOA) || \
5518   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5519   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5520     == NSAlertDefaultReturn;
5521 #else
5522   NSAlert *alert = [[NSAlert alloc] init];
5523   [alert setAlertStyle: NSAlertStyleCritical];
5524   [alert setMessageText: msgFormat];
5525   [alert addButtonWithTitle: defaultButton];
5526   [alert addButtonWithTitle: alternateButton];
5527   NSInteger ret = [alert runModal];
5528   [alert release];
5529   return ret == NSAlertFirstButtonReturn;
5530 #endif
5534 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5536   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5538   bool ret;
5540   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5541     return NSTerminateNow;
5543   ret = runAlertPanel(ns_app_name,
5544                       @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5545                       @"Save Buffers and Exit", @"Cancel");
5547   return ret ? NSTerminateNow : NSTerminateCancel;
5550 static int
5551 not_in_argv (NSString *arg)
5553   int k;
5554   const char *a = [arg UTF8String];
5555   for (k = 1; k < initial_argc; ++k)
5556     if (strcmp (a, initial_argv[k]) == 0) return 0;
5557   return 1;
5560 /*   Notification from the Workspace to open a file */
5561 - (BOOL)application: sender openFile: (NSString *)file
5563   if (ns_do_open_file || not_in_argv (file))
5564     [ns_pending_files addObject: file];
5565   return YES;
5569 /*   Open a file as a temporary file */
5570 - (BOOL)application: sender openTempFile: (NSString *)file
5572   if (ns_do_open_file || not_in_argv (file))
5573     [ns_pending_files addObject: file];
5574   return YES;
5578 /*   Notification from the Workspace to open a file noninteractively (?) */
5579 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5581   if (ns_do_open_file || not_in_argv (file))
5582     [ns_pending_files addObject: file];
5583   return YES;
5586 /*   Notification from the Workspace to open multiple files */
5587 - (void)application: sender openFiles: (NSArray *)fileList
5589   NSEnumerator *files = [fileList objectEnumerator];
5590   NSString *file;
5591   /* Don't open files from the command line unconditionally,
5592      Cocoa parses the command line wrong, --option value tries to open value
5593      if --option is the last option.  */
5594   while ((file = [files nextObject]) != nil)
5595     if (ns_do_open_file || not_in_argv (file))
5596       [ns_pending_files addObject: file];
5598   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5603 /* Handle dock menu requests.  */
5604 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5606   return dockMenu;
5610 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5611 - (void)applicationWillBecomeActive: (NSNotification *)notification
5613   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5614   //ns_app_active=YES;
5617 - (void)applicationDidBecomeActive: (NSNotification *)notification
5619   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5621 #ifdef NS_IMPL_GNUSTEP
5622   if (! applicationDidFinishLaunchingCalled)
5623     [self applicationDidFinishLaunching:notification];
5624 #endif
5625   //ns_app_active=YES;
5627   ns_update_auto_hide_menu_bar ();
5628   // No constraining takes place when the application is not active.
5629   ns_constrain_all_frames ();
5631 - (void)applicationDidResignActive: (NSNotification *)notification
5633   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5635   //ns_app_active=NO;
5636   ns_send_appdefined (-1);
5641 /* ==========================================================================
5643     EmacsApp aux handlers for managing event loop
5645    ========================================================================== */
5648 - (void)timeout_handler: (NSTimer *)timedEntry
5649 /* --------------------------------------------------------------------------
5650      The timeout specified to ns_select has passed.
5651    -------------------------------------------------------------------------- */
5653   /*NSTRACE ("timeout_handler"); */
5654   ns_send_appdefined (-2);
5657 - (void)sendFromMainThread:(id)unused
5659   ns_send_appdefined (nextappdefined);
5662 - (void)fd_handler:(id)unused
5663 /* --------------------------------------------------------------------------
5664      Check data waiting on file descriptors and terminate if so
5665    -------------------------------------------------------------------------- */
5667   int result;
5668   int waiting = 1, nfds;
5669   char c;
5671   fd_set readfds, writefds, *wfds;
5672   struct timespec timeout, *tmo;
5673   NSAutoreleasePool *pool = nil;
5675   /* NSTRACE ("fd_handler"); */
5677   for (;;)
5678     {
5679       [pool release];
5680       pool = [[NSAutoreleasePool alloc] init];
5682       if (waiting)
5683         {
5684           fd_set fds;
5685           FD_ZERO (&fds);
5686           FD_SET (selfds[0], &fds);
5687           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5688           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5689             waiting = 0;
5690         }
5691       else
5692         {
5693           pthread_mutex_lock (&select_mutex);
5694           nfds = select_nfds;
5696           if (select_valid & SELECT_HAVE_READ)
5697             readfds = select_readfds;
5698           else
5699             FD_ZERO (&readfds);
5701           if (select_valid & SELECT_HAVE_WRITE)
5702             {
5703               writefds = select_writefds;
5704               wfds = &writefds;
5705             }
5706           else
5707             wfds = NULL;
5708           if (select_valid & SELECT_HAVE_TMO)
5709             {
5710               timeout = select_timeout;
5711               tmo = &timeout;
5712             }
5713           else
5714             tmo = NULL;
5716           pthread_mutex_unlock (&select_mutex);
5718           FD_SET (selfds[0], &readfds);
5719           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5721           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5723           if (result == 0)
5724             ns_send_appdefined (-2);
5725           else if (result > 0)
5726             {
5727               if (FD_ISSET (selfds[0], &readfds))
5728                 {
5729                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5730                     waiting = 1;
5731                 }
5732               else
5733                 {
5734                   pthread_mutex_lock (&select_mutex);
5735                   if (select_valid & SELECT_HAVE_READ)
5736                     select_readfds = readfds;
5737                   if (select_valid & SELECT_HAVE_WRITE)
5738                     select_writefds = writefds;
5739                   if (select_valid & SELECT_HAVE_TMO)
5740                     select_timeout = timeout;
5741                   pthread_mutex_unlock (&select_mutex);
5743                   ns_send_appdefined (result);
5744                 }
5745             }
5746           waiting = 1;
5747         }
5748     }
5753 /* ==========================================================================
5755     Service provision
5757    ========================================================================== */
5759 /* called from system: queue for next pass through event loop */
5760 - (void)requestService: (NSPasteboard *)pboard
5761               userData: (NSString *)userData
5762                  error: (NSString **)error
5764   [ns_pending_service_names addObject: userData];
5765   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5766       SSDATA (ns_string_from_pasteboard (pboard))]];
5770 /* called from ns_read_socket to clear queue */
5771 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5773   struct frame *emacsframe = SELECTED_FRAME ();
5774   NSEvent *theEvent = [NSApp currentEvent];
5776   NSTRACE ("[EmacsApp fulfillService:withArg:]");
5778   if (!emacs_event)
5779     return NO;
5781   emacs_event->kind = NS_NONKEY_EVENT;
5782   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5783   ns_input_spi_name = build_string ([name UTF8String]);
5784   ns_input_spi_arg = build_string ([arg UTF8String]);
5785   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5786   EV_TRAILER (theEvent);
5788   return YES;
5792 @end  /* EmacsApp */
5796 /* ==========================================================================
5798     EmacsView implementation
5800    ========================================================================== */
5803 @implementation EmacsView
5805 /* needed to inform when window closed from LISP */
5806 - (void) setWindowClosing: (BOOL)closing
5808   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5810   windowClosing = closing;
5814 - (void)dealloc
5816   NSTRACE ("[EmacsView dealloc]");
5817   [toolbar release];
5818   if (fs_state == FULLSCREEN_BOTH)
5819     [nonfs_window release];
5820   [super dealloc];
5824 /* called on font panel selection */
5825 - (void)changeFont: (id)sender
5827   NSEvent *e = [[self window] currentEvent];
5828   struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5829   struct font *font = face->font;
5830   id newFont;
5831   CGFloat size;
5832   NSFont *nsfont;
5834   NSTRACE ("[EmacsView changeFont:]");
5836   if (!emacs_event)
5837     return;
5839 #ifdef NS_IMPL_GNUSTEP
5840   nsfont = ((struct nsfont_info *)font)->nsfont;
5841 #endif
5842 #ifdef NS_IMPL_COCOA
5843   nsfont = (NSFont *) macfont_get_nsctfont (font);
5844 #endif
5846   if ((newFont = [sender convertFont: nsfont]))
5847     {
5848       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5850       emacs_event->kind = NS_NONKEY_EVENT;
5851       emacs_event->modifiers = 0;
5852       emacs_event->code = KEY_NS_CHANGE_FONT;
5854       size = [newFont pointSize];
5855       ns_input_fontsize = make_number (lrint (size));
5856       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5857       EV_TRAILER (e);
5858     }
5862 - (BOOL)acceptsFirstResponder
5864   NSTRACE ("[EmacsView acceptsFirstResponder]");
5865   return YES;
5869 - (void)resetCursorRects
5871   NSRect visible = [self visibleRect];
5872   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5873   NSTRACE ("[EmacsView resetCursorRects]");
5875   if (currentCursor == nil)
5876     currentCursor = [NSCursor arrowCursor];
5878   if (!NSIsEmptyRect (visible))
5879     [self addCursorRect: visible cursor: currentCursor];
5880   [currentCursor setOnMouseEntered: YES];
5885 /*****************************************************************************/
5886 /* Keyboard handling. */
5887 #define NS_KEYLOG 0
5889 - (void)keyDown: (NSEvent *)theEvent
5891   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5892   int code;
5893   unsigned fnKeysym = 0;
5894   static NSMutableArray *nsEvArray;
5895   int left_is_none;
5896   unsigned int flags = [theEvent modifierFlags];
5898   NSTRACE ("[EmacsView keyDown:]");
5900   /* Rhapsody and macOS give up and down events for the arrow keys */
5901   if (ns_fake_keydown == YES)
5902     ns_fake_keydown = NO;
5903   else if ([theEvent type] != NSEventTypeKeyDown)
5904     return;
5906   if (!emacs_event)
5907     return;
5909  if (![[self window] isKeyWindow]
5910      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5911      /* we must avoid an infinite loop here. */
5912      && (EmacsView *)[[theEvent window] delegate] != self)
5913    {
5914      /* XXX: There is an occasional condition in which, when Emacs display
5915          updates a different frame from the current one, and temporarily
5916          selects it, then processes some interrupt-driven input
5917          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5918          for some reason that window has its first responder set to the NSView
5919          most recently updated (I guess), which is not the correct one. */
5920      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5921      return;
5922    }
5924   if (nsEvArray == nil)
5925     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5927   [NSCursor setHiddenUntilMouseMoves: YES];
5929   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5930     {
5931       clear_mouse_face (hlinfo);
5932       hlinfo->mouse_face_hidden = 1;
5933     }
5935   if (!processingCompose)
5936     {
5937       /* When using screen sharing, no left or right information is sent,
5938          so use Left key in those cases.  */
5939       int is_left_key, is_right_key;
5941       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5942         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5944       /* (Carbon way: [theEvent keyCode]) */
5946       /* is it a "function key"? */
5947       /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
5948          flag set (this is probably a bug in the OS).
5949       */
5950       if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
5951         {
5952           fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
5953         }
5954       if (fnKeysym == 0)
5955         {
5956           fnKeysym = ns_convert_key (code);
5957         }
5959       if (fnKeysym)
5960         {
5961           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5962              because Emacs treats Delete and KP-Delete same (in simple.el). */
5963           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5964 #ifdef NS_IMPL_GNUSTEP
5965               /*  GNUstep uses incompatible keycodes, even for those that are
5966                   supposed to be hardware independent.  Just check for delete.
5967                   Keypad delete does not have keysym 0xFFFF.
5968                   See http://savannah.gnu.org/bugs/?25395
5969               */
5970               || (fnKeysym == 0xFFFF && code == 127)
5971 #endif
5972             )
5973             code = 0xFF08; /* backspace */
5974           else
5975             code = fnKeysym;
5976         }
5978       /* are there modifiers? */
5979       emacs_event->modifiers = 0;
5981       if (flags & NSEventModifierFlagHelp)
5982           emacs_event->modifiers |= hyper_modifier;
5984       if (flags & NSEventModifierFlagShift)
5985         emacs_event->modifiers |= shift_modifier;
5987       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5988       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5989         || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
5991       if (is_right_key)
5992         emacs_event->modifiers |= parse_solitary_modifier
5993           (EQ (ns_right_command_modifier, Qleft)
5994            ? ns_command_modifier
5995            : ns_right_command_modifier);
5997       if (is_left_key)
5998         {
5999           emacs_event->modifiers |= parse_solitary_modifier
6000             (ns_command_modifier);
6002           /* if super (default), take input manager's word so things like
6003              dvorak / qwerty layout work */
6004           if (EQ (ns_command_modifier, Qsuper)
6005               && !fnKeysym
6006               && [[theEvent characters] length] != 0)
6007             {
6008               /* XXX: the code we get will be unshifted, so if we have
6009                  a shift modifier, must convert ourselves */
6010               if (!(flags & NSEventModifierFlagShift))
6011                 code = [[theEvent characters] characterAtIndex: 0];
6012 #if 0
6013               /* this is ugly and also requires linking w/Carbon framework
6014                  (for LMGetKbdType) so for now leave this rare (?) case
6015                  undealt with.. in future look into CGEvent methods */
6016               else
6017                 {
6018                   long smv = GetScriptManagerVariable (smKeyScript);
6019                   Handle uchrHandle = GetResource
6020                     ('uchr', GetScriptVariable (smv, smScriptKeys));
6021                   UInt32 dummy = 0;
6022                   UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6023                                  [[theEvent characters] characterAtIndex: 0],
6024                                  kUCKeyActionDisplay,
6025                                  (flags & ~NSEventModifierFlagCommand) >> 8,
6026                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6027                                  &dummy, 1, &dummy, &code);
6028                   code &= 0xFF;
6029                 }
6030 #endif
6031             }
6032         }
6034       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6035       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6036         || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6038       if (is_right_key)
6039           emacs_event->modifiers |= parse_solitary_modifier
6040               (EQ (ns_right_control_modifier, Qleft)
6041                ? ns_control_modifier
6042                : ns_right_control_modifier);
6044       if (is_left_key)
6045         emacs_event->modifiers |= parse_solitary_modifier
6046           (ns_control_modifier);
6048       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6049           emacs_event->modifiers |=
6050             parse_solitary_modifier (ns_function_modifier);
6052       left_is_none = NILP (ns_alternate_modifier)
6053         || EQ (ns_alternate_modifier, Qnone);
6055       is_right_key = (flags & NSRightAlternateKeyMask)
6056         == NSRightAlternateKeyMask;
6057       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6058         || (! is_right_key
6059             && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6061       if (is_right_key)
6062         {
6063           if ((NILP (ns_right_alternate_modifier)
6064                || EQ (ns_right_alternate_modifier, Qnone)
6065                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6066               && !fnKeysym)
6067             {   /* accept pre-interp alt comb */
6068               if ([[theEvent characters] length] > 0)
6069                 code = [[theEvent characters] characterAtIndex: 0];
6070               /*HACK: clear lone shift modifier to stop next if from firing */
6071               if (emacs_event->modifiers == shift_modifier)
6072                 emacs_event->modifiers = 0;
6073             }
6074           else
6075             emacs_event->modifiers |= parse_solitary_modifier
6076               (EQ (ns_right_alternate_modifier, Qleft)
6077                ? ns_alternate_modifier
6078                : ns_right_alternate_modifier);
6079         }
6081       if (is_left_key) /* default = meta */
6082         {
6083           if (left_is_none && !fnKeysym)
6084             {   /* accept pre-interp alt comb */
6085               if ([[theEvent characters] length] > 0)
6086                 code = [[theEvent characters] characterAtIndex: 0];
6087               /*HACK: clear lone shift modifier to stop next if from firing */
6088               if (emacs_event->modifiers == shift_modifier)
6089                 emacs_event->modifiers = 0;
6090             }
6091           else
6092               emacs_event->modifiers |=
6093                 parse_solitary_modifier (ns_alternate_modifier);
6094         }
6096   if (NS_KEYLOG)
6097     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6098              (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6100       /* if it was a function key or had modifiers, pass it directly to emacs */
6101       if (fnKeysym || (emacs_event->modifiers
6102                        && (emacs_event->modifiers != shift_modifier)
6103                        && [[theEvent charactersIgnoringModifiers] length] > 0))
6104 /*[[theEvent characters] length] */
6105         {
6106           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6107           if (code < 0x20)
6108             code |= (1<<28)|(3<<16);
6109           else if (code == 0x7f)
6110             code |= (1<<28)|(3<<16);
6111           else if (!fnKeysym)
6112             emacs_event->kind = code > 0xFF
6113               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6115           emacs_event->code = code;
6116           EV_TRAILER (theEvent);
6117           processingCompose = NO;
6118           return;
6119         }
6120     }
6123   if (NS_KEYLOG && !processingCompose)
6124     fprintf (stderr, "keyDown: Begin compose sequence.\n");
6126   processingCompose = YES;
6127   [nsEvArray addObject: theEvent];
6128   [self interpretKeyEvents: nsEvArray];
6129   [nsEvArray removeObject: theEvent];
6133 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6136 /* <NSTextInput>: called when done composing;
6137    NOTE: also called when we delete over working text, followed immed.
6138          by doCommandBySelector: deleteBackward: */
6139 - (void)insertText: (id)aString
6141   int code;
6142   int len = [(NSString *)aString length];
6143   int i;
6145   NSTRACE ("[EmacsView insertText:]");
6147   if (NS_KEYLOG)
6148     NSLog (@"insertText '%@'\tlen = %d", aString, len);
6149   processingCompose = NO;
6151   if (!emacs_event)
6152     return;
6154   /* first, clear any working text */
6155   if (workingText != nil)
6156     [self deleteWorkingText];
6158   /* now insert the string as keystrokes */
6159   for (i =0; i<len; i++)
6160     {
6161       code = [aString characterAtIndex: i];
6162       /* TODO: still need this? */
6163       if (code == 0x2DC)
6164         code = '~'; /* 0x7E */
6165       if (code != 32) /* Space */
6166         emacs_event->modifiers = 0;
6167       emacs_event->kind
6168         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6169       emacs_event->code = code;
6170       EV_TRAILER ((id)nil);
6171     }
6175 /* <NSTextInput>: inserts display of composing characters */
6176 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6178   NSString *str = [aString respondsToSelector: @selector (string)] ?
6179     [aString string] : aString;
6181   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6183   if (NS_KEYLOG)
6184     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6185            str, (unsigned long)[str length],
6186            (unsigned long)selRange.length,
6187            (unsigned long)selRange.location);
6189   if (workingText != nil)
6190     [self deleteWorkingText];
6191   if ([str length] == 0)
6192     return;
6194   if (!emacs_event)
6195     return;
6197   processingCompose = YES;
6198   workingText = [str copy];
6199   ns_working_text = build_string ([workingText UTF8String]);
6201   emacs_event->kind = NS_TEXT_EVENT;
6202   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6203   EV_TRAILER ((id)nil);
6207 /* delete display of composing characters [not in <NSTextInput>] */
6208 - (void)deleteWorkingText
6210   NSTRACE ("[EmacsView deleteWorkingText]");
6212   if (workingText == nil)
6213     return;
6214   if (NS_KEYLOG)
6215     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6216   [workingText release];
6217   workingText = nil;
6218   processingCompose = NO;
6220   if (!emacs_event)
6221     return;
6223   emacs_event->kind = NS_TEXT_EVENT;
6224   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6225   EV_TRAILER ((id)nil);
6229 - (BOOL)hasMarkedText
6231   NSTRACE ("[EmacsView hasMarkedText]");
6233   return workingText != nil;
6237 - (NSRange)markedRange
6239   NSTRACE ("[EmacsView markedRange]");
6241   NSRange rng = workingText != nil
6242     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6243   if (NS_KEYLOG)
6244     NSLog (@"markedRange request");
6245   return rng;
6249 - (void)unmarkText
6251   NSTRACE ("[EmacsView unmarkText]");
6253   if (NS_KEYLOG)
6254     NSLog (@"unmark (accept) text");
6255   [self deleteWorkingText];
6256   processingCompose = NO;
6260 /* used to position char selection windows, etc. */
6261 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6263   NSRect rect;
6264   NSPoint pt;
6265   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6267   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6269   if (NS_KEYLOG)
6270     NSLog (@"firstRectForCharRange request");
6272   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6273   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6274   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6275   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6276                                        +FRAME_LINE_HEIGHT (emacsframe));
6278   pt = [self convertPoint: pt toView: nil];
6279 #if !defined (NS_IMPL_COCOA) || \
6280   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
6281   pt = [[self window] convertBaseToScreen: pt];
6282   rect.origin = pt;
6283 #else
6284   rect.origin = pt;
6285   rect = [[self window] convertRectToScreen: rect];
6286 #endif
6287   return rect;
6291 - (NSInteger)conversationIdentifier
6293   return (NSInteger)self;
6297 - (void)doCommandBySelector: (SEL)aSelector
6299   NSTRACE ("[EmacsView doCommandBySelector:]");
6301   if (NS_KEYLOG)
6302     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6304   processingCompose = NO;
6305   if (aSelector == @selector (deleteBackward:))
6306     {
6307       /* happens when user backspaces over an ongoing composition:
6308          throw a 'delete' into the event queue */
6309       if (!emacs_event)
6310         return;
6311       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6312       emacs_event->code = 0xFF08;
6313       EV_TRAILER ((id)nil);
6314     }
6317 - (NSArray *)validAttributesForMarkedText
6319   static NSArray *arr = nil;
6320   if (arr == nil) arr = [NSArray new];
6321  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6322   return arr;
6325 - (NSRange)selectedRange
6327   if (NS_KEYLOG)
6328     NSLog (@"selectedRange request");
6329   return NSMakeRange (NSNotFound, 0);
6332 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6333     GNUSTEP_GUI_MINOR_VERSION > 22
6334 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6335 #else
6336 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6337 #endif
6339   if (NS_KEYLOG)
6340     NSLog (@"characterIndexForPoint request");
6341   return 0;
6344 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6346   static NSAttributedString *str = nil;
6347   if (str == nil) str = [NSAttributedString new];
6348   if (NS_KEYLOG)
6349     NSLog (@"attributedSubstringFromRange request");
6350   return str;
6353 /* End <NSTextInput> impl. */
6354 /*****************************************************************************/
6357 /* This is what happens when the user presses a mouse button.  */
6358 - (void)mouseDown: (NSEvent *)theEvent
6360   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6361   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6363   NSTRACE ("[EmacsView mouseDown:]");
6365   [self deleteWorkingText];
6367   if (!emacs_event)
6368     return;
6370   dpyinfo->last_mouse_frame = emacsframe;
6371   /* appears to be needed to prevent spurious movement events generated on
6372      button clicks */
6373   emacsframe->mouse_moved = 0;
6375   if ([theEvent type] == NSEventTypeScrollWheel)
6376     {
6377       CGFloat delta = [theEvent deltaY];
6378       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6379       if (delta == 0)
6380         {
6381           delta = [theEvent deltaX];
6382           if (delta == 0)
6383             {
6384               NSTRACE_MSG ("deltaIsZero");
6385               return;
6386             }
6387           emacs_event->kind = HORIZ_WHEEL_EVENT;
6388         }
6389       else
6390         emacs_event->kind = WHEEL_EVENT;
6392       emacs_event->code = 0;
6393       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6394         ((delta > 0) ? up_modifier : down_modifier);
6395     }
6396   else
6397     {
6398       emacs_event->kind = MOUSE_CLICK_EVENT;
6399       emacs_event->code = EV_BUTTON (theEvent);
6400       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6401                              | EV_UDMODIFIERS (theEvent);
6402     }
6403   XSETINT (emacs_event->x, lrint (p.x));
6404   XSETINT (emacs_event->y, lrint (p.y));
6405   EV_TRAILER (theEvent);
6409 - (void)rightMouseDown: (NSEvent *)theEvent
6411   NSTRACE ("[EmacsView rightMouseDown:]");
6412   [self mouseDown: theEvent];
6416 - (void)otherMouseDown: (NSEvent *)theEvent
6418   NSTRACE ("[EmacsView otherMouseDown:]");
6419   [self mouseDown: theEvent];
6423 - (void)mouseUp: (NSEvent *)theEvent
6425   NSTRACE ("[EmacsView mouseUp:]");
6426   [self mouseDown: theEvent];
6430 - (void)rightMouseUp: (NSEvent *)theEvent
6432   NSTRACE ("[EmacsView rightMouseUp:]");
6433   [self mouseDown: theEvent];
6437 - (void)otherMouseUp: (NSEvent *)theEvent
6439   NSTRACE ("[EmacsView otherMouseUp:]");
6440   [self mouseDown: theEvent];
6444 - (void) scrollWheel: (NSEvent *)theEvent
6446   NSTRACE ("[EmacsView scrollWheel:]");
6447   [self mouseDown: theEvent];
6451 /* Tell emacs the mouse has moved. */
6452 - (void)mouseMoved: (NSEvent *)e
6454   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6455   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6456   Lisp_Object frame;
6457   NSPoint pt;
6459   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6461   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6462   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6463   dpyinfo->last_mouse_motion_x = pt.x;
6464   dpyinfo->last_mouse_motion_y = pt.y;
6466   /* update any mouse face */
6467   if (hlinfo->mouse_face_hidden)
6468     {
6469       hlinfo->mouse_face_hidden = 0;
6470       clear_mouse_face (hlinfo);
6471     }
6473   /* tooltip handling */
6474   previous_help_echo_string = help_echo_string;
6475   help_echo_string = Qnil;
6477   if (!NILP (Vmouse_autoselect_window))
6478     {
6479       NSTRACE_MSG ("mouse_autoselect_window");
6480       static Lisp_Object last_mouse_window;
6481       Lisp_Object window
6482         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6484       if (WINDOWP (window)
6485           && !EQ (window, last_mouse_window)
6486           && !EQ (window, selected_window)
6487           && (!NILP (focus_follows_mouse)
6488               || (EQ (XWINDOW (window)->frame,
6489                       XWINDOW (selected_window)->frame))))
6490         {
6491           NSTRACE_MSG ("in_window");
6492           emacs_event->kind = SELECT_WINDOW_EVENT;
6493           emacs_event->frame_or_window = window;
6494           EV_TRAILER2 (e);
6495         }
6496       /* Remember the last window where we saw the mouse.  */
6497       last_mouse_window = window;
6498     }
6500   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6501     help_echo_string = previous_help_echo_string;
6503   XSETFRAME (frame, emacsframe);
6504   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6505     {
6506       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6507          (note_mouse_highlight), which is called through the
6508          note_mouse_movement () call above */
6509       any_help_event_p = YES;
6510       gen_help_event (help_echo_string, frame, help_echo_window,
6511                       help_echo_object, help_echo_pos);
6512     }
6514   if (emacsframe->mouse_moved && send_appdefined)
6515     ns_send_appdefined (-1);
6519 - (void)mouseDragged: (NSEvent *)e
6521   NSTRACE ("[EmacsView mouseDragged:]");
6522   [self mouseMoved: e];
6526 - (void)rightMouseDragged: (NSEvent *)e
6528   NSTRACE ("[EmacsView rightMouseDragged:]");
6529   [self mouseMoved: e];
6533 - (void)otherMouseDragged: (NSEvent *)e
6535   NSTRACE ("[EmacsView otherMouseDragged:]");
6536   [self mouseMoved: e];
6540 - (BOOL)windowShouldClose: (id)sender
6542   NSEvent *e =[[self window] currentEvent];
6544   NSTRACE ("[EmacsView windowShouldClose:]");
6545   windowClosing = YES;
6546   if (!emacs_event)
6547     return NO;
6548   emacs_event->kind = DELETE_WINDOW_EVENT;
6549   emacs_event->modifiers = 0;
6550   emacs_event->code = 0;
6551   EV_TRAILER (e);
6552   /* Don't close this window, let this be done from lisp code.  */
6553   return NO;
6556 - (void) updateFrameSize: (BOOL) delay
6558   NSWindow *window = [self window];
6559   NSRect wr = [window frame];
6560   int extra = 0;
6561   int oldc = cols, oldr = rows;
6562   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6563   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6564   int neww, newh;
6566   NSTRACE ("[EmacsView updateFrameSize:]");
6567   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6568   NSTRACE_RECT ("Original frame", wr);
6569   NSTRACE_MSG  ("Original columns: %d", cols);
6570   NSTRACE_MSG  ("Original rows: %d", rows);
6572   if (! [self isFullscreen])
6573     {
6574 #ifdef NS_IMPL_GNUSTEP
6575       // GNUstep does not always update the tool bar height.  Force it.
6576       if (toolbar && [toolbar isVisible])
6577           update_frame_tool_bar (emacsframe);
6578 #endif
6580       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6581         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6582     }
6584   if (wait_for_tool_bar)
6585     {
6586       /* The toolbar height is always 0 in fullscreen, so don't wait
6587          for it to become available. */
6588       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6589           && ! [self isFullscreen])
6590         {
6591           NSTRACE_MSG ("Waiting for toolbar");
6592           return;
6593         }
6594       wait_for_tool_bar = NO;
6595     }
6597   neww = (int)wr.size.width - emacsframe->border_width;
6598   newh = (int)wr.size.height - extra;
6600   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6601   NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6602   NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6604   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6605   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6607   if (cols < MINWIDTH)
6608     cols = MINWIDTH;
6610   if (rows < MINHEIGHT)
6611     rows = MINHEIGHT;
6613   NSTRACE_MSG ("New columns: %d", cols);
6614   NSTRACE_MSG ("New rows: %d", rows);
6616   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6617     {
6618       NSView *view = FRAME_NS_VIEW (emacsframe);
6620       change_frame_size (emacsframe,
6621                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6622                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6623                          0, delay, 0, 1);
6624       SET_FRAME_GARBAGED (emacsframe);
6625       cancel_mouse_face (emacsframe);
6627       /* The next two lines appear to be setting the frame to the same
6628          size as it already is.  Why are they there? */
6629       // wr = NSMakeRect (0, 0, neww, newh);
6631       // [view setFrame: wr];
6633       // to do: consider using [NSNotificationCenter postNotificationName:].
6634       [self windowDidMove: // Update top/left.
6635               [NSNotification notificationWithName:NSWindowDidMoveNotification
6636                                             object:[view window]]];
6637     }
6638   else
6639     {
6640       NSTRACE_MSG ("No change");
6641     }
6644 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6645 /* normalize frame to gridded text size */
6647   int extra = 0;
6649   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6650            NSTRACE_ARG_SIZE (frameSize));
6651   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6652   NSTRACE_FSTYPE ("fs_state", fs_state);
6654   if (fs_state == FULLSCREEN_MAXIMIZED
6655       && (maximized_width != (int)frameSize.width
6656           || maximized_height != (int)frameSize.height))
6657     [self setFSValue: FULLSCREEN_NONE];
6658   else if (fs_state == FULLSCREEN_WIDTH
6659            && maximized_width != (int)frameSize.width)
6660     [self setFSValue: FULLSCREEN_NONE];
6661   else if (fs_state == FULLSCREEN_HEIGHT
6662            && maximized_height != (int)frameSize.height)
6663     [self setFSValue: FULLSCREEN_NONE];
6665   if (fs_state == FULLSCREEN_NONE)
6666     maximized_width = maximized_height = -1;
6668   if (! [self isFullscreen])
6669     {
6670       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6671         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6672     }
6674   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6675   if (cols < MINWIDTH)
6676     cols = MINWIDTH;
6678   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6679                                            frameSize.height - extra);
6680   if (rows < MINHEIGHT)
6681     rows = MINHEIGHT;
6682 #ifdef NS_IMPL_COCOA
6683   {
6684     /* this sets window title to have size in it; the wm does this under GS */
6685     NSRect r = [[self window] frame];
6686     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6687       {
6688         if (old_title != 0)
6689           {
6690             xfree (old_title);
6691             old_title = 0;
6692           }
6693       }
6694     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6695              && [[self window] title] != NULL)
6696       {
6697         char *size_title;
6698         NSWindow *window = [self window];
6699         if (old_title == 0)
6700           {
6701             char *t = strdup ([[[self window] title] UTF8String]);
6702             char *pos = strstr (t, "  â€”  ");
6703             if (pos)
6704               *pos = '\0';
6705             old_title = t;
6706           }
6707         size_title = xmalloc (strlen (old_title) + 40);
6708         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6709         [window setTitle: [NSString stringWithUTF8String: size_title]];
6710         [window display];
6711         xfree (size_title);
6712       }
6713   }
6714 #endif /* NS_IMPL_COCOA */
6716   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6718   /* Restrict the new size to the text gird.
6720      Don't restrict the width if the user only adjusted the height, and
6721      vice versa.  (Without this, the frame would shrink, and move
6722      slightly, if the window was resized by dragging one of its
6723      borders.) */
6724   if (!frame_resize_pixelwise)
6725     {
6726       NSRect r = [[self window] frame];
6728       if (r.size.width != frameSize.width)
6729         {
6730           frameSize.width =
6731             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6732         }
6734       if (r.size.height != frameSize.height)
6735         {
6736           frameSize.height =
6737             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6738         }
6739     }
6741   NSTRACE_RETURN_SIZE (frameSize);
6743   return frameSize;
6747 - (void)windowDidResize: (NSNotification *)notification
6749   NSTRACE ("[EmacsView windowDidResize:]");
6750   if (!FRAME_LIVE_P (emacsframe))
6751     {
6752       NSTRACE_MSG ("Ignored (frame dead)");
6753       return;
6754     }
6755   if (emacsframe->output_data.ns->in_animation)
6756     {
6757       NSTRACE_MSG ("Ignored (in animation)");
6758       return;
6759     }
6761   if (! [self fsIsNative])
6762     {
6763       NSWindow *theWindow = [notification object];
6764       /* We can get notification on the non-FS window when in
6765          fullscreen mode.  */
6766       if ([self window] != theWindow) return;
6767     }
6769   NSTRACE_RECT ("frame", [[notification object] frame]);
6771 #ifdef NS_IMPL_GNUSTEP
6772   NSWindow *theWindow = [notification object];
6774    /* In GNUstep, at least currently, it's possible to get a didResize
6775       without getting a willResize.. therefore we need to act as if we got
6776       the willResize now */
6777   NSSize sz = [theWindow frame].size;
6778   sz = [self windowWillResize: theWindow toSize: sz];
6779 #endif /* NS_IMPL_GNUSTEP */
6781   if (cols > 0 && rows > 0)
6782     {
6783       [self updateFrameSize: YES];
6784     }
6786   ns_send_appdefined (-1);
6789 #ifdef NS_IMPL_COCOA
6790 - (void)viewDidEndLiveResize
6792   NSTRACE ("[EmacsView viewDidEndLiveResize]");
6794   [super viewDidEndLiveResize];
6795   if (old_title != 0)
6796     {
6797       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6798       xfree (old_title);
6799       old_title = 0;
6800     }
6801   maximizing_resize = NO;
6803 #endif /* NS_IMPL_COCOA */
6806 - (void)windowDidBecomeKey: (NSNotification *)notification
6807 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6809   [self windowDidBecomeKey];
6813 - (void)windowDidBecomeKey      /* for direct calls */
6815   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6816   struct frame *old_focus = dpyinfo->x_focus_frame;
6818   NSTRACE ("[EmacsView windowDidBecomeKey]");
6820   if (emacsframe != old_focus)
6821     dpyinfo->x_focus_frame = emacsframe;
6823   ns_frame_rehighlight (emacsframe);
6825   if (emacs_event)
6826     {
6827       emacs_event->kind = FOCUS_IN_EVENT;
6828       EV_TRAILER ((id)nil);
6829     }
6833 - (void)windowDidResignKey: (NSNotification *)notification
6834 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6836   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6837   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6838   NSTRACE ("[EmacsView windowDidResignKey:]");
6840   if (is_focus_frame)
6841     dpyinfo->x_focus_frame = 0;
6843   emacsframe->mouse_moved = 0;
6844   ns_frame_rehighlight (emacsframe);
6846   /* FIXME: for some reason needed on second and subsequent clicks away
6847             from sole-frame Emacs to get hollow box to show */
6848   if (!windowClosing && [[self window] isVisible] == YES)
6849     {
6850       x_update_cursor (emacsframe, 1);
6851       x_set_frame_alpha (emacsframe);
6852     }
6854   if (any_help_event_p)
6855     {
6856       Lisp_Object frame;
6857       XSETFRAME (frame, emacsframe);
6858       help_echo_string = Qnil;
6859       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6860     }
6862   if (emacs_event && is_focus_frame)
6863     {
6864       [self deleteWorkingText];
6865       emacs_event->kind = FOCUS_OUT_EVENT;
6866       EV_TRAILER ((id)nil);
6867     }
6871 - (void)windowWillMiniaturize: sender
6873   NSTRACE ("[EmacsView windowWillMiniaturize:]");
6877 - (void)setFrame:(NSRect)frameRect
6879   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6880            NSTRACE_ARG_RECT (frameRect));
6882   [super setFrame:(NSRect)frameRect];
6886 - (BOOL)isFlipped
6888   return YES;
6892 - (BOOL)isOpaque
6894   return NO;
6898 - (void)createToolbar: (struct frame *)f
6900   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
6901   NSWindow *window = [view window];
6903   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6904                    [NSString stringWithFormat: @"Emacs Frame %d",
6905                              ns_window_num]];
6906   [toolbar setVisible: NO];
6907   [window setToolbar: toolbar];
6909   /* Don't set frame garbaged until tool bar is up to date?
6910      This avoids an extra clear and redraw (flicker) at frame creation.  */
6911   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6912   else wait_for_tool_bar = NO;
6915 #ifdef NS_IMPL_COCOA
6916   {
6917     NSButton *toggleButton;
6918     toggleButton = [window standardWindowButton: NSWindowToolbarButton];
6919     [toggleButton setTarget: self];
6920     [toggleButton setAction: @selector (toggleToolbar: )];
6921   }
6922 #endif
6926 - (instancetype) initFrameFromEmacs: (struct frame *)f
6928   NSRect r, wr;
6929   Lisp_Object tem;
6930   NSWindow *win;
6931   NSColor *col;
6932   NSString *name;
6934   NSTRACE ("[EmacsView initFrameFromEmacs:]");
6935   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6937   windowClosing = NO;
6938   processingCompose = NO;
6939   scrollbarsNeedingUpdate = 0;
6940   fs_state = FULLSCREEN_NONE;
6941   fs_before_fs = next_maximized = -1;
6942 #ifdef HAVE_NATIVE_FS
6943   fs_is_native = ns_use_native_fullscreen;
6944 #else
6945   fs_is_native = NO;
6946 #endif
6947   maximized_width = maximized_height = -1;
6948   nonfs_window = nil;
6950   ns_userRect = NSMakeRect (0, 0, 0, 0);
6951   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6952                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6953   [self initWithFrame: r];
6954   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6956   FRAME_NS_VIEW (f) = self;
6957   emacsframe = f;
6958 #ifdef NS_IMPL_COCOA
6959   old_title = 0;
6960   maximizing_resize = NO;
6961 #endif
6963   win = [[EmacsWindow alloc]
6964             initWithContentRect: r
6965                       styleMask: (FRAME_UNDECORATED (f)
6966                                   ? FRAME_UNDECORATED_FLAGS
6967                                   : FRAME_DECORATED_FLAGS
6968 #ifdef NS_IMPL_COCOA
6969                                   | NSWindowStyleMaskResizable
6970                                   | NSWindowStyleMaskMiniaturizable
6971                                   | NSWindowStyleMaskClosable
6972 #endif
6973                                   )
6974                         backing: NSBackingStoreBuffered
6975                           defer: YES];
6977 #ifdef HAVE_NATIVE_FS
6978     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6979 #endif
6981   wr = [win frame];
6982   bwidth = f->border_width = wr.size.width - r.size.width;
6984   [win setAcceptsMouseMovedEvents: YES];
6985   [win setDelegate: self];
6986 #if !defined (NS_IMPL_COCOA) || \
6987   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6988   [win useOptimizedDrawing: YES];
6989 #endif
6991   [[win contentView] addSubview: self];
6993   if (ns_drag_types)
6994     [self registerForDraggedTypes: ns_drag_types];
6996   tem = f->name;
6997   name = [NSString stringWithUTF8String:
6998                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6999   [win setTitle: name];
7001   /* toolbar support */
7002   if (! FRAME_UNDECORATED (f))
7003     [self createToolbar: f];
7005   tem = f->icon_name;
7006   if (!NILP (tem))
7007     [win setMiniwindowTitle:
7008            [NSString stringWithUTF8String: SSDATA (tem)]];
7010   if (FRAME_PARENT_FRAME (f) != NULL)
7011     {
7012       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7013       [parent addChildWindow: win
7014                      ordered: NSWindowAbove];
7015     }
7017   if (FRAME_Z_GROUP (f) != z_group_none)
7018       win.level = NSNormalWindowLevel
7019         + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7021   {
7022     NSScreen *screen = [win screen];
7024     if (screen != 0)
7025       {
7026         NSPoint pt = NSMakePoint
7027           (IN_BOUND (-SCREENMAX, f->left_pos
7028                      + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7029            IN_BOUND (-SCREENMAX,
7030                      NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7031                      SCREENMAX));
7033         [win setFrameTopLeftPoint: pt];
7035         NSTRACE_RECT ("new frame", [win frame]);
7036       }
7037   }
7039   [win makeFirstResponder: self];
7041   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7042                                  (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7043                                  emacsframe);
7044   [win setBackgroundColor: col];
7045   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7046     [win setOpaque: NO];
7048 #if !defined (NS_IMPL_COCOA) || \
7049   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7050   [self allocateGState];
7051 #endif
7052   [NSApp registerServicesMenuSendTypes: ns_send_types
7053                            returnTypes: [NSArray array]];
7055   /* macOS Sierra automatically enables tabbed windows.  We can't
7056      allow this to be enabled until it's available on a Free system.
7057      Currently it only happens by accident and is buggy anyway. */
7058 #if defined (NS_IMPL_COCOA) && \
7059   MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
7060   [win setTabbingMode: NSWindowTabbingModeDisallowed];
7061 #endif
7063   ns_window_num++;
7064   return self;
7068 - (void)windowDidMove: sender
7070   NSWindow *win = [self window];
7071   NSRect r = [win frame];
7072   NSArray *screens = [NSScreen screens];
7073   NSScreen *screen = [screens objectAtIndex: 0];
7075   NSTRACE ("[EmacsView windowDidMove:]");
7077   if (!emacsframe->output_data.ns)
7078     return;
7079   if (screen != nil)
7080     {
7081       emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7082       emacsframe->top_pos =
7083         NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7085       if (emacs_event)
7086         {
7087           emacs_event->kind = MOVE_FRAME_EVENT;
7088           EV_TRAILER ((id)nil);
7089         }
7090     }
7094 /* Called AFTER method below, but before our windowWillResize call there leads
7095    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
7096    location so set_window_size moves the frame. */
7097 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7099   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7100             NSTRACE_FMT_RETURN "YES"),
7101            NSTRACE_ARG_RECT (newFrame));
7103   emacsframe->output_data.ns->zooming = 1;
7104   return YES;
7108 /* Override to do something slightly nonstandard, but nice.  First click on
7109    zoom button will zoom vertically.  Second will zoom completely.  Third
7110    returns to original. */
7111 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7112                         defaultFrame:(NSRect)defaultFrame
7114   // TODO: Rename to "currentFrame" and assign "result" properly in
7115   // all paths.
7116   NSRect result = [sender frame];
7118   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7119             NSTRACE_FMT_RECT "]"),
7120            NSTRACE_ARG_RECT (defaultFrame));
7121   NSTRACE_FSTYPE ("fs_state", fs_state);
7122   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7123   NSTRACE_FSTYPE ("next_maximized", next_maximized);
7124   NSTRACE_RECT   ("ns_userRect", ns_userRect);
7125   NSTRACE_RECT   ("[sender frame]", [sender frame]);
7127   if (fs_before_fs != -1) /* Entering fullscreen */
7128     {
7129       NSTRACE_MSG ("Entering fullscreen");
7130       result = defaultFrame;
7131     }
7132   else
7133     {
7134       // Save the window size and position (frame) before the resize.
7135       if (fs_state != FULLSCREEN_MAXIMIZED
7136           && fs_state != FULLSCREEN_WIDTH)
7137         {
7138           ns_userRect.size.width = result.size.width;
7139           ns_userRect.origin.x   = result.origin.x;
7140         }
7142       if (fs_state != FULLSCREEN_MAXIMIZED
7143           && fs_state != FULLSCREEN_HEIGHT)
7144         {
7145           ns_userRect.size.height = result.size.height;
7146           ns_userRect.origin.y    = result.origin.y;
7147         }
7149       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7151       if (next_maximized == FULLSCREEN_HEIGHT
7152           || (next_maximized == -1
7153               && abs ((int)(defaultFrame.size.height - result.size.height))
7154               > FRAME_LINE_HEIGHT (emacsframe)))
7155         {
7156           /* first click */
7157           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7158           maximized_height = result.size.height = defaultFrame.size.height;
7159           maximized_width = -1;
7160           result.origin.y = defaultFrame.origin.y;
7161           if (ns_userRect.size.height != 0)
7162             {
7163               result.origin.x = ns_userRect.origin.x;
7164               result.size.width = ns_userRect.size.width;
7165             }
7166           [self setFSValue: FULLSCREEN_HEIGHT];
7167 #ifdef NS_IMPL_COCOA
7168           maximizing_resize = YES;
7169 #endif
7170         }
7171       else if (next_maximized == FULLSCREEN_WIDTH)
7172         {
7173           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7174           maximized_width = result.size.width = defaultFrame.size.width;
7175           maximized_height = -1;
7176           result.origin.x = defaultFrame.origin.x;
7177           if (ns_userRect.size.width != 0)
7178             {
7179               result.origin.y = ns_userRect.origin.y;
7180               result.size.height = ns_userRect.size.height;
7181             }
7182           [self setFSValue: FULLSCREEN_WIDTH];
7183         }
7184       else if (next_maximized == FULLSCREEN_MAXIMIZED
7185                || (next_maximized == -1
7186                    && abs ((int)(defaultFrame.size.width - result.size.width))
7187                    > FRAME_COLUMN_WIDTH (emacsframe)))
7188         {
7189           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7191           result = defaultFrame;  /* second click */
7192           maximized_width = result.size.width;
7193           maximized_height = result.size.height;
7194           [self setFSValue: FULLSCREEN_MAXIMIZED];
7195 #ifdef NS_IMPL_COCOA
7196           maximizing_resize = YES;
7197 #endif
7198         }
7199       else
7200         {
7201           /* restore */
7202           NSTRACE_MSG ("Restore");
7203           result = ns_userRect.size.height ? ns_userRect : result;
7204           NSTRACE_RECT ("restore (2)", result);
7205           ns_userRect = NSMakeRect (0, 0, 0, 0);
7206 #ifdef NS_IMPL_COCOA
7207           maximizing_resize = fs_state != FULLSCREEN_NONE;
7208 #endif
7209           [self setFSValue: FULLSCREEN_NONE];
7210           maximized_width = maximized_height = -1;
7211         }
7212     }
7214   if (fs_before_fs == -1) next_maximized = -1;
7216   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
7217   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
7218   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
7219   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7221   [self windowWillResize: sender toSize: result.size];
7223   NSTRACE_RETURN_RECT (result);
7225   return result;
7229 - (void)windowDidDeminiaturize: sender
7231   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7232   if (!emacsframe->output_data.ns)
7233     return;
7235   SET_FRAME_ICONIFIED (emacsframe, 0);
7236   SET_FRAME_VISIBLE (emacsframe, 1);
7237   windows_or_buffers_changed = 63;
7239   if (emacs_event)
7240     {
7241       emacs_event->kind = DEICONIFY_EVENT;
7242       EV_TRAILER ((id)nil);
7243     }
7247 - (void)windowDidExpose: sender
7249   NSTRACE ("[EmacsView windowDidExpose:]");
7250   if (!emacsframe->output_data.ns)
7251     return;
7253   SET_FRAME_VISIBLE (emacsframe, 1);
7254   SET_FRAME_GARBAGED (emacsframe);
7256   if (send_appdefined)
7257     ns_send_appdefined (-1);
7261 - (void)windowDidMiniaturize: sender
7263   NSTRACE ("[EmacsView windowDidMiniaturize:]");
7264   if (!emacsframe->output_data.ns)
7265     return;
7267   SET_FRAME_ICONIFIED (emacsframe, 1);
7268   SET_FRAME_VISIBLE (emacsframe, 0);
7270   if (emacs_event)
7271     {
7272       emacs_event->kind = ICONIFY_EVENT;
7273       EV_TRAILER ((id)nil);
7274     }
7277 #ifdef HAVE_NATIVE_FS
7278 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7279       willUseFullScreenPresentationOptions:
7280   (NSApplicationPresentationOptions)proposedOptions
7282   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7284 #endif
7286 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7288   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7289   [self windowWillEnterFullScreen];
7291 - (void)windowWillEnterFullScreen /* provided for direct calls */
7293   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7294   fs_before_fs = fs_state;
7297 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7299   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7300   [self windowDidEnterFullScreen];
7303 - (void)windowDidEnterFullScreen /* provided for direct calls */
7305   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7306   [self setFSValue: FULLSCREEN_BOTH];
7307   if (! [self fsIsNative])
7308     {
7309       [self windowDidBecomeKey];
7310       [nonfs_window orderOut:self];
7311     }
7312   else
7313     {
7314       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7315 #ifdef NS_IMPL_COCOA
7316 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7317       unsigned val = (unsigned)[NSApp presentationOptions];
7319       // Mac OS X 10.7 bug fix, the menu won't appear without this.
7320       // val is non-zero on other macOS versions.
7321       if (val == 0)
7322         {
7323           NSApplicationPresentationOptions options
7324             = NSApplicationPresentationAutoHideDock
7325             | NSApplicationPresentationAutoHideMenuBar
7326             | NSApplicationPresentationFullScreen
7327             | NSApplicationPresentationAutoHideToolbar;
7329           [NSApp setPresentationOptions: options];
7330         }
7331 #endif
7332 #endif
7333       [toolbar setVisible:tbar_visible];
7334     }
7337 - (void)windowWillExitFullScreen:(NSNotification *)notification
7339   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7340   [self windowWillExitFullScreen];
7343 - (void)windowWillExitFullScreen /* provided for direct calls */
7345   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7346   if (!FRAME_LIVE_P (emacsframe))
7347     {
7348       NSTRACE_MSG ("Ignored (frame dead)");
7349       return;
7350     }
7351   if (next_maximized != -1)
7352     fs_before_fs = next_maximized;
7355 - (void)windowDidExitFullScreen:(NSNotification *)notification
7357   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7358   [self windowDidExitFullScreen];
7361 - (void)windowDidExitFullScreen /* provided for direct calls */
7363   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7364   if (!FRAME_LIVE_P (emacsframe))
7365     {
7366       NSTRACE_MSG ("Ignored (frame dead)");
7367       return;
7368     }
7369   [self setFSValue: fs_before_fs];
7370   fs_before_fs = -1;
7371 #ifdef HAVE_NATIVE_FS
7372   [self updateCollectionBehavior];
7373 #endif
7374   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7375     {
7376       [toolbar setVisible:YES];
7377       update_frame_tool_bar (emacsframe);
7378       [self updateFrameSize:YES];
7379       [[self window] display];
7380     }
7381   else
7382     [toolbar setVisible:NO];
7384   if (next_maximized != -1)
7385     [[self window] performZoom:self];
7388 - (BOOL)fsIsNative
7390   return fs_is_native;
7393 - (BOOL)isFullscreen
7395   BOOL res;
7397   if (! fs_is_native)
7398     {
7399       res = (nonfs_window != nil);
7400     }
7401   else
7402     {
7403 #ifdef HAVE_NATIVE_FS
7404       res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7405 #else
7406       res = NO;
7407 #endif
7408     }
7410   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7411            (int) res);
7413   return res;
7416 #ifdef HAVE_NATIVE_FS
7417 - (void)updateCollectionBehavior
7419   NSTRACE ("[EmacsView updateCollectionBehavior]");
7421   if (! [self isFullscreen])
7422     {
7423       NSWindow *win = [self window];
7424       NSWindowCollectionBehavior b = [win collectionBehavior];
7425       if (ns_use_native_fullscreen)
7426         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7427       else
7428         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7430       [win setCollectionBehavior: b];
7431       fs_is_native = ns_use_native_fullscreen;
7432     }
7434 #endif
7436 - (void)toggleFullScreen: (id)sender
7438   NSWindow *w, *fw;
7439   BOOL onFirstScreen;
7440   struct frame *f;
7441   NSRect r, wr;
7442   NSColor *col;
7444   NSTRACE ("[EmacsView toggleFullScreen:]");
7446   if (fs_is_native)
7447     {
7448 #ifdef HAVE_NATIVE_FS
7449       [[self window] toggleFullScreen:sender];
7450 #endif
7451       return;
7452     }
7454   w = [self window];
7455   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7456   f = emacsframe;
7457   wr = [w frame];
7458   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7459                                  (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7460                                  f);
7462   if (fs_state != FULLSCREEN_BOTH)
7463     {
7464       NSScreen *screen = [w screen];
7466 #if defined (NS_IMPL_COCOA) && \
7467   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7468       /* Hide ghost menu bar on secondary monitor? */
7469       if (! onFirstScreen)
7470         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7471 #endif
7472       /* Hide dock and menubar if we are on the primary screen.  */
7473       if (onFirstScreen)
7474         {
7475 #ifdef NS_IMPL_COCOA
7476           NSApplicationPresentationOptions options
7477             = NSApplicationPresentationAutoHideDock
7478             | NSApplicationPresentationAutoHideMenuBar;
7480           [NSApp setPresentationOptions: options];
7481 #else
7482           [NSMenu setMenuBarVisible:NO];
7483 #endif
7484         }
7486       fw = [[EmacsFSWindow alloc]
7487                        initWithContentRect:[w contentRectForFrameRect:wr]
7488                                  styleMask:NSWindowStyleMaskBorderless
7489                                    backing:NSBackingStoreBuffered
7490                                      defer:YES
7491                                     screen:screen];
7493       [fw setContentView:[w contentView]];
7494       [fw setTitle:[w title]];
7495       [fw setDelegate:self];
7496       [fw setAcceptsMouseMovedEvents: YES];
7497 #if !defined (NS_IMPL_COCOA) || \
7498   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7499       [fw useOptimizedDrawing: YES];
7500 #endif
7501       [fw setBackgroundColor: col];
7502       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7503         [fw setOpaque: NO];
7505       f->border_width = 0;
7507       nonfs_window = w;
7509       [self windowWillEnterFullScreen];
7510       [fw makeKeyAndOrderFront:NSApp];
7511       [fw makeFirstResponder:self];
7512       [w orderOut:self];
7513       r = [fw frameRectForContentRect:[screen frame]];
7514       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7515       [self windowDidEnterFullScreen];
7516       [fw display];
7517     }
7518   else
7519     {
7520       fw = w;
7521       w = nonfs_window;
7522       nonfs_window = nil;
7524       if (onFirstScreen)
7525         {
7526 #ifdef NS_IMPL_COCOA
7527           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7528 #else
7529           [NSMenu setMenuBarVisible:YES];
7530 #endif
7531         }
7533       [w setContentView:[fw contentView]];
7534       [w setBackgroundColor: col];
7535       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7536         [w setOpaque: NO];
7538       f->border_width = bwidth;
7540       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7542       [self windowWillExitFullScreen];
7543       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7544       [fw close];
7545       [w makeKeyAndOrderFront:NSApp];
7546       [self windowDidExitFullScreen];
7547       [self updateFrameSize:YES];
7548     }
7551 - (void)handleFS
7553   NSTRACE ("[EmacsView handleFS]");
7555   if (fs_state != emacsframe->want_fullscreen)
7556     {
7557       if (fs_state == FULLSCREEN_BOTH)
7558         {
7559           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7560           [self toggleFullScreen:self];
7561         }
7563       switch (emacsframe->want_fullscreen)
7564         {
7565         case FULLSCREEN_BOTH:
7566           NSTRACE_MSG ("FULLSCREEN_BOTH");
7567           [self toggleFullScreen:self];
7568           break;
7569         case FULLSCREEN_WIDTH:
7570           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7571           next_maximized = FULLSCREEN_WIDTH;
7572           if (fs_state != FULLSCREEN_BOTH)
7573             [[self window] performZoom:self];
7574           break;
7575         case FULLSCREEN_HEIGHT:
7576           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7577           next_maximized = FULLSCREEN_HEIGHT;
7578           if (fs_state != FULLSCREEN_BOTH)
7579             [[self window] performZoom:self];
7580           break;
7581         case FULLSCREEN_MAXIMIZED:
7582           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7583           next_maximized = FULLSCREEN_MAXIMIZED;
7584           if (fs_state != FULLSCREEN_BOTH)
7585             [[self window] performZoom:self];
7586           break;
7587         case FULLSCREEN_NONE:
7588           NSTRACE_MSG ("FULLSCREEN_NONE");
7589           if (fs_state != FULLSCREEN_BOTH)
7590             {
7591               next_maximized = FULLSCREEN_NONE;
7592               [[self window] performZoom:self];
7593             }
7594           break;
7595         }
7597       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7598     }
7602 - (void) setFSValue: (int)value
7604   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7605            NSTRACE_ARG_FSTYPE(value));
7607   Lisp_Object lval = Qnil;
7608   switch (value)
7609     {
7610     case FULLSCREEN_BOTH:
7611       lval = Qfullboth;
7612       break;
7613     case FULLSCREEN_WIDTH:
7614       lval = Qfullwidth;
7615       break;
7616     case FULLSCREEN_HEIGHT:
7617       lval = Qfullheight;
7618       break;
7619     case FULLSCREEN_MAXIMIZED:
7620       lval = Qmaximized;
7621       break;
7622     }
7623   store_frame_param (emacsframe, Qfullscreen, lval);
7624   fs_state = value;
7627 - (void)mouseEntered: (NSEvent *)theEvent
7629   NSTRACE ("[EmacsView mouseEntered:]");
7630   if (emacsframe)
7631     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7632       = EV_TIMESTAMP (theEvent);
7636 - (void)mouseExited: (NSEvent *)theEvent
7638   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7640   NSTRACE ("[EmacsView mouseExited:]");
7642   if (!hlinfo)
7643     return;
7645   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7646     = EV_TIMESTAMP (theEvent);
7648   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7649     {
7650       clear_mouse_face (hlinfo);
7651       hlinfo->mouse_face_mouse_frame = 0;
7652     }
7656 - (instancetype)menuDown: sender
7658   NSTRACE ("[EmacsView menuDown:]");
7659   if (context_menu_value == -1)
7660     context_menu_value = [sender tag];
7661   else
7662     {
7663       NSInteger tag = [sender tag];
7664       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7665                                     emacsframe->menu_bar_vector,
7666                                     (void *)tag);
7667     }
7669   ns_send_appdefined (-1);
7670   return self;
7674 - (EmacsToolbar *)toolbar
7676   return toolbar;
7680 /* this gets called on toolbar button click */
7681 - (instancetype)toolbarClicked: (id)item
7683   NSEvent *theEvent;
7684   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7686   NSTRACE ("[EmacsView toolbarClicked:]");
7688   if (!emacs_event)
7689     return self;
7691   /* send first event (for some reason two needed) */
7692   theEvent = [[self window] currentEvent];
7693   emacs_event->kind = TOOL_BAR_EVENT;
7694   XSETFRAME (emacs_event->arg, emacsframe);
7695   EV_TRAILER (theEvent);
7697   emacs_event->kind = TOOL_BAR_EVENT;
7698 /*   XSETINT (emacs_event->code, 0); */
7699   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7700                            idx + TOOL_BAR_ITEM_KEY);
7701   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7702   EV_TRAILER (theEvent);
7703   return self;
7707 - (instancetype)toggleToolbar: (id)sender
7709   NSTRACE ("[EmacsView toggleToolbar:]");
7711   if (!emacs_event)
7712     return self;
7714   emacs_event->kind = NS_NONKEY_EVENT;
7715   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7716   EV_TRAILER ((id)nil);
7717   return self;
7721 - (void)drawRect: (NSRect)rect
7723   int x = NSMinX (rect), y = NSMinY (rect);
7724   int width = NSWidth (rect), height = NSHeight (rect);
7726   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7727            NSTRACE_ARG_RECT(rect));
7729   if (!emacsframe || !emacsframe->output_data.ns)
7730     return;
7732   ns_clear_frame_area (emacsframe, x, y, width, height);
7733   block_input ();
7734   expose_frame (emacsframe, x, y, width, height);
7735   unblock_input ();
7737   /*
7738     drawRect: may be called (at least in Mac OS X 10.5) for invisible
7739     views as well for some reason.  Thus, do not infer visibility
7740     here.
7742     emacsframe->async_visible = 1;
7743     emacsframe->async_iconified = 0;
7744   */
7748 /* NSDraggingDestination protocol methods.  Actually this is not really a
7749    protocol, but a category of Object.  O well...  */
7751 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7753   NSTRACE ("[EmacsView draggingEntered:]");
7754   return NSDragOperationGeneric;
7758 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7760   return YES;
7764 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7766   id pb;
7767   int x, y;
7768   NSString *type;
7769   NSEvent *theEvent = [[self window] currentEvent];
7770   NSPoint position;
7771   NSDragOperation op = [sender draggingSourceOperationMask];
7772   int modifiers = 0;
7774   NSTRACE ("[EmacsView performDragOperation:]");
7776   if (!emacs_event)
7777     return NO;
7779   position = [self convertPoint: [sender draggingLocation] fromView: nil];
7780   x = lrint (position.x);  y = lrint (position.y);
7782   pb = [sender draggingPasteboard];
7783   type = [pb availableTypeFromArray: ns_drag_types];
7785   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7786       // URL drags contain all operations (0xf), don't allow all to be set.
7787       (op & 0xf) != 0xf)
7788     {
7789       if (op & NSDragOperationLink)
7790         modifiers |= NSEventModifierFlagControl;
7791       if (op & NSDragOperationCopy)
7792         modifiers |= NSEventModifierFlagOption;
7793       if (op & NSDragOperationGeneric)
7794         modifiers |= NSEventModifierFlagCommand;
7795     }
7797   modifiers = EV_MODIFIERS2 (modifiers);
7798   if (type == 0)
7799     {
7800       return NO;
7801     }
7802   else if ([type isEqualToString: NSFilenamesPboardType])
7803     {
7804       NSArray *files;
7805       NSEnumerator *fenum;
7806       NSString *file;
7808       if (!(files = [pb propertyListForType: type]))
7809         return NO;
7811       fenum = [files objectEnumerator];
7812       while ( (file = [fenum nextObject]) )
7813         {
7814           emacs_event->kind = DRAG_N_DROP_EVENT;
7815           XSETINT (emacs_event->x, x);
7816           XSETINT (emacs_event->y, y);
7817           ns_input_file = append2 (ns_input_file,
7818                                    build_string ([file UTF8String]));
7819           emacs_event->modifiers = modifiers;
7820           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
7821           EV_TRAILER (theEvent);
7822         }
7823       return YES;
7824     }
7825   else if ([type isEqualToString: NSURLPboardType])
7826     {
7827       NSURL *url = [NSURL URLFromPasteboard: pb];
7828       if (url == nil) return NO;
7830       emacs_event->kind = DRAG_N_DROP_EVENT;
7831       XSETINT (emacs_event->x, x);
7832       XSETINT (emacs_event->y, y);
7833       emacs_event->modifiers = modifiers;
7834       emacs_event->arg =  list2 (Qurl,
7835                                  build_string ([[url absoluteString]
7836                                                  UTF8String]));
7837       EV_TRAILER (theEvent);
7839       if ([url isFileURL] != NO)
7840         {
7841           NSString *file = [url path];
7842           ns_input_file = append2 (ns_input_file,
7843                                    build_string ([file UTF8String]));
7844         }
7845       return YES;
7846     }
7847   else if ([type isEqualToString: NSStringPboardType]
7848            || [type isEqualToString: NSTabularTextPboardType])
7849     {
7850       NSString *data;
7852       if (! (data = [pb stringForType: type]))
7853         return NO;
7855       emacs_event->kind = DRAG_N_DROP_EVENT;
7856       XSETINT (emacs_event->x, x);
7857       XSETINT (emacs_event->y, y);
7858       emacs_event->modifiers = modifiers;
7859       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
7860       EV_TRAILER (theEvent);
7861       return YES;
7862     }
7863   else
7864     {
7865       fprintf (stderr, "Invalid data type in dragging pasteboard");
7866       return NO;
7867     }
7871 - (id) validRequestorForSendType: (NSString *)typeSent
7872                       returnType: (NSString *)typeReturned
7874   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7875   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7876       && typeReturned == nil)
7877     {
7878       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7879         return self;
7880     }
7882   return [super validRequestorForSendType: typeSent
7883                                returnType: typeReturned];
7887 /* The next two methods are part of NSServicesRequests informal protocol,
7888    supposedly called when a services menu item is chosen from this app.
7889    But this should not happen because we override the services menu with our
7890    own entries which call ns-perform-service.
7891    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7892    So let's at least stub them out until further investigation can be done. */
7894 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7896   /* we could call ns_string_from_pasteboard(pboard) here but then it should
7897      be written into the buffer in place of the existing selection..
7898      ordinary service calls go through functions defined in ns-win.el */
7899   return NO;
7902 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7904   NSArray *typesDeclared;
7905   Lisp_Object val;
7907   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7909   /* We only support NSStringPboardType */
7910   if ([types containsObject:NSStringPboardType] == NO) {
7911     return NO;
7912   }
7914   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7915   if (CONSP (val) && SYMBOLP (XCAR (val)))
7916     {
7917       val = XCDR (val);
7918       if (CONSP (val) && NILP (XCDR (val)))
7919         val = XCAR (val);
7920     }
7921   if (! STRINGP (val))
7922     return NO;
7924   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7925   [pb declareTypes:typesDeclared owner:nil];
7926   ns_string_to_pasteboard (pb, val);
7927   return YES;
7931 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7932    (gives a miniaturized version of the window); currently we use the latter for
7933    frames whose active buffer doesn't correspond to any file
7934    (e.g., '*scratch*') */
7935 - (instancetype)setMiniwindowImage: (BOOL) setMini
7937   id image = [[self window] miniwindowImage];
7938   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7940   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7941      about "AppleDockIconEnabled" notwithstanding, however the set message
7942      below has its effect nonetheless. */
7943   if (image != emacsframe->output_data.ns->miniimage)
7944     {
7945       if (image && [image isKindOfClass: [EmacsImage class]])
7946         [image release];
7947       [[self window] setMiniwindowImage:
7948                        setMini ? emacsframe->output_data.ns->miniimage : nil];
7949     }
7951   return self;
7955 - (void) setRows: (int) r andColumns: (int) c
7957   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7958   rows = r;
7959   cols = c;
7962 - (int) fullscreenState
7964   return fs_state;
7967 @end  /* EmacsView */
7971 /* ==========================================================================
7973     EmacsWindow implementation
7975    ========================================================================== */
7977 @implementation EmacsWindow
7979 #ifdef NS_IMPL_COCOA
7980 - (id)accessibilityAttributeValue:(NSString *)attribute
7982   Lisp_Object str = Qnil;
7983   struct frame *f = SELECTED_FRAME ();
7984   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7986   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7988   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7989     return NSAccessibilityTextFieldRole;
7991   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7992       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7993     {
7994       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7995     }
7996   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7997     {
7998       if (! NILP (BVAR (curbuf, mark_active)))
7999           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8001       if (NILP (str))
8002         {
8003           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8004           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8005           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8007           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8008             str = make_uninit_multibyte_string (range, byte_range);
8009           else
8010             str = make_uninit_string (range);
8011           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8012              Is this a problem?  */
8013           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8014         }
8015     }
8018   if (! NILP (str))
8019     {
8020       if (CONSP (str) && SYMBOLP (XCAR (str)))
8021         {
8022           str = XCDR (str);
8023           if (CONSP (str) && NILP (XCDR (str)))
8024             str = XCAR (str);
8025         }
8026       if (STRINGP (str))
8027         {
8028           const char *utfStr = SSDATA (str);
8029           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8030           return nsStr;
8031         }
8032     }
8034   return [super accessibilityAttributeValue:attribute];
8036 #endif /* NS_IMPL_COCOA */
8038 /* Constrain size and placement of a frame.
8040    By returning the original "frameRect", the frame is not
8041    constrained. This can lead to unwanted situations where, for
8042    example, the menu bar covers the frame.
8044    The default implementation (accessed using "super") constrains the
8045    frame to the visible area of SCREEN, minus the menu bar (if
8046    present) and the Dock.  Note that default implementation also calls
8047    windowWillResize, with the frame it thinks should have.  (This can
8048    make the frame exit maximized mode.)
8050    Note that this should work in situations where multiple monitors
8051    are present.  Common configurations are side-by-side monitors and a
8052    monitor on top of another (e.g. when a laptop is placed under a
8053    large screen). */
8054 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8056   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8057              NSTRACE_ARG_RECT (frameRect));
8059 #ifdef NS_IMPL_COCOA
8060 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
8061   // If separate spaces is on, it is like each screen is independent.  There is
8062   // no spanning of frames across screens.
8063   if ([NSScreen screensHaveSeparateSpaces])
8064     {
8065       NSTRACE_MSG ("Screens have separate spaces");
8066       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8067       NSTRACE_RETURN_RECT (frameRect);
8068       return frameRect;
8069     }
8070   else
8071 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 */
8072     // Check that the proposed frameRect is visible in at least one
8073     // screen.  If it is not, ask the system to reposition it (only
8074     // for non-child windows).
8076     if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8077     {
8078       NSArray *screens = [NSScreen screens];
8079       NSUInteger nr_screens = [screens count];
8081       int i;
8082       BOOL frame_on_screen = NO;
8084       for (i = 0; i < nr_screens; ++i)
8085         {
8086           NSScreen *s = [screens objectAtIndex: i];
8087           NSRect scrRect = [s frame];
8089           if (NSIntersectsRect(frameRect, scrRect))
8090             {
8091               frame_on_screen = YES;
8092               break;
8093             }
8094         }
8096       if (!frame_on_screen)
8097         {
8098           NSTRACE_MSG ("Frame outside screens; constraining");
8099           frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8100           NSTRACE_RETURN_RECT (frameRect);
8101           return frameRect;
8102         }
8103     }
8104 #endif
8106   return constrain_frame_rect(frameRect,
8107                               [(EmacsView *)[self delegate] isFullscreen]);
8111 - (void)performZoom:(id)sender
8113   NSTRACE ("[EmacsWindow performZoom:]");
8115   return [super performZoom:sender];
8118 - (void)zoom:(id)sender
8120   NSTRACE ("[EmacsWindow zoom:]");
8122   ns_update_auto_hide_menu_bar();
8124   // Below are three zoom implementations.  In the final commit, the
8125   // idea is that the last should be included.
8127 #if 0
8128   // Native zoom done using the standard zoom animation.  Size of the
8129   // resulting frame reduced to accommodate the Dock and, if present,
8130   // the menu-bar.
8131   [super zoom:sender];
8133 #elif 0
8134   // Native zoom done using the standard zoom animation, plus an
8135   // explicit resize to cover the full screen, except the menu-bar and
8136   // dock, if present.
8137   [super zoom:sender];
8139   // After the native zoom, resize the resulting frame to fill the
8140   // entire screen, except the menu-bar.
8141   //
8142   // This works for all practical purposes.  (The only minor oddity is
8143   // when transiting from full-height frame to a maximized, the
8144   // animation reduces the height of the frame slightly (to the 4
8145   // pixels needed to accommodate the Doc) before it snaps back into
8146   // full height.  The user would need a very trained eye to spot
8147   // this.)
8148   NSScreen * screen = [self screen];
8149   if (screen != nil)
8150     {
8151       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8153       NSTRACE_FSTYPE ("fullscreenState", fs_state);
8155       NSRect sr = [screen frame];
8156       struct EmacsMargins margins
8157         = ns_screen_margins_ignoring_hidden_dock(screen);
8159       NSRect wr = [self frame];
8160       NSTRACE_RECT ("Rect after zoom", wr);
8162       NSRect newWr = wr;
8164       if (fs_state == FULLSCREEN_MAXIMIZED
8165           || fs_state == FULLSCREEN_HEIGHT)
8166         {
8167           newWr.origin.y = sr.origin.y + margins.bottom;
8168           newWr.size.height = sr.size.height - margins.top - margins.bottom;
8169         }
8171       if (fs_state == FULLSCREEN_MAXIMIZED
8172           || fs_state == FULLSCREEN_WIDTH)
8173         {
8174           newWr.origin.x = sr.origin.x + margins.left;
8175           newWr.size.width = sr.size.width - margins.right - margins.left;
8176         }
8178       if (newWr.size.width     != wr.size.width
8179           || newWr.size.height != wr.size.height
8180           || newWr.origin.x    != wr.origin.x
8181           || newWr.origin.y    != wr.origin.y)
8182         {
8183           NSTRACE_MSG ("New frame different");
8184           [self setFrame: newWr display: NO];
8185         }
8186     }
8187 #else
8188   // Non-native zoom which is done instantaneously.  The resulting
8189   // frame covers the entire screen, except the menu-bar and dock, if
8190   // present.
8191   NSScreen * screen = [self screen];
8192   if (screen != nil)
8193     {
8194       NSRect sr = [screen frame];
8195       struct EmacsMargins margins
8196         = ns_screen_margins_ignoring_hidden_dock(screen);
8198       sr.size.height -= (margins.top + margins.bottom);
8199       sr.size.width  -= (margins.left + margins.right);
8200       sr.origin.x += margins.left;
8201       sr.origin.y += margins.bottom;
8203       sr = [[self delegate] windowWillUseStandardFrame:self
8204                                           defaultFrame:sr];
8205       [self setFrame: sr display: NO];
8206     }
8207 #endif
8210 - (void)setFrame:(NSRect)windowFrame
8211          display:(BOOL)displayViews
8213   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8214            NSTRACE_ARG_RECT (windowFrame), displayViews);
8216   [super setFrame:windowFrame display:displayViews];
8219 - (void)setFrame:(NSRect)windowFrame
8220          display:(BOOL)displayViews
8221          animate:(BOOL)performAnimation
8223   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8224            " display:%d performAnimation:%d]",
8225            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8227   [super setFrame:windowFrame display:displayViews animate:performAnimation];
8230 - (void)setFrameTopLeftPoint:(NSPoint)point
8232   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8233            NSTRACE_ARG_POINT (point));
8235   [super setFrameTopLeftPoint:point];
8238 - (BOOL)canBecomeKeyWindow
8240   return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8242 @end /* EmacsWindow */
8245 @implementation EmacsFSWindow
8247 - (BOOL)canBecomeKeyWindow
8249   return YES;
8252 - (BOOL)canBecomeMainWindow
8254   return YES;
8257 @end
8259 /* ==========================================================================
8261     EmacsScroller implementation
8263    ========================================================================== */
8266 @implementation EmacsScroller
8268 /* for repeat button push */
8269 #define SCROLL_BAR_FIRST_DELAY 0.5
8270 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8272 + (CGFloat) scrollerWidth
8274   /* TODO: if we want to allow variable widths, this is the place to do it,
8275            however neither GNUstep nor Cocoa support it very well */
8276   CGFloat r;
8277 #if !defined (NS_IMPL_COCOA) || \
8278   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
8279   r = [NSScroller scrollerWidth];
8280 #else
8281   r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8282                                 scrollerStyle: NSScrollerStyleLegacy];
8283 #endif
8284   return r;
8287 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8289   NSTRACE ("[EmacsScroller initFrame: window:]");
8291   if (r.size.width > r.size.height)
8292       horizontal = YES;
8293   else
8294       horizontal = NO;
8296   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8297   [self setContinuous: YES];
8298   [self setEnabled: YES];
8300   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8301      locked against the top and bottom edges, and right edge on macOS, where
8302      scrollers are on right. */
8303 #ifdef NS_IMPL_GNUSTEP
8304   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8305 #else
8306   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8307 #endif
8309   window = XWINDOW (nwin);
8310   condemned = NO;
8311   if (horizontal)
8312     pixel_length = NSWidth (r);
8313   else
8314     pixel_length = NSHeight (r);
8315   if (pixel_length == 0) pixel_length = 1;
8316   min_portion = 20 / pixel_length;
8318   frame = XFRAME (window->frame);
8319   if (FRAME_LIVE_P (frame))
8320     {
8321       int i;
8322       EmacsView *view = FRAME_NS_VIEW (frame);
8323       NSView *sview = [[view window] contentView];
8324       NSArray *subs = [sview subviews];
8326       /* disable optimization stopping redraw of other scrollbars */
8327       view->scrollbarsNeedingUpdate = 0;
8328       for (i =[subs count]-1; i >= 0; i--)
8329         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8330           view->scrollbarsNeedingUpdate++;
8331       [sview addSubview: self];
8332     }
8334 /*  [self setFrame: r]; */
8336   return self;
8340 - (void)setFrame: (NSRect)newRect
8342   NSTRACE ("[EmacsScroller setFrame:]");
8344 /*  block_input (); */
8345   if (horizontal)
8346     pixel_length = NSWidth (newRect);
8347   else
8348     pixel_length = NSHeight (newRect);
8349   if (pixel_length == 0) pixel_length = 1;
8350   min_portion = 20 / pixel_length;
8351   [super setFrame: newRect];
8352 /*  unblock_input (); */
8356 - (void)dealloc
8358   NSTRACE ("[EmacsScroller dealloc]");
8359   if (window)
8360     {
8361       if (horizontal)
8362         wset_horizontal_scroll_bar (window, Qnil);
8363       else
8364         wset_vertical_scroll_bar (window, Qnil);
8365     }
8366   window = 0;
8367   [super dealloc];
8371 - (instancetype)condemn
8373   NSTRACE ("[EmacsScroller condemn]");
8374   condemned =YES;
8375   return self;
8379 - (instancetype)reprieve
8381   NSTRACE ("[EmacsScroller reprieve]");
8382   condemned =NO;
8383   return self;
8387 -(bool)judge
8389   NSTRACE ("[EmacsScroller judge]");
8390   bool ret = condemned;
8391   if (condemned)
8392     {
8393       EmacsView *view;
8394       block_input ();
8395       /* ensure other scrollbar updates after deletion */
8396       view = (EmacsView *)FRAME_NS_VIEW (frame);
8397       if (view != nil)
8398         view->scrollbarsNeedingUpdate++;
8399       if (window)
8400         {
8401           if (horizontal)
8402             wset_horizontal_scroll_bar (window, Qnil);
8403           else
8404             wset_vertical_scroll_bar (window, Qnil);
8405         }
8406       window = 0;
8407       [self removeFromSuperview];
8408       [self release];
8409       unblock_input ();
8410     }
8411   return ret;
8415 - (void)resetCursorRects
8417   NSRect visible = [self visibleRect];
8418   NSTRACE ("[EmacsScroller resetCursorRects]");
8420   if (!NSIsEmptyRect (visible))
8421     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8422   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8426 - (int) checkSamePosition: (int) position portion: (int) portion
8427                     whole: (int) whole
8429   return em_position ==position && em_portion ==portion && em_whole ==whole
8430     && portion != whole; /* needed for resize empty buf */
8434 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8436   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8438   em_position = position;
8439   em_portion = portion;
8440   em_whole = whole;
8442   if (portion >= whole)
8443     {
8444 #ifdef NS_IMPL_COCOA
8445       [self setKnobProportion: 1.0];
8446       [self setDoubleValue: 1.0];
8447 #else
8448       [self setFloatValue: 0.0 knobProportion: 1.0];
8449 #endif
8450     }
8451   else
8452     {
8453       float pos;
8454       CGFloat por;
8455       portion = max ((float)whole*min_portion/pixel_length, portion);
8456       pos = (float)position / (whole - portion);
8457       por = (CGFloat)portion/whole;
8458 #ifdef NS_IMPL_COCOA
8459       [self setKnobProportion: por];
8460       [self setDoubleValue: pos];
8461 #else
8462       [self setFloatValue: pos knobProportion: por];
8463 #endif
8464     }
8466   return self;
8469 /* set up emacs_event */
8470 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8472   Lisp_Object win;
8474   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8476   if (!emacs_event)
8477     return;
8479   emacs_event->part = last_hit_part;
8480   emacs_event->code = 0;
8481   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8482   XSETWINDOW (win, window);
8483   emacs_event->frame_or_window = win;
8484   emacs_event->timestamp = EV_TIMESTAMP (e);
8485   emacs_event->arg = Qnil;
8487   if (horizontal)
8488     {
8489       emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8490       XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8491       XSETINT (emacs_event->y, em_whole);
8492     }
8493   else
8494     {
8495       emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8496       XSETINT (emacs_event->x, loc);
8497       XSETINT (emacs_event->y, pixel_length-20);
8498     }
8500   if (q_event_ptr)
8501     {
8502       n_emacs_events_pending++;
8503       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8504     }
8505   else
8506     hold_event (emacs_event);
8507   EVENT_INIT (*emacs_event);
8508   ns_send_appdefined (-1);
8512 /* called manually thru timer to implement repeated button action w/hold-down */
8513 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8515   NSEvent *e = [[self window] currentEvent];
8516   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8517   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8519   NSTRACE ("[EmacsScroller repeatScroll:]");
8521   /* clear timer if need be */
8522   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8523     {
8524         [scroll_repeat_entry invalidate];
8525         [scroll_repeat_entry release];
8526         scroll_repeat_entry = nil;
8528         if (inKnob)
8529           return self;
8531         scroll_repeat_entry
8532           = [[NSTimer scheduledTimerWithTimeInterval:
8533                         SCROLL_BAR_CONTINUOUS_DELAY
8534                                             target: self
8535                                           selector: @selector (repeatScroll:)
8536                                           userInfo: 0
8537                                            repeats: YES]
8538               retain];
8539     }
8541   [self sendScrollEventAtLoc: 0 fromEvent: e];
8542   return self;
8546 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8547    mouseDragged events without going into a modal loop. */
8548 - (void)mouseDown: (NSEvent *)e
8550   NSRect sr, kr;
8551   /* hitPart is only updated AFTER event is passed on */
8552   NSScrollerPart part = [self testPart: [e locationInWindow]];
8553   CGFloat loc, kloc, pos UNINIT;
8554   int edge = 0;
8556   NSTRACE ("[EmacsScroller mouseDown:]");
8558   switch (part)
8559     {
8560     case NSScrollerDecrementPage:
8561       last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8562     case NSScrollerIncrementPage:
8563       last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8564     case NSScrollerDecrementLine:
8565       last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8566     case NSScrollerIncrementLine:
8567       last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8568     case NSScrollerKnob:
8569       last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8570     case NSScrollerKnobSlot:  /* GNUstep-only */
8571       last_hit_part = scroll_bar_move_ratio; break;
8572     default:  /* NSScrollerNoPart? */
8573       fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8574                (long) part);
8575       return;
8576     }
8578   if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8579     {
8580       /* handle, or on GNUstep possibly slot */
8581       NSEvent *fake_event;
8582       int length;
8584       /* compute float loc in slot and mouse offset on knob */
8585       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8586                       toView: nil];
8587       if (horizontal)
8588         {
8589           length = NSWidth (sr);
8590           loc = ([e locationInWindow].x - NSMinX (sr));
8591         }
8592       else
8593         {
8594           length = NSHeight (sr);
8595           loc = length - ([e locationInWindow].y - NSMinY (sr));
8596         }
8598       if (loc <= 0.0)
8599         {
8600           loc = 0.0;
8601           edge = -1;
8602         }
8603       else if (loc >= length)
8604         {
8605           loc = length;
8606           edge = 1;
8607         }
8609       if (edge)
8610         kloc = 0.5 * edge;
8611       else
8612         {
8613           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8614                           toView: nil];
8615           if (horizontal)
8616             kloc = ([e locationInWindow].x - NSMinX (kr));
8617           else
8618             kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8619         }
8620       last_mouse_offset = kloc;
8622       if (part != NSScrollerKnob)
8623         /* this is a slot click on GNUstep: go straight there */
8624         pos = loc;
8626       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8627       fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8628                                       location: [e locationInWindow]
8629                                  modifierFlags: [e modifierFlags]
8630                                      timestamp: [e timestamp]
8631                                   windowNumber: [e windowNumber]
8632                                        context: nil
8633                                    eventNumber: [e eventNumber]
8634                                     clickCount: [e clickCount]
8635                                       pressure: [e pressure]];
8636       [super mouseUp: fake_event];
8637     }
8638   else
8639     {
8640       pos = 0;      /* ignored */
8642       /* set a timer to repeat, as we can't let superclass do this modally */
8643       scroll_repeat_entry
8644         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8645                                             target: self
8646                                           selector: @selector (repeatScroll:)
8647                                           userInfo: 0
8648                                            repeats: YES]
8649             retain];
8650     }
8652   if (part != NSScrollerKnob)
8653     [self sendScrollEventAtLoc: pos fromEvent: e];
8657 /* Called as we manually track scroller drags, rather than superclass. */
8658 - (void)mouseDragged: (NSEvent *)e
8660     NSRect sr;
8661     double loc, pos;
8662     int length;
8664     NSTRACE ("[EmacsScroller mouseDragged:]");
8666       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8667                       toView: nil];
8669       if (horizontal)
8670         {
8671           length = NSWidth (sr);
8672           loc = ([e locationInWindow].x - NSMinX (sr));
8673         }
8674       else
8675         {
8676           length = NSHeight (sr);
8677           loc = length - ([e locationInWindow].y - NSMinY (sr));
8678         }
8680       if (loc <= 0.0)
8681         {
8682           loc = 0.0;
8683         }
8684       else if (loc >= length + last_mouse_offset)
8685         {
8686           loc = length + last_mouse_offset;
8687         }
8689       pos = (loc - last_mouse_offset);
8690       [self sendScrollEventAtLoc: pos fromEvent: e];
8694 - (void)mouseUp: (NSEvent *)e
8696   NSTRACE ("[EmacsScroller mouseUp:]");
8698   if (scroll_repeat_entry)
8699     {
8700       [scroll_repeat_entry invalidate];
8701       [scroll_repeat_entry release];
8702       scroll_repeat_entry = nil;
8703     }
8704   last_hit_part = scroll_bar_above_handle;
8708 /* treat scrollwheel events in the bar as though they were in the main window */
8709 - (void) scrollWheel: (NSEvent *)theEvent
8711   NSTRACE ("[EmacsScroller scrollWheel:]");
8713   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8714   [view mouseDown: theEvent];
8717 @end  /* EmacsScroller */
8720 #ifdef NS_IMPL_GNUSTEP
8721 /* Dummy class to get rid of startup warnings.  */
8722 @implementation EmacsDocument
8724 @end
8725 #endif
8728 /* ==========================================================================
8730    Font-related functions; these used to be in nsfaces.m
8732    ========================================================================== */
8735 Lisp_Object
8736 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8738   struct font *font = XFONT_OBJECT (font_object);
8739   EmacsView *view = FRAME_NS_VIEW (f);
8740   int font_ascent, font_descent;
8742   if (fontset < 0)
8743     fontset = fontset_from_font (font_object);
8744   FRAME_FONTSET (f) = fontset;
8746   if (FRAME_FONT (f) == font)
8747     /* This font is already set in frame F.  There's nothing more to
8748        do.  */
8749     return font_object;
8751   FRAME_FONT (f) = font;
8753   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8754   FRAME_COLUMN_WIDTH (f) = font->average_width;
8755   get_font_ascent_descent (font, &font_ascent, &font_descent);
8756   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8758   /* Compute the scroll bar width in character columns.  */
8759   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8760     {
8761       int wid = FRAME_COLUMN_WIDTH (f);
8762       FRAME_CONFIG_SCROLL_BAR_COLS (f)
8763         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8764     }
8765   else
8766     {
8767       int wid = FRAME_COLUMN_WIDTH (f);
8768       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8769     }
8771   /* Compute the scroll bar height in character lines.  */
8772   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8773     {
8774       int height = FRAME_LINE_HEIGHT (f);
8775       FRAME_CONFIG_SCROLL_BAR_LINES (f)
8776         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8777     }
8778   else
8779     {
8780       int height = FRAME_LINE_HEIGHT (f);
8781       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8782     }
8784   /* Now make the frame display the given font.  */
8785   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8786     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8787                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8788                        false, Qfont);
8790   return font_object;
8794 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8795 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8796          in 1.43. */
8798 const char *
8799 ns_xlfd_to_fontname (const char *xlfd)
8800 /* --------------------------------------------------------------------------
8801     Convert an X font name (XLFD) to an NS font name.
8802     Only family is used.
8803     The string returned is temporarily allocated.
8804    -------------------------------------------------------------------------- */
8806   char *name = xmalloc (180);
8807   int i, len;
8808   const char *ret;
8810   if (!strncmp (xlfd, "--", 2))
8811     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8812   else
8813     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8815   /* stopgap for malformed XLFD input */
8816   if (strlen (name) == 0)
8817     strcpy (name, "Monaco");
8819   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8820      also uppercase after '-' or ' ' */
8821   name[0] = c_toupper (name[0]);
8822   for (len =strlen (name), i =0; i<len; i++)
8823     {
8824       if (name[i] == '$')
8825         {
8826           name[i] = '-';
8827           if (i+1<len)
8828             name[i+1] = c_toupper (name[i+1]);
8829         }
8830       else if (name[i] == '_')
8831         {
8832           name[i] = ' ';
8833           if (i+1<len)
8834             name[i+1] = c_toupper (name[i+1]);
8835         }
8836     }
8837 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
8838   ret = [[NSString stringWithUTF8String: name] UTF8String];
8839   xfree (name);
8840   return ret;
8844 void
8845 syms_of_nsterm (void)
8847   NSTRACE ("syms_of_nsterm");
8849   ns_antialias_threshold = 10.0;
8851   /* from 23+ we need to tell emacs what modifiers there are.. */
8852   DEFSYM (Qmodifier_value, "modifier-value");
8853   DEFSYM (Qalt, "alt");
8854   DEFSYM (Qhyper, "hyper");
8855   DEFSYM (Qmeta, "meta");
8856   DEFSYM (Qsuper, "super");
8857   DEFSYM (Qcontrol, "control");
8858   DEFSYM (QUTF8_STRING, "UTF8_STRING");
8860   DEFSYM (Qfile, "file");
8861   DEFSYM (Qurl, "url");
8863   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8864   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8865   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8866   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8867   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8869   DEFVAR_LISP ("ns-input-file", ns_input_file,
8870               "The file specified in the last NS event.");
8871   ns_input_file =Qnil;
8873   DEFVAR_LISP ("ns-working-text", ns_working_text,
8874               "String for visualizing working composition sequence.");
8875   ns_working_text =Qnil;
8877   DEFVAR_LISP ("ns-input-font", ns_input_font,
8878               "The font specified in the last NS event.");
8879   ns_input_font =Qnil;
8881   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8882               "The fontsize specified in the last NS event.");
8883   ns_input_fontsize =Qnil;
8885   DEFVAR_LISP ("ns-input-line", ns_input_line,
8886                "The line specified in the last NS event.");
8887   ns_input_line =Qnil;
8889   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8890                "The service name specified in the last NS event.");
8891   ns_input_spi_name =Qnil;
8893   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8894                "The service argument specified in the last NS event.");
8895   ns_input_spi_arg =Qnil;
8897   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8898                "This variable describes the behavior of the alternate or option key.\n\
8899 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8900 that key.\n\
8901 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8902 at all, allowing it to be used at a lower level for accented character entry.");
8903   ns_alternate_modifier = Qmeta;
8905   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8906                "This variable describes the behavior of the right alternate or option key.\n\
8907 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8908 that key.\n\
8909 Set to left means be the same key as `ns-alternate-modifier'.\n\
8910 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8911 at all, allowing it to be used at a lower level for accented character entry.");
8912   ns_right_alternate_modifier = Qleft;
8914   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8915                "This variable describes the behavior of the command key.\n\
8916 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8917 that key.");
8918   ns_command_modifier = Qsuper;
8920   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8921                "This variable describes the behavior of the right command key.\n\
8922 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8923 that key.\n\
8924 Set to left means be the same key as `ns-command-modifier'.\n\
8925 Set to none means that the command / option key is not interpreted by Emacs\n\
8926 at all, allowing it to be used at a lower level for accented character entry.");
8927   ns_right_command_modifier = Qleft;
8929   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8930                "This variable describes the behavior of the control key.\n\
8931 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8932 that key.");
8933   ns_control_modifier = Qcontrol;
8935   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8936                "This variable describes the behavior of the right control key.\n\
8937 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8938 that key.\n\
8939 Set to left means be the same key as `ns-control-modifier'.\n\
8940 Set to none means that the control / option key is not interpreted by Emacs\n\
8941 at all, allowing it to be used at a lower level for accented character entry.");
8942   ns_right_control_modifier = Qleft;
8944   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8945                "This variable describes the behavior of the function key (on laptops).\n\
8946 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
8947 that key.\n\
8948 Set to none means that the function key is not interpreted by Emacs at all,\n\
8949 allowing it to be used at a lower level for accented character entry.");
8950   ns_function_modifier = Qnone;
8952   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8953                "Non-nil (the default) means to render text antialiased.");
8954   ns_antialias_text = Qt;
8956   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8957                "Whether to confirm application quit using dialog.");
8958   ns_confirm_quit = Qnil;
8960   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8961                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8962 Only works on Mac OS X 10.6 or later.  */);
8963   ns_auto_hide_menu_bar = Qnil;
8965   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8966      doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
8967 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
8968 multiple monitors, but lacks tool bar.  This variable is ignored on
8969 Mac OS X < 10.7.  Default is t for 10.7 and later, nil otherwise.  */);
8970 #ifdef HAVE_NATIVE_FS
8971   ns_use_native_fullscreen = YES;
8972 #else
8973   ns_use_native_fullscreen = NO;
8974 #endif
8975   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8977   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8978      doc: /*Non-nil means use animation on non-native fullscreen.
8979 For native fullscreen, this does nothing.
8980 Default is nil.  */);
8981   ns_use_fullscreen_animation = NO;
8983   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8984      doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
8985 Note that this does not apply to images.
8986 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
8987   ns_use_srgb_colorspace = YES;
8989   /* TODO: move to common code */
8990   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8991                doc: /* Which toolkit scroll bars Emacs uses, if any.
8992 A value of nil means Emacs doesn't use toolkit scroll bars.
8993 With the X Window system, the value is a symbol describing the
8994 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
8995 With MS Windows or Nextstep, the value is t.  */);
8996   Vx_toolkit_scroll_bars = Qt;
8998   DEFVAR_BOOL ("x-use-underline-position-properties",
8999                x_use_underline_position_properties,
9000      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9001 A value of nil means ignore them.  If you encounter fonts with bogus
9002 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9003 to 4.1, set this to nil. */);
9004   x_use_underline_position_properties = 0;
9006   DEFVAR_BOOL ("x-underline-at-descent-line",
9007                x_underline_at_descent_line,
9008      doc: /* Non-nil means to draw the underline at the same place as the descent line.
9009 A value of nil means to draw the underline according to the value of the
9010 variable `x-use-underline-position-properties', which is usually at the
9011 baseline level.  The default value is nil.  */);
9012   x_underline_at_descent_line = 0;
9014   /* Tell Emacs about this window system.  */
9015   Fprovide (Qns, Qnil);
9017   DEFSYM (Qcocoa, "cocoa");
9018   DEFSYM (Qgnustep, "gnustep");
9020 #ifdef NS_IMPL_COCOA
9021   Fprovide (Qcocoa, Qnil);
9022   syms_of_macfont ();
9023 #else
9024   Fprovide (Qgnustep, Qnil);
9025   syms_of_nsfont ();
9026 #endif