Implement HiDPI support for underwave on MS-Windows
[emacs.git] / src / nsterm.m
blob95092b29c894be63c1d42ddba2963505735c6d95
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 #if defined (NS_IMPL_COCOA) \
140   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
141   if (ns_use_srgb_colorspace
142 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
143       && [NSColor respondsToSelector:
144                     @selector(colorWithSRGBRed:green:blue:alpha:)]
145 #endif
146       )
147     return [NSColor colorWithSRGBRed: red
148                                green: green
149                                 blue: blue
150                                alpha: alpha];
151 #endif
152   return [NSColor colorWithCalibratedRed: red
153                                    green: green
154                                     blue: blue
155                                    alpha: alpha];
158 - (NSColor *)colorUsingDefaultColorSpace
160   /* FIXMES: We're checking for colorWithSRGBRed here so this will
161      only work in the same place as in the method above.  It should
162      really be a check whether we're on macOS 10.7 or above. */
163 #if defined (NS_IMPL_COCOA) \
164   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
165   if (ns_use_srgb_colorspace
166 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
167       && [NSColor respondsToSelector:
168                     @selector(colorWithSRGBRed:green:blue:alpha:)]
169 #endif
170       )
171     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
172 #endif
173   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
176 @end
178 /* ==========================================================================
180     Local declarations
182    ========================================================================== */
184 /* Convert a symbol indexed with an NSxxx value to a value as defined
185    in keyboard.c (lispy_function_key). I hope this is a correct way
186    of doing things... */
187 static unsigned convert_ns_to_X_keysym[] =
189   NSHomeFunctionKey,            0x50,
190   NSLeftArrowFunctionKey,       0x51,
191   NSUpArrowFunctionKey,         0x52,
192   NSRightArrowFunctionKey,      0x53,
193   NSDownArrowFunctionKey,       0x54,
194   NSPageUpFunctionKey,          0x55,
195   NSPageDownFunctionKey,        0x56,
196   NSEndFunctionKey,             0x57,
197   NSBeginFunctionKey,           0x58,
198   NSSelectFunctionKey,          0x60,
199   NSPrintFunctionKey,           0x61,
200   NSClearLineFunctionKey,       0x0B,
201   NSExecuteFunctionKey,         0x62,
202   NSInsertFunctionKey,          0x63,
203   NSUndoFunctionKey,            0x65,
204   NSRedoFunctionKey,            0x66,
205   NSMenuFunctionKey,            0x67,
206   NSFindFunctionKey,            0x68,
207   NSHelpFunctionKey,            0x6A,
208   NSBreakFunctionKey,           0x6B,
210   NSF1FunctionKey,              0xBE,
211   NSF2FunctionKey,              0xBF,
212   NSF3FunctionKey,              0xC0,
213   NSF4FunctionKey,              0xC1,
214   NSF5FunctionKey,              0xC2,
215   NSF6FunctionKey,              0xC3,
216   NSF7FunctionKey,              0xC4,
217   NSF8FunctionKey,              0xC5,
218   NSF9FunctionKey,              0xC6,
219   NSF10FunctionKey,             0xC7,
220   NSF11FunctionKey,             0xC8,
221   NSF12FunctionKey,             0xC9,
222   NSF13FunctionKey,             0xCA,
223   NSF14FunctionKey,             0xCB,
224   NSF15FunctionKey,             0xCC,
225   NSF16FunctionKey,             0xCD,
226   NSF17FunctionKey,             0xCE,
227   NSF18FunctionKey,             0xCF,
228   NSF19FunctionKey,             0xD0,
229   NSF20FunctionKey,             0xD1,
230   NSF21FunctionKey,             0xD2,
231   NSF22FunctionKey,             0xD3,
232   NSF23FunctionKey,             0xD4,
233   NSF24FunctionKey,             0xD5,
235   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
236   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
237   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
239   NSTabCharacter,               0x09,
240   0x19,                         0x09,  /* left tab->regular since pass shift */
241   NSCarriageReturnCharacter,    0x0D,
242   NSNewlineCharacter,           0x0D,
243   NSEnterCharacter,             0x8D,
245   0x41|NSEventModifierFlagNumericPad,   0xAE,  /* KP_Decimal */
246   0x43|NSEventModifierFlagNumericPad,   0xAA,  /* KP_Multiply */
247   0x45|NSEventModifierFlagNumericPad,   0xAB,  /* KP_Add */
248   0x4B|NSEventModifierFlagNumericPad,   0xAF,  /* KP_Divide */
249   0x4E|NSEventModifierFlagNumericPad,   0xAD,  /* KP_Subtract */
250   0x51|NSEventModifierFlagNumericPad,   0xBD,  /* KP_Equal */
251   0x52|NSEventModifierFlagNumericPad,   0xB0,  /* KP_0 */
252   0x53|NSEventModifierFlagNumericPad,   0xB1,  /* KP_1 */
253   0x54|NSEventModifierFlagNumericPad,   0xB2,  /* KP_2 */
254   0x55|NSEventModifierFlagNumericPad,   0xB3,  /* KP_3 */
255   0x56|NSEventModifierFlagNumericPad,   0xB4,  /* KP_4 */
256   0x57|NSEventModifierFlagNumericPad,   0xB5,  /* KP_5 */
257   0x58|NSEventModifierFlagNumericPad,   0xB6,  /* KP_6 */
258   0x59|NSEventModifierFlagNumericPad,   0xB7,  /* KP_7 */
259   0x5B|NSEventModifierFlagNumericPad,   0xB8,  /* KP_8 */
260   0x5C|NSEventModifierFlagNumericPad,   0xB9,  /* KP_9 */
262   0x1B,                         0x1B   /* escape */
265 /* On macOS picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
266    the maximum font size to NOT antialias.  On GNUstep there is currently
267    no way to control this behavior. */
268 float ns_antialias_threshold;
270 NSArray *ns_send_types = 0, *ns_return_types = 0;
271 static NSArray *ns_drag_types = 0;
272 NSString *ns_app_name = @"Emacs";  /* default changed later */
274 /* Display variables */
275 struct ns_display_info *x_display_list; /* Chain of existing displays */
276 long context_menu_value = 0;
278 /* display update */
279 static struct frame *ns_updating_frame;
280 static NSView *focus_view = NULL;
281 static int ns_window_num = 0;
282 #ifdef NS_IMPL_GNUSTEP
283 static NSRect uRect;            // TODO: This is dead, remove it?
284 #endif
285 static BOOL gsaved = NO;
286 static BOOL ns_fake_keydown = NO;
287 #ifdef NS_IMPL_COCOA
288 static BOOL ns_menu_bar_is_hidden = NO;
289 #endif
290 /*static int debug_lock = 0; */
292 /* event loop */
293 static BOOL send_appdefined = YES;
294 #define NO_APPDEFINED_DATA (-8)
295 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
296 static NSTimer *timed_entry = 0;
297 static NSTimer *scroll_repeat_entry = nil;
298 static fd_set select_readfds, select_writefds;
299 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
300 static int select_nfds = 0, select_valid = 0;
301 static struct timespec select_timeout = { 0, 0 };
302 static int selfds[2] = { -1, -1 };
303 static pthread_mutex_t select_mutex;
304 static NSAutoreleasePool *outerpool;
305 static struct input_event *emacs_event = NULL;
306 static struct input_event *q_event_ptr = NULL;
307 static int n_emacs_events_pending = 0;
308 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
309   *ns_pending_service_args;
310 static BOOL ns_do_open_file = NO;
311 static BOOL ns_last_use_native_fullscreen;
313 /* Non-zero means that a HELP_EVENT has been generated since Emacs
314    start.  */
316 static BOOL any_help_event_p = NO;
318 static struct {
319   struct input_event *q;
320   int nr, cap;
321 } hold_event_q = {
322   NULL, 0, 0
325 static NSString *represented_filename = nil;
326 static struct frame *represented_frame = 0;
328 #ifdef NS_IMPL_COCOA
330  * State for pending menu activation:
331  * MENU_NONE     Normal state
332  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
333  *               run lisp to update the menu.
334  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
335  *               will open.
336  */
337 #define MENU_NONE 0
338 #define MENU_PENDING 1
339 #define MENU_OPENING 2
340 static int menu_will_open_state = MENU_NONE;
342 /* Saved position for menu click.  */
343 static CGPoint menu_mouse_point;
344 #endif
346 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
347 #define NS_FUNCTION_KEY_MASK 0x800000
348 #define NSLeftControlKeyMask    (0x000001 | NSEventModifierFlagControl)
349 #define NSRightControlKeyMask   (0x002000 | NSEventModifierFlagControl)
350 #define NSLeftCommandKeyMask    (0x000008 | NSEventModifierFlagCommand)
351 #define NSRightCommandKeyMask   (0x000010 | NSEventModifierFlagCommand)
352 #define NSLeftAlternateKeyMask  (0x000020 | NSEventModifierFlagOption)
353 #define NSRightAlternateKeyMask (0x000040 | NSEventModifierFlagOption)
354 #define EV_MODIFIERS2(flags)                          \
355     (((flags & NSEventModifierFlagHelp) ?           \
356            hyper_modifier : 0)                        \
357      | (!EQ (ns_right_alternate_modifier, Qleft) && \
358         ((flags & NSRightAlternateKeyMask) \
359          == NSRightAlternateKeyMask) ? \
360            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
361      | ((flags & NSEventModifierFlagOption) ?                 \
362            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
363      | ((flags & NSEventModifierFlagShift) ?     \
364            shift_modifier : 0)                        \
365      | (!EQ (ns_right_control_modifier, Qleft) && \
366         ((flags & NSRightControlKeyMask) \
367          == NSRightControlKeyMask) ? \
368            parse_solitary_modifier (ns_right_control_modifier) : 0) \
369      | ((flags & NSEventModifierFlagControl) ?      \
370            parse_solitary_modifier (ns_control_modifier) : 0)     \
371      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
372            parse_solitary_modifier (ns_function_modifier) : 0)    \
373      | (!EQ (ns_right_command_modifier, Qleft) && \
374         ((flags & NSRightCommandKeyMask) \
375          == NSRightCommandKeyMask) ? \
376            parse_solitary_modifier (ns_right_command_modifier) : 0) \
377      | ((flags & NSEventModifierFlagCommand) ?      \
378            parse_solitary_modifier (ns_command_modifier):0))
379 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
381 #define EV_UDMODIFIERS(e)                                      \
382     ((([e type] == NSEventTypeLeftMouseDown) ? down_modifier : 0)       \
383      | (([e type] == NSEventTypeRightMouseDown) ? down_modifier : 0)    \
384      | (([e type] == NSEventTypeOtherMouseDown) ? down_modifier : 0)    \
385      | (([e type] == NSEventTypeLeftMouseDragged) ? down_modifier : 0)  \
386      | (([e type] == NSEventTypeRightMouseDragged) ? down_modifier : 0) \
387      | (([e type] == NSEventTypeOtherMouseDragged) ? down_modifier : 0) \
388      | (([e type] == NSEventTypeLeftMouseUp)   ? up_modifier   : 0)     \
389      | (([e type] == NSEventTypeRightMouseUp)   ? up_modifier   : 0)    \
390      | (([e type] == NSEventTypeOtherMouseUp)   ? up_modifier   : 0))
392 #define EV_BUTTON(e)                                                         \
393     ((([e type] == NSEventTypeLeftMouseDown) || ([e type] == NSEventTypeLeftMouseUp)) ? 0 :    \
394       (([e type] == NSEventTypeRightMouseDown) || ([e type] == NSEventTypeRightMouseUp)) ? 2 : \
395      [e buttonNumber] - 1)
397 /* Convert the time field to a timestamp in milliseconds. */
398 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
400 /* This is a piece of code which is common to all the event handling
401    methods.  Maybe it should even be a function.  */
402 #define EV_TRAILER(e)                                                   \
403   {                                                                     \
404     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
405     EV_TRAILER2 (e);                                                    \
406   }
408 #define EV_TRAILER2(e)                                                  \
409   {                                                                     \
410       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
411       if (q_event_ptr)                                                  \
412         {                                                               \
413           Lisp_Object tem = Vinhibit_quit;                              \
414           Vinhibit_quit = Qt;                                           \
415           n_emacs_events_pending++;                                     \
416           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
417           Vinhibit_quit = tem;                                          \
418         }                                                               \
419       else                                                              \
420         hold_event (emacs_event);                                       \
421       EVENT_INIT (*emacs_event);                                        \
422       ns_send_appdefined (-1);                                          \
423     }
426 /* GNUstep always shows decorations if the window is resizable,
427    miniaturizable or closable, but Cocoa does strange things in native
428    fullscreen mode if you don't have at least resizable enabled.
430    These flags will be OR'd or XOR'd with the NSWindow's styleMask
431    property depending on what we're doing. */
432 #ifdef NS_IMPL_COCOA
433 #define FRAME_DECORATED_FLAGS NSWindowStyleMaskTitled
434 #else
435 #define FRAME_DECORATED_FLAGS (NSWindowStyleMaskTitled              \
436                                | NSWindowStyleMaskResizable         \
437                                | NSWindowStyleMaskMiniaturizable    \
438                                | NSWindowStyleMaskClosable)
439 #endif
440 #define FRAME_UNDECORATED_FLAGS NSWindowStyleMaskBorderless
442 /* TODO: get rid of need for these forward declarations */
443 static void ns_condemn_scroll_bars (struct frame *f);
444 static void ns_judge_scroll_bars (struct frame *f);
447 /* ==========================================================================
449     Utilities
451    ========================================================================== */
453 void
454 ns_set_represented_filename (NSString *fstr, struct frame *f)
456   represented_filename = [fstr retain];
457   represented_frame = f;
460 void
461 ns_init_events (struct input_event *ev)
463   EVENT_INIT (*ev);
464   emacs_event = ev;
467 void
468 ns_finish_events (void)
470   emacs_event = NULL;
473 static void
474 hold_event (struct input_event *event)
476   if (hold_event_q.nr == hold_event_q.cap)
477     {
478       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
479       else hold_event_q.cap *= 2;
480       hold_event_q.q =
481         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
482     }
484   hold_event_q.q[hold_event_q.nr++] = *event;
485   /* Make sure ns_read_socket is called, i.e. we have input.  */
486   raise (SIGIO);
487   send_appdefined = YES;
490 static Lisp_Object
491 append2 (Lisp_Object list, Lisp_Object item)
492 /* --------------------------------------------------------------------------
493    Utility to append to a list
494    -------------------------------------------------------------------------- */
496   return CALLN (Fnconc, list, list1 (item));
500 const char *
501 ns_etc_directory (void)
502 /* If running as a self-contained app bundle, return as a string the
503    filename of the etc directory, if present; else nil.  */
505   NSBundle *bundle = [NSBundle mainBundle];
506   NSString *resourceDir = [bundle resourcePath];
507   NSString *resourcePath;
508   NSFileManager *fileManager = [NSFileManager defaultManager];
509   BOOL isDir;
511   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
512   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
513     {
514       if (isDir) return [resourcePath UTF8String];
515     }
516   return NULL;
520 const char *
521 ns_exec_path (void)
522 /* If running as a self-contained app bundle, return as a path string
523    the filenames of the libexec and bin directories, ie libexec:bin.
524    Otherwise, return nil.
525    Normally, Emacs does not add its own bin/ directory to the PATH.
526    However, a self-contained NS build has a different layout, with
527    bin/ and libexec/ subdirectories in the directory that contains
528    Emacs.app itself.
529    We put libexec first, because init_callproc_1 uses the first
530    element to initialize exec-directory.  An alternative would be
531    for init_callproc to check for invocation-directory/libexec.
534   NSBundle *bundle = [NSBundle mainBundle];
535   NSString *resourceDir = [bundle resourcePath];
536   NSString *binDir = [bundle bundlePath];
537   NSString *resourcePath, *resourcePaths;
538   NSRange range;
539   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
540   NSFileManager *fileManager = [NSFileManager defaultManager];
541   NSArray *paths;
542   NSEnumerator *pathEnum;
543   BOOL isDir;
545   range = [resourceDir rangeOfString: @"Contents"];
546   if (range.location != NSNotFound)
547     {
548       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
549 #ifdef NS_IMPL_COCOA
550       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
551 #endif
552     }
554   paths = [binDir stringsByAppendingPaths:
555                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
556   pathEnum = [paths objectEnumerator];
557   resourcePaths = @"";
559   while ((resourcePath = [pathEnum nextObject]))
560     {
561       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
562         if (isDir)
563           {
564             if ([resourcePaths length] > 0)
565               resourcePaths
566                 = [resourcePaths stringByAppendingString: pathSeparator];
567             resourcePaths
568               = [resourcePaths stringByAppendingString: resourcePath];
569           }
570     }
571   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
573   return NULL;
577 const char *
578 ns_load_path (void)
579 /* If running as a self-contained app bundle, return as a path string
580    the filenames of the site-lisp and lisp directories.
581    Ie, site-lisp:lisp.  Otherwise, return nil.  */
583   NSBundle *bundle = [NSBundle mainBundle];
584   NSString *resourceDir = [bundle resourcePath];
585   NSString *resourcePath, *resourcePaths;
586   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
587   NSFileManager *fileManager = [NSFileManager defaultManager];
588   BOOL isDir;
589   NSArray *paths = [resourceDir stringsByAppendingPaths:
590                               [NSArray arrayWithObjects:
591                                          @"site-lisp", @"lisp", nil]];
592   NSEnumerator *pathEnum = [paths objectEnumerator];
593   resourcePaths = @"";
595   /* Hack to skip site-lisp.  */
596   if (no_site_lisp) resourcePath = [pathEnum nextObject];
598   while ((resourcePath = [pathEnum nextObject]))
599     {
600       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
601         if (isDir)
602           {
603             if ([resourcePaths length] > 0)
604               resourcePaths
605                 = [resourcePaths stringByAppendingString: pathSeparator];
606             resourcePaths
607               = [resourcePaths stringByAppendingString: resourcePath];
608           }
609     }
610   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
612   return NULL;
616 void
617 ns_init_locale (void)
618 /* macOS doesn't set any environment variables for the locale when run
619    from the GUI. Get the locale from the OS and set LANG. */
621   NSLocale *locale = [NSLocale currentLocale];
623   NSTRACE ("ns_init_locale");
625   @try
626     {
627       /* It seems macOS should probably use UTF-8 everywhere.
628          'localeIdentifier' does not specify the encoding, and I can't
629          find any way to get the OS to tell us which encoding to use,
630          so hard-code '.UTF-8'. */
631       NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
632                                      [locale localeIdentifier]];
634       /* Set LANG to locale, but not if LANG is already set. */
635       setenv("LANG", [localeID UTF8String], 0);
636     }
637   @catch (NSException *e)
638     {
639       NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
640     }
644 void
645 ns_release_object (void *obj)
646 /* --------------------------------------------------------------------------
647     Release an object (callable from C)
648    -------------------------------------------------------------------------- */
650     [(id)obj release];
654 void
655 ns_retain_object (void *obj)
656 /* --------------------------------------------------------------------------
657     Retain an object (callable from C)
658    -------------------------------------------------------------------------- */
660     [(id)obj retain];
664 void *
665 ns_alloc_autorelease_pool (void)
666 /* --------------------------------------------------------------------------
667      Allocate a pool for temporary objects (callable from C)
668    -------------------------------------------------------------------------- */
670   return [[NSAutoreleasePool alloc] init];
674 void
675 ns_release_autorelease_pool (void *pool)
676 /* --------------------------------------------------------------------------
677      Free a pool and temporary objects it refers to (callable from C)
678    -------------------------------------------------------------------------- */
680   ns_release_object (pool);
684 static BOOL
685 ns_menu_bar_should_be_hidden (void)
686 /* True, if the menu bar should be hidden.  */
688   return !NILP (ns_auto_hide_menu_bar)
689     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
693 struct EmacsMargins
695   CGFloat top;
696   CGFloat bottom;
697   CGFloat left;
698   CGFloat right;
702 static struct EmacsMargins
703 ns_screen_margins (NSScreen *screen)
704 /* The parts of SCREEN used by the operating system.  */
706   NSTRACE ("ns_screen_margins");
708   struct EmacsMargins margins;
710   NSRect screenFrame = [screen frame];
711   NSRect screenVisibleFrame = [screen visibleFrame];
713   /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
714      menu bar, check this explicitly.  */
715   if (ns_menu_bar_should_be_hidden())
716     {
717       margins.top = 0;
718     }
719   else
720     {
721       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
722       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
723                                  + screenVisibleFrame.size.height);
725       margins.top = frameTop - visibleFrameTop;
726     }
728   {
729     CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
730     CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
731                                  + screenVisibleFrame.size.width);
732     margins.right = frameRight - visibleFrameRight;
733   }
735   margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
736   margins.left   = screenVisibleFrame.origin.x - screenFrame.origin.x;
738   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
739                margins.left,
740                margins.right,
741                margins.top,
742                margins.bottom);
744   return margins;
748 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
749    assumed to contain a hidden dock.  macOS currently use 4 pixels for
750    this, however, to be future compatible, a larger value is used.  */
751 #define DOCK_IGNORE_LIMIT 6
753 static struct EmacsMargins
754 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
755 /* The parts of SCREEN used by the operating system, excluding the parts
756 reserved for an hidden dock.  */
758   NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
760   struct EmacsMargins margins = ns_screen_margins(screen);
762   /* macOS (currently) reserved 4 pixels along the edge where a hidden
763      dock is located.  Unfortunately, it's not possible to find the
764      location and information about if the dock is hidden.  Instead,
765      it is assumed that if the margin of an edge is less than
766      DOCK_IGNORE_LIMIT, it contains a hidden dock.  */
767   if (margins.left <= DOCK_IGNORE_LIMIT)
768     {
769       margins.left = 0;
770     }
771   if (margins.right <= DOCK_IGNORE_LIMIT)
772     {
773       margins.right = 0;
774     }
775   if (margins.top <= DOCK_IGNORE_LIMIT)
776     {
777       margins.top = 0;
778     }
779   /* Note: This doesn't occur in current versions of macOS, but
780      included for completeness and future compatibility.  */
781   if (margins.bottom <= DOCK_IGNORE_LIMIT)
782     {
783       margins.bottom = 0;
784     }
786   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
787                margins.left,
788                margins.right,
789                margins.top,
790                margins.bottom);
792   return margins;
796 static CGFloat
797 ns_menu_bar_height (NSScreen *screen)
798 /* The height of the menu bar, if visible.
800    Note: Don't use this when fullscreen is enabled -- the screen
801    sometimes includes, sometimes excludes the menu bar area.  */
803   struct EmacsMargins margins = ns_screen_margins(screen);
805   CGFloat res = margins.top;
807   NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
809   return res;
813 /* ==========================================================================
815     Focus (clipping) and screen update
817    ========================================================================== */
820 // Window constraining
821 // -------------------
823 // To ensure that the windows are not placed under the menu bar, they
824 // are typically moved by the call-back constrainFrameRect. However,
825 // by overriding it, it's possible to inhibit this, leaving the window
826 // in it's original position.
828 // It's possible to hide the menu bar. However, technically, it's only
829 // possible to hide it when the application is active. To ensure that
830 // this work properly, the menu bar and window constraining are
831 // deferred until the application becomes active.
833 // Even though it's not possible to manually move a window above the
834 // top of the screen, it is allowed if it's done programmatically,
835 // when the menu is hidden. This allows the editable area to cover the
836 // full screen height.
838 // Test cases
839 // ----------
841 // Use the following extra files:
843 //    init.el:
844 //       ;; Hide menu and place frame slightly above the top of the screen.
845 //       (setq ns-auto-hide-menu-bar t)
846 //       (set-frame-position (selected-frame) 0 -20)
848 // Test 1:
850 //    emacs -Q -l init.el
852 //    Result: No menu bar, and the title bar should be above the screen.
854 // Test 2:
856 //    emacs -Q
858 //    Result: Menu bar visible, frame placed immediately below the menu.
861 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
863   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
864              NSTRACE_ARG_RECT (frameRect));
866   // --------------------
867   // Collect information about the screen the frame is covering.
868   //
870   NSArray *screens = [NSScreen screens];
871   NSUInteger nr_screens = [screens count];
873   int i;
875   // The height of the menu bar, if present in any screen the frame is
876   // displayed in.
877   int menu_bar_height = 0;
879   // A rectangle covering all the screen the frame is displayed in.
880   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
881   for (i = 0; i < nr_screens; ++i )
882     {
883       NSScreen *s = [screens objectAtIndex: i];
884       NSRect scrRect = [s frame];
886       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
887                    i, NSTRACE_ARG_RECT (scrRect));
889       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
890         {
891           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
893           if (!isFullscreen)
894             {
895               CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
896               menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
897             }
898         }
899     }
901   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
903   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
905   if (multiscreenRect.size.width == 0
906       || multiscreenRect.size.height == 0)
907     {
908       // Failed to find any monitor, give up.
909       NSTRACE_MSG ("multiscreenRect empty");
910       NSTRACE_RETURN_RECT (frameRect);
911       return frameRect;
912     }
915   // --------------------
916   // Find a suitable placement.
917   //
919   if (ns_menu_bar_should_be_hidden())
920     {
921       // When the menu bar is hidden, the user may place part of the
922       // frame above the top of the screen, for example to hide the
923       // title bar.
924       //
925       // Hence, keep the original position.
926     }
927   else
928     {
929       // Ensure that the frame is below the menu bar, or below the top
930       // of the screen.
931       //
932       // This assume that the menu bar is placed at the top in the
933       // rectangle that covers the monitors.  (It doesn't have to be,
934       // but if it's not it's hard to do anything useful.)
935       CGFloat topOfWorkArea = (multiscreenRect.origin.y
936                                + multiscreenRect.size.height
937                                - menu_bar_height);
939       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
940       if (topOfFrame > topOfWorkArea)
941         {
942           frameRect.origin.y -= topOfFrame - topOfWorkArea;
943           NSTRACE_RECT ("After placement adjust", frameRect);
944         }
945     }
947   // Include the following section to restrict frame to the screens.
948   // (If so, update it to allow the frame to stretch down below the
949   // screen.)
950 #if 0
951   // --------------------
952   // Ensure frame doesn't stretch below the screens.
953   //
955   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
957   if (diff > 0)
958     {
959       frameRect.origin.y = multiscreenRect.origin.y;
960       frameRect.size.height -= diff;
961     }
962 #endif
964   NSTRACE_RETURN_RECT (frameRect);
965   return frameRect;
969 static void
970 ns_constrain_all_frames (void)
971 /* --------------------------------------------------------------------------
972      Ensure that the menu bar doesn't cover any frames.
973    -------------------------------------------------------------------------- */
975   Lisp_Object tail, frame;
977   NSTRACE ("ns_constrain_all_frames");
979   block_input ();
981   FOR_EACH_FRAME (tail, frame)
982     {
983       struct frame *f = XFRAME (frame);
984       if (FRAME_NS_P (f))
985         {
986           EmacsView *view = FRAME_NS_VIEW (f);
988           if (![view isFullscreen])
989             {
990               [[view window]
991                 setFrame:constrain_frame_rect([[view window] frame], false)
992                  display:NO];
993             }
994         }
995     }
997   unblock_input ();
1001 static void
1002 ns_update_auto_hide_menu_bar (void)
1003 /* --------------------------------------------------------------------------
1004      Show or hide the menu bar, based on user setting.
1005    -------------------------------------------------------------------------- */
1007 #ifdef NS_IMPL_COCOA
1008   NSTRACE ("ns_update_auto_hide_menu_bar");
1010   block_input ();
1012   if (NSApp != nil && [NSApp isActive])
1013     {
1014       // Note, "setPresentationOptions" triggers an error unless the
1015       // application is active.
1016       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
1018       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
1019         {
1020           NSApplicationPresentationOptions options
1021             = NSApplicationPresentationDefault;
1023           if (menu_bar_should_be_hidden)
1024             options |= NSApplicationPresentationAutoHideMenuBar
1025               | NSApplicationPresentationAutoHideDock;
1027           [NSApp setPresentationOptions: options];
1029           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1031           if (!ns_menu_bar_is_hidden)
1032             {
1033               ns_constrain_all_frames ();
1034             }
1035         }
1036     }
1038   unblock_input ();
1039 #endif
1043 static void
1044 ns_update_begin (struct frame *f)
1045 /* --------------------------------------------------------------------------
1046    Prepare for a grouped sequence of drawing calls
1047    external (RIF) call; whole frame, called before update_window_begin
1048    -------------------------------------------------------------------------- */
1050   EmacsView *view = FRAME_NS_VIEW (f);
1051   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1053   ns_update_auto_hide_menu_bar ();
1055 #ifdef NS_IMPL_COCOA
1056   if ([view isFullscreen] && [view fsIsNative])
1057   {
1058     // Fix reappearing tool bar in fullscreen for Mac OS X 10.7
1059     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1060     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1061     if (! tbar_visible != ! [toolbar isVisible])
1062       [toolbar setVisible: tbar_visible];
1063   }
1064 #endif
1066   ns_updating_frame = f;
1067   [view lockFocus];
1069   /* drawRect may have been called for say the minibuffer, and then clip path
1070      is for the minibuffer.  But the display engine may draw more because
1071      we have set the frame as garbaged.  So reset clip path to the whole
1072      view.  */
1073 #ifdef NS_IMPL_COCOA
1074   {
1075     NSBezierPath *bp;
1076     NSRect r = [view frame];
1077     NSRect cr = [[view window] frame];
1078     /* If a large frame size is set, r may be larger than the window frame
1079        before constrained.  In that case don't change the clip path, as we
1080        will clear in to the tool bar and title bar.  */
1081     if (r.size.height
1082         + FRAME_NS_TITLEBAR_HEIGHT (f)
1083         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1084       {
1085         bp = [[NSBezierPath bezierPathWithRect: r] retain];
1086         [bp setClip];
1087         [bp release];
1088       }
1089   }
1090 #endif
1092 #ifdef NS_IMPL_GNUSTEP
1093   uRect = NSMakeRect (0, 0, 0, 0);
1094 #endif
1098 static void
1099 ns_update_window_begin (struct window *w)
1100 /* --------------------------------------------------------------------------
1101    Prepare for a grouped sequence of drawing calls
1102    external (RIF) call; for one window, called after update_begin
1103    -------------------------------------------------------------------------- */
1105   struct frame *f = XFRAME (WINDOW_FRAME (w));
1106   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1108   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1109   w->output_cursor = w->cursor;
1111   block_input ();
1113   if (f == hlinfo->mouse_face_mouse_frame)
1114     {
1115       /* Don't do highlighting for mouse motion during the update.  */
1116       hlinfo->mouse_face_defer = 1;
1118         /* If the frame needs to be redrawn,
1119            simply forget about any prior mouse highlighting.  */
1120       if (FRAME_GARBAGED_P (f))
1121         hlinfo->mouse_face_window = Qnil;
1123       /* (further code for mouse faces ifdef'd out in other terms elided) */
1124     }
1126   unblock_input ();
1130 static void
1131 ns_update_window_end (struct window *w, bool cursor_on_p,
1132                       bool mouse_face_overwritten_p)
1133 /* --------------------------------------------------------------------------
1134    Finished a grouped sequence of drawing calls
1135    external (RIF) call; for one window called before update_end
1136    -------------------------------------------------------------------------- */
1138   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1140   /* note: this fn is nearly identical in all terms */
1141   if (!w->pseudo_window_p)
1142     {
1143       block_input ();
1145       if (cursor_on_p)
1146         display_and_set_cursor (w, 1,
1147                                 w->output_cursor.hpos, w->output_cursor.vpos,
1148                                 w->output_cursor.x, w->output_cursor.y);
1150       if (draw_window_fringes (w, 1))
1151         {
1152           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1153             x_draw_right_divider (w);
1154           else
1155             x_draw_vertical_border (w);
1156         }
1158       unblock_input ();
1159     }
1161   /* If a row with mouse-face was overwritten, arrange for
1162      frame_up_to_date to redisplay the mouse highlight.  */
1163   if (mouse_face_overwritten_p)
1164     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1168 static void
1169 ns_update_end (struct frame *f)
1170 /* --------------------------------------------------------------------------
1171    Finished a grouped sequence of drawing calls
1172    external (RIF) call; for whole frame, called after update_window_end
1173    -------------------------------------------------------------------------- */
1175   EmacsView *view = FRAME_NS_VIEW (f);
1177   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1179 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1180   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1182   block_input ();
1184   [view unlockFocus];
1185   [[view window] flushWindow];
1187   unblock_input ();
1188   ns_updating_frame = NULL;
1191 static void
1192 ns_focus (struct frame *f, NSRect *r, int n)
1193 /* --------------------------------------------------------------------------
1194    Internal: Focus on given frame.  During small local updates this is used to
1195      draw, however during large updates, ns_update_begin and ns_update_end are
1196      called to wrap the whole thing, in which case these calls are stubbed out.
1197      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1198      the back end won't do this automatically, and will just end up flushing
1199      the entire window.
1200    -------------------------------------------------------------------------- */
1202   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1203   if (r != NULL)
1204     {
1205       NSTRACE_RECT ("r", *r);
1206     }
1208   if (f != ns_updating_frame)
1209     {
1210       NSView *view = FRAME_NS_VIEW (f);
1211       if (view != focus_view)
1212         {
1213           if (focus_view != NULL)
1214             {
1215               [focus_view unlockFocus];
1216               [[focus_view window] flushWindow];
1217 /*debug_lock--; */
1218             }
1220           if (view)
1221             [view lockFocus];
1222           focus_view = view;
1223 /*if (view) debug_lock++; */
1224         }
1225     }
1227   /* clipping */
1228   if (r)
1229     {
1230       [[NSGraphicsContext currentContext] saveGraphicsState];
1231       if (n == 2)
1232         NSRectClipList (r, 2);
1233       else
1234         NSRectClip (*r);
1235       gsaved = YES;
1236     }
1240 static void
1241 ns_unfocus (struct frame *f)
1242 /* --------------------------------------------------------------------------
1243      Internal: Remove focus on given frame
1244    -------------------------------------------------------------------------- */
1246   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1248   if (gsaved)
1249     {
1250       [[NSGraphicsContext currentContext] restoreGraphicsState];
1251       gsaved = NO;
1252     }
1254   if (f != ns_updating_frame)
1255     {
1256       if (focus_view != NULL)
1257         {
1258           [focus_view unlockFocus];
1259           [[focus_view window] flushWindow];
1260           focus_view = NULL;
1261 /*debug_lock--; */
1262         }
1263     }
1267 static void
1268 ns_clip_to_row (struct window *w, struct glyph_row *row,
1269                 enum glyph_row_area area, BOOL gc)
1270 /* --------------------------------------------------------------------------
1271      Internal (but parallels other terms): Focus drawing on given row
1272    -------------------------------------------------------------------------- */
1274   struct frame *f = XFRAME (WINDOW_FRAME (w));
1275   NSRect clip_rect;
1276   int window_x, window_y, window_width;
1278   window_box (w, area, &window_x, &window_y, &window_width, 0);
1280   clip_rect.origin.x = window_x;
1281   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1282   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1283   clip_rect.size.width = window_width;
1284   clip_rect.size.height = row->visible_height;
1286   ns_focus (f, &clip_rect, 1);
1290 /* ==========================================================================
1292     Visible bell and beep.
1294    ========================================================================== */
1297 // This bell implementation shows the visual bell image asynchronously
1298 // from the rest of Emacs. This is done by adding a NSView to the
1299 // superview of the Emacs window and removing it using a timer.
1301 // Unfortunately, some Emacs operations, like scrolling, is done using
1302 // low-level primitives that copy the content of the window, including
1303 // the bell image. To some extent, this is handled by removing the
1304 // image prior to scrolling and marking that the window is in need for
1305 // redisplay.
1307 // To test this code, make sure that there is no artifacts of the bell
1308 // image in the following situations. Use a non-empty buffer (like the
1309 // tutorial) to ensure that a scroll is performed:
1311 // * Single-window: C-g C-v
1313 // * Side-by-windows: C-x 3 C-g C-v
1315 // * Windows above each other: C-x 2 C-g C-v
1317 @interface EmacsBell : NSImageView
1319   // Number of currently active bell:s.
1320   unsigned int nestCount;
1321   NSView * mView;
1322   bool isAttached;
1324 - (void)show:(NSView *)view;
1325 - (void)hide;
1326 - (void)remove;
1327 @end
1329 @implementation EmacsBell
1331 - (id)init
1333   NSTRACE ("[EmacsBell init]");
1334   if ((self = [super init]))
1335     {
1336       nestCount = 0;
1337       isAttached = false;
1338 #ifdef NS_IMPL_GNUSTEP
1339       // GNUstep doesn't provide named images.  This was reported in
1340       // 2011, see https://savannah.gnu.org/bugs/?33396
1341       //
1342       // As a drop in replacement, a semitransparent gray square is used.
1343       self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1344       [self.image lockFocus];
1345       [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1346       NSRectFill(NSMakeRect(0, 0, 32, 32));
1347       [self.image unlockFocus];
1348 #else
1349       self.image = [NSImage imageNamed:NSImageNameCaution];
1350       [self.image setSize:NSMakeSize(self.image.size.width * 5,
1351                                      self.image.size.height * 5)];
1352 #endif
1353     }
1354   return self;
1357 - (void)show:(NSView *)view
1359   NSTRACE ("[EmacsBell show:]");
1360   NSTRACE_MSG ("nestCount: %u", nestCount);
1362   // Show the image, unless it's already shown.
1363   if (nestCount == 0)
1364     {
1365       NSRect rect = [view bounds];
1366       NSPoint pos;
1367       pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
1368       pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1370       [self setFrameOrigin:pos];
1371       [self setFrameSize:self.image.size];
1373       isAttached = true;
1374       mView = view;
1375       [[[view window] contentView] addSubview:self
1376                                    positioned:NSWindowAbove
1377                                    relativeTo:nil];
1378     }
1380   ++nestCount;
1382   [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1386 - (void)hide
1388   // Note: Trace output from this method isn't shown, reason unknown.
1389   // NSTRACE ("[EmacsBell hide]");
1391   if (nestCount > 0)
1392     --nestCount;
1394   // Remove the image once the last bell became inactive.
1395   if (nestCount == 0)
1396     {
1397       [self remove];
1398     }
1402 -(void)remove
1404   NSTRACE ("[EmacsBell remove]");
1405   if (isAttached)
1406     {
1407       NSTRACE_MSG ("removeFromSuperview");
1408       [self removeFromSuperview];
1409       mView.needsDisplay = YES;
1410       isAttached = false;
1411     }
1414 @end
1417 static EmacsBell * bell_view = nil;
1419 static void
1420 ns_ring_bell (struct frame *f)
1421 /* --------------------------------------------------------------------------
1422      "Beep" routine
1423    -------------------------------------------------------------------------- */
1425   NSTRACE ("ns_ring_bell");
1426   if (visible_bell)
1427     {
1428       struct frame *frame = SELECTED_FRAME ();
1429       NSView *view;
1431       if (bell_view == nil)
1432         {
1433           bell_view = [[EmacsBell alloc] init];
1434           [bell_view retain];
1435         }
1437       block_input ();
1439       view = FRAME_NS_VIEW (frame);
1440       if (view != nil)
1441         {
1442           [bell_view show:view];
1443         }
1445       unblock_input ();
1446     }
1447   else
1448     {
1449       NSBeep ();
1450     }
1454 static void
1455 hide_bell (void)
1456 /* --------------------------------------------------------------------------
1457      Ensure the bell is hidden.
1458    -------------------------------------------------------------------------- */
1460   NSTRACE ("hide_bell");
1462   if (bell_view != nil)
1463     {
1464       [bell_view remove];
1465     }
1469 /* ==========================================================================
1471     Frame / window manager related functions
1473    ========================================================================== */
1476 static void
1477 ns_raise_frame (struct frame *f, BOOL make_key)
1478 /* --------------------------------------------------------------------------
1479      Bring window to foreground and if make_key is YES, give it focus.
1480    -------------------------------------------------------------------------- */
1482   NSView *view;
1484   check_window_system (f);
1485   view = FRAME_NS_VIEW (f);
1486   block_input ();
1487   if (FRAME_VISIBLE_P (f))
1488     {
1489       if (make_key)
1490         [[view window] makeKeyAndOrderFront: NSApp];
1491       else
1492         [[view window] orderFront: NSApp];
1493     }
1494   unblock_input ();
1498 static void
1499 ns_lower_frame (struct frame *f)
1500 /* --------------------------------------------------------------------------
1501      Send window to back
1502    -------------------------------------------------------------------------- */
1504   NSView *view;
1506   check_window_system (f);
1507   view = FRAME_NS_VIEW (f);
1508   block_input ();
1509   [[view window] orderBack: NSApp];
1510   unblock_input ();
1514 static void
1515 ns_frame_raise_lower (struct frame *f, bool raise)
1516 /* --------------------------------------------------------------------------
1517      External (hook)
1518    -------------------------------------------------------------------------- */
1520   NSTRACE ("ns_frame_raise_lower");
1522   if (raise)
1523     ns_raise_frame (f, YES);
1524   else
1525     ns_lower_frame (f);
1529 static void
1530 ns_frame_rehighlight (struct frame *frame)
1531 /* --------------------------------------------------------------------------
1532      External (hook): called on things like window switching within frame
1533    -------------------------------------------------------------------------- */
1535   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1536   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1538   NSTRACE ("ns_frame_rehighlight");
1539   if (dpyinfo->x_focus_frame)
1540     {
1541       dpyinfo->x_highlight_frame
1542         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1543            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1544            : dpyinfo->x_focus_frame);
1545       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1546         {
1547           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1548           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1549         }
1550     }
1551   else
1552       dpyinfo->x_highlight_frame = 0;
1554   if (dpyinfo->x_highlight_frame &&
1555          dpyinfo->x_highlight_frame != old_highlight)
1556     {
1557       if (old_highlight)
1558         {
1559           x_update_cursor (old_highlight, 1);
1560           x_set_frame_alpha (old_highlight);
1561         }
1562       if (dpyinfo->x_highlight_frame)
1563         {
1564           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1565           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1566         }
1567     }
1571 void
1572 x_make_frame_visible (struct frame *f)
1573 /* --------------------------------------------------------------------------
1574      External: Show the window (X11 semantics)
1575    -------------------------------------------------------------------------- */
1577   NSTRACE ("x_make_frame_visible");
1578   /* XXX: at some points in past this was not needed, as the only place that
1579      called this (frame.c:Fraise_frame ()) also called raise_lower;
1580      if this ends up the case again, comment this out again. */
1581   if (!FRAME_VISIBLE_P (f))
1582     {
1583       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1584       NSWindow *window = [view window];
1586       SET_FRAME_VISIBLE (f, 1);
1587       ns_raise_frame (f, ! FRAME_NO_FOCUS_ON_MAP (f));
1589       /* Making a new frame from a fullscreen frame will make the new frame
1590          fullscreen also.  So skip handleFS as this will print an error.  */
1591       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1592           && [view isFullscreen])
1593         return;
1595       if (f->want_fullscreen != FULLSCREEN_NONE)
1596         {
1597           block_input ();
1598           [view handleFS];
1599           unblock_input ();
1600         }
1602       /* Making a frame invisible seems to break the parent->child
1603          relationship, so reinstate it. */
1604       if ([window parentWindow] == nil && FRAME_PARENT_FRAME (f) != NULL)
1605         {
1606           NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1608           block_input ();
1609           [parent addChildWindow: window
1610                          ordered: NSWindowAbove];
1611           unblock_input ();
1613           /* If the parent frame moved while the child frame was
1614              invisible, the child frame's position won't have been
1615              updated.  Make sure it's in the right place now. */
1616           x_set_offset(f, f->left_pos, f->top_pos, 0);
1617         }
1618     }
1622 void
1623 x_make_frame_invisible (struct frame *f)
1624 /* --------------------------------------------------------------------------
1625      External: Hide the window (X11 semantics)
1626    -------------------------------------------------------------------------- */
1628   NSView *view;
1629   NSTRACE ("x_make_frame_invisible");
1630   check_window_system (f);
1631   view = FRAME_NS_VIEW (f);
1632   [[view window] orderOut: NSApp];
1633   SET_FRAME_VISIBLE (f, 0);
1634   SET_FRAME_ICONIFIED (f, 0);
1638 void
1639 x_iconify_frame (struct frame *f)
1640 /* --------------------------------------------------------------------------
1641      External: Iconify window
1642    -------------------------------------------------------------------------- */
1644   NSView *view;
1645   struct ns_display_info *dpyinfo;
1647   NSTRACE ("x_iconify_frame");
1648   check_window_system (f);
1649   view = FRAME_NS_VIEW (f);
1650   dpyinfo = FRAME_DISPLAY_INFO (f);
1652   if (dpyinfo->x_highlight_frame == f)
1653     dpyinfo->x_highlight_frame = 0;
1655   if ([[view window] windowNumber] <= 0)
1656     {
1657       /* the window is still deferred.  Make it very small, bring it
1658          on screen and order it out. */
1659       NSRect s = { { 100, 100}, {0, 0} };
1660       NSRect t;
1661       t = [[view window] frame];
1662       [[view window] setFrame: s display: NO];
1663       [[view window] orderBack: NSApp];
1664       [[view window] orderOut: NSApp];
1665       [[view window] setFrame: t display: NO];
1666     }
1668   /* Processing input while Emacs is being minimized can cause a
1669      crash, so block it for the duration. */
1670   block_input();
1671   [[view window] miniaturize: NSApp];
1672   unblock_input();
1675 /* Free X resources of frame F.  */
1677 void
1678 x_free_frame_resources (struct frame *f)
1680   NSView *view;
1681   struct ns_display_info *dpyinfo;
1682   Mouse_HLInfo *hlinfo;
1684   NSTRACE ("x_free_frame_resources");
1685   check_window_system (f);
1686   view = FRAME_NS_VIEW (f);
1687   dpyinfo = FRAME_DISPLAY_INFO (f);
1688   hlinfo = MOUSE_HL_INFO (f);
1690   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1692   block_input ();
1694   free_frame_menubar (f);
1695   free_frame_faces (f);
1697   if (f == dpyinfo->x_focus_frame)
1698     dpyinfo->x_focus_frame = 0;
1699   if (f == dpyinfo->x_highlight_frame)
1700     dpyinfo->x_highlight_frame = 0;
1701   if (f == hlinfo->mouse_face_mouse_frame)
1702     reset_mouse_highlight (hlinfo);
1704   if (f->output_data.ns->miniimage != nil)
1705     [f->output_data.ns->miniimage release];
1707   [[view window] close];
1708   [view release];
1710   xfree (f->output_data.ns);
1712   unblock_input ();
1715 void
1716 x_destroy_window (struct frame *f)
1717 /* --------------------------------------------------------------------------
1718      External: Delete the window
1719    -------------------------------------------------------------------------- */
1721   NSTRACE ("x_destroy_window");
1723   /* If this frame has a parent window, detach it as not doing so can
1724      cause a crash in GNUStep. */
1725   if (FRAME_PARENT_FRAME (f) != NULL)
1726     {
1727       NSWindow *child = [FRAME_NS_VIEW (f) window];
1728       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
1730       [parent removeChildWindow: child];
1731     }
1733   check_window_system (f);
1734   x_free_frame_resources (f);
1735   ns_window_num--;
1739 void
1740 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1741 /* --------------------------------------------------------------------------
1742      External: Position the window
1743    -------------------------------------------------------------------------- */
1745   NSView *view = FRAME_NS_VIEW (f);
1746   NSArray *screens = [NSScreen screens];
1747   NSScreen *fscreen = [screens objectAtIndex: 0];
1748   NSScreen *screen = [[view window] screen];
1750   NSTRACE ("x_set_offset");
1752   block_input ();
1754   f->left_pos = xoff;
1755   f->top_pos = yoff;
1757   if (view != nil && screen && fscreen)
1758     {
1759       f->left_pos = f->size_hint_flags & XNegative
1760         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1761         : f->left_pos;
1762       /* We use visibleFrame here to take menu bar into account.
1763          Ideally we should also adjust left/top with visibleFrame.origin.  */
1765       f->top_pos = f->size_hint_flags & YNegative
1766         ? ([screen visibleFrame].size.height + f->top_pos
1767            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1768            - FRAME_TOOLBAR_HEIGHT (f))
1769         : f->top_pos;
1770 #ifdef NS_IMPL_GNUSTEP
1771       if (FRAME_PARENT_FRAME (f) == NULL)
1772         {
1773           if (f->left_pos < 100)
1774             f->left_pos = 100;  /* don't overlap menu */
1775         }
1776 #endif
1777       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1778          menu bar.  */
1779       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos
1780                                                 + NS_PARENT_WINDOW_LEFT_POS (f)),
1781                                 SCREENMAXBOUND (NS_PARENT_WINDOW_TOP_POS (f)
1782                                                 - f->top_pos));
1783       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1784       [[view window] setFrameTopLeftPoint: pt];
1785       f->size_hint_flags &= ~(XNegative|YNegative);
1786     }
1788   unblock_input ();
1792 void
1793 x_set_window_size (struct frame *f,
1794                    bool change_gravity,
1795                    int width,
1796                    int height,
1797                    bool pixelwise)
1798 /* --------------------------------------------------------------------------
1799      Adjust window pixel size based on given character grid size
1800      Impl is a bit more complex than other terms, need to do some
1801      internal clipping.
1802    -------------------------------------------------------------------------- */
1804   EmacsView *view = FRAME_NS_VIEW (f);
1805   NSWindow *window = [view window];
1806   NSRect wr = [window frame];
1807   int pixelwidth, pixelheight;
1808   int orig_height = wr.size.height;
1810   NSTRACE ("x_set_window_size");
1812   if (view == nil)
1813     return;
1815   NSTRACE_RECT ("current", wr);
1816   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1817   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1819   block_input ();
1821   if (pixelwise)
1822     {
1823       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1824       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1825     }
1826   else
1827     {
1828       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1829       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1830     }
1832   wr.size.width = pixelwidth + f->border_width;
1833   wr.size.height = pixelheight;
1834   if (! [view isFullscreen])
1835     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1836       + FRAME_TOOLBAR_HEIGHT (f);
1838   /* Do not try to constrain to this screen.  We may have multiple
1839      screens, and want Emacs to span those.  Constraining to screen
1840      prevents that, and that is not nice to the user.  */
1841  if (f->output_data.ns->zooming)
1842    f->output_data.ns->zooming = 0;
1843  else
1844    wr.origin.y += orig_height - wr.size.height;
1846  frame_size_history_add
1847    (f, Qx_set_window_size_1, width, height,
1848     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1849            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1850            make_number (f->border_width),
1851            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1852            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1854   [window setFrame: wr display: YES];
1856   [view updateFrameSize: NO];
1857   unblock_input ();
1860 #ifdef NS_IMPL_COCOA
1861 void
1862 x_set_undecorated (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1863 /* --------------------------------------------------------------------------
1864      Set frame F's `undecorated' parameter.  If non-nil, F's window-system
1865      window is drawn without decorations, title, minimize/maximize boxes
1866      and external borders.  This usually means that the window cannot be
1867      dragged, resized, iconified, maximized or deleted with the mouse.  If
1868      nil, draw the frame with all the elements listed above unless these
1869      have been suspended via window manager settings.
1871      GNUStep cannot change an existing window's style.
1872    -------------------------------------------------------------------------- */
1874   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1875   NSWindow *window = [view window];
1877   NSTRACE ("x_set_undecorated");
1879   if (!EQ (new_value, old_value))
1880     {
1881       block_input ();
1883       if (NILP (new_value))
1884         {
1885           FRAME_UNDECORATED (f) = false;
1886           [window setStyleMask: ((window.styleMask | FRAME_DECORATED_FLAGS)
1887                                   ^ FRAME_UNDECORATED_FLAGS)];
1889           [view createToolbar: f];
1890         }
1891       else
1892         {
1893           [window setToolbar: nil];
1894           /* Do I need to release the toolbar here? */
1896           FRAME_UNDECORATED (f) = true;
1897           [window setStyleMask: ((window.styleMask | FRAME_UNDECORATED_FLAGS)
1898                                  ^ FRAME_DECORATED_FLAGS)];
1899         }
1901       /* At this point it seems we don't have an active NSResponder,
1902          so some key presses (TAB) are swallowed by the system. */
1903       [window makeFirstResponder: view];
1905       [view updateFrameSize: NO];
1906       unblock_input ();
1907     }
1909 #endif /* NS_IMPL_COCOA */
1911 void
1912 x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1913 /* --------------------------------------------------------------------------
1914      Set frame F's `parent-frame' parameter.  If non-nil, make F a child
1915      frame of the frame specified by that parameter.  Technically, this
1916      makes F's window-system window a child window of the parent frame's
1917      window-system window.  If nil, make F's window-system window a
1918      top-level window--a child of its display's root window.
1920      A child frame's `left' and `top' parameters specify positions
1921      relative to the top-left corner of its parent frame's native
1922      rectangle.  On macOS moving a parent frame moves all its child
1923      frames too, keeping their position relative to the parent
1924      unaltered.  When a parent frame is iconified or made invisible, its
1925      child frames are made invisible.  When a parent frame is deleted,
1926      its child frames are deleted too.
1928      Whether a child frame has a tool bar may be window-system or window
1929      manager dependent.  It's advisable to disable it via the frame
1930      parameter settings.
1932      Some window managers may not honor this parameter.
1933    -------------------------------------------------------------------------- */
1935   struct frame *p = NULL;
1936   NSWindow *parent, *child;
1938   NSTRACE ("x_set_parent_frame");
1940   if (!NILP (new_value)
1941       && (!FRAMEP (new_value)
1942           || !FRAME_LIVE_P (p = XFRAME (new_value))
1943           || !FRAME_X_P (p)))
1944     {
1945       store_frame_param (f, Qparent_frame, old_value);
1946       error ("Invalid specification of `parent-frame'");
1947     }
1949   if (p != FRAME_PARENT_FRAME (f))
1950     {
1951       parent = [FRAME_NS_VIEW (p) window];
1952       child = [FRAME_NS_VIEW (f) window];
1954       block_input ();
1955       [parent addChildWindow: child
1956                      ordered: NSWindowAbove];
1957       unblock_input ();
1959       fset_parent_frame (f, new_value);
1960     }
1963 void
1964 x_set_no_focus_on_map (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1965 /* Set frame F's `no-focus-on-map' parameter which, if non-nil, means
1966  * that F's window-system window does not want to receive input focus
1967  * when it is mapped.  (A frame's window is mapped when the frame is
1968  * displayed for the first time and when the frame changes its state
1969  * from `iconified' or `invisible' to `visible'.)
1971  * Some window managers may not honor this parameter. */
1973   NSTRACE ("x_set_no_focus_on_map");
1975   if (!EQ (new_value, old_value))
1976     {
1977       FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1978     }
1981 void
1982 x_set_no_accept_focus (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1983 /*  Set frame F's `no-accept-focus' parameter which, if non-nil, hints
1984  * that F's window-system window does not want to receive input focus
1985  * via mouse clicks or by moving the mouse into it.
1987  * If non-nil, this may have the unwanted side-effect that a user cannot
1988  * scroll a non-selected frame with the mouse.
1990  * Some window managers may not honor this parameter. */
1992   NSTRACE ("x_set_no_accept_focus");
1994   if (!EQ (new_value, old_value))
1995     FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1998 void
1999 x_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
2000 /* Set frame F's `z-group' parameter.  If `above', F's window-system
2001    window is displayed above all windows that do not have the `above'
2002    property set.  If nil, F's window is shown below all windows that
2003    have the `above' property set and above all windows that have the
2004    `below' property set.  If `below', F's window is displayed below
2005    all windows that do.
2007    Some window managers may not honor this parameter. */
2009   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2010   NSWindow *window = [view window];
2012   NSTRACE ("x_set_z_group");
2014   if (NILP (new_value))
2015     {
2016       window.level = NSNormalWindowLevel;
2017       FRAME_Z_GROUP (f) = z_group_none;
2018     }
2019   else if (EQ (new_value, Qabove))
2020     {
2021       window.level = NSNormalWindowLevel + 1;
2022       FRAME_Z_GROUP (f) = z_group_above;
2023     }
2024   else if (EQ (new_value, Qabove_suspended))
2025     {
2026       /* Not sure what level this should be. */
2027       window.level = NSNormalWindowLevel + 1;
2028       FRAME_Z_GROUP (f) = z_group_above_suspended;
2029     }
2030   else if (EQ (new_value, Qbelow))
2031     {
2032       window.level = NSNormalWindowLevel - 1;
2033       FRAME_Z_GROUP (f) = z_group_below;
2034     }
2035   else
2036     error ("Invalid z-group specification");
2039 static void
2040 ns_fullscreen_hook (struct frame *f)
2042   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
2044   NSTRACE ("ns_fullscreen_hook");
2046   if (!FRAME_VISIBLE_P (f))
2047     return;
2049    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
2050     {
2051       /* Old style fs don't initiate correctly if created from
2052          init/default-frame alist, so use a timer (not nice...).
2053       */
2054       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
2055                                      selector: @selector (handleFS)
2056                                      userInfo: nil repeats: NO];
2057       return;
2058     }
2060   block_input ();
2061   [view handleFS];
2062   unblock_input ();
2065 /* ==========================================================================
2067     Color management
2069    ========================================================================== */
2072 NSColor *
2073 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
2075   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2076   if (idx < 1 || idx >= color_table->avail)
2077     return nil;
2078   return color_table->colors[idx];
2082 unsigned long
2083 ns_index_color (NSColor *color, struct frame *f)
2085   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
2086   ptrdiff_t idx;
2087   ptrdiff_t i;
2089   if (!color_table->colors)
2090     {
2091       color_table->size = NS_COLOR_CAPACITY;
2092       color_table->avail = 1; /* skip idx=0 as marker */
2093       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
2094       color_table->colors[0] = nil;
2095       color_table->empty_indices = [[NSMutableSet alloc] init];
2096     }
2098   /* Do we already have this color?  */
2099   for (i = 1; i < color_table->avail; i++)
2100     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
2101       return i;
2103   if ([color_table->empty_indices count] > 0)
2104     {
2105       NSNumber *index = [color_table->empty_indices anyObject];
2106       [color_table->empty_indices removeObject: index];
2107       idx = [index unsignedLongValue];
2108     }
2109   else
2110     {
2111       if (color_table->avail == color_table->size)
2112         color_table->colors =
2113           xpalloc (color_table->colors, &color_table->size, 1,
2114                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
2115       idx = color_table->avail++;
2116     }
2118   color_table->colors[idx] = color;
2119   [color retain];
2120 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
2121   return idx;
2125 static int
2126 ns_get_color (const char *name, NSColor **col)
2127 /* --------------------------------------------------------------------------
2128      Parse a color name
2129    -------------------------------------------------------------------------- */
2130 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
2131    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
2132    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
2134   NSColor *new = nil;
2135   static char hex[20];
2136   int scaling = 0;
2137   float r = -1.0, g, b;
2138   NSString *nsname = [NSString stringWithUTF8String: name];
2140   NSTRACE ("ns_get_color(%s, **)", name);
2142   block_input ();
2144   if ([nsname isEqualToString: @"ns_selection_bg_color"])
2145     {
2146 #ifdef NS_IMPL_COCOA
2147       NSString *defname = [[NSUserDefaults standardUserDefaults]
2148                             stringForKey: @"AppleHighlightColor"];
2149       if (defname != nil)
2150         nsname = defname;
2151       else
2152 #endif
2153       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
2154         {
2155           *col = [new colorUsingDefaultColorSpace];
2156           unblock_input ();
2157           return 0;
2158         }
2159       else
2160         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
2162       name = [nsname UTF8String];
2163     }
2164   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
2165     {
2166       /* NOTE: macOS applications normally don't set foreground
2167          selection, but text may be unreadable if we don't.
2168       */
2169       if ((new = [NSColor selectedTextColor]) != nil)
2170         {
2171           *col = [new colorUsingDefaultColorSpace];
2172           unblock_input ();
2173           return 0;
2174         }
2176       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
2177       name = [nsname UTF8String];
2178     }
2180   /* First, check for some sort of numeric specification. */
2181   hex[0] = '\0';
2183   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
2184     {
2185       NSScanner *scanner = [NSScanner scannerWithString: nsname];
2186       [scanner scanFloat: &r];
2187       [scanner scanFloat: &g];
2188       [scanner scanFloat: &b];
2189     }
2190   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
2191     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2192   else if (name[0] == '#')        /* An old X11 format; convert to newer */
2193     {
2194       int len = (strlen(name) - 1);
2195       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2196       int i;
2197       scaling = strlen(name+start) / 3;
2198       for (i = 0; i < 3; i++)
2199         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2200                  name + start + i * scaling);
2201       hex[3 * (scaling + 1) - 1] = '\0';
2202     }
2204   if (hex[0])
2205     {
2206       unsigned int rr, gg, bb;
2207       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2208       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2209         {
2210           r = rr / fscale;
2211           g = gg / fscale;
2212           b = bb / fscale;
2213         }
2214     }
2216   if (r >= 0.0F)
2217     {
2218       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2219       unblock_input ();
2220       return 0;
2221     }
2223   /* Otherwise, color is expected to be from a list */
2224   {
2225     NSEnumerator *lenum, *cenum;
2226     NSString *name;
2227     NSColorList *clist;
2229 #ifdef NS_IMPL_GNUSTEP
2230     /* XXX: who is wrong, the requestor or the implementation? */
2231     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2232         == NSOrderedSame)
2233       nsname = @"highlightColor";
2234 #endif
2236     lenum = [[NSColorList availableColorLists] objectEnumerator];
2237     while ( (clist = [lenum nextObject]) && new == nil)
2238       {
2239         cenum = [[clist allKeys] objectEnumerator];
2240         while ( (name = [cenum nextObject]) && new == nil )
2241           {
2242             if ([name compare: nsname
2243                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
2244               new = [clist colorWithKey: name];
2245           }
2246       }
2247   }
2249   if (new)
2250     *col = [new colorUsingDefaultColorSpace];
2251   unblock_input ();
2252   return new ? 0 : 1;
2257 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2258 /* --------------------------------------------------------------------------
2259      Convert a Lisp string object to a NS color
2260    -------------------------------------------------------------------------- */
2262   NSTRACE ("ns_lisp_to_color");
2263   if (STRINGP (color))
2264     return ns_get_color (SSDATA (color), col);
2265   else if (SYMBOLP (color))
2266     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2267   return 1;
2271 void
2272 ns_query_color(void *col, XColor *color_def, int setPixel)
2273 /* --------------------------------------------------------------------------
2274          Get ARGB values out of NSColor col and put them into color_def.
2275          If setPixel, set the pixel to a concatenated version.
2276          and set color_def pixel to the resulting index.
2277    -------------------------------------------------------------------------- */
2279   EmacsCGFloat r, g, b, a;
2281   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2282   color_def->red   = r * 65535;
2283   color_def->green = g * 65535;
2284   color_def->blue  = b * 65535;
2286   if (setPixel == YES)
2287     color_def->pixel
2288       = ARGB_TO_ULONG((int)(a*255),
2289                       (int)(r*255), (int)(g*255), (int)(b*255));
2293 bool
2294 ns_defined_color (struct frame *f,
2295                   const char *name,
2296                   XColor *color_def,
2297                   bool alloc,
2298                   bool makeIndex)
2299 /* --------------------------------------------------------------------------
2300          Return true if named color found, and set color_def rgb accordingly.
2301          If makeIndex and alloc are nonzero put the color in the color_table,
2302          and set color_def pixel to the resulting index.
2303          If makeIndex is zero, set color_def pixel to ARGB.
2304          Return false if not found
2305    -------------------------------------------------------------------------- */
2307   NSColor *col;
2308   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2310   block_input ();
2311   if (ns_get_color (name, &col) != 0) /* Color not found  */
2312     {
2313       unblock_input ();
2314       return 0;
2315     }
2316   if (makeIndex && alloc)
2317     color_def->pixel = ns_index_color (col, f);
2318   ns_query_color (col, color_def, !makeIndex);
2319   unblock_input ();
2320   return 1;
2324 void
2325 x_set_frame_alpha (struct frame *f)
2326 /* --------------------------------------------------------------------------
2327      change the entire-frame transparency
2328    -------------------------------------------------------------------------- */
2330   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2331   double alpha = 1.0;
2332   double alpha_min = 1.0;
2334   NSTRACE ("x_set_frame_alpha");
2336   if (dpyinfo->x_highlight_frame == f)
2337     alpha = f->alpha[0];
2338   else
2339     alpha = f->alpha[1];
2341   if (FLOATP (Vframe_alpha_lower_limit))
2342     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2343   else if (INTEGERP (Vframe_alpha_lower_limit))
2344     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2346   if (alpha < 0.0)
2347     return;
2348   else if (1.0 < alpha)
2349     alpha = 1.0;
2350   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2351     alpha = alpha_min;
2353 #ifdef NS_IMPL_COCOA
2354   {
2355     EmacsView *view = FRAME_NS_VIEW (f);
2356   [[view window] setAlphaValue: alpha];
2357   }
2358 #endif
2362 /* ==========================================================================
2364     Mouse handling
2366    ========================================================================== */
2369 void
2370 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2371 /* --------------------------------------------------------------------------
2372      Programmatically reposition mouse pointer in pixel coordinates
2373    -------------------------------------------------------------------------- */
2375   NSTRACE ("frame_set_mouse_pixel_position");
2377   /* FIXME: what about GNUstep? */
2378 #ifdef NS_IMPL_COCOA
2379   CGPoint mouse_pos =
2380     CGPointMake(f->left_pos + pix_x,
2381                 f->top_pos + pix_y +
2382                 FRAME_NS_TITLEBAR_HEIGHT(f) + FRAME_TOOLBAR_HEIGHT(f));
2383   CGWarpMouseCursorPosition (mouse_pos);
2384 #endif
2387 static int
2388 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2389 /*   ------------------------------------------------------------------------
2390      Called by EmacsView on mouseMovement events.  Passes on
2391      to emacs mainstream code if we moved off of a rect of interest
2392      known as last_mouse_glyph.
2393      ------------------------------------------------------------------------ */
2395   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2396   NSRect *r;
2398 //  NSTRACE ("note_mouse_movement");
2400   dpyinfo->last_mouse_motion_frame = frame;
2401   r = &dpyinfo->last_mouse_glyph;
2403   /* Note, this doesn't get called for enter/leave, since we don't have a
2404      position.  Those are taken care of in the corresponding NSView methods. */
2406   /* has movement gone beyond last rect we were tracking? */
2407   if (x < r->origin.x || x >= r->origin.x + r->size.width
2408       || y < r->origin.y || y >= r->origin.y + r->size.height)
2409     {
2410       ns_update_begin (frame);
2411       frame->mouse_moved = 1;
2412       note_mouse_highlight (frame, x, y);
2413       remember_mouse_glyph (frame, x, y, r);
2414       ns_update_end (frame);
2415       return 1;
2416     }
2418   return 0;
2422 static void
2423 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2424                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2425                    Time *time)
2426 /* --------------------------------------------------------------------------
2427     External (hook): inform emacs about mouse position and hit parts.
2428     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2429     x & y should be position in the scrollbar (the whole bar, not the handle)
2430     and length of scrollbar respectively
2431    -------------------------------------------------------------------------- */
2433   id view;
2434   NSPoint position;
2435   Lisp_Object frame, tail;
2436   struct frame *f;
2437   struct ns_display_info *dpyinfo;
2439   NSTRACE ("ns_mouse_position");
2441   if (*fp == NULL)
2442     {
2443       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2444       return;
2445     }
2447   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2449   block_input ();
2451   /* Clear the mouse-moved flag for every frame on this display.  */
2452   FOR_EACH_FRAME (tail, frame)
2453     if (FRAME_NS_P (XFRAME (frame))
2454         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2455       XFRAME (frame)->mouse_moved = 0;
2457   dpyinfo->last_mouse_scroll_bar = nil;
2458   if (dpyinfo->last_mouse_frame
2459       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2460     f = dpyinfo->last_mouse_frame;
2461   else
2462     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2464   if (f && FRAME_NS_P (f))
2465     {
2466       view = FRAME_NS_VIEW (*fp);
2468       position = [[view window] mouseLocationOutsideOfEventStream];
2469       position = [view convertPoint: position fromView: nil];
2470       remember_mouse_glyph (f, position.x, position.y,
2471                             &dpyinfo->last_mouse_glyph);
2472       NSTRACE_POINT ("position", position);
2474       if (bar_window) *bar_window = Qnil;
2475       if (part) *part = scroll_bar_above_handle;
2477       if (x) XSETINT (*x, lrint (position.x));
2478       if (y) XSETINT (*y, lrint (position.y));
2479       if (time)
2480         *time = dpyinfo->last_mouse_movement_time;
2481       *fp = f;
2482     }
2484   unblock_input ();
2488 static void
2489 ns_frame_up_to_date (struct frame *f)
2490 /* --------------------------------------------------------------------------
2491     External (hook): Fix up mouse highlighting right after a full update.
2492     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2493    -------------------------------------------------------------------------- */
2495   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2497   if (FRAME_NS_P (f))
2498     {
2499       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2500       if (f == hlinfo->mouse_face_mouse_frame)
2501         {
2502           block_input ();
2503           ns_update_begin(f);
2504           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2505                                 hlinfo->mouse_face_mouse_x,
2506                                 hlinfo->mouse_face_mouse_y);
2507           ns_update_end(f);
2508           unblock_input ();
2509         }
2510     }
2514 static void
2515 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2516 /* --------------------------------------------------------------------------
2517     External (RIF): set frame mouse pointer type.
2518    -------------------------------------------------------------------------- */
2520   NSTRACE ("ns_define_frame_cursor");
2521   if (FRAME_POINTER_TYPE (f) != cursor)
2522     {
2523       EmacsView *view = FRAME_NS_VIEW (f);
2524       FRAME_POINTER_TYPE (f) = cursor;
2525       [[view window] invalidateCursorRectsForView: view];
2526       /* Redisplay assumes this function also draws the changed frame
2527          cursor, but this function doesn't, so do it explicitly.  */
2528       x_update_cursor (f, 1);
2529     }
2534 /* ==========================================================================
2536     Keyboard handling
2538    ========================================================================== */
2541 static unsigned
2542 ns_convert_key (unsigned code)
2543 /* --------------------------------------------------------------------------
2544     Internal call used by NSView-keyDown.
2545    -------------------------------------------------------------------------- */
2547   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2548   unsigned keysym;
2549   /* An array would be faster, but less easy to read. */
2550   for (keysym = 0; keysym < last_keysym; keysym += 2)
2551     if (code == convert_ns_to_X_keysym[keysym])
2552       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2553   return 0;
2554 /* if decide to use keyCode and Carbon table, use this line:
2555      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2559 char *
2560 x_get_keysym_name (int keysym)
2561 /* --------------------------------------------------------------------------
2562     Called by keyboard.c.  Not sure if the return val is important, except
2563     that it be unique.
2564    -------------------------------------------------------------------------- */
2566   static char value[16];
2567   NSTRACE ("x_get_keysym_name");
2568   sprintf (value, "%d", keysym);
2569   return value;
2574 /* ==========================================================================
2576     Block drawing operations
2578    ========================================================================== */
2581 static void
2582 ns_redraw_scroll_bars (struct frame *f)
2584   int i;
2585   id view;
2586   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2587   NSTRACE ("ns_redraw_scroll_bars");
2588   for (i =[subviews count]-1; i >= 0; i--)
2589     {
2590       view = [subviews objectAtIndex: i];
2591       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2592       [view display];
2593     }
2597 void
2598 ns_clear_frame (struct frame *f)
2599 /* --------------------------------------------------------------------------
2600       External (hook): Erase the entire frame
2601    -------------------------------------------------------------------------- */
2603   NSView *view = FRAME_NS_VIEW (f);
2604   NSRect r;
2606   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2608  /* comes on initial frame because we have
2609     after-make-frame-functions = select-frame */
2610  if (!FRAME_DEFAULT_FACE (f))
2611    return;
2613   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2615   r = [view bounds];
2617   block_input ();
2618   ns_focus (f, &r, 1);
2619   [ns_lookup_indexed_color (NS_FACE_BACKGROUND
2620                             (FACE_FROM_ID (f, DEFAULT_FACE_ID)), f) set];
2621   NSRectFill (r);
2622   ns_unfocus (f);
2624   /* as of 2006/11 or so this is now needed */
2625   ns_redraw_scroll_bars (f);
2626   unblock_input ();
2630 static void
2631 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2632 /* --------------------------------------------------------------------------
2633     External (RIF):  Clear section of frame
2634    -------------------------------------------------------------------------- */
2636   NSRect r = NSMakeRect (x, y, width, height);
2637   NSView *view = FRAME_NS_VIEW (f);
2638   struct face *face = FRAME_DEFAULT_FACE (f);
2640   if (!view || !face)
2641     return;
2643   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2645   r = NSIntersectionRect (r, [view frame]);
2646   ns_focus (f, &r, 1);
2647   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2649   NSRectFill (r);
2651   ns_unfocus (f);
2652   return;
2655 static void
2656 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2658   NSTRACE ("ns_copy_bits");
2660   if (FRAME_NS_VIEW (f))
2661     {
2662       hide_bell();              // Ensure the bell image isn't scrolled.
2664       ns_focus (f, &dest, 1);
2665       [FRAME_NS_VIEW (f) scrollRect: src
2666                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2667                                                  dest.origin.y - src.origin.y)];
2668       ns_unfocus (f);
2669     }
2672 static void
2673 ns_scroll_run (struct window *w, struct run *run)
2674 /* --------------------------------------------------------------------------
2675     External (RIF):  Insert or delete n lines at line vpos
2676    -------------------------------------------------------------------------- */
2678   struct frame *f = XFRAME (w->frame);
2679   int x, y, width, height, from_y, to_y, bottom_y;
2681   NSTRACE ("ns_scroll_run");
2683   /* begin copy from other terms */
2684   /* Get frame-relative bounding box of the text display area of W,
2685      without mode lines.  Include in this box the left and right
2686      fringe of W.  */
2687   window_box (w, ANY_AREA, &x, &y, &width, &height);
2689   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2690   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2691   bottom_y = y + height;
2693   if (to_y < from_y)
2694     {
2695       /* Scrolling up.  Make sure we don't copy part of the mode
2696          line at the bottom.  */
2697       if (from_y + run->height > bottom_y)
2698         height = bottom_y - from_y;
2699       else
2700         height = run->height;
2701     }
2702   else
2703     {
2704       /* Scrolling down.  Make sure we don't copy over the mode line.
2705          at the bottom.  */
2706       if (to_y + run->height > bottom_y)
2707         height = bottom_y - to_y;
2708       else
2709         height = run->height;
2710     }
2711   /* end copy from other terms */
2713   if (height == 0)
2714       return;
2716   block_input ();
2718   x_clear_cursor (w);
2720   {
2721     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2722     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2724     ns_copy_bits (f, srcRect , dstRect);
2725   }
2727   unblock_input ();
2731 static void
2732 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2733 /* --------------------------------------------------------------------------
2734     External (RIF): preparatory to fringe update after text was updated
2735    -------------------------------------------------------------------------- */
2737   struct frame *f;
2738   int width, height;
2740   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2742   /* begin copy from other terms */
2743   eassert (w);
2745   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2746     desired_row->redraw_fringe_bitmaps_p = 1;
2748   /* When a window has disappeared, make sure that no rest of
2749      full-width rows stays visible in the internal border.  */
2750   if (windows_or_buffers_changed
2751       && desired_row->full_width_p
2752       && (f = XFRAME (w->frame),
2753           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2754           width != 0)
2755       && (height = desired_row->visible_height,
2756           height > 0))
2757     {
2758       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2760       block_input ();
2761       ns_clear_frame_area (f, 0, y, width, height);
2762       ns_clear_frame_area (f,
2763                            FRAME_PIXEL_WIDTH (f) - width,
2764                            y, width, height);
2765       unblock_input ();
2766     }
2770 static void
2771 ns_shift_glyphs_for_insert (struct frame *f,
2772                            int x, int y, int width, int height,
2773                            int shift_by)
2774 /* --------------------------------------------------------------------------
2775     External (RIF): copy an area horizontally, don't worry about clearing src
2776    -------------------------------------------------------------------------- */
2778   NSRect srcRect = NSMakeRect (x, y, width, height);
2779   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2781   NSTRACE ("ns_shift_glyphs_for_insert");
2783   ns_copy_bits (f, srcRect, dstRect);
2788 /* ==========================================================================
2790     Character encoding and metrics
2792    ========================================================================== */
2795 static void
2796 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2797 /* --------------------------------------------------------------------------
2798      External (RIF); compute left/right overhang of whole string and set in s
2799    -------------------------------------------------------------------------- */
2801   struct font *font = s->font;
2803   if (s->char2b)
2804     {
2805       struct font_metrics metrics;
2806       unsigned int codes[2];
2807       codes[0] = *(s->char2b);
2808       codes[1] = *(s->char2b + s->nchars - 1);
2810       font->driver->text_extents (font, codes, 2, &metrics);
2811       s->left_overhang = -metrics.lbearing;
2812       s->right_overhang
2813         = metrics.rbearing > metrics.width
2814         ? metrics.rbearing - metrics.width : 0;
2815     }
2816   else
2817     {
2818       s->left_overhang = 0;
2819       if (EQ (font->driver->type, Qns))
2820         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2821           FONT_HEIGHT (font) * 0.2 : 0;
2822       else
2823         s->right_overhang = 0;
2824     }
2829 /* ==========================================================================
2831     Fringe and cursor drawing
2833    ========================================================================== */
2836 extern int max_used_fringe_bitmap;
2837 static void
2838 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2839                       struct draw_fringe_bitmap_params *p)
2840 /* --------------------------------------------------------------------------
2841     External (RIF); fringe-related
2842    -------------------------------------------------------------------------- */
2844   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2845      periodic bitmap is used to create a continuous pattern.  Since a
2846      bitmap is rendered one text line at a time, the start offset (dh)
2847      of the bitmap varies.  Concretely, this is used for the empty
2848      line indicator.
2850      For a bitmap, "h + dh" is the full height and is always
2851      invariant.  For a normal bitmap "dh" is zero.
2853      For example, when the period is three and the full height is 72
2854      the following combinations exists:
2856        h=72 dh=0
2857        h=71 dh=1
2858        h=70 dh=2 */
2860   struct frame *f = XFRAME (WINDOW_FRAME (w));
2861   struct face *face = p->face;
2862   static EmacsImage **bimgs = NULL;
2863   static int nBimgs = 0;
2865   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2866   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2867                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2869   /* grow bimgs if needed */
2870   if (nBimgs < max_used_fringe_bitmap)
2871     {
2872       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2873       memset (bimgs + nBimgs, 0,
2874               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2875       nBimgs = max_used_fringe_bitmap;
2876     }
2878   /* Must clip because of partially visible lines.  */
2879   ns_clip_to_row (w, row, ANY_AREA, YES);
2881   if (!p->overlay_p)
2882     {
2883       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2885       if (bx >= 0 && nx > 0)
2886         {
2887           NSRect r = NSMakeRect (bx, by, nx, ny);
2888           NSRectClip (r);
2889           [ns_lookup_indexed_color (face->background, f) set];
2890           NSRectFill (r);
2891         }
2892     }
2894   if (p->which)
2895     {
2896       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2897       EmacsImage *img = bimgs[p->which - 1];
2899       if (!img)
2900         {
2901           // Note: For "periodic" images, allocate one EmacsImage for
2902           // the base image, and use it for all dh:s.
2903           unsigned short *bits = p->bits;
2904           int full_height = p->h + p->dh;
2905           int i;
2906           unsigned char *cbits = xmalloc (full_height);
2908           for (i = 0; i < full_height; i++)
2909             cbits[i] = bits[i];
2910           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2911                                          height: full_height
2912                                              fg: 0 bg: 0];
2913           bimgs[p->which - 1] = img;
2914           xfree (cbits);
2915         }
2917       NSTRACE_RECT ("r", r);
2919       NSRectClip (r);
2920       /* Since we composite the bitmap instead of just blitting it, we need
2921          to erase the whole background. */
2922       [ns_lookup_indexed_color(face->background, f) set];
2923       NSRectFill (r);
2925       {
2926         NSColor *bm_color;
2927         if (!p->cursor_p)
2928           bm_color = ns_lookup_indexed_color(face->foreground, f);
2929         else if (p->overlay_p)
2930           bm_color = ns_lookup_indexed_color(face->background, f);
2931         else
2932           bm_color = f->output_data.ns->cursor_color;
2933         [img setXBMColor: bm_color];
2934       }
2936 #ifdef NS_IMPL_COCOA
2937       // Note: For periodic images, the full image height is "h + hd".
2938       // By using the height h, a suitable part of the image is used.
2939       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2941       NSTRACE_RECT ("fromRect", fromRect);
2943       [img drawInRect: r
2944               fromRect: fromRect
2945              operation: NSCompositingOperationSourceOver
2946               fraction: 1.0
2947            respectFlipped: YES
2948                 hints: nil];
2949 #else
2950       {
2951         NSPoint pt = r.origin;
2952         pt.y += p->h;
2953         [img compositeToPoint: pt operation: NSCompositingOperationSourceOver];
2954       }
2955 #endif
2956     }
2957   ns_unfocus (f);
2961 static void
2962 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2963                        int x, int y, enum text_cursor_kinds cursor_type,
2964                        int cursor_width, bool on_p, bool active_p)
2965 /* --------------------------------------------------------------------------
2966      External call (RIF): draw cursor.
2967      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2968    -------------------------------------------------------------------------- */
2970   NSRect r, s;
2971   int fx, fy, h, cursor_height;
2972   struct frame *f = WINDOW_XFRAME (w);
2973   struct glyph *phys_cursor_glyph;
2974   struct glyph *cursor_glyph;
2975   struct face *face;
2976   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2978   /* If cursor is out of bounds, don't draw garbage.  This can happen
2979      in mini-buffer windows when switching between echo area glyphs
2980      and mini-buffer.  */
2982   NSTRACE ("ns_draw_window_cursor");
2984   if (!on_p)
2985     return;
2987   w->phys_cursor_type = cursor_type;
2988   w->phys_cursor_on_p = on_p;
2990   if (cursor_type == NO_CURSOR)
2991     {
2992       w->phys_cursor_width = 0;
2993       return;
2994     }
2996   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2997     {
2998       if (glyph_row->exact_window_width_line_p
2999           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
3000         {
3001           glyph_row->cursor_in_fringe_p = 1;
3002           draw_fringe_bitmap (w, glyph_row, 0);
3003         }
3004       return;
3005     }
3007   /* We draw the cursor (with NSRectFill), then draw the glyph on top
3008      (other terminals do it the other way round).  We must set
3009      w->phys_cursor_width to the cursor width.  For bar cursors, that
3010      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
3011   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
3013   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
3014      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
3015   if (cursor_type == BAR_CURSOR)
3016     {
3017       if (cursor_width < 1)
3018         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
3020       /* The bar cursor should never be wider than the glyph. */
3021       if (cursor_width < w->phys_cursor_width)
3022         w->phys_cursor_width = cursor_width;
3023     }
3024   /* If we have an HBAR, "cursor_width" MAY specify height. */
3025   else if (cursor_type == HBAR_CURSOR)
3026     {
3027       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
3028       if (cursor_height > glyph_row->height)
3029         cursor_height = glyph_row->height;
3030       if (h > cursor_height) // Cursor smaller than line height, move down
3031         fy += h - cursor_height;
3032       h = cursor_height;
3033     }
3035   r.origin.x = fx, r.origin.y = fy;
3036   r.size.height = h;
3037   r.size.width = w->phys_cursor_width;
3039   /* Prevent the cursor from being drawn outside the text area. */
3040   ns_clip_to_row (w, glyph_row, TEXT_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
3043   face = FACE_FROM_ID_OR_NULL (f, phys_cursor_glyph->face_id);
3044   if (face && NS_FACE_BACKGROUND (face)
3045       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
3046     {
3047       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
3048       hollow_color = FRAME_CURSOR_COLOR (f);
3049     }
3050   else
3051     [FRAME_CURSOR_COLOR (f) set];
3053 #ifdef NS_IMPL_COCOA
3054   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
3055            atomic.  Cleaner ways of doing this should be investigated.
3056            One way would be to set a global variable DRAWING_CURSOR
3057            when making the call to draw_phys..(), don't focus in that
3058            case, then move the ns_unfocus() here after that call. */
3059   NSDisableScreenUpdates ();
3060 #endif
3062   switch (cursor_type)
3063     {
3064     case DEFAULT_CURSOR:
3065     case NO_CURSOR:
3066       break;
3067     case FILLED_BOX_CURSOR:
3068       NSRectFill (r);
3069       break;
3070     case HOLLOW_BOX_CURSOR:
3071       NSRectFill (r);
3072       [hollow_color set];
3073       NSRectFill (NSInsetRect (r, 1, 1));
3074       [FRAME_CURSOR_COLOR (f) set];
3075       break;
3076     case HBAR_CURSOR:
3077       NSRectFill (r);
3078       break;
3079     case BAR_CURSOR:
3080       s = r;
3081       /* If the character under cursor is R2L, draw the bar cursor
3082          on the right of its glyph, rather than on the left.  */
3083       cursor_glyph = get_phys_cursor_glyph (w);
3084       if ((cursor_glyph->resolved_level & 1) != 0)
3085         s.origin.x += cursor_glyph->pixel_width - s.size.width;
3087       NSRectFill (s);
3088       break;
3089     }
3090   ns_unfocus (f);
3092   /* draw the character under the cursor */
3093   if (cursor_type != NO_CURSOR)
3094     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
3096 #ifdef NS_IMPL_COCOA
3097   NSEnableScreenUpdates ();
3098 #endif
3103 static void
3104 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3105 /* --------------------------------------------------------------------------
3106      External (RIF): Draw a vertical line.
3107    -------------------------------------------------------------------------- */
3109   struct frame *f = XFRAME (WINDOW_FRAME (w));
3110   struct face *face;
3111   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
3113   NSTRACE ("ns_draw_vertical_window_border");
3115   face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3117   ns_focus (f, &r, 1);
3118   if (face)
3119     [ns_lookup_indexed_color(face->foreground, f) set];
3121   NSRectFill(r);
3122   ns_unfocus (f);
3126 static void
3127 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3128 /* --------------------------------------------------------------------------
3129      External (RIF): Draw a window divider.
3130    -------------------------------------------------------------------------- */
3132   struct frame *f = XFRAME (WINDOW_FRAME (w));
3133   struct face *face;
3134   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
3136   NSTRACE ("ns_draw_window_divider");
3138   face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3140   ns_focus (f, &r, 1);
3141   if (face)
3142     [ns_lookup_indexed_color(face->foreground, f) set];
3144   NSRectFill(r);
3145   ns_unfocus (f);
3148 static void
3149 ns_show_hourglass (struct frame *f)
3151   /* TODO: add NSProgressIndicator to all frames.  */
3154 static void
3155 ns_hide_hourglass (struct frame *f)
3157   /* TODO: remove NSProgressIndicator from all frames.  */
3160 /* ==========================================================================
3162     Glyph drawing operations
3164    ========================================================================== */
3166 static int
3167 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3168 /* --------------------------------------------------------------------------
3169     Wrapper utility to account for internal border width on full-width lines,
3170     and allow top full-width rows to hit the frame top.  nr should be pointer
3171     to two successive NSRects.  Number of rects actually used is returned.
3172    -------------------------------------------------------------------------- */
3174   int n = get_glyph_string_clip_rects (s, nr, 2);
3175   return n;
3178 /* --------------------------------------------------------------------
3179    Draw a wavy line under glyph string s. The wave fills wave_height
3180    pixels from y.
3182                     x          wave_length = 2
3183                                  --
3184                 y    *   *   *   *   *
3185                      |* * * * * * * * *
3186     wave_height = 3  | *   *   *   *
3187   --------------------------------------------------------------------- */
3189 static void
3190 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3192   int wave_height = 3, wave_length = 2;
3193   int y, dx, dy, odd, xmax;
3194   NSPoint a, b;
3195   NSRect waveClip;
3197   dx = wave_length;
3198   dy = wave_height - 1;
3199   y =  s->ybase - wave_height + 3;
3200   xmax = x + width;
3202   /* Find and set clipping rectangle */
3203   waveClip = NSMakeRect (x, y, width, wave_height);
3204   [[NSGraphicsContext currentContext] saveGraphicsState];
3205   NSRectClip (waveClip);
3207   /* Draw the waves */
3208   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3209   b.x = a.x + dx;
3210   odd = (int)(a.x/dx) % 2;
3211   a.y = b.y = y + 0.5;
3213   if (odd)
3214     a.y += dy;
3215   else
3216     b.y += dy;
3218   while (a.x <= xmax)
3219     {
3220       [NSBezierPath strokeLineFromPoint:a toPoint:b];
3221       a.x = b.x, a.y = b.y;
3222       b.x += dx, b.y = y + 0.5 + odd*dy;
3223       odd = !odd;
3224     }
3226   /* Restore previous clipping rectangle(s) */
3227   [[NSGraphicsContext currentContext] restoreGraphicsState];
3232 static void
3233 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3234                          NSColor *defaultCol, CGFloat width, CGFloat x)
3235 /* --------------------------------------------------------------------------
3236    Draw underline, overline, and strike-through on glyph string s.
3237    -------------------------------------------------------------------------- */
3239   if (s->for_overlaps)
3240     return;
3242   /* Do underline. */
3243   if (face->underline_p)
3244     {
3245       if (s->face->underline_type == FACE_UNDER_WAVE)
3246         {
3247           if (face->underline_defaulted_p)
3248             [defaultCol set];
3249           else
3250             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3252           ns_draw_underwave (s, width, x);
3253         }
3254       else if (s->face->underline_type == FACE_UNDER_LINE)
3255         {
3257           NSRect r;
3258           unsigned long thickness, position;
3260           /* If the prev was underlined, match its appearance. */
3261           if (s->prev && s->prev->face->underline_p
3262               && s->prev->face->underline_type == FACE_UNDER_LINE
3263               && s->prev->underline_thickness > 0)
3264             {
3265               thickness = s->prev->underline_thickness;
3266               position = s->prev->underline_position;
3267             }
3268           else
3269             {
3270               struct font *font = font_for_underline_metrics (s);
3271               unsigned long descent = s->y + s->height - s->ybase;
3273               /* Use underline thickness of font, defaulting to 1. */
3274               thickness = (font && font->underline_thickness > 0)
3275                 ? font->underline_thickness : 1;
3277               /* Determine the offset of underlining from the baseline. */
3278               if (x_underline_at_descent_line)
3279                 position = descent - thickness;
3280               else if (x_use_underline_position_properties
3281                        && font && font->underline_position >= 0)
3282                 position = font->underline_position;
3283               else if (font)
3284                 position = lround (font->descent / 2);
3285               else
3286                 position = underline_minimum_offset;
3288               position = max (position, underline_minimum_offset);
3290               /* Ensure underlining is not cropped. */
3291               if (descent <= position)
3292                 {
3293                   position = descent - 1;
3294                   thickness = 1;
3295                 }
3296               else if (descent < position + thickness)
3297                 thickness = 1;
3298             }
3300           s->underline_thickness = thickness;
3301           s->underline_position = position;
3303           r = NSMakeRect (x, s->ybase + position, width, thickness);
3305           if (face->underline_defaulted_p)
3306             [defaultCol set];
3307           else
3308             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3309           NSRectFill (r);
3310         }
3311     }
3312   /* Do overline. We follow other terms in using a thickness of 1
3313      and ignoring overline_margin. */
3314   if (face->overline_p)
3315     {
3316       NSRect r;
3317       r = NSMakeRect (x, s->y, width, 1);
3319       if (face->overline_color_defaulted_p)
3320         [defaultCol set];
3321       else
3322         [ns_lookup_indexed_color (face->overline_color, s->f) set];
3323       NSRectFill (r);
3324     }
3326   /* Do strike-through.  We follow other terms for thickness and
3327      vertical position.*/
3328   if (face->strike_through_p)
3329     {
3330       NSRect r;
3331       /* Y-coordinate and height of the glyph string's first glyph.
3332          We cannot use s->y and s->height because those could be
3333          larger if there are taller display elements (e.g., characters
3334          displayed with a larger font) in the same glyph row.  */
3335       int glyph_y = s->ybase - s->first_glyph->ascent;
3336       int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
3337       /* Strike-through width and offset from the glyph string's
3338          top edge.  */
3339       unsigned long h = 1;
3340       unsigned long dy;
3342       dy = lrint ((glyph_height - h) / 2);
3343       r = NSMakeRect (x, glyph_y + dy, width, 1);
3345       if (face->strike_through_color_defaulted_p)
3346         [defaultCol set];
3347       else
3348         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3349       NSRectFill (r);
3350     }
3353 static void
3354 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3355              char left_p, char right_p)
3356 /* --------------------------------------------------------------------------
3357     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3358     Note we can't just use an NSDrawRect command, because of the possibility
3359     of some sides not being drawn, and because the rect will be filled.
3360    -------------------------------------------------------------------------- */
3362   NSRect s = r;
3363   [col set];
3365   /* top, bottom */
3366   s.size.height = thickness;
3367   NSRectFill (s);
3368   s.origin.y += r.size.height - thickness;
3369   NSRectFill (s);
3371   s.size.height = r.size.height;
3372   s.origin.y = r.origin.y;
3374   /* left, right (optional) */
3375   s.size.width = thickness;
3376   if (left_p)
3377     NSRectFill (s);
3378   if (right_p)
3379     {
3380       s.origin.x += r.size.width - thickness;
3381       NSRectFill (s);
3382     }
3386 static void
3387 ns_draw_relief (NSRect r, int thickness, char raised_p,
3388                char top_p, char bottom_p, char left_p, char right_p,
3389                struct glyph_string *s)
3390 /* --------------------------------------------------------------------------
3391     Draw a relief rect inside r, optionally leaving some sides open.
3392     Note we can't just use an NSDrawBezel command, because of the possibility
3393     of some sides not being drawn, and because the rect will be filled.
3394    -------------------------------------------------------------------------- */
3396   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3397   NSColor *newBaseCol = nil;
3398   NSRect sr = r;
3400   NSTRACE ("ns_draw_relief");
3402   /* set up colors */
3404   if (s->face->use_box_color_for_shadows_p)
3405     {
3406       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3407     }
3408 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3409            && s->img->pixmap
3410            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3411        {
3412          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3413        } */
3414   else
3415     {
3416       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3417     }
3419   if (newBaseCol == nil)
3420     newBaseCol = [NSColor grayColor];
3422   if (newBaseCol != baseCol)  /* TODO: better check */
3423     {
3424       [baseCol release];
3425       baseCol = [newBaseCol retain];
3426       [lightCol release];
3427       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3428       [darkCol release];
3429       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3430     }
3432   [(raised_p ? lightCol : darkCol) set];
3434   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3436   /* top */
3437   sr.size.height = thickness;
3438   if (top_p) NSRectFill (sr);
3440   /* left */
3441   sr.size.height = r.size.height;
3442   sr.size.width = thickness;
3443   if (left_p) NSRectFill (sr);
3445   [(raised_p ? darkCol : lightCol) set];
3447   /* bottom */
3448   sr.size.width = r.size.width;
3449   sr.size.height = thickness;
3450   sr.origin.y += r.size.height - thickness;
3451   if (bottom_p) NSRectFill (sr);
3453   /* right */
3454   sr.size.height = r.size.height;
3455   sr.origin.y = r.origin.y;
3456   sr.size.width = thickness;
3457   sr.origin.x += r.size.width - thickness;
3458   if (right_p) NSRectFill (sr);
3462 static void
3463 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3464 /* --------------------------------------------------------------------------
3465       Function modeled after x_draw_glyph_string_box ().
3466       Sets up parameters for drawing.
3467    -------------------------------------------------------------------------- */
3469   int right_x, last_x;
3470   char left_p, right_p;
3471   struct glyph *last_glyph;
3472   NSRect r;
3473   int thickness;
3474   struct face *face;
3476   if (s->hl == DRAW_MOUSE_FACE)
3477     {
3478       face = FACE_FROM_ID_OR_NULL (s->f,
3479                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3480       if (!face)
3481         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3482     }
3483   else
3484     face = s->face;
3486   thickness = face->box_line_width;
3488   NSTRACE ("ns_dumpglyphs_box_or_relief");
3490   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3491             ? WINDOW_RIGHT_EDGE_X (s->w)
3492             : window_box_right (s->w, s->area));
3493   last_glyph = (s->cmp || s->img
3494                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3496   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3497               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3499   left_p = (s->first_glyph->left_box_line_p
3500             || (s->hl == DRAW_MOUSE_FACE
3501                 && (s->prev == NULL || s->prev->hl != s->hl)));
3502   right_p = (last_glyph->right_box_line_p
3503              || (s->hl == DRAW_MOUSE_FACE
3504                  && (s->next == NULL || s->next->hl != s->hl)));
3506   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3508   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3509   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3510     {
3511       ns_draw_box (r, abs (thickness),
3512                    ns_lookup_indexed_color (face->box_color, s->f),
3513                   left_p, right_p);
3514     }
3515   else
3516     {
3517       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3518                      1, 1, left_p, right_p, s);
3519     }
3523 static void
3524 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3525 /* --------------------------------------------------------------------------
3526       Modeled after x_draw_glyph_string_background, which draws BG in
3527       certain cases.  Others are left to the text rendering routine.
3528    -------------------------------------------------------------------------- */
3530   NSTRACE ("ns_maybe_dumpglyphs_background");
3532   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3533     {
3534       int box_line_width = max (s->face->box_line_width, 0);
3535       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3536           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3537              dimensions, since the actual glyphs might be much
3538              smaller.  So in that case we always clear the rectangle
3539              with background color.  */
3540           || FONT_TOO_HIGH (s->font)
3541           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3542         {
3543           struct face *face;
3544           if (s->hl == DRAW_MOUSE_FACE)
3545             {
3546               face
3547                 = FACE_FROM_ID_OR_NULL (s->f,
3548                                         MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3549               if (!face)
3550                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3551             }
3552           else
3553             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3554           if (!face->stipple)
3555             [(NS_FACE_BACKGROUND (face) != 0
3556               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3557               : FRAME_BACKGROUND_COLOR (s->f)) set];
3558           else
3559             {
3560               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3561               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3562             }
3564           if (s->hl != DRAW_CURSOR)
3565             {
3566               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3567                                     s->background_width,
3568                                     s->height-2*box_line_width);
3569               NSRectFill (r);
3570             }
3572           s->background_filled_p = 1;
3573         }
3574     }
3578 static void
3579 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3580 /* --------------------------------------------------------------------------
3581       Renders an image and associated borders.
3582    -------------------------------------------------------------------------- */
3584   EmacsImage *img = s->img->pixmap;
3585   int box_line_vwidth = max (s->face->box_line_width, 0);
3586   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3587   int bg_x, bg_y, bg_height;
3588   int th;
3589   char raised_p;
3590   NSRect br;
3591   struct face *face;
3592   NSColor *tdCol;
3594   NSTRACE ("ns_dumpglyphs_image");
3596   if (s->face->box != FACE_NO_BOX
3597       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3598     x += abs (s->face->box_line_width);
3600   bg_x = x;
3601   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3602   bg_height = s->height;
3603   /* other terms have this, but was causing problems w/tabbar mode */
3604   /* - 2 * box_line_vwidth; */
3606   if (s->slice.x == 0) x += s->img->hmargin;
3607   if (s->slice.y == 0) y += s->img->vmargin;
3609   /* Draw BG: if we need larger area than image itself cleared, do that,
3610      otherwise, since we composite the image under NS (instead of mucking
3611      with its background color), we must clear just the image area. */
3612   if (s->hl == DRAW_MOUSE_FACE)
3613     {
3614       face = FACE_FROM_ID_OR_NULL (s->f,
3615                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3616       if (!face)
3617        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3618     }
3619   else
3620     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3622   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3624   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3625       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3626     {
3627       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3628       s->background_filled_p = 1;
3629     }
3630   else
3631     {
3632       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3633     }
3635   NSRectFill (br);
3637   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3638   if (img != nil)
3639     {
3640 #ifdef NS_IMPL_COCOA
3641       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3642       NSRect ir = NSMakeRect (s->slice.x,
3643                               s->img->height - s->slice.y - s->slice.height,
3644                               s->slice.width, s->slice.height);
3645       [img drawInRect: dr
3646              fromRect: ir
3647              operation: NSCompositingOperationSourceOver
3648               fraction: 1.0
3649            respectFlipped: YES
3650                 hints: nil];
3651 #else
3652       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3653                   operation: NSCompositingOperationSourceOver];
3654 #endif
3655     }
3657   if (s->hl == DRAW_CURSOR)
3658     {
3659     [FRAME_CURSOR_COLOR (s->f) set];
3660     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3661       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3662     else
3663       /* Currently on NS img->mask is always 0. Since
3664          get_window_cursor_type specifies a hollow box cursor when on
3665          a non-masked image we never reach this clause. But we put it
3666          in in anticipation of better support for image masks on
3667          NS. */
3668       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3669     }
3670   else
3671     {
3672       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3673     }
3675   /* Draw underline, overline, strike-through. */
3676   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3678   /* Draw relief, if requested */
3679   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3680     {
3681       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3682         {
3683           th = tool_bar_button_relief >= 0 ?
3684             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3685           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3686         }
3687       else
3688         {
3689           th = abs (s->img->relief);
3690           raised_p = (s->img->relief > 0);
3691         }
3693       r.origin.x = x - th;
3694       r.origin.y = y - th;
3695       r.size.width = s->slice.width + 2*th-1;
3696       r.size.height = s->slice.height + 2*th-1;
3697       ns_draw_relief (r, th, raised_p,
3698                       s->slice.y == 0,
3699                       s->slice.y + s->slice.height == s->img->height,
3700                       s->slice.x == 0,
3701                       s->slice.x + s->slice.width == s->img->width, s);
3702     }
3704   /* If there is no mask, the background won't be seen,
3705      so draw a rectangle on the image for the cursor.
3706      Do this for all images, getting transparency right is not reliable.  */
3707   if (s->hl == DRAW_CURSOR)
3708     {
3709       int thickness = abs (s->img->relief);
3710       if (thickness == 0) thickness = 1;
3711       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3712     }
3716 static void
3717 ns_dumpglyphs_stretch (struct glyph_string *s)
3719   NSRect r[2];
3720   int n, i;
3721   struct face *face;
3722   NSColor *fgCol, *bgCol;
3724   if (!s->background_filled_p)
3725     {
3726       n = ns_get_glyph_string_clip_rect (s, r);
3727       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3729       ns_focus (s->f, r, n);
3731       if (s->hl == DRAW_MOUSE_FACE)
3732        {
3733          face = FACE_FROM_ID_OR_NULL (s->f,
3734                                       MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3735          if (!face)
3736            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3737        }
3738       else
3739        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3741       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3742       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3744       for (i = 0; i < n; ++i)
3745         {
3746           if (!s->row->full_width_p)
3747             {
3748               int overrun, leftoverrun;
3750               /* truncate to avoid overwriting fringe and/or scrollbar */
3751               overrun = max (0, (s->x + s->background_width)
3752                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3753                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3754               r[i].size.width -= overrun;
3756               /* truncate to avoid overwriting to left of the window box */
3757               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3758                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3760               if (leftoverrun > 0)
3761                 {
3762                   r[i].origin.x += leftoverrun;
3763                   r[i].size.width -= leftoverrun;
3764                 }
3766               /* XXX: Try to work between problem where a stretch glyph on
3767                  a partially-visible bottom row will clear part of the
3768                  modeline, and another where list-buffers headers and similar
3769                  rows erroneously have visible_height set to 0.  Not sure
3770                  where this is coming from as other terms seem not to show. */
3771               r[i].size.height = min (s->height, s->row->visible_height);
3772             }
3774           [bgCol set];
3776           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3777              overwriting cursor (usually when cursor on a tab) */
3778           if (s->hl == DRAW_CURSOR)
3779             {
3780               CGFloat x, width;
3782               x = r[i].origin.x;
3783               width = s->w->phys_cursor_width;
3784               r[i].size.width -= width;
3785               r[i].origin.x += width;
3787               NSRectFill (r[i]);
3789               /* Draw overlining, etc. on the cursor. */
3790               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3791                 ns_draw_text_decoration (s, face, bgCol, width, x);
3792               else
3793                 ns_draw_text_decoration (s, face, fgCol, width, x);
3794             }
3795           else
3796             {
3797               NSRectFill (r[i]);
3798             }
3800           /* Draw overlining, etc. on the stretch glyph (or the part
3801              of the stretch glyph after the cursor). */
3802           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3803                                    r[i].origin.x);
3804         }
3805       ns_unfocus (s->f);
3806       s->background_filled_p = 1;
3807     }
3811 static void
3812 ns_draw_glyph_string_foreground (struct glyph_string *s)
3814   int x, flags;
3815   struct font *font = s->font;
3817   /* If first glyph of S has a left box line, start drawing the text
3818      of S to the right of that box line.  */
3819   if (s->face && s->face->box != FACE_NO_BOX
3820       && s->first_glyph->left_box_line_p)
3821     x = s->x + eabs (s->face->box_line_width);
3822   else
3823     x = s->x;
3825   flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3826     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3827      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3828       NS_DUMPGLYPH_NORMAL));
3830   font->driver->draw
3831     (s, s->cmp_from, s->nchars, x, s->ybase,
3832      (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3833      || flags == NS_DUMPGLYPH_MOUSEFACE);
3837 static void
3838 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3840   int i, j, x;
3841   struct font *font = s->font;
3843   /* If first glyph of S has a left box line, start drawing the text
3844      of S to the right of that box line.  */
3845   if (s->face && s->face->box != FACE_NO_BOX
3846       && s->first_glyph->left_box_line_p)
3847     x = s->x + eabs (s->face->box_line_width);
3848   else
3849     x = s->x;
3851   /* S is a glyph string for a composition.  S->cmp_from is the index
3852      of the first character drawn for glyphs of this composition.
3853      S->cmp_from == 0 means we are drawing the very first character of
3854      this composition.  */
3856   /* Draw a rectangle for the composition if the font for the very
3857      first character of the composition could not be loaded.  */
3858   if (s->font_not_found_p)
3859     {
3860       if (s->cmp_from == 0)
3861         {
3862           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3863           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3864         }
3865     }
3866   else if (! s->first_glyph->u.cmp.automatic)
3867     {
3868       int y = s->ybase;
3870       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3871         /* TAB in a composition means display glyphs with padding
3872            space on the left or right.  */
3873         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3874           {
3875             int xx = x + s->cmp->offsets[j * 2];
3876             int yy = y - s->cmp->offsets[j * 2 + 1];
3878             font->driver->draw (s, j, j + 1, xx, yy, false);
3879             if (s->face->overstrike)
3880               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3881           }
3882     }
3883   else
3884     {
3885       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3886       Lisp_Object glyph;
3887       int y = s->ybase;
3888       int width = 0;
3890       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3891         {
3892           glyph = LGSTRING_GLYPH (gstring, i);
3893           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3894             width += LGLYPH_WIDTH (glyph);
3895           else
3896             {
3897               int xoff, yoff, wadjust;
3899               if (j < i)
3900                 {
3901                   font->driver->draw (s, j, i, x, y, false);
3902                   if (s->face->overstrike)
3903                     font->driver->draw (s, j, i, x + 1, y, false);
3904                   x += width;
3905                 }
3906               xoff = LGLYPH_XOFF (glyph);
3907               yoff = LGLYPH_YOFF (glyph);
3908               wadjust = LGLYPH_WADJUST (glyph);
3909               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3910               if (s->face->overstrike)
3911                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3912                                     false);
3913               x += wadjust;
3914               j = i + 1;
3915               width = 0;
3916             }
3917         }
3918       if (j < i)
3919         {
3920           font->driver->draw (s, j, i, x, y, false);
3921           if (s->face->overstrike)
3922             font->driver->draw (s, j, i, x + 1, y, false);
3923         }
3924     }
3927 static void
3928 ns_draw_glyph_string (struct glyph_string *s)
3929 /* --------------------------------------------------------------------------
3930       External (RIF): Main draw-text call.
3931    -------------------------------------------------------------------------- */
3933   /* TODO (optimize): focus for box and contents draw */
3934   NSRect r[2];
3935   int n;
3936   char box_drawn_p = 0;
3937   struct font *font = s->face->font;
3938   if (! font) font = FRAME_FONT (s->f);
3940   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3942   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3943     {
3944       int width;
3945       struct glyph_string *next;
3947       for (width = 0, next = s->next;
3948            next && width < s->right_overhang;
3949            width += next->width, next = next->next)
3950         if (next->first_glyph->type != IMAGE_GLYPH)
3951           {
3952             if (next->first_glyph->type != STRETCH_GLYPH)
3953               {
3954                 n = ns_get_glyph_string_clip_rect (s->next, r);
3955                 ns_focus (s->f, r, n);
3956                 ns_maybe_dumpglyphs_background (s->next, 1);
3957                 ns_unfocus (s->f);
3958               }
3959             else
3960               {
3961                 ns_dumpglyphs_stretch (s->next);
3962               }
3963             next->num_clips = 0;
3964           }
3965     }
3967   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3968         && (s->first_glyph->type == CHAR_GLYPH
3969             || s->first_glyph->type == COMPOSITE_GLYPH))
3970     {
3971       n = ns_get_glyph_string_clip_rect (s, r);
3972       ns_focus (s->f, r, n);
3973       ns_maybe_dumpglyphs_background (s, 1);
3974       ns_dumpglyphs_box_or_relief (s);
3975       ns_unfocus (s->f);
3976       box_drawn_p = 1;
3977     }
3979   switch (s->first_glyph->type)
3980     {
3982     case IMAGE_GLYPH:
3983       n = ns_get_glyph_string_clip_rect (s, r);
3984       ns_focus (s->f, r, n);
3985       ns_dumpglyphs_image (s, r[0]);
3986       ns_unfocus (s->f);
3987       break;
3989     case STRETCH_GLYPH:
3990       ns_dumpglyphs_stretch (s);
3991       break;
3993     case CHAR_GLYPH:
3994     case COMPOSITE_GLYPH:
3995       n = ns_get_glyph_string_clip_rect (s, r);
3996       ns_focus (s->f, r, n);
3998       if (s->for_overlaps || (s->cmp_from > 0
3999                               && ! s->first_glyph->u.cmp.automatic))
4000         s->background_filled_p = 1;
4001       else
4002         ns_maybe_dumpglyphs_background
4003           (s, s->first_glyph->type == COMPOSITE_GLYPH);
4005       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4006         {
4007           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4008           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4009           NS_FACE_FOREGROUND (s->face) = tmp;
4010         }
4012       {
4013         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
4015         if (isComposite)
4016           ns_draw_composite_glyph_string_foreground (s);
4017         else
4018           ns_draw_glyph_string_foreground (s);
4019       }
4021       {
4022         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
4023                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
4024                                                    s->f)
4025                         : FRAME_FOREGROUND_COLOR (s->f));
4026         [col set];
4028         /* Draw underline, overline, strike-through. */
4029         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
4030       }
4032       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
4033         {
4034           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
4035           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
4036           NS_FACE_FOREGROUND (s->face) = tmp;
4037         }
4039       ns_unfocus (s->f);
4040       break;
4042     case GLYPHLESS_GLYPH:
4043       n = ns_get_glyph_string_clip_rect (s, r);
4044       ns_focus (s->f, r, n);
4046       if (s->for_overlaps || (s->cmp_from > 0
4047                               && ! s->first_glyph->u.cmp.automatic))
4048         s->background_filled_p = 1;
4049       else
4050         ns_maybe_dumpglyphs_background
4051           (s, s->first_glyph->type == COMPOSITE_GLYPH);
4052       /* ... */
4053       /* Not yet implemented.  */
4054       /* ... */
4055       ns_unfocus (s->f);
4056       break;
4058     default:
4059       emacs_abort ();
4060     }
4062   /* Draw box if not done already. */
4063   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
4064     {
4065       n = ns_get_glyph_string_clip_rect (s, r);
4066       ns_focus (s->f, r, n);
4067       ns_dumpglyphs_box_or_relief (s);
4068       ns_unfocus (s->f);
4069     }
4071   s->num_clips = 0;
4076 /* ==========================================================================
4078     Event loop
4080    ========================================================================== */
4083 static void
4084 ns_send_appdefined (int value)
4085 /* --------------------------------------------------------------------------
4086     Internal: post an appdefined event which EmacsApp-sendEvent will
4087               recognize and take as a command to halt the event loop.
4088    -------------------------------------------------------------------------- */
4090   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
4092   // GNUstep needs postEvent to happen on the main thread.
4093   // Cocoa needs nextEventMatchingMask to happen on the main thread too.
4094   if (! [[NSThread currentThread] isMainThread])
4095     {
4096       EmacsApp *app = (EmacsApp *)NSApp;
4097       app->nextappdefined = value;
4098       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
4099                             withObject:nil
4100                          waitUntilDone:NO];
4101       return;
4102     }
4104   /* Only post this event if we haven't already posted one.  This will end
4105        the [NXApp run] main loop after having processed all events queued at
4106        this moment.  */
4108 #ifdef NS_IMPL_COCOA
4109   if (! send_appdefined)
4110     {
4111       /* OS X 10.10.1 swallows the AppDefined event we are sending ourselves
4112          in certain situations (rapid incoming events).
4113          So check if we have one, if not add one.  */
4114       NSEvent *appev = [NSApp nextEventMatchingMask:NSEventMaskApplicationDefined
4115                                           untilDate:[NSDate distantPast]
4116                                              inMode:NSDefaultRunLoopMode
4117                                             dequeue:NO];
4118       if (! appev) send_appdefined = YES;
4119     }
4120 #endif
4122   if (send_appdefined)
4123     {
4124       NSEvent *nxev;
4126       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
4127       send_appdefined = NO;
4129       /* Don't need wakeup timer any more */
4130       if (timed_entry)
4131         {
4132           [timed_entry invalidate];
4133           [timed_entry release];
4134           timed_entry = nil;
4135         }
4137       nxev = [NSEvent otherEventWithType: NSEventTypeApplicationDefined
4138                                 location: NSMakePoint (0, 0)
4139                            modifierFlags: 0
4140                                timestamp: 0
4141                             windowNumber: [[NSApp mainWindow] windowNumber]
4142                                  context: [NSApp context]
4143                                  subtype: 0
4144                                    data1: value
4145                                    data2: 0];
4147       /* Post an application defined event on the event queue.  When this is
4148          received the [NXApp run] will return, thus having processed all
4149          events which are currently queued.  */
4150       [NSApp postEvent: nxev atStart: NO];
4151     }
4154 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4155 static void
4156 check_native_fs ()
4158   Lisp_Object frame, tail;
4160   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
4161     return;
4163   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
4165   FOR_EACH_FRAME (tail, frame)
4166     {
4167       struct frame *f = XFRAME (frame);
4168       if (FRAME_NS_P (f))
4169         {
4170           EmacsView *view = FRAME_NS_VIEW (f);
4171           [view updateCollectionBehavior];
4172         }
4173     }
4175 #endif
4177 /* GNUstep does not have cancelTracking.  */
4178 #ifdef NS_IMPL_COCOA
4179 /* Check if menu open should be canceled or continued as normal.  */
4180 void
4181 ns_check_menu_open (NSMenu *menu)
4183   /* Click in menu bar? */
4184   NSArray *a = [[NSApp mainMenu] itemArray];
4185   int i;
4186   BOOL found = NO;
4188   if (menu == nil) // Menu tracking ended.
4189     {
4190       if (menu_will_open_state == MENU_OPENING)
4191         menu_will_open_state = MENU_NONE;
4192       return;
4193     }
4195   for (i = 0; ! found && i < [a count]; i++)
4196     found = menu == [[a objectAtIndex:i] submenu];
4197   if (found)
4198     {
4199       if (menu_will_open_state == MENU_NONE && emacs_event)
4200         {
4201           NSEvent *theEvent = [NSApp currentEvent];
4202           struct frame *emacsframe = SELECTED_FRAME ();
4204           [menu cancelTracking];
4205           menu_will_open_state = MENU_PENDING;
4206           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4207           EV_TRAILER (theEvent);
4209           CGEventRef ourEvent = CGEventCreate (NULL);
4210           menu_mouse_point = CGEventGetLocation (ourEvent);
4211           CFRelease (ourEvent);
4212         }
4213       else if (menu_will_open_state == MENU_OPENING)
4214         {
4215           menu_will_open_state = MENU_NONE;
4216         }
4217     }
4220 /* Redo saved menu click if state is MENU_PENDING.  */
4221 void
4222 ns_check_pending_open_menu ()
4224   if (menu_will_open_state == MENU_PENDING)
4225     {
4226       CGEventSourceRef source
4227         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4229       CGEventRef event = CGEventCreateMouseEvent (source,
4230                                                   kCGEventLeftMouseDown,
4231                                                   menu_mouse_point,
4232                                                   kCGMouseButtonLeft);
4233       CGEventSetType (event, kCGEventLeftMouseDown);
4234       CGEventPost (kCGHIDEventTap, event);
4235       CFRelease (event);
4236       CFRelease (source);
4238       menu_will_open_state = MENU_OPENING;
4239     }
4241 #endif /* NS_IMPL_COCOA */
4243 static int
4244 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4245 /* --------------------------------------------------------------------------
4246      External (hook): Post an event to ourself and keep reading events until
4247      we read it back again.  In effect process all events which were waiting.
4248      From 21+ we have to manage the event buffer ourselves.
4249    -------------------------------------------------------------------------- */
4251   struct input_event ev;
4252   int nevents;
4254   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4256 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4257   check_native_fs ();
4258 #endif
4260   if ([NSApp modalWindow] != nil)
4261     return -1;
4263   if (hold_event_q.nr > 0)
4264     {
4265       int i;
4266       for (i = 0; i < hold_event_q.nr; ++i)
4267         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4268       hold_event_q.nr = 0;
4269       return i;
4270     }
4272   if ([NSThread isMainThread])
4273     {
4274       block_input ();
4275       n_emacs_events_pending = 0;
4276       ns_init_events (&ev);
4277       q_event_ptr = hold_quit;
4279       /* we manage autorelease pools by allocate/reallocate each time around
4280          the loop; strict nesting is occasionally violated but seems not to
4281          matter.. earlier methods using full nesting caused major memory leaks */
4282       [outerpool release];
4283       outerpool = [[NSAutoreleasePool alloc] init];
4285       /* If have pending open-file requests, attend to the next one of those. */
4286       if (ns_pending_files && [ns_pending_files count] != 0
4287           && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4288         {
4289           [ns_pending_files removeObjectAtIndex: 0];
4290         }
4291       /* Deal with pending service requests. */
4292       else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4293                && [(EmacsApp *)
4294                     NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4295                                  withArg: [ns_pending_service_args objectAtIndex: 0]])
4296         {
4297           [ns_pending_service_names removeObjectAtIndex: 0];
4298           [ns_pending_service_args removeObjectAtIndex: 0];
4299         }
4300       else
4301         {
4302           /* Run and wait for events.  We must always send one NX_APPDEFINED event
4303              to ourself, otherwise [NXApp run] will never exit.  */
4304           send_appdefined = YES;
4305           ns_send_appdefined (-1);
4307           [NSApp run];
4308         }
4310       nevents = n_emacs_events_pending;
4311       n_emacs_events_pending = 0;
4312       ns_finish_events ();
4313       q_event_ptr = NULL;
4314       unblock_input ();
4315     }
4316   else
4317     return -1;
4319   return nevents;
4324 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4325            fd_set *exceptfds, struct timespec *timeout,
4326            sigset_t *sigmask)
4327 /* --------------------------------------------------------------------------
4328      Replacement for select, checking for events
4329    -------------------------------------------------------------------------- */
4331   int result;
4332   int t, k, nr = 0;
4333   struct input_event event;
4334   char c;
4336   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4338 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
4339   check_native_fs ();
4340 #endif
4342   if (hold_event_q.nr > 0)
4343     {
4344       /* We already have events pending. */
4345       raise (SIGIO);
4346       errno = EINTR;
4347       return -1;
4348     }
4350   for (k = 0; k < nfds+1; k++)
4351     {
4352       if (readfds && FD_ISSET(k, readfds)) ++nr;
4353       if (writefds && FD_ISSET(k, writefds)) ++nr;
4354     }
4356   if (NSApp == nil
4357       || ![NSThread isMainThread]
4358       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4359     return thread_select(pselect, nfds, readfds, writefds,
4360                          exceptfds, timeout, sigmask);
4361   else
4362     {
4363       struct timespec t = {0, 0};
4364       thread_select(pselect, 0, NULL, NULL, NULL, &t, sigmask);
4365     }
4367   [outerpool release];
4368   outerpool = [[NSAutoreleasePool alloc] init];
4371   send_appdefined = YES;
4372   if (nr > 0)
4373     {
4374       pthread_mutex_lock (&select_mutex);
4375       select_nfds = nfds;
4376       select_valid = 0;
4377       if (readfds)
4378         {
4379           select_readfds = *readfds;
4380           select_valid += SELECT_HAVE_READ;
4381         }
4382       if (writefds)
4383         {
4384           select_writefds = *writefds;
4385           select_valid += SELECT_HAVE_WRITE;
4386         }
4388       if (timeout)
4389         {
4390           select_timeout = *timeout;
4391           select_valid += SELECT_HAVE_TMO;
4392         }
4394       pthread_mutex_unlock (&select_mutex);
4396       /* Inform fd_handler that select should be called */
4397       c = 'g';
4398       emacs_write_sig (selfds[1], &c, 1);
4399     }
4400   else if (nr == 0 && timeout)
4401     {
4402       /* No file descriptor, just a timeout, no need to wake fd_handler  */
4403       double time = timespectod (*timeout);
4404       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4405                                                       target: NSApp
4406                                                     selector:
4407                                   @selector (timeout_handler:)
4408                                                     userInfo: 0
4409                                                      repeats: NO]
4410                       retain];
4411     }
4412   else /* No timeout and no file descriptors, can this happen?  */
4413     {
4414       /* Send appdefined so we exit from the loop */
4415       ns_send_appdefined (-1);
4416     }
4418   block_input ();
4419   ns_init_events (&event);
4421   [NSApp run];
4423   ns_finish_events ();
4424   if (nr > 0 && readfds)
4425     {
4426       c = 's';
4427       emacs_write_sig (selfds[1], &c, 1);
4428     }
4429   unblock_input ();
4431   t = last_appdefined_event_data;
4433   if (t != NO_APPDEFINED_DATA)
4434     {
4435       last_appdefined_event_data = NO_APPDEFINED_DATA;
4437       if (t == -2)
4438         {
4439           /* The NX_APPDEFINED event we received was a timeout. */
4440           result = 0;
4441         }
4442       else if (t == -1)
4443         {
4444           /* The NX_APPDEFINED event we received was the result of
4445              at least one real input event arriving.  */
4446           errno = EINTR;
4447           result = -1;
4448         }
4449       else
4450         {
4451           /* Received back from select () in fd_handler; copy the results */
4452           pthread_mutex_lock (&select_mutex);
4453           if (readfds) *readfds = select_readfds;
4454           if (writefds) *writefds = select_writefds;
4455           pthread_mutex_unlock (&select_mutex);
4456           result = t;
4457         }
4458     }
4459   else
4460     {
4461       errno = EINTR;
4462       result = -1;
4463     }
4465   return result;
4468 #ifdef HAVE_PTHREAD
4469 void
4470 ns_run_loop_break ()
4471 /* Break out of the NS run loop in ns_select or ns_read_socket. */
4473   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_run_loop_break");
4475   /* If we don't have a GUI, don't send the event. */
4476   if (NSApp != NULL)
4477     ns_send_appdefined(-1);
4479 #endif
4482 /* ==========================================================================
4484     Scrollbar handling
4486    ========================================================================== */
4489 static void
4490 ns_set_vertical_scroll_bar (struct window *window,
4491                            int portion, int whole, int position)
4492 /* --------------------------------------------------------------------------
4493       External (hook): Update or add scrollbar
4494    -------------------------------------------------------------------------- */
4496   Lisp_Object win;
4497   NSRect r, v;
4498   struct frame *f = XFRAME (WINDOW_FRAME (window));
4499   EmacsView *view = FRAME_NS_VIEW (f);
4500   EmacsScroller *bar;
4501   int window_y, window_height;
4502   int top, left, height, width;
4503   BOOL update_p = YES;
4505   /* optimization; display engine sends WAY too many of these.. */
4506   if (!NILP (window->vertical_scroll_bar))
4507     {
4508       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4509       if ([bar checkSamePosition: position portion: portion whole: whole])
4510         {
4511           if (view->scrollbarsNeedingUpdate == 0)
4512             {
4513               if (!windows_or_buffers_changed)
4514                   return;
4515             }
4516           else
4517             view->scrollbarsNeedingUpdate--;
4518           update_p = NO;
4519         }
4520     }
4522   NSTRACE ("ns_set_vertical_scroll_bar");
4524   /* Get dimensions.  */
4525   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4526   top = window_y;
4527   height = window_height;
4528   width = NS_SCROLL_BAR_WIDTH (f);
4529   left = WINDOW_SCROLL_BAR_AREA_X (window);
4531   r = NSMakeRect (left, top, width, height);
4532   /* the parent view is flipped, so we need to flip y value */
4533   v = [view frame];
4534   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4536   XSETWINDOW (win, window);
4537   block_input ();
4539   /* we want at least 5 lines to display a scrollbar */
4540   if (WINDOW_TOTAL_LINES (window) < 5)
4541     {
4542       if (!NILP (window->vertical_scroll_bar))
4543         {
4544           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4545           [bar removeFromSuperview];
4546           wset_vertical_scroll_bar (window, Qnil);
4547           [bar release];
4548         }
4549       ns_clear_frame_area (f, left, top, width, height);
4550       unblock_input ();
4551       return;
4552     }
4554   if (NILP (window->vertical_scroll_bar))
4555     {
4556       if (width > 0 && height > 0)
4557         ns_clear_frame_area (f, left, top, width, height);
4559       bar = [[EmacsScroller alloc] initFrame: r window: win];
4560       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4561       update_p = YES;
4562     }
4563   else
4564     {
4565       NSRect oldRect;
4566       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4567       oldRect = [bar frame];
4568       r.size.width = oldRect.size.width;
4569       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4570         {
4571           if (oldRect.origin.x != r.origin.x)
4572               ns_clear_frame_area (f, left, top, width, height);
4573           [bar setFrame: r];
4574         }
4575     }
4577   if (update_p)
4578     [bar setPosition: position portion: portion whole: whole];
4579   unblock_input ();
4583 static void
4584 ns_set_horizontal_scroll_bar (struct window *window,
4585                               int portion, int whole, int position)
4586 /* --------------------------------------------------------------------------
4587       External (hook): Update or add scrollbar
4588    -------------------------------------------------------------------------- */
4590   Lisp_Object win;
4591   NSRect r, v;
4592   struct frame *f = XFRAME (WINDOW_FRAME (window));
4593   EmacsView *view = FRAME_NS_VIEW (f);
4594   EmacsScroller *bar;
4595   int top, height, left, width;
4596   int window_x, window_width;
4597   BOOL update_p = YES;
4599   /* optimization; display engine sends WAY too many of these.. */
4600   if (!NILP (window->horizontal_scroll_bar))
4601     {
4602       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4603       if ([bar checkSamePosition: position portion: portion whole: whole])
4604         {
4605           if (view->scrollbarsNeedingUpdate == 0)
4606             {
4607               if (!windows_or_buffers_changed)
4608                   return;
4609             }
4610           else
4611             view->scrollbarsNeedingUpdate--;
4612           update_p = NO;
4613         }
4614     }
4616   NSTRACE ("ns_set_horizontal_scroll_bar");
4618   /* Get dimensions.  */
4619   window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4620   left = window_x;
4621   width = window_width;
4622   height = NS_SCROLL_BAR_HEIGHT (f);
4623   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4625   r = NSMakeRect (left, top, width, height);
4626   /* the parent view is flipped, so we need to flip y value */
4627   v = [view frame];
4628   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4630   XSETWINDOW (win, window);
4631   block_input ();
4633   if (NILP (window->horizontal_scroll_bar))
4634     {
4635       if (width > 0 && height > 0)
4636         ns_clear_frame_area (f, left, top, width, height);
4638       bar = [[EmacsScroller alloc] initFrame: r window: win];
4639       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4640       update_p = YES;
4641     }
4642   else
4643     {
4644       NSRect oldRect;
4645       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4646       oldRect = [bar frame];
4647       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4648         {
4649           if (oldRect.origin.y != r.origin.y)
4650             ns_clear_frame_area (f, left, top, width, height);
4651           [bar setFrame: r];
4652           update_p = YES;
4653         }
4654     }
4656   /* If there are both horizontal and vertical scroll-bars they leave
4657      a square that belongs to neither. We need to clear it otherwise
4658      it fills with junk. */
4659   if (!NILP (window->vertical_scroll_bar))
4660     ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4661                          NS_SCROLL_BAR_HEIGHT (f), height);
4663   if (update_p)
4664     [bar setPosition: position portion: portion whole: whole];
4665   unblock_input ();
4669 static void
4670 ns_condemn_scroll_bars (struct frame *f)
4671 /* --------------------------------------------------------------------------
4672      External (hook): arrange for all frame's scrollbars to be removed
4673      at next call to judge_scroll_bars, except for those redeemed.
4674    -------------------------------------------------------------------------- */
4676   int i;
4677   id view;
4678   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4680   NSTRACE ("ns_condemn_scroll_bars");
4682   for (i =[subviews count]-1; i >= 0; i--)
4683     {
4684       view = [subviews objectAtIndex: i];
4685       if ([view isKindOfClass: [EmacsScroller class]])
4686         [view condemn];
4687     }
4691 static void
4692 ns_redeem_scroll_bar (struct window *window)
4693 /* --------------------------------------------------------------------------
4694      External (hook): arrange to spare this window's scrollbar
4695      at next call to judge_scroll_bars.
4696    -------------------------------------------------------------------------- */
4698   id bar;
4699   NSTRACE ("ns_redeem_scroll_bar");
4700   if (!NILP (window->vertical_scroll_bar)
4701       && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4702     {
4703       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4704       [bar reprieve];
4705     }
4707   if (!NILP (window->horizontal_scroll_bar)
4708       && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4709     {
4710       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4711       [bar reprieve];
4712     }
4716 static void
4717 ns_judge_scroll_bars (struct frame *f)
4718 /* --------------------------------------------------------------------------
4719      External (hook): destroy all scrollbars on frame that weren't
4720      redeemed after call to condemn_scroll_bars.
4721    -------------------------------------------------------------------------- */
4723   int i;
4724   id view;
4725   EmacsView *eview = FRAME_NS_VIEW (f);
4726   NSArray *subviews = [[eview superview] subviews];
4727   BOOL removed = NO;
4729   NSTRACE ("ns_judge_scroll_bars");
4730   for (i = [subviews count]-1; i >= 0; --i)
4731     {
4732       view = [subviews objectAtIndex: i];
4733       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4734       if ([view judge])
4735         removed = YES;
4736     }
4738   if (removed)
4739     [eview updateFrameSize: NO];
4742 /* ==========================================================================
4744     Initialization
4746    ========================================================================== */
4749 x_display_pixel_height (struct ns_display_info *dpyinfo)
4751   NSArray *screens = [NSScreen screens];
4752   NSEnumerator *enumerator = [screens objectEnumerator];
4753   NSScreen *screen;
4754   NSRect frame;
4756   frame = NSZeroRect;
4757   while ((screen = [enumerator nextObject]) != nil)
4758     frame = NSUnionRect (frame, [screen frame]);
4760   return NSHeight (frame);
4764 x_display_pixel_width (struct ns_display_info *dpyinfo)
4766   NSArray *screens = [NSScreen screens];
4767   NSEnumerator *enumerator = [screens objectEnumerator];
4768   NSScreen *screen;
4769   NSRect frame;
4771   frame = NSZeroRect;
4772   while ((screen = [enumerator nextObject]) != nil)
4773     frame = NSUnionRect (frame, [screen frame]);
4775   return NSWidth (frame);
4779 static Lisp_Object ns_string_to_lispmod (const char *s)
4780 /* --------------------------------------------------------------------------
4781      Convert modifier name to lisp symbol
4782    -------------------------------------------------------------------------- */
4784   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4785     return Qmeta;
4786   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4787     return Qsuper;
4788   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4789     return Qcontrol;
4790   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4791     return Qalt;
4792   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4793     return Qhyper;
4794   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4795     return Qnone;
4796   else
4797     return Qnil;
4801 static void
4802 ns_default (const char *parameter, Lisp_Object *result,
4803            Lisp_Object yesval, Lisp_Object noval,
4804            BOOL is_float, BOOL is_modstring)
4805 /* --------------------------------------------------------------------------
4806       Check a parameter value in user's preferences
4807    -------------------------------------------------------------------------- */
4809   const char *value = ns_get_defaults_value (parameter);
4811   if (value)
4812     {
4813       double f;
4814       char *pos;
4815       if (c_strcasecmp (value, "YES") == 0)
4816         *result = yesval;
4817       else if (c_strcasecmp (value, "NO") == 0)
4818         *result = noval;
4819       else if (is_float && (f = strtod (value, &pos), pos != value))
4820         *result = make_float (f);
4821       else if (is_modstring && value)
4822         *result = ns_string_to_lispmod (value);
4823       else fprintf (stderr,
4824                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4825     }
4829 static void
4830 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4831 /* --------------------------------------------------------------------------
4832       Initialize global info and storage for display.
4833    -------------------------------------------------------------------------- */
4835     NSScreen *screen = [NSScreen mainScreen];
4836     NSWindowDepth depth = [screen depth];
4838     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4839     dpyinfo->resy = 72.27;
4840     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4841                                                   NSColorSpaceFromDepth (depth)]
4842                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4843                                                  NSColorSpaceFromDepth (depth)];
4844     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4845     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4846     dpyinfo->color_table->colors = NULL;
4847     dpyinfo->root_window = 42; /* a placeholder.. */
4848     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4849     dpyinfo->n_fonts = 0;
4850     dpyinfo->smallest_font_height = 1;
4851     dpyinfo->smallest_char_width = 1;
4853     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4857 /* This and next define (many of the) public functions in this file. */
4858 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4859          with using despite presence in the "system dependent" redisplay
4860          interface.  In addition, many of the ns_ methods have code that is
4861          shared with all terms, indicating need for further refactoring. */
4862 extern frame_parm_handler ns_frame_parm_handlers[];
4863 static struct redisplay_interface ns_redisplay_interface =
4865   ns_frame_parm_handlers,
4866   x_produce_glyphs,
4867   x_write_glyphs,
4868   x_insert_glyphs,
4869   x_clear_end_of_line,
4870   ns_scroll_run,
4871   ns_after_update_window_line,
4872   ns_update_window_begin,
4873   ns_update_window_end,
4874   0, /* flush_display */
4875   x_clear_window_mouse_face,
4876   x_get_glyph_overhangs,
4877   x_fix_overlapping_area,
4878   ns_draw_fringe_bitmap,
4879   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4880   0, /* destroy_fringe_bitmap */
4881   ns_compute_glyph_string_overhangs,
4882   ns_draw_glyph_string,
4883   ns_define_frame_cursor,
4884   ns_clear_frame_area,
4885   ns_draw_window_cursor,
4886   ns_draw_vertical_window_border,
4887   ns_draw_window_divider,
4888   ns_shift_glyphs_for_insert,
4889   ns_show_hourglass,
4890   ns_hide_hourglass
4894 static void
4895 ns_delete_display (struct ns_display_info *dpyinfo)
4897   /* TODO... */
4901 /* This function is called when the last frame on a display is deleted. */
4902 static void
4903 ns_delete_terminal (struct terminal *terminal)
4905   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4907   NSTRACE ("ns_delete_terminal");
4909   /* Protect against recursive calls.  delete_frame in
4910      delete_terminal calls us back when it deletes our last frame.  */
4911   if (!terminal->name)
4912     return;
4914   block_input ();
4916   x_destroy_all_bitmaps (dpyinfo);
4917   ns_delete_display (dpyinfo);
4918   unblock_input ();
4922 static struct terminal *
4923 ns_create_terminal (struct ns_display_info *dpyinfo)
4924 /* --------------------------------------------------------------------------
4925       Set up use of NS before we make the first connection.
4926    -------------------------------------------------------------------------- */
4928   struct terminal *terminal;
4930   NSTRACE ("ns_create_terminal");
4932   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4934   terminal->display_info.ns = dpyinfo;
4935   dpyinfo->terminal = terminal;
4937   terminal->clear_frame_hook = ns_clear_frame;
4938   terminal->ring_bell_hook = ns_ring_bell;
4939   terminal->update_begin_hook = ns_update_begin;
4940   terminal->update_end_hook = ns_update_end;
4941   terminal->read_socket_hook = ns_read_socket;
4942   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4943   terminal->mouse_position_hook = ns_mouse_position;
4944   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4945   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4946   terminal->fullscreen_hook = ns_fullscreen_hook;
4947   terminal->menu_show_hook = ns_menu_show;
4948   terminal->popup_dialog_hook = ns_popup_dialog;
4949   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4950   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4951   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4952   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4953   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4954   terminal->delete_frame_hook = x_destroy_window;
4955   terminal->delete_terminal_hook = ns_delete_terminal;
4956   /* Other hooks are NULL by default.  */
4958   return terminal;
4962 struct ns_display_info *
4963 ns_term_init (Lisp_Object display_name)
4964 /* --------------------------------------------------------------------------
4965      Start the Application and get things rolling.
4966    -------------------------------------------------------------------------- */
4968   struct terminal *terminal;
4969   struct ns_display_info *dpyinfo;
4970   static int ns_initialized = 0;
4971   Lisp_Object tmp;
4973   if (ns_initialized) return x_display_list;
4974   ns_initialized = 1;
4976   block_input ();
4978   NSTRACE ("ns_term_init");
4980   [outerpool release];
4981   outerpool = [[NSAutoreleasePool alloc] init];
4983   /* count object allocs (About, click icon); on macOS use ObjectAlloc tool */
4984   /*GSDebugAllocationActive (YES); */
4985   block_input ();
4987   baud_rate = 38400;
4988   Fset_input_interrupt_mode (Qnil);
4990   if (selfds[0] == -1)
4991     {
4992       if (emacs_pipe (selfds) != 0)
4993         {
4994           fprintf (stderr, "Failed to create pipe: %s\n",
4995                    emacs_strerror (errno));
4996           emacs_abort ();
4997         }
4999       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
5000       FD_ZERO (&select_readfds);
5001       FD_ZERO (&select_writefds);
5002       pthread_mutex_init (&select_mutex, NULL);
5003     }
5005   ns_pending_files = [[NSMutableArray alloc] init];
5006   ns_pending_service_names = [[NSMutableArray alloc] init];
5007   ns_pending_service_args = [[NSMutableArray alloc] init];
5009 /* Start app and create the main menu, window, view.
5010      Needs to be here because ns_initialize_display_info () uses AppKit classes.
5011      The view will then ask the NSApp to stop and return to Emacs. */
5012   [EmacsApp sharedApplication];
5013   if (NSApp == nil)
5014     return NULL;
5015   [NSApp setDelegate: NSApp];
5017   /* Start the select thread.  */
5018   [NSThread detachNewThreadSelector:@selector (fd_handler:)
5019                            toTarget:NSApp
5020                          withObject:nil];
5022   /* debugging: log all notifications */
5023   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
5024                                          selector: @selector (logNotification:)
5025                                              name: nil object: nil]; */
5027   dpyinfo = xzalloc (sizeof *dpyinfo);
5029   ns_initialize_display_info (dpyinfo);
5030   terminal = ns_create_terminal (dpyinfo);
5032   terminal->kboard = allocate_kboard (Qns);
5033   /* Don't let the initial kboard remain current longer than necessary.
5034      That would cause problems if a file loaded on startup tries to
5035      prompt in the mini-buffer.  */
5036   if (current_kboard == initial_kboard)
5037     current_kboard = terminal->kboard;
5038   terminal->kboard->reference_count++;
5040   dpyinfo->next = x_display_list;
5041   x_display_list = dpyinfo;
5043   dpyinfo->name_list_element = Fcons (display_name, Qnil);
5045   terminal->name = xlispstrdup (display_name);
5047   unblock_input ();
5049   if (!inhibit_x_resources)
5050     {
5051       ns_default ("GSFontAntiAlias", &ns_antialias_text,
5052                  Qt, Qnil, NO, NO);
5053       tmp = Qnil;
5054       /* this is a standard variable */
5055       ns_default ("AppleAntiAliasingThreshold", &tmp,
5056                  make_float (10.0), make_float (6.0), YES, NO);
5057       ns_antialias_threshold = NILP (tmp) ? 10.0 : extract_float (tmp);
5058     }
5060   NSTRACE_MSG ("Colors");
5062   {
5063     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
5065     if ( cl == nil )
5066       {
5067         Lisp_Object color_file, color_map, color;
5068         unsigned long c;
5069         char *name;
5071         color_file = Fexpand_file_name (build_string ("rgb.txt"),
5072                          Fsymbol_value (intern ("data-directory")));
5074         color_map = Fx_load_color_file (color_file);
5075         if (NILP (color_map))
5076           fatal ("Could not read %s.\n", SDATA (color_file));
5078         cl = [[NSColorList alloc] initWithName: @"Emacs"];
5079         for ( ; CONSP (color_map); color_map = XCDR (color_map))
5080           {
5081             color = XCAR (color_map);
5082             name = SSDATA (XCAR (color));
5083             c = XINT (XCDR (color));
5084             [cl setColor:
5085                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
5086                                       green: GREEN_FROM_ULONG (c) / 255.0
5087                                        blue: BLUE_FROM_ULONG (c) / 255.0
5088                                       alpha: 1.0]
5089                   forKey: [NSString stringWithUTF8String: name]];
5090           }
5091         [cl writeToFile: nil];
5092       }
5093   }
5095   NSTRACE_MSG ("Versions");
5097   {
5098 #ifdef NS_IMPL_GNUSTEP
5099     Vwindow_system_version = build_string (gnustep_base_version);
5100 #else
5101     /*PSnextrelease (128, c); */
5102     char c[DBL_BUFSIZE_BOUND];
5103     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
5104     Vwindow_system_version = make_unibyte_string (c, len);
5105 #endif
5106   }
5108   delete_keyboard_wait_descriptor (0);
5110   ns_app_name = [[NSProcessInfo processInfo] processName];
5112   /* Set up macOS app menu */
5114   NSTRACE_MSG ("Menu init");
5116 #ifdef NS_IMPL_COCOA
5117   {
5118     NSMenu *appMenu;
5119     NSMenuItem *item;
5120     /* set up the application menu */
5121     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
5122     [svcsMenu setAutoenablesItems: NO];
5123     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
5124     [appMenu setAutoenablesItems: NO];
5125     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
5126     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
5128     [appMenu insertItemWithTitle: @"About Emacs"
5129                           action: @selector (orderFrontStandardAboutPanel:)
5130                    keyEquivalent: @""
5131                          atIndex: 0];
5132     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
5133     [appMenu insertItemWithTitle: @"Preferences..."
5134                           action: @selector (showPreferencesWindow:)
5135                    keyEquivalent: @","
5136                          atIndex: 2];
5137     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
5138     item = [appMenu insertItemWithTitle: @"Services"
5139                                  action: @selector (menuDown:)
5140                           keyEquivalent: @""
5141                                 atIndex: 4];
5142     [appMenu setSubmenu: svcsMenu forItem: item];
5143     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
5144     [appMenu insertItemWithTitle: @"Hide Emacs"
5145                           action: @selector (hide:)
5146                    keyEquivalent: @"h"
5147                          atIndex: 6];
5148     item =  [appMenu insertItemWithTitle: @"Hide Others"
5149                           action: @selector (hideOtherApplications:)
5150                    keyEquivalent: @"h"
5151                          atIndex: 7];
5152     [item setKeyEquivalentModifierMask: NSEventModifierFlagCommand | NSEventModifierFlagOption];
5153     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
5154     [appMenu insertItemWithTitle: @"Quit Emacs"
5155                           action: @selector (terminate:)
5156                    keyEquivalent: @"q"
5157                          atIndex: 9];
5159     item = [mainMenu insertItemWithTitle: ns_app_name
5160                                   action: @selector (menuDown:)
5161                            keyEquivalent: @""
5162                                  atIndex: 0];
5163     [mainMenu setSubmenu: appMenu forItem: item];
5164     [dockMenu insertItemWithTitle: @"New Frame"
5165                            action: @selector (newFrame:)
5166                     keyEquivalent: @""
5167                           atIndex: 0];
5169     [NSApp setMainMenu: mainMenu];
5170     [NSApp setAppleMenu: appMenu];
5171     [NSApp setServicesMenu: svcsMenu];
5172     /* Needed at least on Cocoa, to get dock menu to show windows */
5173     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5175     [[NSNotificationCenter defaultCenter]
5176       addObserver: mainMenu
5177          selector: @selector (trackingNotification:)
5178              name: NSMenuDidBeginTrackingNotification object: mainMenu];
5179     [[NSNotificationCenter defaultCenter]
5180       addObserver: mainMenu
5181          selector: @selector (trackingNotification:)
5182              name: NSMenuDidEndTrackingNotification object: mainMenu];
5183   }
5184 #endif /* macOS menu setup */
5186   /* Register our external input/output types, used for determining
5187      applicable services and also drag/drop eligibility. */
5189   NSTRACE_MSG ("Input/output types");
5191   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5192   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5193                       retain];
5194   ns_drag_types = [[NSArray arrayWithObjects:
5195                             NSStringPboardType,
5196                             NSTabularTextPboardType,
5197                             NSFilenamesPboardType,
5198                             NSURLPboardType, nil] retain];
5200   /* If fullscreen is in init/default-frame-alist, focus isn't set
5201      right for fullscreen windows, so set this.  */
5202   [NSApp activateIgnoringOtherApps:YES];
5204   NSTRACE_MSG ("Call NSApp run");
5206   [NSApp run];
5207   ns_do_open_file = YES;
5209 #ifdef NS_IMPL_GNUSTEP
5210   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5211      We must re-catch it so subprocess works.  */
5212   catch_child_signal ();
5213 #endif
5215   NSTRACE_MSG ("ns_term_init done");
5217   unblock_input ();
5219   return dpyinfo;
5223 void
5224 ns_term_shutdown (int sig)
5226   [[NSUserDefaults standardUserDefaults] synchronize];
5228   /* code not reached in emacs.c after this is called by shut_down_emacs: */
5229   if (STRINGP (Vauto_save_list_file_name))
5230     unlink (SSDATA (Vauto_save_list_file_name));
5232   if (sig == 0 || sig == SIGTERM)
5233     {
5234       [NSApp terminate: NSApp];
5235     }
5236   else // force a stack trace to happen
5237     {
5238       emacs_abort ();
5239     }
5243 /* ==========================================================================
5245     EmacsApp implementation
5247    ========================================================================== */
5250 @implementation EmacsApp
5252 - (id)init
5254   NSTRACE ("[EmacsApp init]");
5256   if ((self = [super init]))
5257     {
5258 #ifdef NS_IMPL_COCOA
5259       self->isFirst = YES;
5260 #endif
5261 #ifdef NS_IMPL_GNUSTEP
5262       self->applicationDidFinishLaunchingCalled = NO;
5263 #endif
5264     }
5266   return self;
5269 #ifdef NS_IMPL_COCOA
5270 - (void)run
5272   NSTRACE ("[EmacsApp run]");
5274 #ifndef NSAppKitVersionNumber10_9
5275 #define NSAppKitVersionNumber10_9 1265
5276 #endif
5278     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5279       {
5280         [super run];
5281         return;
5282       }
5284   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5286   if (isFirst) [self finishLaunching];
5287   isFirst = NO;
5289   shouldKeepRunning = YES;
5290   do
5291     {
5292       [pool release];
5293       pool = [[NSAutoreleasePool alloc] init];
5295       NSEvent *event =
5296         [self nextEventMatchingMask:NSEventMaskAny
5297                           untilDate:[NSDate distantFuture]
5298                              inMode:NSDefaultRunLoopMode
5299                             dequeue:YES];
5301       [self sendEvent:event];
5302       [self updateWindows];
5303     } while (shouldKeepRunning);
5305   [pool release];
5308 - (void)stop: (id)sender
5310   NSTRACE ("[EmacsApp stop:]");
5312     shouldKeepRunning = NO;
5313     // Stop possible dialog also.  Noop if no dialog present.
5314     // The file dialog still leaks 7k - 10k on 10.9 though.
5315     [super stop:sender];
5317 #endif /* NS_IMPL_COCOA */
5319 - (void)logNotification: (NSNotification *)notification
5321   NSTRACE ("[EmacsApp logNotification:]");
5323   const char *name = [[notification name] UTF8String];
5324   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5325       && !strstr (name, "WindowNumber"))
5326     NSLog (@"notification: '%@'", [notification name]);
5330 - (void)sendEvent: (NSEvent *)theEvent
5331 /* --------------------------------------------------------------------------
5332      Called when NSApp is running for each event received.  Used to stop
5333      the loop when we choose, since there's no way to just run one iteration.
5334    -------------------------------------------------------------------------- */
5336   int type = [theEvent type];
5337   NSWindow *window = [theEvent window];
5339   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5340   NSTRACE_MSG ("Type: %d", type);
5342 #ifdef NS_IMPL_GNUSTEP
5343   // Keyboard events aren't propagated to file dialogs for some reason.
5344   if ([NSApp modalWindow] != nil &&
5345       (type == NSEventTypeKeyDown || type == NSEventTypeKeyUp || type == NSEventTypeFlagsChanged))
5346     {
5347       [[NSApp modalWindow] sendEvent: theEvent];
5348       return;
5349     }
5350 #endif
5352   if (represented_filename != nil && represented_frame)
5353     {
5354       NSString *fstr = represented_filename;
5355       NSView *view = FRAME_NS_VIEW (represented_frame);
5356 #ifdef NS_IMPL_COCOA
5357       /* work around a bug observed on 10.3 and later where
5358          setTitleWithRepresentedFilename does not clear out previous state
5359          if given filename does not exist */
5360       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5361         [[view window] setRepresentedFilename: @""];
5362 #endif
5363       [[view window] setRepresentedFilename: fstr];
5364       [represented_filename release];
5365       represented_filename = nil;
5366       represented_frame = NULL;
5367     }
5369   if (type == NSEventTypeApplicationDefined)
5370     {
5371       switch ([theEvent data2])
5372         {
5373 #ifdef NS_IMPL_COCOA
5374         case NSAPP_DATA2_RUNASSCRIPT:
5375           ns_run_ascript ();
5376           [self stop: self];
5377           return;
5378 #endif
5379         case NSAPP_DATA2_RUNFILEDIALOG:
5380           ns_run_file_dialog ();
5381           [self stop: self];
5382           return;
5383         }
5384     }
5386   if (type == NSEventTypeCursorUpdate && window == nil)
5387     {
5388       fprintf (stderr, "Dropping external cursor update event.\n");
5389       return;
5390     }
5392   if (type == NSEventTypeApplicationDefined)
5393     {
5394       /* Events posted by ns_send_appdefined interrupt the run loop here.
5395          But, if a modal window is up, an appdefined can still come through,
5396          (e.g., from a makeKeyWindow event) but stopping self also stops the
5397          modal loop. Just defer it until later. */
5398       if ([NSApp modalWindow] == nil)
5399         {
5400           last_appdefined_event_data = [theEvent data1];
5401           [self stop: self];
5402         }
5403       else
5404         {
5405           send_appdefined = YES;
5406         }
5407     }
5410 #ifdef NS_IMPL_COCOA
5411   /* If no dialog and none of our frames have focus and it is a move, skip it.
5412      It is a mouse move in an auxiliary menu, i.e. on the top right on macOS,
5413      such as Wifi, sound, date or similar.
5414      This prevents "spooky" highlighting in the frame under the menu.  */
5415   if (type == NSEventTypeMouseMoved && [NSApp modalWindow] == nil)
5416     {
5417       struct ns_display_info *di;
5418       BOOL has_focus = NO;
5419       for (di = x_display_list; ! has_focus && di; di = di->next)
5420         has_focus = di->x_focus_frame != 0;
5421       if (! has_focus)
5422         return;
5423     }
5424 #endif
5426   NSTRACE_UNSILENCE();
5428   [super sendEvent: theEvent];
5432 - (void)showPreferencesWindow: (id)sender
5434   struct frame *emacsframe = SELECTED_FRAME ();
5435   NSEvent *theEvent = [NSApp currentEvent];
5437   if (!emacs_event)
5438     return;
5439   emacs_event->kind = NS_NONKEY_EVENT;
5440   emacs_event->code = KEY_NS_SHOW_PREFS;
5441   emacs_event->modifiers = 0;
5442   EV_TRAILER (theEvent);
5446 - (void)newFrame: (id)sender
5448   NSTRACE ("[EmacsApp newFrame:]");
5450   struct frame *emacsframe = SELECTED_FRAME ();
5451   NSEvent *theEvent = [NSApp currentEvent];
5453   if (!emacs_event)
5454     return;
5455   emacs_event->kind = NS_NONKEY_EVENT;
5456   emacs_event->code = KEY_NS_NEW_FRAME;
5457   emacs_event->modifiers = 0;
5458   EV_TRAILER (theEvent);
5462 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5463 - (BOOL) openFile: (NSString *)fileName
5465   NSTRACE ("[EmacsApp openFile:]");
5467   struct frame *emacsframe = SELECTED_FRAME ();
5468   NSEvent *theEvent = [NSApp currentEvent];
5470   if (!emacs_event)
5471     return NO;
5473   emacs_event->kind = NS_NONKEY_EVENT;
5474   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5475   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5476   ns_input_line = Qnil; /* can be start or cons start,end */
5477   emacs_event->modifiers =0;
5478   EV_TRAILER (theEvent);
5480   return YES;
5484 /* **************************************************************************
5486       EmacsApp delegate implementation
5488    ************************************************************************** */
5490 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5491 /* --------------------------------------------------------------------------
5492      When application is loaded, terminate event loop in ns_term_init
5493    -------------------------------------------------------------------------- */
5495   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5497 #ifdef NS_IMPL_GNUSTEP
5498   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5499 #endif
5500   [NSApp setServicesProvider: NSApp];
5502   [self antialiasThresholdDidChange:nil];
5503 #ifdef NS_IMPL_COCOA
5504   [[NSNotificationCenter defaultCenter]
5505     addObserver:self
5506        selector:@selector(antialiasThresholdDidChange:)
5507            name:NSAntialiasThresholdChangedNotification
5508          object:nil];
5509 #endif
5511 #ifdef NS_IMPL_COCOA
5512   if ([NSApp activationPolicy] == NSApplicationActivationPolicyProhibited) {
5513     /* Set the app's activation policy to regular when we run outside
5514        of a bundle.  This is already done for us by Info.plist when we
5515        run inside a bundle. */
5516     [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
5517     [NSApp setApplicationIconImage:
5518              [EmacsImage
5519                allocInitFromFile:
5520                  build_string("icons/hicolor/128x128/apps/emacs.png")]];
5521   }
5522 #endif
5524   ns_send_appdefined (-2);
5527 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5529 #ifdef NS_IMPL_COCOA
5530   macfont_update_antialias_threshold ();
5531 #endif
5535 /* Termination sequences:
5536     C-x C-c:
5537     Cmd-Q:
5538     MenuBar | File | Exit:
5539     Select Quit from App menubar:
5540         -terminate
5541         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5542         ns_term_shutdown()
5544     Select Quit from Dock menu:
5545     Logout attempt:
5546         -appShouldTerminate
5547           Cancel -> Nothing else
5548           Accept ->
5550           -terminate
5551           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5552           ns_term_shutdown()
5556 - (void) terminate: (id)sender
5558   NSTRACE ("[EmacsApp terminate:]");
5560   struct frame *emacsframe = SELECTED_FRAME ();
5562   if (!emacs_event)
5563     return;
5565   emacs_event->kind = NS_NONKEY_EVENT;
5566   emacs_event->code = KEY_NS_POWER_OFF;
5567   emacs_event->arg = Qt; /* mark as non-key event */
5568   EV_TRAILER ((id)nil);
5571 static bool
5572 runAlertPanel(NSString *title,
5573               NSString *msgFormat,
5574               NSString *defaultButton,
5575               NSString *alternateButton)
5577 #ifdef NS_IMPL_GNUSTEP
5578   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5579     == NSAlertDefaultReturn;
5580 #else
5581   NSAlert *alert = [[NSAlert alloc] init];
5582   [alert setAlertStyle: NSAlertStyleCritical];
5583   [alert setMessageText: msgFormat];
5584   [alert addButtonWithTitle: defaultButton];
5585   [alert addButtonWithTitle: alternateButton];
5586   NSInteger ret = [alert runModal];
5587   [alert release];
5588   return ret == NSAlertFirstButtonReturn;
5589 #endif
5593 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5595   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5597   bool ret;
5599   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5600     return NSTerminateNow;
5602   ret = runAlertPanel(ns_app_name,
5603                       @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5604                       @"Save Buffers and Exit", @"Cancel");
5606   return ret ? NSTerminateNow : NSTerminateCancel;
5609 static int
5610 not_in_argv (NSString *arg)
5612   int k;
5613   const char *a = [arg UTF8String];
5614   for (k = 1; k < initial_argc; ++k)
5615     if (strcmp (a, initial_argv[k]) == 0) return 0;
5616   return 1;
5619 /*   Notification from the Workspace to open a file */
5620 - (BOOL)application: sender openFile: (NSString *)file
5622   if (ns_do_open_file || not_in_argv (file))
5623     [ns_pending_files addObject: file];
5624   return YES;
5628 /*   Open a file as a temporary file */
5629 - (BOOL)application: sender openTempFile: (NSString *)file
5631   if (ns_do_open_file || not_in_argv (file))
5632     [ns_pending_files addObject: file];
5633   return YES;
5637 /*   Notification from the Workspace to open a file noninteractively (?) */
5638 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5640   if (ns_do_open_file || not_in_argv (file))
5641     [ns_pending_files addObject: file];
5642   return YES;
5645 /*   Notification from the Workspace to open multiple files */
5646 - (void)application: sender openFiles: (NSArray *)fileList
5648   NSEnumerator *files = [fileList objectEnumerator];
5649   NSString *file;
5650   /* Don't open files from the command line unconditionally,
5651      Cocoa parses the command line wrong, --option value tries to open value
5652      if --option is the last option.  */
5653   while ((file = [files nextObject]) != nil)
5654     if (ns_do_open_file || not_in_argv (file))
5655       [ns_pending_files addObject: file];
5657   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5662 /* Handle dock menu requests.  */
5663 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5665   return dockMenu;
5669 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5670 - (void)applicationWillBecomeActive: (NSNotification *)notification
5672   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5673   //ns_app_active=YES;
5676 - (void)applicationDidBecomeActive: (NSNotification *)notification
5678   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5680 #ifdef NS_IMPL_GNUSTEP
5681   if (! applicationDidFinishLaunchingCalled)
5682     [self applicationDidFinishLaunching:notification];
5683 #endif
5684   //ns_app_active=YES;
5686   ns_update_auto_hide_menu_bar ();
5687   // No constraining takes place when the application is not active.
5688   ns_constrain_all_frames ();
5690 - (void)applicationDidResignActive: (NSNotification *)notification
5692   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5694   //ns_app_active=NO;
5695   ns_send_appdefined (-1);
5700 /* ==========================================================================
5702     EmacsApp aux handlers for managing event loop
5704    ========================================================================== */
5707 - (void)timeout_handler: (NSTimer *)timedEntry
5708 /* --------------------------------------------------------------------------
5709      The timeout specified to ns_select has passed.
5710    -------------------------------------------------------------------------- */
5712   /*NSTRACE ("timeout_handler"); */
5713   ns_send_appdefined (-2);
5716 - (void)sendFromMainThread:(id)unused
5718   ns_send_appdefined (nextappdefined);
5721 - (void)fd_handler:(id)unused
5722 /* --------------------------------------------------------------------------
5723      Check data waiting on file descriptors and terminate if so
5724    -------------------------------------------------------------------------- */
5726   int result;
5727   int waiting = 1, nfds;
5728   char c;
5730   fd_set readfds, writefds, *wfds;
5731   struct timespec timeout, *tmo;
5732   NSAutoreleasePool *pool = nil;
5734   /* NSTRACE ("fd_handler"); */
5736   for (;;)
5737     {
5738       [pool release];
5739       pool = [[NSAutoreleasePool alloc] init];
5741       if (waiting)
5742         {
5743           fd_set fds;
5744           FD_ZERO (&fds);
5745           FD_SET (selfds[0], &fds);
5746           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5747           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5748             waiting = 0;
5749         }
5750       else
5751         {
5752           pthread_mutex_lock (&select_mutex);
5753           nfds = select_nfds;
5755           if (select_valid & SELECT_HAVE_READ)
5756             readfds = select_readfds;
5757           else
5758             FD_ZERO (&readfds);
5760           if (select_valid & SELECT_HAVE_WRITE)
5761             {
5762               writefds = select_writefds;
5763               wfds = &writefds;
5764             }
5765           else
5766             wfds = NULL;
5767           if (select_valid & SELECT_HAVE_TMO)
5768             {
5769               timeout = select_timeout;
5770               tmo = &timeout;
5771             }
5772           else
5773             tmo = NULL;
5775           pthread_mutex_unlock (&select_mutex);
5777           FD_SET (selfds[0], &readfds);
5778           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5780           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5782           if (result == 0)
5783             ns_send_appdefined (-2);
5784           else if (result > 0)
5785             {
5786               if (FD_ISSET (selfds[0], &readfds))
5787                 {
5788                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5789                     waiting = 1;
5790                 }
5791               else
5792                 {
5793                   pthread_mutex_lock (&select_mutex);
5794                   if (select_valid & SELECT_HAVE_READ)
5795                     select_readfds = readfds;
5796                   if (select_valid & SELECT_HAVE_WRITE)
5797                     select_writefds = writefds;
5798                   if (select_valid & SELECT_HAVE_TMO)
5799                     select_timeout = timeout;
5800                   pthread_mutex_unlock (&select_mutex);
5802                   ns_send_appdefined (result);
5803                 }
5804             }
5805           waiting = 1;
5806         }
5807     }
5812 /* ==========================================================================
5814     Service provision
5816    ========================================================================== */
5818 /* called from system: queue for next pass through event loop */
5819 - (void)requestService: (NSPasteboard *)pboard
5820               userData: (NSString *)userData
5821                  error: (NSString **)error
5823   [ns_pending_service_names addObject: userData];
5824   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5825       SSDATA (ns_string_from_pasteboard (pboard))]];
5829 /* called from ns_read_socket to clear queue */
5830 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5832   struct frame *emacsframe = SELECTED_FRAME ();
5833   NSEvent *theEvent = [NSApp currentEvent];
5835   NSTRACE ("[EmacsApp fulfillService:withArg:]");
5837   if (!emacs_event)
5838     return NO;
5840   emacs_event->kind = NS_NONKEY_EVENT;
5841   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5842   ns_input_spi_name = build_string ([name UTF8String]);
5843   ns_input_spi_arg = build_string ([arg UTF8String]);
5844   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5845   EV_TRAILER (theEvent);
5847   return YES;
5851 @end  /* EmacsApp */
5855 /* ==========================================================================
5857     EmacsView implementation
5859    ========================================================================== */
5862 @implementation EmacsView
5864 /* needed to inform when window closed from LISP */
5865 - (void) setWindowClosing: (BOOL)closing
5867   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5869   windowClosing = closing;
5873 - (void)dealloc
5875   NSTRACE ("[EmacsView dealloc]");
5876   [toolbar release];
5877   if (fs_state == FULLSCREEN_BOTH)
5878     [nonfs_window release];
5879   [super dealloc];
5883 /* called on font panel selection */
5884 - (void)changeFont: (id)sender
5886   NSEvent *e = [[self window] currentEvent];
5887   struct face *face = FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID);
5888   struct font *font = face->font;
5889   id newFont;
5890   CGFloat size;
5891   NSFont *nsfont;
5893   NSTRACE ("[EmacsView changeFont:]");
5895   if (!emacs_event)
5896     return;
5898 #ifdef NS_IMPL_GNUSTEP
5899   nsfont = ((struct nsfont_info *)font)->nsfont;
5900 #endif
5901 #ifdef NS_IMPL_COCOA
5902   nsfont = (NSFont *) macfont_get_nsctfont (font);
5903 #endif
5905   if ((newFont = [sender convertFont: nsfont]))
5906     {
5907       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5909       emacs_event->kind = NS_NONKEY_EVENT;
5910       emacs_event->modifiers = 0;
5911       emacs_event->code = KEY_NS_CHANGE_FONT;
5913       size = [newFont pointSize];
5914       ns_input_fontsize = make_number (lrint (size));
5915       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5916       EV_TRAILER (e);
5917     }
5921 - (BOOL)acceptsFirstResponder
5923   NSTRACE ("[EmacsView acceptsFirstResponder]");
5924   return YES;
5928 - (void)resetCursorRects
5930   NSRect visible = [self visibleRect];
5931   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5932   NSTRACE ("[EmacsView resetCursorRects]");
5934   if (currentCursor == nil)
5935     currentCursor = [NSCursor arrowCursor];
5937   if (!NSIsEmptyRect (visible))
5938     [self addCursorRect: visible cursor: currentCursor];
5939   [currentCursor setOnMouseEntered: YES];
5944 /*****************************************************************************/
5945 /* Keyboard handling. */
5946 #define NS_KEYLOG 0
5948 - (void)keyDown: (NSEvent *)theEvent
5950   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5951   int code;
5952   unsigned fnKeysym = 0;
5953   static NSMutableArray *nsEvArray;
5954   int left_is_none;
5955   unsigned int flags = [theEvent modifierFlags];
5957   NSTRACE ("[EmacsView keyDown:]");
5959   /* Rhapsody and macOS give up and down events for the arrow keys */
5960   if (ns_fake_keydown == YES)
5961     ns_fake_keydown = NO;
5962   else if ([theEvent type] != NSEventTypeKeyDown)
5963     return;
5965   if (!emacs_event)
5966     return;
5968  if (![[self window] isKeyWindow]
5969      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5970      /* we must avoid an infinite loop here. */
5971      && (EmacsView *)[[theEvent window] delegate] != self)
5972    {
5973      /* XXX: There is an occasional condition in which, when Emacs display
5974          updates a different frame from the current one, and temporarily
5975          selects it, then processes some interrupt-driven input
5976          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5977          for some reason that window has its first responder set to the NSView
5978          most recently updated (I guess), which is not the correct one. */
5979      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5980      return;
5981    }
5983   if (nsEvArray == nil)
5984     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5986   [NSCursor setHiddenUntilMouseMoves: YES];
5988   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5989     {
5990       clear_mouse_face (hlinfo);
5991       hlinfo->mouse_face_hidden = 1;
5992     }
5994   if (!processingCompose)
5995     {
5996       /* When using screen sharing, no left or right information is sent,
5997          so use Left key in those cases.  */
5998       int is_left_key, is_right_key;
6000       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
6001         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
6003       /* (Carbon way: [theEvent keyCode]) */
6005       /* is it a "function key"? */
6006       /* Note: Sometimes a plain key will have the NSEventModifierFlagNumericPad
6007          flag set (this is probably a bug in the OS).
6008       */
6009       if (code < 0x00ff && (flags&NSEventModifierFlagNumericPad))
6010         {
6011           fnKeysym = ns_convert_key ([theEvent keyCode] | NSEventModifierFlagNumericPad);
6012         }
6013       if (fnKeysym == 0)
6014         {
6015           fnKeysym = ns_convert_key (code);
6016         }
6018       if (fnKeysym)
6019         {
6020           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
6021              because Emacs treats Delete and KP-Delete same (in simple.el). */
6022           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
6023 #ifdef NS_IMPL_GNUSTEP
6024               /*  GNUstep uses incompatible keycodes, even for those that are
6025                   supposed to be hardware independent.  Just check for delete.
6026                   Keypad delete does not have keysym 0xFFFF.
6027                   See http://savannah.gnu.org/bugs/?25395
6028               */
6029               || (fnKeysym == 0xFFFF && code == 127)
6030 #endif
6031             )
6032             code = 0xFF08; /* backspace */
6033           else
6034             code = fnKeysym;
6035         }
6037       /* are there modifiers? */
6038       emacs_event->modifiers = 0;
6040       if (flags & NSEventModifierFlagHelp)
6041           emacs_event->modifiers |= hyper_modifier;
6043       if (flags & NSEventModifierFlagShift)
6044         emacs_event->modifiers |= shift_modifier;
6046       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
6047       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
6048         || (! is_right_key && (flags & NSEventModifierFlagCommand) == NSEventModifierFlagCommand);
6050       if (is_right_key)
6051         emacs_event->modifiers |= parse_solitary_modifier
6052           (EQ (ns_right_command_modifier, Qleft)
6053            ? ns_command_modifier
6054            : ns_right_command_modifier);
6056       if (is_left_key)
6057         {
6058           emacs_event->modifiers |= parse_solitary_modifier
6059             (ns_command_modifier);
6061           /* if super (default), take input manager's word so things like
6062              dvorak / qwerty layout work */
6063           if (EQ (ns_command_modifier, Qsuper)
6064               && !fnKeysym
6065               && [[theEvent characters] length] != 0)
6066             {
6067               /* XXX: the code we get will be unshifted, so if we have
6068                  a shift modifier, must convert ourselves */
6069               if (!(flags & NSEventModifierFlagShift))
6070                 code = [[theEvent characters] characterAtIndex: 0];
6071 #if 0
6072               /* this is ugly and also requires linking w/Carbon framework
6073                  (for LMGetKbdType) so for now leave this rare (?) case
6074                  undealt with.. in future look into CGEvent methods */
6075               else
6076                 {
6077                   long smv = GetScriptManagerVariable (smKeyScript);
6078                   Handle uchrHandle = GetResource
6079                     ('uchr', GetScriptVariable (smv, smScriptKeys));
6080                   UInt32 dummy = 0;
6081                   UCKeyTranslate ((UCKeyboardLayout *) *uchrHandle,
6082                                  [[theEvent characters] characterAtIndex: 0],
6083                                  kUCKeyActionDisplay,
6084                                  (flags & ~NSEventModifierFlagCommand) >> 8,
6085                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
6086                                  &dummy, 1, &dummy, &code);
6087                   code &= 0xFF;
6088                 }
6089 #endif
6090             }
6091         }
6093       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
6094       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
6095         || (! is_right_key && (flags & NSEventModifierFlagControl) == NSEventModifierFlagControl);
6097       if (is_right_key)
6098           emacs_event->modifiers |= parse_solitary_modifier
6099               (EQ (ns_right_control_modifier, Qleft)
6100                ? ns_control_modifier
6101                : ns_right_control_modifier);
6103       if (is_left_key)
6104         emacs_event->modifiers |= parse_solitary_modifier
6105           (ns_control_modifier);
6107       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
6108           emacs_event->modifiers |=
6109             parse_solitary_modifier (ns_function_modifier);
6111       left_is_none = NILP (ns_alternate_modifier)
6112         || EQ (ns_alternate_modifier, Qnone);
6114       is_right_key = (flags & NSRightAlternateKeyMask)
6115         == NSRightAlternateKeyMask;
6116       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
6117         || (! is_right_key
6118             && (flags & NSEventModifierFlagOption) == NSEventModifierFlagOption);
6120       if (is_right_key)
6121         {
6122           if ((NILP (ns_right_alternate_modifier)
6123                || EQ (ns_right_alternate_modifier, Qnone)
6124                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
6125               && !fnKeysym)
6126             {   /* accept pre-interp alt comb */
6127               if ([[theEvent characters] length] > 0)
6128                 code = [[theEvent characters] characterAtIndex: 0];
6129               /*HACK: clear lone shift modifier to stop next if from firing */
6130               if (emacs_event->modifiers == shift_modifier)
6131                 emacs_event->modifiers = 0;
6132             }
6133           else
6134             emacs_event->modifiers |= parse_solitary_modifier
6135               (EQ (ns_right_alternate_modifier, Qleft)
6136                ? ns_alternate_modifier
6137                : ns_right_alternate_modifier);
6138         }
6140       if (is_left_key) /* default = meta */
6141         {
6142           if (left_is_none && !fnKeysym)
6143             {   /* accept pre-interp alt comb */
6144               if ([[theEvent characters] length] > 0)
6145                 code = [[theEvent characters] characterAtIndex: 0];
6146               /*HACK: clear lone shift modifier to stop next if from firing */
6147               if (emacs_event->modifiers == shift_modifier)
6148                 emacs_event->modifiers = 0;
6149             }
6150           else
6151               emacs_event->modifiers |=
6152                 parse_solitary_modifier (ns_alternate_modifier);
6153         }
6155   if (NS_KEYLOG)
6156     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
6157              (unsigned) code, fnKeysym, flags, emacs_event->modifiers);
6159       /* if it was a function key or had modifiers, pass it directly to emacs */
6160       if (fnKeysym || (emacs_event->modifiers
6161                        && (emacs_event->modifiers != shift_modifier)
6162                        && [[theEvent charactersIgnoringModifiers] length] > 0))
6163 /*[[theEvent characters] length] */
6164         {
6165           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6166           if (code < 0x20)
6167             code |= (1<<28)|(3<<16);
6168           else if (code == 0x7f)
6169             code |= (1<<28)|(3<<16);
6170           else if (!fnKeysym)
6171             emacs_event->kind = code > 0xFF
6172               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6174           emacs_event->code = code;
6175           EV_TRAILER (theEvent);
6176           processingCompose = NO;
6177           return;
6178         }
6179     }
6182   if (NS_KEYLOG && !processingCompose)
6183     fprintf (stderr, "keyDown: Begin compose sequence.\n");
6185   processingCompose = YES;
6186   [nsEvArray addObject: theEvent];
6187   [self interpretKeyEvents: nsEvArray];
6188   [nsEvArray removeObject: theEvent];
6192 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6195 /* <NSTextInput>: called when done composing;
6196    NOTE: also called when we delete over working text, followed immed.
6197          by doCommandBySelector: deleteBackward: */
6198 - (void)insertText: (id)aString
6200   int code;
6201   int len = [(NSString *)aString length];
6202   int i;
6204   NSTRACE ("[EmacsView insertText:]");
6206   if (NS_KEYLOG)
6207     NSLog (@"insertText '%@'\tlen = %d", aString, len);
6208   processingCompose = NO;
6210   if (!emacs_event)
6211     return;
6213   /* first, clear any working text */
6214   if (workingText != nil)
6215     [self deleteWorkingText];
6217   /* now insert the string as keystrokes */
6218   for (i =0; i<len; i++)
6219     {
6220       code = [aString characterAtIndex: i];
6221       /* TODO: still need this? */
6222       if (code == 0x2DC)
6223         code = '~'; /* 0x7E */
6224       if (code != 32) /* Space */
6225         emacs_event->modifiers = 0;
6226       emacs_event->kind
6227         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6228       emacs_event->code = code;
6229       EV_TRAILER ((id)nil);
6230     }
6234 /* <NSTextInput>: inserts display of composing characters */
6235 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6237   NSString *str = [aString respondsToSelector: @selector (string)] ?
6238     [aString string] : aString;
6240   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6242   if (NS_KEYLOG)
6243     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6244            str, (unsigned long)[str length],
6245            (unsigned long)selRange.length,
6246            (unsigned long)selRange.location);
6248   if (workingText != nil)
6249     [self deleteWorkingText];
6250   if ([str length] == 0)
6251     return;
6253   if (!emacs_event)
6254     return;
6256   processingCompose = YES;
6257   workingText = [str copy];
6258   ns_working_text = build_string ([workingText UTF8String]);
6260   emacs_event->kind = NS_TEXT_EVENT;
6261   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6262   EV_TRAILER ((id)nil);
6266 /* delete display of composing characters [not in <NSTextInput>] */
6267 - (void)deleteWorkingText
6269   NSTRACE ("[EmacsView deleteWorkingText]");
6271   if (workingText == nil)
6272     return;
6273   if (NS_KEYLOG)
6274     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6275   [workingText release];
6276   workingText = nil;
6277   processingCompose = NO;
6279   if (!emacs_event)
6280     return;
6282   emacs_event->kind = NS_TEXT_EVENT;
6283   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6284   EV_TRAILER ((id)nil);
6288 - (BOOL)hasMarkedText
6290   NSTRACE ("[EmacsView hasMarkedText]");
6292   return workingText != nil;
6296 - (NSRange)markedRange
6298   NSTRACE ("[EmacsView markedRange]");
6300   NSRange rng = workingText != nil
6301     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6302   if (NS_KEYLOG)
6303     NSLog (@"markedRange request");
6304   return rng;
6308 - (void)unmarkText
6310   NSTRACE ("[EmacsView unmarkText]");
6312   if (NS_KEYLOG)
6313     NSLog (@"unmark (accept) text");
6314   [self deleteWorkingText];
6315   processingCompose = NO;
6319 /* used to position char selection windows, etc. */
6320 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6322   NSRect rect;
6323   NSPoint pt;
6324   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6326   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6328   if (NS_KEYLOG)
6329     NSLog (@"firstRectForCharRange request");
6331   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6332   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6333   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6334   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6335                                        +FRAME_LINE_HEIGHT (emacsframe));
6337   pt = [self convertPoint: pt toView: nil];
6339 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
6340 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6341   if ([[self window] respondsToSelector: @selector(convertRectToScreen:)])
6342     {
6343 #endif
6344       rect.origin = pt;
6345       rect = [(EmacsWindow *) [self window] convertRectToScreen: rect];
6346 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
6347     }
6348   else
6349 #endif
6350 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
6351 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
6352   || defined (NS_IMPL_GNUSTEP)
6353     {
6354       pt = [[self window] convertBaseToScreen: pt];
6355       rect.origin = pt;
6356     }
6357 #endif
6359   return rect;
6363 - (NSInteger)conversationIdentifier
6365   return (NSInteger)self;
6369 - (void)doCommandBySelector: (SEL)aSelector
6371   NSTRACE ("[EmacsView doCommandBySelector:]");
6373   if (NS_KEYLOG)
6374     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6376   processingCompose = NO;
6377   if (aSelector == @selector (deleteBackward:))
6378     {
6379       /* happens when user backspaces over an ongoing composition:
6380          throw a 'delete' into the event queue */
6381       if (!emacs_event)
6382         return;
6383       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6384       emacs_event->code = 0xFF08;
6385       EV_TRAILER ((id)nil);
6386     }
6389 - (NSArray *)validAttributesForMarkedText
6391   static NSArray *arr = nil;
6392   if (arr == nil) arr = [NSArray new];
6393  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6394   return arr;
6397 - (NSRange)selectedRange
6399   if (NS_KEYLOG)
6400     NSLog (@"selectedRange request");
6401   return NSMakeRange (NSNotFound, 0);
6404 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6405     GNUSTEP_GUI_MINOR_VERSION > 22
6406 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6407 #else
6408 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6409 #endif
6411   if (NS_KEYLOG)
6412     NSLog (@"characterIndexForPoint request");
6413   return 0;
6416 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6418   static NSAttributedString *str = nil;
6419   if (str == nil) str = [NSAttributedString new];
6420   if (NS_KEYLOG)
6421     NSLog (@"attributedSubstringFromRange request");
6422   return str;
6425 /* End <NSTextInput> impl. */
6426 /*****************************************************************************/
6429 /* This is what happens when the user presses a mouse button.  */
6430 - (void)mouseDown: (NSEvent *)theEvent
6432   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6433   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6435   NSTRACE ("[EmacsView mouseDown:]");
6437   [self deleteWorkingText];
6439   if (!emacs_event)
6440     return;
6442   dpyinfo->last_mouse_frame = emacsframe;
6443   /* appears to be needed to prevent spurious movement events generated on
6444      button clicks */
6445   emacsframe->mouse_moved = 0;
6447   if ([theEvent type] == NSEventTypeScrollWheel)
6448     {
6449       CGFloat delta = [theEvent deltaY];
6450       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6451       if (delta == 0)
6452         {
6453           delta = [theEvent deltaX];
6454           if (delta == 0)
6455             {
6456               NSTRACE_MSG ("deltaIsZero");
6457               return;
6458             }
6459           emacs_event->kind = HORIZ_WHEEL_EVENT;
6460         }
6461       else
6462         emacs_event->kind = WHEEL_EVENT;
6464       emacs_event->code = 0;
6465       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6466         ((delta > 0) ? up_modifier : down_modifier);
6467     }
6468   else
6469     {
6470       emacs_event->kind = MOUSE_CLICK_EVENT;
6471       emacs_event->code = EV_BUTTON (theEvent);
6472       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6473                              | EV_UDMODIFIERS (theEvent);
6474     }
6475   XSETINT (emacs_event->x, lrint (p.x));
6476   XSETINT (emacs_event->y, lrint (p.y));
6477   EV_TRAILER (theEvent);
6481 - (void)rightMouseDown: (NSEvent *)theEvent
6483   NSTRACE ("[EmacsView rightMouseDown:]");
6484   [self mouseDown: theEvent];
6488 - (void)otherMouseDown: (NSEvent *)theEvent
6490   NSTRACE ("[EmacsView otherMouseDown:]");
6491   [self mouseDown: theEvent];
6495 - (void)mouseUp: (NSEvent *)theEvent
6497   NSTRACE ("[EmacsView mouseUp:]");
6498   [self mouseDown: theEvent];
6502 - (void)rightMouseUp: (NSEvent *)theEvent
6504   NSTRACE ("[EmacsView rightMouseUp:]");
6505   [self mouseDown: theEvent];
6509 - (void)otherMouseUp: (NSEvent *)theEvent
6511   NSTRACE ("[EmacsView otherMouseUp:]");
6512   [self mouseDown: theEvent];
6516 - (void) scrollWheel: (NSEvent *)theEvent
6518   NSTRACE ("[EmacsView scrollWheel:]");
6519   [self mouseDown: theEvent];
6523 /* Tell emacs the mouse has moved. */
6524 - (void)mouseMoved: (NSEvent *)e
6526   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6527   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6528   Lisp_Object frame;
6529   NSPoint pt;
6531   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6533   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6534   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6535   dpyinfo->last_mouse_motion_x = pt.x;
6536   dpyinfo->last_mouse_motion_y = pt.y;
6538   /* update any mouse face */
6539   if (hlinfo->mouse_face_hidden)
6540     {
6541       hlinfo->mouse_face_hidden = 0;
6542       clear_mouse_face (hlinfo);
6543     }
6545   /* tooltip handling */
6546   previous_help_echo_string = help_echo_string;
6547   help_echo_string = Qnil;
6549   if (!NILP (Vmouse_autoselect_window))
6550     {
6551       NSTRACE_MSG ("mouse_autoselect_window");
6552       static Lisp_Object last_mouse_window;
6553       Lisp_Object window
6554         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6556       if (WINDOWP (window)
6557           && !EQ (window, last_mouse_window)
6558           && !EQ (window, selected_window)
6559           && (!NILP (focus_follows_mouse)
6560               || (EQ (XWINDOW (window)->frame,
6561                       XWINDOW (selected_window)->frame))))
6562         {
6563           NSTRACE_MSG ("in_window");
6564           emacs_event->kind = SELECT_WINDOW_EVENT;
6565           emacs_event->frame_or_window = window;
6566           EV_TRAILER2 (e);
6567         }
6568       /* Remember the last window where we saw the mouse.  */
6569       last_mouse_window = window;
6570     }
6572   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6573     help_echo_string = previous_help_echo_string;
6575   XSETFRAME (frame, emacsframe);
6576   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6577     {
6578       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6579          (note_mouse_highlight), which is called through the
6580          note_mouse_movement () call above */
6581       any_help_event_p = YES;
6582       gen_help_event (help_echo_string, frame, help_echo_window,
6583                       help_echo_object, help_echo_pos);
6584     }
6586   if (emacsframe->mouse_moved && send_appdefined)
6587     ns_send_appdefined (-1);
6591 - (void)mouseDragged: (NSEvent *)e
6593   NSTRACE ("[EmacsView mouseDragged:]");
6594   [self mouseMoved: e];
6598 - (void)rightMouseDragged: (NSEvent *)e
6600   NSTRACE ("[EmacsView rightMouseDragged:]");
6601   [self mouseMoved: e];
6605 - (void)otherMouseDragged: (NSEvent *)e
6607   NSTRACE ("[EmacsView otherMouseDragged:]");
6608   [self mouseMoved: e];
6612 - (BOOL)windowShouldClose: (id)sender
6614   NSEvent *e =[[self window] currentEvent];
6616   NSTRACE ("[EmacsView windowShouldClose:]");
6617   windowClosing = YES;
6618   if (!emacs_event)
6619     return NO;
6620   emacs_event->kind = DELETE_WINDOW_EVENT;
6621   emacs_event->modifiers = 0;
6622   emacs_event->code = 0;
6623   EV_TRAILER (e);
6624   /* Don't close this window, let this be done from lisp code.  */
6625   return NO;
6628 - (void) updateFrameSize: (BOOL) delay
6630   NSWindow *window = [self window];
6631   NSRect wr = [window frame];
6632   int extra = 0;
6633   int oldc = cols, oldr = rows;
6634   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6635   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6636   int neww, newh;
6638   NSTRACE ("[EmacsView updateFrameSize:]");
6639   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6640   NSTRACE_RECT ("Original frame", wr);
6641   NSTRACE_MSG  ("Original columns: %d", cols);
6642   NSTRACE_MSG  ("Original rows: %d", rows);
6644   if (! [self isFullscreen])
6645     {
6646 #ifdef NS_IMPL_GNUSTEP
6647       // GNUstep does not always update the tool bar height.  Force it.
6648       if (toolbar && [toolbar isVisible])
6649           update_frame_tool_bar (emacsframe);
6650 #endif
6652       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6653         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6654     }
6656   if (wait_for_tool_bar)
6657     {
6658       /* The toolbar height is always 0 in fullscreen, so don't wait
6659          for it to become available. */
6660       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0
6661           && ! [self isFullscreen])
6662         {
6663           NSTRACE_MSG ("Waiting for toolbar");
6664           return;
6665         }
6666       wait_for_tool_bar = NO;
6667     }
6669   neww = (int)wr.size.width - emacsframe->border_width;
6670   newh = (int)wr.size.height - extra;
6672   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6673   NSTRACE_MSG ("FRAME_TOOLBAR_HEIGHT: %d", FRAME_TOOLBAR_HEIGHT (emacsframe));
6674   NSTRACE_MSG ("FRAME_NS_TITLEBAR_HEIGHT: %d", FRAME_NS_TITLEBAR_HEIGHT (emacsframe));
6676   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6677   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6679   if (cols < MINWIDTH)
6680     cols = MINWIDTH;
6682   if (rows < MINHEIGHT)
6683     rows = MINHEIGHT;
6685   NSTRACE_MSG ("New columns: %d", cols);
6686   NSTRACE_MSG ("New rows: %d", rows);
6688   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6689     {
6690       NSView *view = FRAME_NS_VIEW (emacsframe);
6692       change_frame_size (emacsframe,
6693                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6694                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6695                          0, delay, 0, 1);
6696       SET_FRAME_GARBAGED (emacsframe);
6697       cancel_mouse_face (emacsframe);
6699       /* The next two lines appear to be setting the frame to the same
6700          size as it already is.  Why are they there? */
6701       // wr = NSMakeRect (0, 0, neww, newh);
6703       // [view setFrame: wr];
6705       // to do: consider using [NSNotificationCenter postNotificationName:].
6706       [self windowDidMove: // Update top/left.
6707               [NSNotification notificationWithName:NSWindowDidMoveNotification
6708                                             object:[view window]]];
6709     }
6710   else
6711     {
6712       NSTRACE_MSG ("No change");
6713     }
6716 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6717 /* normalize frame to gridded text size */
6719   int extra = 0;
6721   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6722            NSTRACE_ARG_SIZE (frameSize));
6723   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6724   NSTRACE_FSTYPE ("fs_state", fs_state);
6726   if (fs_state == FULLSCREEN_MAXIMIZED
6727       && (maximized_width != (int)frameSize.width
6728           || maximized_height != (int)frameSize.height))
6729     [self setFSValue: FULLSCREEN_NONE];
6730   else if (fs_state == FULLSCREEN_WIDTH
6731            && maximized_width != (int)frameSize.width)
6732     [self setFSValue: FULLSCREEN_NONE];
6733   else if (fs_state == FULLSCREEN_HEIGHT
6734            && maximized_height != (int)frameSize.height)
6735     [self setFSValue: FULLSCREEN_NONE];
6737   if (fs_state == FULLSCREEN_NONE)
6738     maximized_width = maximized_height = -1;
6740   if (! [self isFullscreen])
6741     {
6742       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6743         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6744     }
6746   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6747   if (cols < MINWIDTH)
6748     cols = MINWIDTH;
6750   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6751                                            frameSize.height - extra);
6752   if (rows < MINHEIGHT)
6753     rows = MINHEIGHT;
6754 #ifdef NS_IMPL_COCOA
6755   {
6756     /* this sets window title to have size in it; the wm does this under GS */
6757     NSRect r = [[self window] frame];
6758     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6759       {
6760         if (old_title != 0)
6761           {
6762             xfree (old_title);
6763             old_title = 0;
6764           }
6765       }
6766     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize
6767              && [[self window] title] != NULL)
6768       {
6769         char *size_title;
6770         NSWindow *window = [self window];
6771         if (old_title == 0)
6772           {
6773             char *t = strdup ([[[self window] title] UTF8String]);
6774             char *pos = strstr (t, "  â€”  ");
6775             if (pos)
6776               *pos = '\0';
6777             old_title = t;
6778           }
6779         size_title = xmalloc (strlen (old_title) + 40);
6780         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6781         [window setTitle: [NSString stringWithUTF8String: size_title]];
6782         [window display];
6783         xfree (size_title);
6784       }
6785   }
6786 #endif /* NS_IMPL_COCOA */
6788   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6790   /* Restrict the new size to the text gird.
6792      Don't restrict the width if the user only adjusted the height, and
6793      vice versa.  (Without this, the frame would shrink, and move
6794      slightly, if the window was resized by dragging one of its
6795      borders.) */
6796   if (!frame_resize_pixelwise)
6797     {
6798       NSRect r = [[self window] frame];
6800       if (r.size.width != frameSize.width)
6801         {
6802           frameSize.width =
6803             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6804         }
6806       if (r.size.height != frameSize.height)
6807         {
6808           frameSize.height =
6809             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6810         }
6811     }
6813   NSTRACE_RETURN_SIZE (frameSize);
6815   return frameSize;
6819 - (void)windowDidResize: (NSNotification *)notification
6821   NSTRACE ("[EmacsView windowDidResize:]");
6822   if (!FRAME_LIVE_P (emacsframe))
6823     {
6824       NSTRACE_MSG ("Ignored (frame dead)");
6825       return;
6826     }
6827   if (emacsframe->output_data.ns->in_animation)
6828     {
6829       NSTRACE_MSG ("Ignored (in animation)");
6830       return;
6831     }
6833   if (! [self fsIsNative])
6834     {
6835       NSWindow *theWindow = [notification object];
6836       /* We can get notification on the non-FS window when in
6837          fullscreen mode.  */
6838       if ([self window] != theWindow) return;
6839     }
6841   NSTRACE_RECT ("frame", [[notification object] frame]);
6843 #ifdef NS_IMPL_GNUSTEP
6844   NSWindow *theWindow = [notification object];
6846    /* In GNUstep, at least currently, it's possible to get a didResize
6847       without getting a willResize.. therefore we need to act as if we got
6848       the willResize now */
6849   NSSize sz = [theWindow frame].size;
6850   sz = [self windowWillResize: theWindow toSize: sz];
6851 #endif /* NS_IMPL_GNUSTEP */
6853   if (cols > 0 && rows > 0)
6854     {
6855       [self updateFrameSize: YES];
6856     }
6858   ns_send_appdefined (-1);
6861 #ifdef NS_IMPL_COCOA
6862 - (void)viewDidEndLiveResize
6864   NSTRACE ("[EmacsView viewDidEndLiveResize]");
6866   [super viewDidEndLiveResize];
6867   if (old_title != 0)
6868     {
6869       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6870       xfree (old_title);
6871       old_title = 0;
6872     }
6873   maximizing_resize = NO;
6875 #endif /* NS_IMPL_COCOA */
6878 - (void)windowDidBecomeKey: (NSNotification *)notification
6879 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6881   [self windowDidBecomeKey];
6885 - (void)windowDidBecomeKey      /* for direct calls */
6887   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6888   struct frame *old_focus = dpyinfo->x_focus_frame;
6890   NSTRACE ("[EmacsView windowDidBecomeKey]");
6892   if (emacsframe != old_focus)
6893     dpyinfo->x_focus_frame = emacsframe;
6895   ns_frame_rehighlight (emacsframe);
6897   if (emacs_event)
6898     {
6899       emacs_event->kind = FOCUS_IN_EVENT;
6900       EV_TRAILER ((id)nil);
6901     }
6905 - (void)windowDidResignKey: (NSNotification *)notification
6906 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6908   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6909   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6910   NSTRACE ("[EmacsView windowDidResignKey:]");
6912   if (is_focus_frame)
6913     dpyinfo->x_focus_frame = 0;
6915   emacsframe->mouse_moved = 0;
6916   ns_frame_rehighlight (emacsframe);
6918   /* FIXME: for some reason needed on second and subsequent clicks away
6919             from sole-frame Emacs to get hollow box to show */
6920   if (!windowClosing && [[self window] isVisible] == YES)
6921     {
6922       x_update_cursor (emacsframe, 1);
6923       x_set_frame_alpha (emacsframe);
6924     }
6926   if (any_help_event_p)
6927     {
6928       Lisp_Object frame;
6929       XSETFRAME (frame, emacsframe);
6930       help_echo_string = Qnil;
6931       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6932     }
6934   if (emacs_event && is_focus_frame)
6935     {
6936       [self deleteWorkingText];
6937       emacs_event->kind = FOCUS_OUT_EVENT;
6938       EV_TRAILER ((id)nil);
6939     }
6943 - (void)windowWillMiniaturize: sender
6945   NSTRACE ("[EmacsView windowWillMiniaturize:]");
6949 - (void)setFrame:(NSRect)frameRect
6951   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6952            NSTRACE_ARG_RECT (frameRect));
6954   [super setFrame:(NSRect)frameRect];
6958 - (BOOL)isFlipped
6960   return YES;
6964 - (BOOL)isOpaque
6966   return NO;
6970 - (void)createToolbar: (struct frame *)f
6972   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
6973   NSWindow *window = [view window];
6975   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6976                    [NSString stringWithFormat: @"Emacs Frame %d",
6977                              ns_window_num]];
6978   [toolbar setVisible: NO];
6979   [window setToolbar: toolbar];
6981   /* Don't set frame garbaged until tool bar is up to date?
6982      This avoids an extra clear and redraw (flicker) at frame creation.  */
6983   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6984   else wait_for_tool_bar = NO;
6987 #ifdef NS_IMPL_COCOA
6988   {
6989     NSButton *toggleButton;
6990     toggleButton = [window standardWindowButton: NSWindowToolbarButton];
6991     [toggleButton setTarget: self];
6992     [toggleButton setAction: @selector (toggleToolbar: )];
6993   }
6994 #endif
6998 - (instancetype) initFrameFromEmacs: (struct frame *)f
7000   NSRect r, wr;
7001   Lisp_Object tem;
7002   NSWindow *win;
7003   NSColor *col;
7004   NSString *name;
7006   NSTRACE ("[EmacsView initFrameFromEmacs:]");
7007   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
7009   windowClosing = NO;
7010   processingCompose = NO;
7011   scrollbarsNeedingUpdate = 0;
7012   fs_state = FULLSCREEN_NONE;
7013   fs_before_fs = next_maximized = -1;
7015   fs_is_native = NO;
7016 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7017 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7018   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7019 #endif
7020     fs_is_native = ns_use_native_fullscreen;
7021 #endif
7023   maximized_width = maximized_height = -1;
7024   nonfs_window = nil;
7026   ns_userRect = NSMakeRect (0, 0, 0, 0);
7027   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
7028                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
7029   [self initWithFrame: r];
7030   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
7032   FRAME_NS_VIEW (f) = self;
7033   emacsframe = f;
7034 #ifdef NS_IMPL_COCOA
7035   old_title = 0;
7036   maximizing_resize = NO;
7037 #endif
7039   win = [[EmacsWindow alloc]
7040             initWithContentRect: r
7041                       styleMask: (FRAME_UNDECORATED (f)
7042                                   ? FRAME_UNDECORATED_FLAGS
7043                                   : FRAME_DECORATED_FLAGS
7044 #ifdef NS_IMPL_COCOA
7045                                   | NSWindowStyleMaskResizable
7046                                   | NSWindowStyleMaskMiniaturizable
7047                                   | NSWindowStyleMaskClosable
7048 #endif
7049                                   )
7050                         backing: NSBackingStoreBuffered
7051                           defer: YES];
7053 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7054 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7055   if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7056 #endif
7057     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
7058 #endif
7060   wr = [win frame];
7061   bwidth = f->border_width = wr.size.width - r.size.width;
7063   [win setAcceptsMouseMovedEvents: YES];
7064   [win setDelegate: self];
7065 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7066 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7067   if ([win respondsToSelector: @selector(useOptimizedDrawing:)])
7068 #endif
7069     [win useOptimizedDrawing: YES];
7070 #endif
7072   [[win contentView] addSubview: self];
7074   if (ns_drag_types)
7075     [self registerForDraggedTypes: ns_drag_types];
7077   tem = f->name;
7078   name = [NSString stringWithUTF8String:
7079                    NILP (tem) ? "Emacs" : SSDATA (tem)];
7080   [win setTitle: name];
7082   /* toolbar support */
7083   if (! FRAME_UNDECORATED (f))
7084     [self createToolbar: f];
7086   tem = f->icon_name;
7087   if (!NILP (tem))
7088     [win setMiniwindowTitle:
7089            [NSString stringWithUTF8String: SSDATA (tem)]];
7091   if (FRAME_PARENT_FRAME (f) != NULL)
7092     {
7093       NSWindow *parent = [FRAME_NS_VIEW (FRAME_PARENT_FRAME (f)) window];
7094       [parent addChildWindow: win
7095                      ordered: NSWindowAbove];
7096     }
7098   if (FRAME_Z_GROUP (f) != z_group_none)
7099       win.level = NSNormalWindowLevel
7100         + (FRAME_Z_GROUP_BELOW (f) ? -1 : 1);
7102   {
7103     NSScreen *screen = [win screen];
7105     if (screen != 0)
7106       {
7107         NSPoint pt = NSMakePoint
7108           (IN_BOUND (-SCREENMAX, f->left_pos
7109                      + NS_PARENT_WINDOW_LEFT_POS (f), SCREENMAX),
7110            IN_BOUND (-SCREENMAX,
7111                      NS_PARENT_WINDOW_TOP_POS (f) - f->top_pos,
7112                      SCREENMAX));
7114         [win setFrameTopLeftPoint: pt];
7116         NSTRACE_RECT ("new frame", [win frame]);
7117       }
7118   }
7120   [win makeFirstResponder: self];
7122   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7123                                  (FACE_FROM_ID (emacsframe, DEFAULT_FACE_ID)),
7124                                  emacsframe);
7125   [win setBackgroundColor: col];
7126   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7127     [win setOpaque: NO];
7129 #if !defined (NS_IMPL_COCOA) \
7130   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7131 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7132   if ([self respondsToSelector: @selector(allocateGState)])
7133 #endif
7134     [self allocateGState];
7135 #endif
7136   [NSApp registerServicesMenuSendTypes: ns_send_types
7137                            returnTypes: [NSArray array]];
7139   /* macOS Sierra automatically enables tabbed windows.  We can't
7140      allow this to be enabled until it's available on a Free system.
7141      Currently it only happens by accident and is buggy anyway. */
7142 #if defined (NS_IMPL_COCOA) \
7143   && MAC_OS_X_VERSION_MAX_ALLOWED >= 101200
7144 #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
7145   if ([win respondsToSelector: @selector(setTabbingMode:)])
7146 #endif
7147     [win setTabbingMode: NSWindowTabbingModeDisallowed];
7148 #endif
7150   ns_window_num++;
7151   return self;
7155 - (void)windowDidMove: sender
7157   NSWindow *win = [self window];
7158   NSRect r = [win frame];
7159   NSArray *screens = [NSScreen screens];
7160   NSScreen *screen = [screens objectAtIndex: 0];
7162   NSTRACE ("[EmacsView windowDidMove:]");
7164   if (!emacsframe->output_data.ns)
7165     return;
7166   if (screen != nil)
7167     {
7168       emacsframe->left_pos = r.origin.x - NS_PARENT_WINDOW_LEFT_POS (emacsframe);
7169       emacsframe->top_pos =
7170         NS_PARENT_WINDOW_TOP_POS (emacsframe) - (r.origin.y + r.size.height);
7172       if (emacs_event)
7173         {
7174           emacs_event->kind = MOVE_FRAME_EVENT;
7175           EV_TRAILER ((id)nil);
7176         }
7177     }
7181 /* Called AFTER method below, but before our windowWillResize call there leads
7182    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
7183    location so set_window_size moves the frame. */
7184 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
7186   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
7187             NSTRACE_FMT_RETURN "YES"),
7188            NSTRACE_ARG_RECT (newFrame));
7190   emacsframe->output_data.ns->zooming = 1;
7191   return YES;
7195 /* Override to do something slightly nonstandard, but nice.  First click on
7196    zoom button will zoom vertically.  Second will zoom completely.  Third
7197    returns to original. */
7198 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
7199                         defaultFrame:(NSRect)defaultFrame
7201   // TODO: Rename to "currentFrame" and assign "result" properly in
7202   // all paths.
7203   NSRect result = [sender frame];
7205   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
7206             NSTRACE_FMT_RECT "]"),
7207            NSTRACE_ARG_RECT (defaultFrame));
7208   NSTRACE_FSTYPE ("fs_state", fs_state);
7209   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
7210   NSTRACE_FSTYPE ("next_maximized", next_maximized);
7211   NSTRACE_RECT   ("ns_userRect", ns_userRect);
7212   NSTRACE_RECT   ("[sender frame]", [sender frame]);
7214   if (fs_before_fs != -1) /* Entering fullscreen */
7215     {
7216       NSTRACE_MSG ("Entering fullscreen");
7217       result = defaultFrame;
7218     }
7219   else
7220     {
7221       // Save the window size and position (frame) before the resize.
7222       if (fs_state != FULLSCREEN_MAXIMIZED
7223           && fs_state != FULLSCREEN_WIDTH)
7224         {
7225           ns_userRect.size.width = result.size.width;
7226           ns_userRect.origin.x   = result.origin.x;
7227         }
7229       if (fs_state != FULLSCREEN_MAXIMIZED
7230           && fs_state != FULLSCREEN_HEIGHT)
7231         {
7232           ns_userRect.size.height = result.size.height;
7233           ns_userRect.origin.y    = result.origin.y;
7234         }
7236       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7238       if (next_maximized == FULLSCREEN_HEIGHT
7239           || (next_maximized == -1
7240               && abs ((int)(defaultFrame.size.height - result.size.height))
7241               > FRAME_LINE_HEIGHT (emacsframe)))
7242         {
7243           /* first click */
7244           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7245           maximized_height = result.size.height = defaultFrame.size.height;
7246           maximized_width = -1;
7247           result.origin.y = defaultFrame.origin.y;
7248           if (ns_userRect.size.height != 0)
7249             {
7250               result.origin.x = ns_userRect.origin.x;
7251               result.size.width = ns_userRect.size.width;
7252             }
7253           [self setFSValue: FULLSCREEN_HEIGHT];
7254 #ifdef NS_IMPL_COCOA
7255           maximizing_resize = YES;
7256 #endif
7257         }
7258       else if (next_maximized == FULLSCREEN_WIDTH)
7259         {
7260           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7261           maximized_width = result.size.width = defaultFrame.size.width;
7262           maximized_height = -1;
7263           result.origin.x = defaultFrame.origin.x;
7264           if (ns_userRect.size.width != 0)
7265             {
7266               result.origin.y = ns_userRect.origin.y;
7267               result.size.height = ns_userRect.size.height;
7268             }
7269           [self setFSValue: FULLSCREEN_WIDTH];
7270         }
7271       else if (next_maximized == FULLSCREEN_MAXIMIZED
7272                || (next_maximized == -1
7273                    && abs ((int)(defaultFrame.size.width - result.size.width))
7274                    > FRAME_COLUMN_WIDTH (emacsframe)))
7275         {
7276           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7278           result = defaultFrame;  /* second click */
7279           maximized_width = result.size.width;
7280           maximized_height = result.size.height;
7281           [self setFSValue: FULLSCREEN_MAXIMIZED];
7282 #ifdef NS_IMPL_COCOA
7283           maximizing_resize = YES;
7284 #endif
7285         }
7286       else
7287         {
7288           /* restore */
7289           NSTRACE_MSG ("Restore");
7290           result = ns_userRect.size.height ? ns_userRect : result;
7291           NSTRACE_RECT ("restore (2)", result);
7292           ns_userRect = NSMakeRect (0, 0, 0, 0);
7293 #ifdef NS_IMPL_COCOA
7294           maximizing_resize = fs_state != FULLSCREEN_NONE;
7295 #endif
7296           [self setFSValue: FULLSCREEN_NONE];
7297           maximized_width = maximized_height = -1;
7298         }
7299     }
7301   if (fs_before_fs == -1) next_maximized = -1;
7303   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
7304   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
7305   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
7306   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7308   [self windowWillResize: sender toSize: result.size];
7310   NSTRACE_RETURN_RECT (result);
7312   return result;
7316 - (void)windowDidDeminiaturize: sender
7318   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7319   if (!emacsframe->output_data.ns)
7320     return;
7322   SET_FRAME_ICONIFIED (emacsframe, 0);
7323   SET_FRAME_VISIBLE (emacsframe, 1);
7324   windows_or_buffers_changed = 63;
7326   if (emacs_event)
7327     {
7328       emacs_event->kind = DEICONIFY_EVENT;
7329       EV_TRAILER ((id)nil);
7330     }
7334 - (void)windowDidExpose: sender
7336   NSTRACE ("[EmacsView windowDidExpose:]");
7337   if (!emacsframe->output_data.ns)
7338     return;
7340   SET_FRAME_VISIBLE (emacsframe, 1);
7341   SET_FRAME_GARBAGED (emacsframe);
7343   if (send_appdefined)
7344     ns_send_appdefined (-1);
7348 - (void)windowDidMiniaturize: sender
7350   NSTRACE ("[EmacsView windowDidMiniaturize:]");
7351   if (!emacsframe->output_data.ns)
7352     return;
7354   SET_FRAME_ICONIFIED (emacsframe, 1);
7355   SET_FRAME_VISIBLE (emacsframe, 0);
7357   if (emacs_event)
7358     {
7359       emacs_event->kind = ICONIFY_EVENT;
7360       EV_TRAILER ((id)nil);
7361     }
7364 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7365 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7366       willUseFullScreenPresentationOptions:
7367   (NSApplicationPresentationOptions)proposedOptions
7369   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7371 #endif
7373 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7375   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7376   [self windowWillEnterFullScreen];
7378 - (void)windowWillEnterFullScreen /* provided for direct calls */
7380   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7381   fs_before_fs = fs_state;
7384 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7386   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7387   [self windowDidEnterFullScreen];
7390 - (void)windowDidEnterFullScreen /* provided for direct calls */
7392   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7393   [self setFSValue: FULLSCREEN_BOTH];
7394   if (! [self fsIsNative])
7395     {
7396       [self windowDidBecomeKey];
7397       [nonfs_window orderOut:self];
7398     }
7399   else
7400     {
7401       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7402 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 \
7403   && MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
7404       unsigned val = (unsigned)[NSApp presentationOptions];
7406       // Mac OS X 10.7 bug fix, the menu won't appear without this.
7407       // val is non-zero on other macOS versions.
7408       if (val == 0)
7409         {
7410           NSApplicationPresentationOptions options
7411             = NSApplicationPresentationAutoHideDock
7412             | NSApplicationPresentationAutoHideMenuBar
7413             | NSApplicationPresentationFullScreen
7414             | NSApplicationPresentationAutoHideToolbar;
7416           [NSApp setPresentationOptions: options];
7417         }
7418 #endif
7419       [toolbar setVisible:tbar_visible];
7420     }
7423 - (void)windowWillExitFullScreen:(NSNotification *)notification
7425   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7426   [self windowWillExitFullScreen];
7429 - (void)windowWillExitFullScreen /* provided for direct calls */
7431   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7432   if (!FRAME_LIVE_P (emacsframe))
7433     {
7434       NSTRACE_MSG ("Ignored (frame dead)");
7435       return;
7436     }
7437   if (next_maximized != -1)
7438     fs_before_fs = next_maximized;
7441 - (void)windowDidExitFullScreen:(NSNotification *)notification
7443   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7444   [self windowDidExitFullScreen];
7447 - (void)windowDidExitFullScreen /* provided for direct calls */
7449   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7450   if (!FRAME_LIVE_P (emacsframe))
7451     {
7452       NSTRACE_MSG ("Ignored (frame dead)");
7453       return;
7454     }
7455   [self setFSValue: fs_before_fs];
7456   fs_before_fs = -1;
7457 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7458   [self updateCollectionBehavior];
7459 #endif
7460   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7461     {
7462       [toolbar setVisible:YES];
7463       update_frame_tool_bar (emacsframe);
7464       [self updateFrameSize:YES];
7465       [[self window] display];
7466     }
7467   else
7468     [toolbar setVisible:NO];
7470   if (next_maximized != -1)
7471     [[self window] performZoom:self];
7474 - (BOOL)fsIsNative
7476   return fs_is_native;
7479 - (BOOL)isFullscreen
7481   BOOL res;
7483   if (! fs_is_native)
7484     {
7485       res = (nonfs_window != nil);
7486     }
7487   else
7488     {
7489 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7490       res = (([[self window] styleMask] & NSWindowStyleMaskFullScreen) != 0);
7491 #else
7492       res = NO;
7493 #endif
7494     }
7496   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7497            (int) res);
7499   return res;
7502 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7503 - (void)updateCollectionBehavior
7505   NSTRACE ("[EmacsView updateCollectionBehavior]");
7507   if (! [self isFullscreen])
7508     {
7509       NSWindow *win = [self window];
7510       NSWindowCollectionBehavior b = [win collectionBehavior];
7511       if (ns_use_native_fullscreen)
7512         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7513       else
7514         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7516       [win setCollectionBehavior: b];
7517 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7518       if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_7)
7519 #endif
7520         fs_is_native = ns_use_native_fullscreen;
7521     }
7523 #endif
7525 - (void)toggleFullScreen: (id)sender
7527   NSWindow *w, *fw;
7528   BOOL onFirstScreen;
7529   struct frame *f;
7530   NSRect r, wr;
7531   NSColor *col;
7533   NSTRACE ("[EmacsView toggleFullScreen:]");
7535   if (fs_is_native)
7536     {
7537 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
7538 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
7539       if ([[self window] respondsToSelector: @selector(toggleFullScreen:)])
7540 #endif
7541         [[self window] toggleFullScreen:sender];
7542 #endif
7543       return;
7544     }
7546   w = [self window];
7547   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7548   f = emacsframe;
7549   wr = [w frame];
7550   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7551                                  (FACE_FROM_ID (f, DEFAULT_FACE_ID)),
7552                                  f);
7554   if (fs_state != FULLSCREEN_BOTH)
7555     {
7556       NSScreen *screen = [w screen];
7558 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
7559       /* Hide ghost menu bar on secondary monitor? */
7560       if (! onFirstScreen
7561 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
7562           && [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)]
7563 #endif
7564           )
7565         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7566 #endif
7567       /* Hide dock and menubar if we are on the primary screen.  */
7568       if (onFirstScreen)
7569         {
7570 #ifdef NS_IMPL_COCOA
7571           NSApplicationPresentationOptions options
7572             = NSApplicationPresentationAutoHideDock
7573             | NSApplicationPresentationAutoHideMenuBar;
7575           [NSApp setPresentationOptions: options];
7576 #else
7577           [NSMenu setMenuBarVisible:NO];
7578 #endif
7579         }
7581       fw = [[EmacsFSWindow alloc]
7582                        initWithContentRect:[w contentRectForFrameRect:wr]
7583                                  styleMask:NSWindowStyleMaskBorderless
7584                                    backing:NSBackingStoreBuffered
7585                                      defer:YES
7586                                     screen:screen];
7588       [fw setContentView:[w contentView]];
7589       [fw setTitle:[w title]];
7590       [fw setDelegate:self];
7591       [fw setAcceptsMouseMovedEvents: YES];
7592 #if !defined (NS_IMPL_COCOA) \
7593   || MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
7594 #if MAC_OS_X_VERSION_MAX_ALLOWED > 1090
7595       if ([fw respondsToSelector: @selector(useOptimizedDrawing:)])
7596 #endif
7597         [fw useOptimizedDrawing: YES];
7598 #endif
7599       [fw setBackgroundColor: col];
7600       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7601         [fw setOpaque: NO];
7603       f->border_width = 0;
7605       nonfs_window = w;
7607       [self windowWillEnterFullScreen];
7608       [fw makeKeyAndOrderFront:NSApp];
7609       [fw makeFirstResponder:self];
7610       [w orderOut:self];
7611       r = [fw frameRectForContentRect:[screen frame]];
7612       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7613       [self windowDidEnterFullScreen];
7614       [fw display];
7615     }
7616   else
7617     {
7618       fw = w;
7619       w = nonfs_window;
7620       nonfs_window = nil;
7622       if (onFirstScreen)
7623         {
7624 #ifdef NS_IMPL_COCOA
7625           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7626 #else
7627           [NSMenu setMenuBarVisible:YES];
7628 #endif
7629         }
7631       [w setContentView:[fw contentView]];
7632       [w setBackgroundColor: col];
7633       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7634         [w setOpaque: NO];
7636       f->border_width = bwidth;
7638       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7640       [self windowWillExitFullScreen];
7641       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7642       [fw close];
7643       [w makeKeyAndOrderFront:NSApp];
7644       [self windowDidExitFullScreen];
7645       [self updateFrameSize:YES];
7646     }
7649 - (void)handleFS
7651   NSTRACE ("[EmacsView handleFS]");
7653   if (fs_state != emacsframe->want_fullscreen)
7654     {
7655       if (fs_state == FULLSCREEN_BOTH)
7656         {
7657           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7658           [self toggleFullScreen:self];
7659         }
7661       switch (emacsframe->want_fullscreen)
7662         {
7663         case FULLSCREEN_BOTH:
7664           NSTRACE_MSG ("FULLSCREEN_BOTH");
7665           [self toggleFullScreen:self];
7666           break;
7667         case FULLSCREEN_WIDTH:
7668           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7669           next_maximized = FULLSCREEN_WIDTH;
7670           if (fs_state != FULLSCREEN_BOTH)
7671             [[self window] performZoom:self];
7672           break;
7673         case FULLSCREEN_HEIGHT:
7674           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7675           next_maximized = FULLSCREEN_HEIGHT;
7676           if (fs_state != FULLSCREEN_BOTH)
7677             [[self window] performZoom:self];
7678           break;
7679         case FULLSCREEN_MAXIMIZED:
7680           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7681           next_maximized = FULLSCREEN_MAXIMIZED;
7682           if (fs_state != FULLSCREEN_BOTH)
7683             [[self window] performZoom:self];
7684           break;
7685         case FULLSCREEN_NONE:
7686           NSTRACE_MSG ("FULLSCREEN_NONE");
7687           if (fs_state != FULLSCREEN_BOTH)
7688             {
7689               next_maximized = FULLSCREEN_NONE;
7690               [[self window] performZoom:self];
7691             }
7692           break;
7693         }
7695       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7696     }
7700 - (void) setFSValue: (int)value
7702   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7703            NSTRACE_ARG_FSTYPE(value));
7705   Lisp_Object lval = Qnil;
7706   switch (value)
7707     {
7708     case FULLSCREEN_BOTH:
7709       lval = Qfullboth;
7710       break;
7711     case FULLSCREEN_WIDTH:
7712       lval = Qfullwidth;
7713       break;
7714     case FULLSCREEN_HEIGHT:
7715       lval = Qfullheight;
7716       break;
7717     case FULLSCREEN_MAXIMIZED:
7718       lval = Qmaximized;
7719       break;
7720     }
7721   store_frame_param (emacsframe, Qfullscreen, lval);
7722   fs_state = value;
7725 - (void)mouseEntered: (NSEvent *)theEvent
7727   NSTRACE ("[EmacsView mouseEntered:]");
7728   if (emacsframe)
7729     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7730       = EV_TIMESTAMP (theEvent);
7734 - (void)mouseExited: (NSEvent *)theEvent
7736   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7738   NSTRACE ("[EmacsView mouseExited:]");
7740   if (!hlinfo)
7741     return;
7743   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7744     = EV_TIMESTAMP (theEvent);
7746   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7747     {
7748       clear_mouse_face (hlinfo);
7749       hlinfo->mouse_face_mouse_frame = 0;
7750     }
7754 - (instancetype)menuDown: sender
7756   NSTRACE ("[EmacsView menuDown:]");
7757   if (context_menu_value == -1)
7758     context_menu_value = [sender tag];
7759   else
7760     {
7761       NSInteger tag = [sender tag];
7762       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7763                                     emacsframe->menu_bar_vector,
7764                                     (void *)tag);
7765     }
7767   ns_send_appdefined (-1);
7768   return self;
7772 - (EmacsToolbar *)toolbar
7774   return toolbar;
7778 /* this gets called on toolbar button click */
7779 - (instancetype)toolbarClicked: (id)item
7781   NSEvent *theEvent;
7782   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7784   NSTRACE ("[EmacsView toolbarClicked:]");
7786   if (!emacs_event)
7787     return self;
7789   /* send first event (for some reason two needed) */
7790   theEvent = [[self window] currentEvent];
7791   emacs_event->kind = TOOL_BAR_EVENT;
7792   XSETFRAME (emacs_event->arg, emacsframe);
7793   EV_TRAILER (theEvent);
7795   emacs_event->kind = TOOL_BAR_EVENT;
7796 /*   XSETINT (emacs_event->code, 0); */
7797   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7798                            idx + TOOL_BAR_ITEM_KEY);
7799   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7800   EV_TRAILER (theEvent);
7801   return self;
7805 - (instancetype)toggleToolbar: (id)sender
7807   NSTRACE ("[EmacsView toggleToolbar:]");
7809   if (!emacs_event)
7810     return self;
7812   emacs_event->kind = NS_NONKEY_EVENT;
7813   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7814   EV_TRAILER ((id)nil);
7815   return self;
7819 - (void)drawRect: (NSRect)rect
7821   int x = NSMinX (rect), y = NSMinY (rect);
7822   int width = NSWidth (rect), height = NSHeight (rect);
7824   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7825            NSTRACE_ARG_RECT(rect));
7827   if (!emacsframe || !emacsframe->output_data.ns)
7828     return;
7830   ns_clear_frame_area (emacsframe, x, y, width, height);
7831   block_input ();
7832   expose_frame (emacsframe, x, y, width, height);
7833   unblock_input ();
7835   /*
7836     drawRect: may be called (at least in Mac OS X 10.5) for invisible
7837     views as well for some reason.  Thus, do not infer visibility
7838     here.
7840     emacsframe->async_visible = 1;
7841     emacsframe->async_iconified = 0;
7842   */
7846 /* NSDraggingDestination protocol methods.  Actually this is not really a
7847    protocol, but a category of Object.  O well...  */
7849 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7851   NSTRACE ("[EmacsView draggingEntered:]");
7852   return NSDragOperationGeneric;
7856 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7858   return YES;
7862 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7864   id pb;
7865   int x, y;
7866   NSString *type;
7867   NSEvent *theEvent = [[self window] currentEvent];
7868   NSPoint position;
7869   NSDragOperation op = [sender draggingSourceOperationMask];
7870   int modifiers = 0;
7872   NSTRACE ("[EmacsView performDragOperation:]");
7874   if (!emacs_event)
7875     return NO;
7877   position = [self convertPoint: [sender draggingLocation] fromView: nil];
7878   x = lrint (position.x);  y = lrint (position.y);
7880   pb = [sender draggingPasteboard];
7881   type = [pb availableTypeFromArray: ns_drag_types];
7883   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7884       // URL drags contain all operations (0xf), don't allow all to be set.
7885       (op & 0xf) != 0xf)
7886     {
7887       if (op & NSDragOperationLink)
7888         modifiers |= NSEventModifierFlagControl;
7889       if (op & NSDragOperationCopy)
7890         modifiers |= NSEventModifierFlagOption;
7891       if (op & NSDragOperationGeneric)
7892         modifiers |= NSEventModifierFlagCommand;
7893     }
7895   modifiers = EV_MODIFIERS2 (modifiers);
7896   if (type == 0)
7897     {
7898       return NO;
7899     }
7900   else if ([type isEqualToString: NSFilenamesPboardType])
7901     {
7902       NSArray *files;
7903       NSEnumerator *fenum;
7904       NSString *file;
7906       if (!(files = [pb propertyListForType: type]))
7907         return NO;
7909       fenum = [files objectEnumerator];
7910       while ( (file = [fenum nextObject]) )
7911         {
7912           emacs_event->kind = DRAG_N_DROP_EVENT;
7913           XSETINT (emacs_event->x, x);
7914           XSETINT (emacs_event->y, y);
7915           ns_input_file = append2 (ns_input_file,
7916                                    build_string ([file UTF8String]));
7917           emacs_event->modifiers = modifiers;
7918           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
7919           EV_TRAILER (theEvent);
7920         }
7921       return YES;
7922     }
7923   else if ([type isEqualToString: NSURLPboardType])
7924     {
7925       NSURL *url = [NSURL URLFromPasteboard: pb];
7926       if (url == nil) return NO;
7928       emacs_event->kind = DRAG_N_DROP_EVENT;
7929       XSETINT (emacs_event->x, x);
7930       XSETINT (emacs_event->y, y);
7931       emacs_event->modifiers = modifiers;
7932       emacs_event->arg =  list2 (Qurl,
7933                                  build_string ([[url absoluteString]
7934                                                  UTF8String]));
7935       EV_TRAILER (theEvent);
7937       if ([url isFileURL] != NO)
7938         {
7939           NSString *file = [url path];
7940           ns_input_file = append2 (ns_input_file,
7941                                    build_string ([file UTF8String]));
7942         }
7943       return YES;
7944     }
7945   else if ([type isEqualToString: NSStringPboardType]
7946            || [type isEqualToString: NSTabularTextPboardType])
7947     {
7948       NSString *data;
7950       if (! (data = [pb stringForType: type]))
7951         return NO;
7953       emacs_event->kind = DRAG_N_DROP_EVENT;
7954       XSETINT (emacs_event->x, x);
7955       XSETINT (emacs_event->y, y);
7956       emacs_event->modifiers = modifiers;
7957       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
7958       EV_TRAILER (theEvent);
7959       return YES;
7960     }
7961   else
7962     {
7963       fprintf (stderr, "Invalid data type in dragging pasteboard");
7964       return NO;
7965     }
7969 - (id) validRequestorForSendType: (NSString *)typeSent
7970                       returnType: (NSString *)typeReturned
7972   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7973   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7974       && typeReturned == nil)
7975     {
7976       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7977         return self;
7978     }
7980   return [super validRequestorForSendType: typeSent
7981                                returnType: typeReturned];
7985 /* The next two methods are part of NSServicesRequests informal protocol,
7986    supposedly called when a services menu item is chosen from this app.
7987    But this should not happen because we override the services menu with our
7988    own entries which call ns-perform-service.
7989    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7990    So let's at least stub them out until further investigation can be done. */
7992 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7994   /* we could call ns_string_from_pasteboard(pboard) here but then it should
7995      be written into the buffer in place of the existing selection..
7996      ordinary service calls go through functions defined in ns-win.el */
7997   return NO;
8000 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
8002   NSArray *typesDeclared;
8003   Lisp_Object val;
8005   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
8007   /* We only support NSStringPboardType */
8008   if ([types containsObject:NSStringPboardType] == NO) {
8009     return NO;
8010   }
8012   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8013   if (CONSP (val) && SYMBOLP (XCAR (val)))
8014     {
8015       val = XCDR (val);
8016       if (CONSP (val) && NILP (XCDR (val)))
8017         val = XCAR (val);
8018     }
8019   if (! STRINGP (val))
8020     return NO;
8022   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
8023   [pb declareTypes:typesDeclared owner:nil];
8024   ns_string_to_pasteboard (pb, val);
8025   return YES;
8029 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
8030    (gives a miniaturized version of the window); currently we use the latter for
8031    frames whose active buffer doesn't correspond to any file
8032    (e.g., '*scratch*') */
8033 - (instancetype)setMiniwindowImage: (BOOL) setMini
8035   id image = [[self window] miniwindowImage];
8036   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
8038   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
8039      about "AppleDockIconEnabled" notwithstanding, however the set message
8040      below has its effect nonetheless. */
8041   if (image != emacsframe->output_data.ns->miniimage)
8042     {
8043       if (image && [image isKindOfClass: [EmacsImage class]])
8044         [image release];
8045       [[self window] setMiniwindowImage:
8046                        setMini ? emacsframe->output_data.ns->miniimage : nil];
8047     }
8049   return self;
8053 - (void) setRows: (int) r andColumns: (int) c
8055   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
8056   rows = r;
8057   cols = c;
8060 - (int) fullscreenState
8062   return fs_state;
8065 @end  /* EmacsView */
8069 /* ==========================================================================
8071     EmacsWindow implementation
8073    ========================================================================== */
8075 @implementation EmacsWindow
8077 #ifdef NS_IMPL_COCOA
8078 - (id)accessibilityAttributeValue:(NSString *)attribute
8080   Lisp_Object str = Qnil;
8081   struct frame *f = SELECTED_FRAME ();
8082   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
8084   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
8086   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
8087     return NSAccessibilityTextFieldRole;
8089   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
8090       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
8091     {
8092       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8093     }
8094   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
8095     {
8096       if (! NILP (BVAR (curbuf, mark_active)))
8097           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
8099       if (NILP (str))
8100         {
8101           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
8102           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
8103           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
8105           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
8106             str = make_uninit_multibyte_string (range, byte_range);
8107           else
8108             str = make_uninit_string (range);
8109           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
8110              Is this a problem?  */
8111           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
8112         }
8113     }
8116   if (! NILP (str))
8117     {
8118       if (CONSP (str) && SYMBOLP (XCAR (str)))
8119         {
8120           str = XCDR (str);
8121           if (CONSP (str) && NILP (XCDR (str)))
8122             str = XCAR (str);
8123         }
8124       if (STRINGP (str))
8125         {
8126           const char *utfStr = SSDATA (str);
8127           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
8128           return nsStr;
8129         }
8130     }
8132   return [super accessibilityAttributeValue:attribute];
8134 #endif /* NS_IMPL_COCOA */
8136 /* Constrain size and placement of a frame.
8138    By returning the original "frameRect", the frame is not
8139    constrained. This can lead to unwanted situations where, for
8140    example, the menu bar covers the frame.
8142    The default implementation (accessed using "super") constrains the
8143    frame to the visible area of SCREEN, minus the menu bar (if
8144    present) and the Dock.  Note that default implementation also calls
8145    windowWillResize, with the frame it thinks should have.  (This can
8146    make the frame exit maximized mode.)
8148    Note that this should work in situations where multiple monitors
8149    are present.  Common configurations are side-by-side monitors and a
8150    monitor on top of another (e.g. when a laptop is placed under a
8151    large screen). */
8152 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
8154   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
8155              NSTRACE_ARG_RECT (frameRect));
8157 #ifdef NS_IMPL_COCOA
8158 #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
8159   // If separate spaces is on, it is like each screen is independent.  There is
8160   // no spanning of frames across screens.
8161   if (
8162 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
8163       [NSScreen respondsToSelector: @selector(screensHaveSeparateSpaces)] &&
8164 #endif
8165       [NSScreen screensHaveSeparateSpaces])
8166     {
8167       NSTRACE_MSG ("Screens have separate spaces");
8168       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8169       NSTRACE_RETURN_RECT (frameRect);
8170       return frameRect;
8171     }
8172   else
8173 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1090 */
8175     // Check that the proposed frameRect is visible in at least one
8176     // screen.  If it is not, ask the system to reposition it (only
8177     // for non-child windows).
8179     if (!FRAME_PARENT_FRAME (((EmacsView *)[self delegate])->emacsframe))
8180     {
8181       NSArray *screens = [NSScreen screens];
8182       NSUInteger nr_screens = [screens count];
8184       int i;
8185       BOOL frame_on_screen = NO;
8187       for (i = 0; i < nr_screens; ++i)
8188         {
8189           NSScreen *s = [screens objectAtIndex: i];
8190           NSRect scrRect = [s frame];
8192           if (NSIntersectsRect(frameRect, scrRect))
8193             {
8194               frame_on_screen = YES;
8195               break;
8196             }
8197         }
8199       if (!frame_on_screen)
8200         {
8201           NSTRACE_MSG ("Frame outside screens; constraining");
8202           frameRect = [super constrainFrameRect:frameRect toScreen:screen];
8203           NSTRACE_RETURN_RECT (frameRect);
8204           return frameRect;
8205         }
8206     }
8207 #endif
8209   return constrain_frame_rect(frameRect,
8210                               [(EmacsView *)[self delegate] isFullscreen]);
8214 - (void)performZoom:(id)sender
8216   NSTRACE ("[EmacsWindow performZoom:]");
8218   return [super performZoom:sender];
8221 - (void)zoom:(id)sender
8223   NSTRACE ("[EmacsWindow zoom:]");
8225   ns_update_auto_hide_menu_bar();
8227   // Below are three zoom implementations.  In the final commit, the
8228   // idea is that the last should be included.
8230 #if 0
8231   // Native zoom done using the standard zoom animation.  Size of the
8232   // resulting frame reduced to accommodate the Dock and, if present,
8233   // the menu-bar.
8234   [super zoom:sender];
8236 #elif 0
8237   // Native zoom done using the standard zoom animation, plus an
8238   // explicit resize to cover the full screen, except the menu-bar and
8239   // dock, if present.
8240   [super zoom:sender];
8242   // After the native zoom, resize the resulting frame to fill the
8243   // entire screen, except the menu-bar.
8244   //
8245   // This works for all practical purposes.  (The only minor oddity is
8246   // when transiting from full-height frame to a maximized, the
8247   // animation reduces the height of the frame slightly (to the 4
8248   // pixels needed to accommodate the Doc) before it snaps back into
8249   // full height.  The user would need a very trained eye to spot
8250   // this.)
8251   NSScreen * screen = [self screen];
8252   if (screen != nil)
8253     {
8254       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
8256       NSTRACE_FSTYPE ("fullscreenState", fs_state);
8258       NSRect sr = [screen frame];
8259       struct EmacsMargins margins
8260         = ns_screen_margins_ignoring_hidden_dock(screen);
8262       NSRect wr = [self frame];
8263       NSTRACE_RECT ("Rect after zoom", wr);
8265       NSRect newWr = wr;
8267       if (fs_state == FULLSCREEN_MAXIMIZED
8268           || fs_state == FULLSCREEN_HEIGHT)
8269         {
8270           newWr.origin.y = sr.origin.y + margins.bottom;
8271           newWr.size.height = sr.size.height - margins.top - margins.bottom;
8272         }
8274       if (fs_state == FULLSCREEN_MAXIMIZED
8275           || fs_state == FULLSCREEN_WIDTH)
8276         {
8277           newWr.origin.x = sr.origin.x + margins.left;
8278           newWr.size.width = sr.size.width - margins.right - margins.left;
8279         }
8281       if (newWr.size.width     != wr.size.width
8282           || newWr.size.height != wr.size.height
8283           || newWr.origin.x    != wr.origin.x
8284           || newWr.origin.y    != wr.origin.y)
8285         {
8286           NSTRACE_MSG ("New frame different");
8287           [self setFrame: newWr display: NO];
8288         }
8289     }
8290 #else
8291   // Non-native zoom which is done instantaneously.  The resulting
8292   // frame covers the entire screen, except the menu-bar and dock, if
8293   // present.
8294   NSScreen * screen = [self screen];
8295   if (screen != nil)
8296     {
8297       NSRect sr = [screen frame];
8298       struct EmacsMargins margins
8299         = ns_screen_margins_ignoring_hidden_dock(screen);
8301       sr.size.height -= (margins.top + margins.bottom);
8302       sr.size.width  -= (margins.left + margins.right);
8303       sr.origin.x += margins.left;
8304       sr.origin.y += margins.bottom;
8306       sr = [[self delegate] windowWillUseStandardFrame:self
8307                                           defaultFrame:sr];
8308       [self setFrame: sr display: NO];
8309     }
8310 #endif
8313 - (void)setFrame:(NSRect)windowFrame
8314          display:(BOOL)displayViews
8316   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8317            NSTRACE_ARG_RECT (windowFrame), displayViews);
8319   [super setFrame:windowFrame display:displayViews];
8322 - (void)setFrame:(NSRect)windowFrame
8323          display:(BOOL)displayViews
8324          animate:(BOOL)performAnimation
8326   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8327            " display:%d performAnimation:%d]",
8328            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8330   [super setFrame:windowFrame display:displayViews animate:performAnimation];
8333 - (void)setFrameTopLeftPoint:(NSPoint)point
8335   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8336            NSTRACE_ARG_POINT (point));
8338   [super setFrameTopLeftPoint:point];
8341 - (BOOL)canBecomeKeyWindow
8343   return !FRAME_NO_ACCEPT_FOCUS (((EmacsView *)[self delegate])->emacsframe);
8345 @end /* EmacsWindow */
8348 @implementation EmacsFSWindow
8350 - (BOOL)canBecomeKeyWindow
8352   return YES;
8355 - (BOOL)canBecomeMainWindow
8357   return YES;
8360 @end
8362 /* ==========================================================================
8364     EmacsScroller implementation
8366    ========================================================================== */
8369 @implementation EmacsScroller
8371 /* for repeat button push */
8372 #define SCROLL_BAR_FIRST_DELAY 0.5
8373 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8375 + (CGFloat) scrollerWidth
8377   /* TODO: if we want to allow variable widths, this is the place to do it,
8378            however neither GNUstep nor Cocoa support it very well */
8379   CGFloat r;
8380 #if defined (NS_IMPL_COCOA) \
8381   && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
8382 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8383   if ([NSScroller respondsToSelector:
8384                     @selector(scrollerWidthForControlSize:scrollerStyle:)])
8385 #endif
8386     r = [NSScroller scrollerWidthForControlSize: NSControlSizeRegular
8387                                   scrollerStyle: NSScrollerStyleLegacy];
8388 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
8389   else
8390 #endif
8391 #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
8392 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1070 \
8393   || defined (NS_IMPL_GNUSTEP)
8394     r = [NSScroller scrollerWidth];
8395 #endif
8396   return r;
8399 - (instancetype)initFrame: (NSRect )r window: (Lisp_Object)nwin
8401   NSTRACE ("[EmacsScroller initFrame: window:]");
8403   if (r.size.width > r.size.height)
8404       horizontal = YES;
8405   else
8406       horizontal = NO;
8408   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8409   [self setContinuous: YES];
8410   [self setEnabled: YES];
8412   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8413      locked against the top and bottom edges, and right edge on macOS, where
8414      scrollers are on right. */
8415 #ifdef NS_IMPL_GNUSTEP
8416   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8417 #else
8418   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8419 #endif
8421   window = XWINDOW (nwin);
8422   condemned = NO;
8423   if (horizontal)
8424     pixel_length = NSWidth (r);
8425   else
8426     pixel_length = NSHeight (r);
8427   if (pixel_length == 0) pixel_length = 1;
8428   min_portion = 20 / pixel_length;
8430   frame = XFRAME (window->frame);
8431   if (FRAME_LIVE_P (frame))
8432     {
8433       int i;
8434       EmacsView *view = FRAME_NS_VIEW (frame);
8435       NSView *sview = [[view window] contentView];
8436       NSArray *subs = [sview subviews];
8438       /* disable optimization stopping redraw of other scrollbars */
8439       view->scrollbarsNeedingUpdate = 0;
8440       for (i =[subs count]-1; i >= 0; i--)
8441         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8442           view->scrollbarsNeedingUpdate++;
8443       [sview addSubview: self];
8444     }
8446 /*  [self setFrame: r]; */
8448   return self;
8452 - (void)setFrame: (NSRect)newRect
8454   NSTRACE ("[EmacsScroller setFrame:]");
8456 /*  block_input (); */
8457   if (horizontal)
8458     pixel_length = NSWidth (newRect);
8459   else
8460     pixel_length = NSHeight (newRect);
8461   if (pixel_length == 0) pixel_length = 1;
8462   min_portion = 20 / pixel_length;
8463   [super setFrame: newRect];
8464 /*  unblock_input (); */
8468 - (void)dealloc
8470   NSTRACE ("[EmacsScroller dealloc]");
8471   if (window)
8472     {
8473       if (horizontal)
8474         wset_horizontal_scroll_bar (window, Qnil);
8475       else
8476         wset_vertical_scroll_bar (window, Qnil);
8477     }
8478   window = 0;
8479   [super dealloc];
8483 - (instancetype)condemn
8485   NSTRACE ("[EmacsScroller condemn]");
8486   condemned =YES;
8487   return self;
8491 - (instancetype)reprieve
8493   NSTRACE ("[EmacsScroller reprieve]");
8494   condemned =NO;
8495   return self;
8499 -(bool)judge
8501   NSTRACE ("[EmacsScroller judge]");
8502   bool ret = condemned;
8503   if (condemned)
8504     {
8505       EmacsView *view;
8506       block_input ();
8507       /* ensure other scrollbar updates after deletion */
8508       view = (EmacsView *)FRAME_NS_VIEW (frame);
8509       if (view != nil)
8510         view->scrollbarsNeedingUpdate++;
8511       if (window)
8512         {
8513           if (horizontal)
8514             wset_horizontal_scroll_bar (window, Qnil);
8515           else
8516             wset_vertical_scroll_bar (window, Qnil);
8517         }
8518       window = 0;
8519       [self removeFromSuperview];
8520       [self release];
8521       unblock_input ();
8522     }
8523   return ret;
8527 - (void)resetCursorRects
8529   NSRect visible = [self visibleRect];
8530   NSTRACE ("[EmacsScroller resetCursorRects]");
8532   if (!NSIsEmptyRect (visible))
8533     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8534   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8538 - (int) checkSamePosition: (int) position portion: (int) portion
8539                     whole: (int) whole
8541   return em_position ==position && em_portion ==portion && em_whole ==whole
8542     && portion != whole; /* needed for resize empty buf */
8546 - (instancetype)setPosition: (int)position portion: (int)portion whole: (int)whole
8548   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8550   em_position = position;
8551   em_portion = portion;
8552   em_whole = whole;
8554   if (portion >= whole)
8555     {
8556 #ifdef NS_IMPL_COCOA
8557       [self setKnobProportion: 1.0];
8558       [self setDoubleValue: 1.0];
8559 #else
8560       [self setFloatValue: 0.0 knobProportion: 1.0];
8561 #endif
8562     }
8563   else
8564     {
8565       float pos;
8566       CGFloat por;
8567       portion = max ((float)whole*min_portion/pixel_length, portion);
8568       pos = (float)position / (whole - portion);
8569       por = (CGFloat)portion/whole;
8570 #ifdef NS_IMPL_COCOA
8571       [self setKnobProportion: por];
8572       [self setDoubleValue: pos];
8573 #else
8574       [self setFloatValue: pos knobProportion: por];
8575 #endif
8576     }
8578   return self;
8581 /* set up emacs_event */
8582 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8584   Lisp_Object win;
8586   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8588   if (!emacs_event)
8589     return;
8591   emacs_event->part = last_hit_part;
8592   emacs_event->code = 0;
8593   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8594   XSETWINDOW (win, window);
8595   emacs_event->frame_or_window = win;
8596   emacs_event->timestamp = EV_TIMESTAMP (e);
8597   emacs_event->arg = Qnil;
8599   if (horizontal)
8600     {
8601       emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8602       XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8603       XSETINT (emacs_event->y, em_whole);
8604     }
8605   else
8606     {
8607       emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8608       XSETINT (emacs_event->x, loc);
8609       XSETINT (emacs_event->y, pixel_length-20);
8610     }
8612   if (q_event_ptr)
8613     {
8614       n_emacs_events_pending++;
8615       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8616     }
8617   else
8618     hold_event (emacs_event);
8619   EVENT_INIT (*emacs_event);
8620   ns_send_appdefined (-1);
8624 /* called manually thru timer to implement repeated button action w/hold-down */
8625 - (instancetype)repeatScroll: (NSTimer *)scrollEntry
8627   NSEvent *e = [[self window] currentEvent];
8628   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8629   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8631   NSTRACE ("[EmacsScroller repeatScroll:]");
8633   /* clear timer if need be */
8634   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8635     {
8636         [scroll_repeat_entry invalidate];
8637         [scroll_repeat_entry release];
8638         scroll_repeat_entry = nil;
8640         if (inKnob)
8641           return self;
8643         scroll_repeat_entry
8644           = [[NSTimer scheduledTimerWithTimeInterval:
8645                         SCROLL_BAR_CONTINUOUS_DELAY
8646                                             target: self
8647                                           selector: @selector (repeatScroll:)
8648                                           userInfo: 0
8649                                            repeats: YES]
8650               retain];
8651     }
8653   [self sendScrollEventAtLoc: 0 fromEvent: e];
8654   return self;
8658 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8659    mouseDragged events without going into a modal loop. */
8660 - (void)mouseDown: (NSEvent *)e
8662   NSRect sr, kr;
8663   /* hitPart is only updated AFTER event is passed on */
8664   NSScrollerPart part = [self testPart: [e locationInWindow]];
8665   CGFloat loc, kloc, pos UNINIT;
8666   int edge = 0;
8668   NSTRACE ("[EmacsScroller mouseDown:]");
8670   switch (part)
8671     {
8672     case NSScrollerDecrementPage:
8673       last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8674     case NSScrollerIncrementPage:
8675       last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8676     case NSScrollerDecrementLine:
8677       last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8678     case NSScrollerIncrementLine:
8679       last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8680     case NSScrollerKnob:
8681       last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8682     case NSScrollerKnobSlot:  /* GNUstep-only */
8683       last_hit_part = scroll_bar_move_ratio; break;
8684     default:  /* NSScrollerNoPart? */
8685       fprintf (stderr, "EmacsScroller-mouseDown: unexpected part %ld\n",
8686                (long) part);
8687       return;
8688     }
8690   if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8691     {
8692       /* handle, or on GNUstep possibly slot */
8693       NSEvent *fake_event;
8694       int length;
8696       /* compute float loc in slot and mouse offset on knob */
8697       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8698                       toView: nil];
8699       if (horizontal)
8700         {
8701           length = NSWidth (sr);
8702           loc = ([e locationInWindow].x - NSMinX (sr));
8703         }
8704       else
8705         {
8706           length = NSHeight (sr);
8707           loc = length - ([e locationInWindow].y - NSMinY (sr));
8708         }
8710       if (loc <= 0.0)
8711         {
8712           loc = 0.0;
8713           edge = -1;
8714         }
8715       else if (loc >= length)
8716         {
8717           loc = length;
8718           edge = 1;
8719         }
8721       if (edge)
8722         kloc = 0.5 * edge;
8723       else
8724         {
8725           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8726                           toView: nil];
8727           if (horizontal)
8728             kloc = ([e locationInWindow].x - NSMinX (kr));
8729           else
8730             kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8731         }
8732       last_mouse_offset = kloc;
8734       if (part != NSScrollerKnob)
8735         /* this is a slot click on GNUstep: go straight there */
8736         pos = loc;
8738       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8739       fake_event = [NSEvent mouseEventWithType: NSEventTypeLeftMouseUp
8740                                       location: [e locationInWindow]
8741                                  modifierFlags: [e modifierFlags]
8742                                      timestamp: [e timestamp]
8743                                   windowNumber: [e windowNumber]
8744                                        context: nil
8745                                    eventNumber: [e eventNumber]
8746                                     clickCount: [e clickCount]
8747                                       pressure: [e pressure]];
8748       [super mouseUp: fake_event];
8749     }
8750   else
8751     {
8752       pos = 0;      /* ignored */
8754       /* set a timer to repeat, as we can't let superclass do this modally */
8755       scroll_repeat_entry
8756         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8757                                             target: self
8758                                           selector: @selector (repeatScroll:)
8759                                           userInfo: 0
8760                                            repeats: YES]
8761             retain];
8762     }
8764   if (part != NSScrollerKnob)
8765     [self sendScrollEventAtLoc: pos fromEvent: e];
8769 /* Called as we manually track scroller drags, rather than superclass. */
8770 - (void)mouseDragged: (NSEvent *)e
8772     NSRect sr;
8773     double loc, pos;
8774     int length;
8776     NSTRACE ("[EmacsScroller mouseDragged:]");
8778       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8779                       toView: nil];
8781       if (horizontal)
8782         {
8783           length = NSWidth (sr);
8784           loc = ([e locationInWindow].x - NSMinX (sr));
8785         }
8786       else
8787         {
8788           length = NSHeight (sr);
8789           loc = length - ([e locationInWindow].y - NSMinY (sr));
8790         }
8792       if (loc <= 0.0)
8793         {
8794           loc = 0.0;
8795         }
8796       else if (loc >= length + last_mouse_offset)
8797         {
8798           loc = length + last_mouse_offset;
8799         }
8801       pos = (loc - last_mouse_offset);
8802       [self sendScrollEventAtLoc: pos fromEvent: e];
8806 - (void)mouseUp: (NSEvent *)e
8808   NSTRACE ("[EmacsScroller mouseUp:]");
8810   if (scroll_repeat_entry)
8811     {
8812       [scroll_repeat_entry invalidate];
8813       [scroll_repeat_entry release];
8814       scroll_repeat_entry = nil;
8815     }
8816   last_hit_part = scroll_bar_above_handle;
8820 /* treat scrollwheel events in the bar as though they were in the main window */
8821 - (void) scrollWheel: (NSEvent *)theEvent
8823   NSTRACE ("[EmacsScroller scrollWheel:]");
8825   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8826   [view mouseDown: theEvent];
8829 @end  /* EmacsScroller */
8832 #ifdef NS_IMPL_GNUSTEP
8833 /* Dummy class to get rid of startup warnings.  */
8834 @implementation EmacsDocument
8836 @end
8837 #endif
8840 /* ==========================================================================
8842    Font-related functions; these used to be in nsfaces.m
8844    ========================================================================== */
8847 Lisp_Object
8848 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8850   struct font *font = XFONT_OBJECT (font_object);
8851   EmacsView *view = FRAME_NS_VIEW (f);
8852   int font_ascent, font_descent;
8854   if (fontset < 0)
8855     fontset = fontset_from_font (font_object);
8856   FRAME_FONTSET (f) = fontset;
8858   if (FRAME_FONT (f) == font)
8859     /* This font is already set in frame F.  There's nothing more to
8860        do.  */
8861     return font_object;
8863   FRAME_FONT (f) = font;
8865   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8866   FRAME_COLUMN_WIDTH (f) = font->average_width;
8867   get_font_ascent_descent (font, &font_ascent, &font_descent);
8868   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8870   /* Compute the scroll bar width in character columns.  */
8871   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8872     {
8873       int wid = FRAME_COLUMN_WIDTH (f);
8874       FRAME_CONFIG_SCROLL_BAR_COLS (f)
8875         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8876     }
8877   else
8878     {
8879       int wid = FRAME_COLUMN_WIDTH (f);
8880       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8881     }
8883   /* Compute the scroll bar height in character lines.  */
8884   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8885     {
8886       int height = FRAME_LINE_HEIGHT (f);
8887       FRAME_CONFIG_SCROLL_BAR_LINES (f)
8888         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8889     }
8890   else
8891     {
8892       int height = FRAME_LINE_HEIGHT (f);
8893       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8894     }
8896   /* Now make the frame display the given font.  */
8897   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8898     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8899                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8900                        false, Qfont);
8902   return font_object;
8906 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8907 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8908          in 1.43. */
8910 const char *
8911 ns_xlfd_to_fontname (const char *xlfd)
8912 /* --------------------------------------------------------------------------
8913     Convert an X font name (XLFD) to an NS font name.
8914     Only family is used.
8915     The string returned is temporarily allocated.
8916    -------------------------------------------------------------------------- */
8918   char *name = xmalloc (180);
8919   int i, len;
8920   const char *ret;
8922   if (!strncmp (xlfd, "--", 2))
8923     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8924   else
8925     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8927   /* stopgap for malformed XLFD input */
8928   if (strlen (name) == 0)
8929     strcpy (name, "Monaco");
8931   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8932      also uppercase after '-' or ' ' */
8933   name[0] = c_toupper (name[0]);
8934   for (len =strlen (name), i =0; i<len; i++)
8935     {
8936       if (name[i] == '$')
8937         {
8938           name[i] = '-';
8939           if (i+1<len)
8940             name[i+1] = c_toupper (name[i+1]);
8941         }
8942       else if (name[i] == '_')
8943         {
8944           name[i] = ' ';
8945           if (i+1<len)
8946             name[i+1] = c_toupper (name[i+1]);
8947         }
8948     }
8949 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
8950   ret = [[NSString stringWithUTF8String: name] UTF8String];
8951   xfree (name);
8952   return ret;
8956 void
8957 syms_of_nsterm (void)
8959   NSTRACE ("syms_of_nsterm");
8961   ns_antialias_threshold = 10.0;
8963   /* from 23+ we need to tell emacs what modifiers there are.. */
8964   DEFSYM (Qmodifier_value, "modifier-value");
8965   DEFSYM (Qalt, "alt");
8966   DEFSYM (Qhyper, "hyper");
8967   DEFSYM (Qmeta, "meta");
8968   DEFSYM (Qsuper, "super");
8969   DEFSYM (Qcontrol, "control");
8970   DEFSYM (QUTF8_STRING, "UTF8_STRING");
8972   DEFSYM (Qfile, "file");
8973   DEFSYM (Qurl, "url");
8975   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8976   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8977   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8978   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8979   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8981   DEFVAR_LISP ("ns-input-file", ns_input_file,
8982               "The file specified in the last NS event.");
8983   ns_input_file =Qnil;
8985   DEFVAR_LISP ("ns-working-text", ns_working_text,
8986               "String for visualizing working composition sequence.");
8987   ns_working_text =Qnil;
8989   DEFVAR_LISP ("ns-input-font", ns_input_font,
8990               "The font specified in the last NS event.");
8991   ns_input_font =Qnil;
8993   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8994               "The fontsize specified in the last NS event.");
8995   ns_input_fontsize =Qnil;
8997   DEFVAR_LISP ("ns-input-line", ns_input_line,
8998                "The line specified in the last NS event.");
8999   ns_input_line =Qnil;
9001   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
9002                "The service name specified in the last NS event.");
9003   ns_input_spi_name =Qnil;
9005   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
9006                "The service argument specified in the last NS event.");
9007   ns_input_spi_arg =Qnil;
9009   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
9010                "This variable describes the behavior of the alternate or option key.\n\
9011 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9012 that key.\n\
9013 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9014 at all, allowing it to be used at a lower level for accented character entry.");
9015   ns_alternate_modifier = Qmeta;
9017   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
9018                "This variable describes the behavior of the right alternate or option key.\n\
9019 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9020 that key.\n\
9021 Set to left means be the same key as `ns-alternate-modifier'.\n\
9022 Set to none means that the alternate / option key is not interpreted by Emacs\n\
9023 at all, allowing it to be used at a lower level for accented character entry.");
9024   ns_right_alternate_modifier = Qleft;
9026   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
9027                "This variable describes the behavior of the command key.\n\
9028 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9029 that key.");
9030   ns_command_modifier = Qsuper;
9032   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
9033                "This variable describes the behavior of the right command key.\n\
9034 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9035 that key.\n\
9036 Set to left means be the same key as `ns-command-modifier'.\n\
9037 Set to none means that the command / option key is not interpreted by Emacs\n\
9038 at all, allowing it to be used at a lower level for accented character entry.");
9039   ns_right_command_modifier = Qleft;
9041   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
9042                "This variable describes the behavior of the control key.\n\
9043 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9044 that key.");
9045   ns_control_modifier = Qcontrol;
9047   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
9048                "This variable describes the behavior of the right control key.\n\
9049 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9050 that key.\n\
9051 Set to left means be the same key as `ns-control-modifier'.\n\
9052 Set to none means that the control / option key is not interpreted by Emacs\n\
9053 at all, allowing it to be used at a lower level for accented character entry.");
9054   ns_right_control_modifier = Qleft;
9056   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
9057                "This variable describes the behavior of the function key (on laptops).\n\
9058 Set to the symbol control, meta, alt, super, or hyper means it is taken to be\n\
9059 that key.\n\
9060 Set to none means that the function key is not interpreted by Emacs at all,\n\
9061 allowing it to be used at a lower level for accented character entry.");
9062   ns_function_modifier = Qnone;
9064   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
9065                "Non-nil (the default) means to render text antialiased.");
9066   ns_antialias_text = Qt;
9068   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
9069                "Whether to confirm application quit using dialog.");
9070   ns_confirm_quit = Qnil;
9072   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
9073                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
9074 Only works on Mac OS X 10.6 or later.  */);
9075   ns_auto_hide_menu_bar = Qnil;
9077   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
9078      doc: /*Non-nil means to use native fullscreen on Mac OS X 10.7 and later.
9079 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
9080 multiple monitors, but lacks tool bar.  This variable is ignored on
9081 Mac OS X < 10.7.  Default is t.  */);
9082   ns_use_native_fullscreen = YES;
9083   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
9085   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
9086      doc: /*Non-nil means use animation on non-native fullscreen.
9087 For native fullscreen, this does nothing.
9088 Default is nil.  */);
9089   ns_use_fullscreen_animation = NO;
9091   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
9092      doc: /*Non-nil means to use sRGB colorspace on Mac OS X 10.7 and later.
9093 Note that this does not apply to images.
9094 This variable is ignored on Mac OS X < 10.7 and GNUstep.  */);
9095   ns_use_srgb_colorspace = YES;
9097   /* TODO: move to common code */
9098   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
9099                doc: /* Which toolkit scroll bars Emacs uses, if any.
9100 A value of nil means Emacs doesn't use toolkit scroll bars.
9101 With the X Window system, the value is a symbol describing the
9102 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
9103 With MS Windows or Nextstep, the value is t.  */);
9104   Vx_toolkit_scroll_bars = Qt;
9106   DEFVAR_BOOL ("x-use-underline-position-properties",
9107                x_use_underline_position_properties,
9108      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
9109 A value of nil means ignore them.  If you encounter fonts with bogus
9110 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
9111 to 4.1, set this to nil. */);
9112   x_use_underline_position_properties = 0;
9114   DEFVAR_BOOL ("x-underline-at-descent-line",
9115                x_underline_at_descent_line,
9116      doc: /* Non-nil means to draw the underline at the same place as the descent line.
9117 A value of nil means to draw the underline according to the value of the
9118 variable `x-use-underline-position-properties', which is usually at the
9119 baseline level.  The default value is nil.  */);
9120   x_underline_at_descent_line = 0;
9122   /* Tell Emacs about this window system.  */
9123   Fprovide (Qns, Qnil);
9125   DEFSYM (Qcocoa, "cocoa");
9126   DEFSYM (Qgnustep, "gnustep");
9128 #ifdef NS_IMPL_COCOA
9129   Fprovide (Qcocoa, Qnil);
9130   syms_of_macfont ();
9131 #else
9132   Fprovide (Qgnustep, Qnil);
9133   syms_of_nsfont ();
9134 #endif