Fix 'current-column' in presence of :relative-width
[emacs.git] / src / nsterm.m
blob14f2beb44894c7671a69410bc551430056c3dc7f
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2015 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
11 (at 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 MacOSX/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 /* call tracing */
72 #if 0
73 int term_trace_num = 0;
74 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
75                                 __FILE__, __LINE__, ++term_trace_num)
76 #else
77 #define NSTRACE(x)
78 #endif
80 /* Detailed tracing. "S" means "size" and "LL" stands for "lower left". */
81 #if 0
82 int term_trace_num = 0;
83 #define NSTRACE_SIZE(str,size) fprintf (stderr,                         \
84                                    "%s:%d: [%d]   " str                 \
85                                    " (S:%.0f x %.0f)\n", \
86                                    __FILE__, __LINE__, ++term_trace_num,\
87                                    size.height,                       \
88                                    size.width)
89 #define NSTRACE_RECT(s,r) fprintf (stderr,                              \
90                                    "%s:%d: [%d]   " s                   \
91                                    " (LL:%.0f x %.0f -> S:%.0f x %.0f)\n", \
92                                    __FILE__, __LINE__, ++term_trace_num,\
93                                    r.origin.x,                          \
94                                    r.origin.y,                          \
95                                    r.size.height,                       \
96                                    r.size.width)
97 #else
98 #define NSTRACE_SIZE(str,size)
99 #define NSTRACE_RECT(s,r)
100 #endif
102 extern NSString *NSMenuDidBeginTrackingNotification;
104 /* ==========================================================================
106    NSColor, EmacsColor category.
108    ========================================================================== */
109 @implementation NSColor (EmacsColor)
110 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
111                          blue:(CGFloat)blue alpha:(CGFloat)alpha
113 #ifdef NS_IMPL_COCOA
114 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
115   if (ns_use_srgb_colorspace)
116       return [NSColor colorWithSRGBRed: red
117                                  green: green
118                                   blue: blue
119                                  alpha: alpha];
120 #endif
121 #endif
122   return [NSColor colorWithCalibratedRed: red
123                                    green: green
124                                     blue: blue
125                                    alpha: alpha];
128 - (NSColor *)colorUsingDefaultColorSpace
130 #ifdef NS_IMPL_COCOA
131 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
132   if (ns_use_srgb_colorspace)
133     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
134 #endif
135 #endif
136   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
139 @end
141 /* ==========================================================================
143     Local declarations
145    ========================================================================== */
147 /* Convert a symbol indexed with an NSxxx value to a value as defined
148    in keyboard.c (lispy_function_key). I hope this is a correct way
149    of doing things... */
150 static unsigned convert_ns_to_X_keysym[] =
152   NSHomeFunctionKey,            0x50,
153   NSLeftArrowFunctionKey,       0x51,
154   NSUpArrowFunctionKey,         0x52,
155   NSRightArrowFunctionKey,      0x53,
156   NSDownArrowFunctionKey,       0x54,
157   NSPageUpFunctionKey,          0x55,
158   NSPageDownFunctionKey,        0x56,
159   NSEndFunctionKey,             0x57,
160   NSBeginFunctionKey,           0x58,
161   NSSelectFunctionKey,          0x60,
162   NSPrintFunctionKey,           0x61,
163   NSClearLineFunctionKey,       0x0B,
164   NSExecuteFunctionKey,         0x62,
165   NSInsertFunctionKey,          0x63,
166   NSUndoFunctionKey,            0x65,
167   NSRedoFunctionKey,            0x66,
168   NSMenuFunctionKey,            0x67,
169   NSFindFunctionKey,            0x68,
170   NSHelpFunctionKey,            0x6A,
171   NSBreakFunctionKey,           0x6B,
173   NSF1FunctionKey,              0xBE,
174   NSF2FunctionKey,              0xBF,
175   NSF3FunctionKey,              0xC0,
176   NSF4FunctionKey,              0xC1,
177   NSF5FunctionKey,              0xC2,
178   NSF6FunctionKey,              0xC3,
179   NSF7FunctionKey,              0xC4,
180   NSF8FunctionKey,              0xC5,
181   NSF9FunctionKey,              0xC6,
182   NSF10FunctionKey,             0xC7,
183   NSF11FunctionKey,             0xC8,
184   NSF12FunctionKey,             0xC9,
185   NSF13FunctionKey,             0xCA,
186   NSF14FunctionKey,             0xCB,
187   NSF15FunctionKey,             0xCC,
188   NSF16FunctionKey,             0xCD,
189   NSF17FunctionKey,             0xCE,
190   NSF18FunctionKey,             0xCF,
191   NSF19FunctionKey,             0xD0,
192   NSF20FunctionKey,             0xD1,
193   NSF21FunctionKey,             0xD2,
194   NSF22FunctionKey,             0xD3,
195   NSF23FunctionKey,             0xD4,
196   NSF24FunctionKey,             0xD5,
198   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
199   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
200   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
202   NSTabCharacter,               0x09,
203   0x19,                         0x09,  /* left tab->regular since pass shift */
204   NSCarriageReturnCharacter,    0x0D,
205   NSNewlineCharacter,           0x0D,
206   NSEnterCharacter,             0x8D,
208   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
209   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
210   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
211   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
212   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
213   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
214   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
215   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
216   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
217   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
218   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
219   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
220   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
221   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
222   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
223   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
225   0x1B,                         0x1B   /* escape */
228 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
229    the maximum font size to NOT antialias.  On GNUstep there is currently
230    no way to control this behavior. */
231 float ns_antialias_threshold;
233 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
234 NSString *ns_app_name = @"Emacs";  /* default changed later */
236 /* Display variables */
237 struct ns_display_info *x_display_list; /* Chain of existing displays */
238 long context_menu_value = 0;
240 /* display update */
241 static struct frame *ns_updating_frame;
242 static NSView *focus_view = NULL;
243 static int ns_window_num = 0;
244 #ifdef NS_IMPL_GNUSTEP
245 static NSRect uRect;
246 #endif
247 static BOOL gsaved = NO;
248 static BOOL ns_fake_keydown = NO;
249 #ifdef NS_IMPL_COCOA
250 static BOOL ns_menu_bar_is_hidden = NO;
251 #endif
252 /*static int debug_lock = 0; */
254 /* event loop */
255 static BOOL send_appdefined = YES;
256 #define NO_APPDEFINED_DATA (-8)
257 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
258 static NSTimer *timed_entry = 0;
259 static NSTimer *scroll_repeat_entry = nil;
260 static fd_set select_readfds, select_writefds;
261 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
262 static int select_nfds = 0, select_valid = 0;
263 static struct timespec select_timeout = { 0, 0 };
264 static int selfds[2] = { -1, -1 };
265 static pthread_mutex_t select_mutex;
266 static int apploopnr = 0;
267 static NSAutoreleasePool *outerpool;
268 static struct input_event *emacs_event = NULL;
269 static struct input_event *q_event_ptr = NULL;
270 static int n_emacs_events_pending = 0;
271 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
272   *ns_pending_service_args;
273 static BOOL ns_do_open_file = NO;
274 static BOOL ns_last_use_native_fullscreen;
276 /* Non-zero means that a HELP_EVENT has been generated since Emacs
277    start.  */
279 static BOOL any_help_event_p = NO;
281 static struct {
282   struct input_event *q;
283   int nr, cap;
284 } hold_event_q = {
285   NULL, 0, 0
288 static NSString *represented_filename = nil;
289 static struct frame *represented_frame = 0;
291 #ifdef NS_IMPL_COCOA
293  * State for pending menu activation:
294  * MENU_NONE     Normal state
295  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
296  *               run lisp to update the menu.
297  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
298  *               will open.
299  */
300 #define MENU_NONE 0
301 #define MENU_PENDING 1
302 #define MENU_OPENING 2
303 static int menu_will_open_state = MENU_NONE;
305 /* Saved position for menu click.  */
306 static CGPoint menu_mouse_point;
307 #endif
309 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
310 #define NS_FUNCTION_KEY_MASK 0x800000
311 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
312 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
313 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
314 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
315 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
316 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
317 #define EV_MODIFIERS2(flags)                          \
318     (((flags & NSHelpKeyMask) ?           \
319            hyper_modifier : 0)                        \
320      | (!EQ (ns_right_alternate_modifier, Qleft) && \
321         ((flags & NSRightAlternateKeyMask) \
322          == NSRightAlternateKeyMask) ? \
323            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
324      | ((flags & NSAlternateKeyMask) ?                 \
325            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
326      | ((flags & NSShiftKeyMask) ?     \
327            shift_modifier : 0)                        \
328      | (!EQ (ns_right_control_modifier, Qleft) && \
329         ((flags & NSRightControlKeyMask) \
330          == NSRightControlKeyMask) ? \
331            parse_solitary_modifier (ns_right_control_modifier) : 0) \
332      | ((flags & NSControlKeyMask) ?      \
333            parse_solitary_modifier (ns_control_modifier) : 0)     \
334      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
335            parse_solitary_modifier (ns_function_modifier) : 0)    \
336      | (!EQ (ns_right_command_modifier, Qleft) && \
337         ((flags & NSRightCommandKeyMask) \
338          == NSRightCommandKeyMask) ? \
339            parse_solitary_modifier (ns_right_command_modifier) : 0) \
340      | ((flags & NSCommandKeyMask) ?      \
341            parse_solitary_modifier (ns_command_modifier):0))
342 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
344 #define EV_UDMODIFIERS(e)                                      \
345     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
346      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
347      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
348      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
349      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
350      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
351      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
352      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
353      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
355 #define EV_BUTTON(e)                                                         \
356     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
357       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
358      [e buttonNumber] - 1)
360 /* Convert the time field to a timestamp in milliseconds. */
361 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
363 /* This is a piece of code which is common to all the event handling
364    methods.  Maybe it should even be a function.  */
365 #define EV_TRAILER(e)                                                   \
366   {                                                                     \
367     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
368     EV_TRAILER2 (e);                                                    \
369   }
371 #define EV_TRAILER2(e)                                                  \
372   {                                                                     \
373       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
374       if (q_event_ptr)                                                  \
375         {                                                               \
376           Lisp_Object tem = Vinhibit_quit;                              \
377           Vinhibit_quit = Qt;                                           \
378           n_emacs_events_pending++;                                     \
379           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
380           Vinhibit_quit = tem;                                          \
381         }                                                               \
382       else                                                              \
383         hold_event (emacs_event);                                       \
384       EVENT_INIT (*emacs_event);                                        \
385       ns_send_appdefined (-1);                                          \
386     }
388 /* TODO: get rid of need for these forward declarations */
389 static void ns_condemn_scroll_bars (struct frame *f);
390 static void ns_judge_scroll_bars (struct frame *f);
391 void x_set_frame_alpha (struct frame *f);
394 /* ==========================================================================
396     Utilities
398    ========================================================================== */
400 void
401 ns_set_represented_filename (NSString* fstr, struct frame *f)
403   represented_filename = [fstr retain];
404   represented_frame = f;
407 void
408 ns_init_events (struct input_event* ev)
410   EVENT_INIT (*ev);
411   emacs_event = ev;
414 void
415 ns_finish_events ()
417   emacs_event = NULL;
420 static void
421 hold_event (struct input_event *event)
423   if (hold_event_q.nr == hold_event_q.cap)
424     {
425       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
426       else hold_event_q.cap *= 2;
427       hold_event_q.q =
428         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
429     }
431   hold_event_q.q[hold_event_q.nr++] = *event;
432   /* Make sure ns_read_socket is called, i.e. we have input.  */
433   raise (SIGIO);
434   send_appdefined = YES;
437 static Lisp_Object
438 append2 (Lisp_Object list, Lisp_Object item)
439 /* --------------------------------------------------------------------------
440    Utility to append to a list
441    -------------------------------------------------------------------------- */
443   Lisp_Object array[2];
444   array[0] = list;
445   array[1] = list1 (item);
446   return Fnconc (2, &array[0]);
450 const char *
451 ns_etc_directory (void)
452 /* If running as a self-contained app bundle, return as a string the
453    filename of the etc directory, if present; else nil.  */
455   NSBundle *bundle = [NSBundle mainBundle];
456   NSString *resourceDir = [bundle resourcePath];
457   NSString *resourcePath;
458   NSFileManager *fileManager = [NSFileManager defaultManager];
459   BOOL isDir;
461   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
462   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
463     {
464       if (isDir) return [resourcePath UTF8String];
465     }
466   return NULL;
470 const char *
471 ns_exec_path (void)
472 /* If running as a self-contained app bundle, return as a path string
473    the filenames of the libexec and bin directories, ie libexec:bin.
474    Otherwise, return nil.
475    Normally, Emacs does not add its own bin/ directory to the PATH.
476    However, a self-contained NS build has a different layout, with
477    bin/ and libexec/ subdirectories in the directory that contains
478    Emacs.app itself.
479    We put libexec first, because init_callproc_1 uses the first
480    element to initialize exec-directory.  An alternative would be
481    for init_callproc to check for invocation-directory/libexec.
484   NSBundle *bundle = [NSBundle mainBundle];
485   NSString *resourceDir = [bundle resourcePath];
486   NSString *binDir = [bundle bundlePath];
487   NSString *resourcePath, *resourcePaths;
488   NSRange range;
489   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
490   NSFileManager *fileManager = [NSFileManager defaultManager];
491   NSArray *paths;
492   NSEnumerator *pathEnum;
493   BOOL isDir;
495   range = [resourceDir rangeOfString: @"Contents"];
496   if (range.location != NSNotFound)
497     {
498       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
499 #ifdef NS_IMPL_COCOA
500       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
501 #endif
502     }
504   paths = [binDir stringsByAppendingPaths:
505                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
506   pathEnum = [paths objectEnumerator];
507   resourcePaths = @"";
509   while ((resourcePath = [pathEnum nextObject]))
510     {
511       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
512         if (isDir)
513           {
514             if ([resourcePaths length] > 0)
515               resourcePaths
516                 = [resourcePaths stringByAppendingString: pathSeparator];
517             resourcePaths
518               = [resourcePaths stringByAppendingString: resourcePath];
519           }
520     }
521   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
523   return NULL;
527 const char *
528 ns_load_path (void)
529 /* If running as a self-contained app bundle, return as a path string
530    the filenames of the site-lisp and lisp directories.
531    Ie, site-lisp:lisp.  Otherwise, return nil.  */
533   NSBundle *bundle = [NSBundle mainBundle];
534   NSString *resourceDir = [bundle resourcePath];
535   NSString *resourcePath, *resourcePaths;
536   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
537   NSFileManager *fileManager = [NSFileManager defaultManager];
538   BOOL isDir;
539   NSArray *paths = [resourceDir stringsByAppendingPaths:
540                               [NSArray arrayWithObjects:
541                                          @"site-lisp", @"lisp", nil]];
542   NSEnumerator *pathEnum = [paths objectEnumerator];
543   resourcePaths = @"";
545   /* Hack to skip site-lisp.  */
546   if (no_site_lisp) resourcePath = [pathEnum nextObject];
548   while ((resourcePath = [pathEnum nextObject]))
549     {
550       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
551         if (isDir)
552           {
553             if ([resourcePaths length] > 0)
554               resourcePaths
555                 = [resourcePaths stringByAppendingString: pathSeparator];
556             resourcePaths
557               = [resourcePaths stringByAppendingString: resourcePath];
558           }
559     }
560   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
562   return NULL;
565 static void
566 ns_timeout (int usecs)
567 /* --------------------------------------------------------------------------
568      Blocking timer utility used by ns_ring_bell
569    -------------------------------------------------------------------------- */
571   struct timespec wakeup = timespec_add (current_timespec (),
572                                          make_timespec (0, usecs * 1000));
574   /* Keep waiting until past the time wakeup.  */
575   while (1)
576     {
577       struct timespec timeout, now = current_timespec ();
578       if (timespec_cmp (wakeup, now) <= 0)
579         break;
580       timeout = timespec_sub (wakeup, now);
582       /* Try to wait that long--but we might wake up sooner.  */
583       pselect (0, NULL, NULL, NULL, &timeout, NULL);
584     }
588 void
589 ns_release_object (void *obj)
590 /* --------------------------------------------------------------------------
591     Release an object (callable from C)
592    -------------------------------------------------------------------------- */
594     [(id)obj release];
598 void
599 ns_retain_object (void *obj)
600 /* --------------------------------------------------------------------------
601     Retain an object (callable from C)
602    -------------------------------------------------------------------------- */
604     [(id)obj retain];
608 void *
609 ns_alloc_autorelease_pool (void)
610 /* --------------------------------------------------------------------------
611      Allocate a pool for temporary objects (callable from C)
612    -------------------------------------------------------------------------- */
614   return [[NSAutoreleasePool alloc] init];
618 void
619 ns_release_autorelease_pool (void *pool)
620 /* --------------------------------------------------------------------------
621      Free a pool and temporary objects it refers to (callable from C)
622    -------------------------------------------------------------------------- */
624   ns_release_object (pool);
629 /* ==========================================================================
631     Focus (clipping) and screen update
633    ========================================================================== */
636 // Window constraining
637 // -------------------
639 // To ensure that the windows are not placed under the menu bar, they
640 // are typically moved by the call-back constrainFrameRect. However,
641 // by overriding it, it's possible to inhibit this, leaving the window
642 // in it's original position.
644 // It's possible to hide the menu bar. However, technically, it's only
645 // possible to hide it when the application is active. To ensure that
646 // this work properly, the menu bar and window constraining are
647 // deferred until the application becomes active.
649 // Even though it's not possible to manually move a window above the
650 // top of the screen, it is allowed if it's done programmatically,
651 // when the menu is hidden. This allows the editable area to cover the
652 // full screen height.
654 // Test cases
655 // ----------
657 // Use the following extra files:
659 //    init.el:
660 //       ;; Hide menu and place frame slightly above the top of the screen.
661 //       (setq ns-auto-hide-menu-bar t)
662 //       (set-frame-position (selected-frame) 0 -20)
664 // Test 1:
666 //    emacs -Q -l init.el
668 //    Result: No menu bar, and the title bar should be above the screen.
670 // Test 2:
672 //    emacs -Q
674 //    Result: Menu bar visible, frame placed immediately below the menu.
677 static void
678 ns_constrain_all_frames (void)
680   Lisp_Object tail, frame;
682   FOR_EACH_FRAME (tail, frame)
683     {
684       struct frame *f = XFRAME (frame);
685       if (FRAME_NS_P (f))
686         {
687           NSView *view = FRAME_NS_VIEW (f);
688           /* This no-op will trigger the default window placing
689            * constraint system. */
690           [[view window] setFrameOrigin:[[view window] frame].origin];
691         }
692     }
696 /* True, if the menu bar should be hidden.  */
698 static BOOL
699 ns_menu_bar_should_be_hidden (void)
701   return !NILP (ns_auto_hide_menu_bar)
702     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
706 /* Show or hide the menu bar, based on user setting.  */
708 static void
709 ns_update_auto_hide_menu_bar (void)
711 #ifdef NS_IMPL_COCOA
712   block_input ();
714   NSTRACE (ns_update_auto_hide_menu_bar);
716   if (NSApp != nil && [NSApp isActive])
717     {
718       // Note, "setPresentationOptions" triggers an error unless the
719       // application is active.
720       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
722       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
723         {
724           NSApplicationPresentationOptions options
725             = NSApplicationPresentationDefault;
727           if (menu_bar_should_be_hidden)
728             options |= NSApplicationPresentationAutoHideMenuBar
729               | NSApplicationPresentationAutoHideDock;
731           [NSApp setPresentationOptions: options];
733           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
735           if (!ns_menu_bar_is_hidden)
736             {
737               ns_constrain_all_frames ();
738             }
739         }
740     }
742   unblock_input ();
743 #endif
747 static void
748 ns_update_begin (struct frame *f)
749 /* --------------------------------------------------------------------------
750    Prepare for a grouped sequence of drawing calls
751    external (RIF) call; whole frame, called before update_window_begin
752    -------------------------------------------------------------------------- */
754   EmacsView *view = FRAME_NS_VIEW (f);
755   NSTRACE (ns_update_begin);
757   ns_update_auto_hide_menu_bar ();
759 #ifdef NS_IMPL_COCOA
760   if ([view isFullscreen] && [view fsIsNative])
761   {
762     // Fix reappearing tool bar in fullscreen for OSX 10.7
763     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
764     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
765     if (! tbar_visible != ! [toolbar isVisible])
766       [toolbar setVisible: tbar_visible];
767   }
768 #endif
770   ns_updating_frame = f;
771   [view lockFocus];
773   /* drawRect may have been called for say the minibuffer, and then clip path
774      is for the minibuffer.  But the display engine may draw more because
775      we have set the frame as garbaged.  So reset clip path to the whole
776      view.  */
777 #ifdef NS_IMPL_COCOA
778   {
779     NSBezierPath *bp;
780     NSRect r = [view frame];
781     NSRect cr = [[view window] frame];
782     /* If a large frame size is set, r may be larger than the window frame
783        before constrained.  In that case don't change the clip path, as we
784        will clear in to the tool bar and title bar.  */
785     if (r.size.height
786         + FRAME_NS_TITLEBAR_HEIGHT (f)
787         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
788       {
789         bp = [[NSBezierPath bezierPathWithRect: r] retain];
790         [bp setClip];
791         [bp release];
792       }
793   }
794 #endif
796 #ifdef NS_IMPL_GNUSTEP
797   uRect = NSMakeRect (0, 0, 0, 0);
798 #endif
802 static void
803 ns_update_window_begin (struct window *w)
804 /* --------------------------------------------------------------------------
805    Prepare for a grouped sequence of drawing calls
806    external (RIF) call; for one window, called after update_begin
807    -------------------------------------------------------------------------- */
809   struct frame *f = XFRAME (WINDOW_FRAME (w));
810   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
812   NSTRACE (ns_update_window_begin);
813   w->output_cursor = w->cursor;
815   block_input ();
817   if (f == hlinfo->mouse_face_mouse_frame)
818     {
819       /* Don't do highlighting for mouse motion during the update.  */
820       hlinfo->mouse_face_defer = 1;
822         /* If the frame needs to be redrawn,
823            simply forget about any prior mouse highlighting.  */
824       if (FRAME_GARBAGED_P (f))
825         hlinfo->mouse_face_window = Qnil;
827       /* (further code for mouse faces ifdef'd out in other terms elided) */
828     }
830   unblock_input ();
834 static void
835 ns_update_window_end (struct window *w, bool cursor_on_p,
836                       bool mouse_face_overwritten_p)
837 /* --------------------------------------------------------------------------
838    Finished a grouped sequence of drawing calls
839    external (RIF) call; for one window called before update_end
840    -------------------------------------------------------------------------- */
842   /* note: this fn is nearly identical in all terms */
843   if (!w->pseudo_window_p)
844     {
845       block_input ();
847       if (cursor_on_p)
848         display_and_set_cursor (w, 1,
849                                 w->output_cursor.hpos, w->output_cursor.vpos,
850                                 w->output_cursor.x, w->output_cursor.y);
852       if (draw_window_fringes (w, 1))
853         {
854           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
855             x_draw_right_divider (w);
856           else
857             x_draw_vertical_border (w);
858         }
860       unblock_input ();
861     }
863   /* If a row with mouse-face was overwritten, arrange for
864      frame_up_to_date to redisplay the mouse highlight.  */
865   if (mouse_face_overwritten_p)
866     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
868   NSTRACE (update_window_end);
872 static void
873 ns_update_end (struct frame *f)
874 /* --------------------------------------------------------------------------
875    Finished a grouped sequence of drawing calls
876    external (RIF) call; for whole frame, called after update_window_end
877    -------------------------------------------------------------------------- */
879   EmacsView *view = FRAME_NS_VIEW (f);
881 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
882   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
884   block_input ();
886   [view unlockFocus];
887   [[view window] flushWindow];
889   unblock_input ();
890   ns_updating_frame = NULL;
891   NSTRACE (ns_update_end);
894 static void
895 ns_focus (struct frame *f, NSRect *r, int n)
896 /* --------------------------------------------------------------------------
897    Internal: Focus on given frame.  During small local updates this is used to
898      draw, however during large updates, ns_update_begin and ns_update_end are
899      called to wrap the whole thing, in which case these calls are stubbed out.
900      Except, on GNUstep, we accumulate the rectangle being drawn into, because
901      the back end won't do this automatically, and will just end up flushing
902      the entire window.
903    -------------------------------------------------------------------------- */
905 //  NSTRACE (ns_focus);
906 /* static int c =0;
907    fprintf (stderr, "focus: %d", c++);
908    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
909    fprintf (stderr, "\n"); */
911   if (f != ns_updating_frame)
912     {
913       NSView *view = FRAME_NS_VIEW (f);
914       if (view != focus_view)
915         {
916           if (focus_view != NULL)
917             {
918               [focus_view unlockFocus];
919               [[focus_view window] flushWindow];
920 /*debug_lock--; */
921             }
923           if (view)
924             [view lockFocus];
925           focus_view = view;
926 /*if (view) debug_lock++; */
927         }
928     }
930   /* clipping */
931   if (r)
932     {
933       [[NSGraphicsContext currentContext] saveGraphicsState];
934       if (n == 2)
935         NSRectClipList (r, 2);
936       else
937         NSRectClip (*r);
938       gsaved = YES;
939     }
943 static void
944 ns_unfocus (struct frame *f)
945 /* --------------------------------------------------------------------------
946      Internal: Remove focus on given frame
947    -------------------------------------------------------------------------- */
949 //  NSTRACE (ns_unfocus);
951   if (gsaved)
952     {
953       [[NSGraphicsContext currentContext] restoreGraphicsState];
954       gsaved = NO;
955     }
957   if (f != ns_updating_frame)
958     {
959       if (focus_view != NULL)
960         {
961           [focus_view unlockFocus];
962           [[focus_view window] flushWindow];
963           focus_view = NULL;
964 /*debug_lock--; */
965         }
966     }
970 static void
971 ns_clip_to_row (struct window *w, struct glyph_row *row,
972                 enum glyph_row_area area, BOOL gc)
973 /* --------------------------------------------------------------------------
974      Internal (but parallels other terms): Focus drawing on given row
975    -------------------------------------------------------------------------- */
977   struct frame *f = XFRAME (WINDOW_FRAME (w));
978   NSRect clip_rect;
979   int window_x, window_y, window_width;
981   window_box (w, area, &window_x, &window_y, &window_width, 0);
983   clip_rect.origin.x = window_x;
984   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
985   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
986   clip_rect.size.width = window_width;
987   clip_rect.size.height = row->visible_height;
989   ns_focus (f, &clip_rect, 1);
993 static void
994 ns_ring_bell (struct frame *f)
995 /* --------------------------------------------------------------------------
996      "Beep" routine
997    -------------------------------------------------------------------------- */
999   NSTRACE (ns_ring_bell);
1000   if (visible_bell)
1001     {
1002       NSAutoreleasePool *pool;
1003       struct frame *frame = SELECTED_FRAME ();
1004       NSView *view;
1006       block_input ();
1007       pool = [[NSAutoreleasePool alloc] init];
1009       view = FRAME_NS_VIEW (frame);
1010       if (view != nil)
1011         {
1012           NSRect r, surr;
1013           NSPoint dim = NSMakePoint (128, 128);
1015           r = [view bounds];
1016           r.origin.x += (r.size.width - dim.x) / 2;
1017           r.origin.y += (r.size.height - dim.y) / 2;
1018           r.size.width = dim.x;
1019           r.size.height = dim.y;
1020           surr = NSInsetRect (r, -2, -2);
1021           ns_focus (frame, &surr, 1);
1022           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
1023           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
1024                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
1025           NSRectFill (r);
1026           [[view window] flushWindow];
1027           ns_timeout (150000);
1028           [[view window] restoreCachedImage];
1029           [[view window] flushWindow];
1030           ns_unfocus (frame);
1031         }
1032       [pool release];
1033       unblock_input ();
1034     }
1035   else
1036     {
1037       NSBeep ();
1038     }
1041 /* ==========================================================================
1043     Frame / window manager related functions
1045    ========================================================================== */
1048 static void
1049 ns_raise_frame (struct frame *f)
1050 /* --------------------------------------------------------------------------
1051      Bring window to foreground and make it active
1052    -------------------------------------------------------------------------- */
1054   NSView *view;
1055   check_window_system (f);
1056   view = FRAME_NS_VIEW (f);
1057   block_input ();
1058   if (FRAME_VISIBLE_P (f))
1059     [[view window] makeKeyAndOrderFront: NSApp];
1060   unblock_input ();
1064 static void
1065 ns_lower_frame (struct frame *f)
1066 /* --------------------------------------------------------------------------
1067      Send window to back
1068    -------------------------------------------------------------------------- */
1070   NSView *view;
1071   check_window_system (f);
1072   view = FRAME_NS_VIEW (f);
1073   block_input ();
1074   [[view window] orderBack: NSApp];
1075   unblock_input ();
1079 static void
1080 ns_frame_raise_lower (struct frame *f, bool raise)
1081 /* --------------------------------------------------------------------------
1082      External (hook)
1083    -------------------------------------------------------------------------- */
1085   NSTRACE (ns_frame_raise_lower);
1087   if (raise)
1088     ns_raise_frame (f);
1089   else
1090     ns_lower_frame (f);
1094 static void
1095 ns_frame_rehighlight (struct frame *frame)
1096 /* --------------------------------------------------------------------------
1097      External (hook): called on things like window switching within frame
1098    -------------------------------------------------------------------------- */
1100   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1101   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1103   NSTRACE (ns_frame_rehighlight);
1104   if (dpyinfo->x_focus_frame)
1105     {
1106       dpyinfo->x_highlight_frame
1107         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1108            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1109            : dpyinfo->x_focus_frame);
1110       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1111         {
1112           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1113           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1114         }
1115     }
1116   else
1117       dpyinfo->x_highlight_frame = 0;
1119   if (dpyinfo->x_highlight_frame &&
1120          dpyinfo->x_highlight_frame != old_highlight)
1121     {
1122       if (old_highlight)
1123         {
1124           x_update_cursor (old_highlight, 1);
1125           x_set_frame_alpha (old_highlight);
1126         }
1127       if (dpyinfo->x_highlight_frame)
1128         {
1129           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1130           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1131         }
1132     }
1136 void
1137 x_make_frame_visible (struct frame *f)
1138 /* --------------------------------------------------------------------------
1139      External: Show the window (X11 semantics)
1140    -------------------------------------------------------------------------- */
1142   NSTRACE (x_make_frame_visible);
1143   /* XXX: at some points in past this was not needed, as the only place that
1144      called this (frame.c:Fraise_frame ()) also called raise_lower;
1145      if this ends up the case again, comment this out again. */
1146   if (!FRAME_VISIBLE_P (f))
1147     {
1148       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1150       SET_FRAME_VISIBLE (f, 1);
1151       ns_raise_frame (f);
1153       /* Making a new frame from a fullscreen frame will make the new frame
1154          fullscreen also.  So skip handleFS as this will print an error.  */
1155       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1156           && [view isFullscreen])
1157         return;
1159       if (f->want_fullscreen != FULLSCREEN_NONE)
1160         {
1161           block_input ();
1162           [view handleFS];
1163           unblock_input ();
1164         }
1165     }
1169 void
1170 x_make_frame_invisible (struct frame *f)
1171 /* --------------------------------------------------------------------------
1172      External: Hide the window (X11 semantics)
1173    -------------------------------------------------------------------------- */
1175   NSView *view;
1176   NSTRACE (x_make_frame_invisible);
1177   check_window_system (f);
1178   view = FRAME_NS_VIEW (f);
1179   [[view window] orderOut: NSApp];
1180   SET_FRAME_VISIBLE (f, 0);
1181   SET_FRAME_ICONIFIED (f, 0);
1185 void
1186 x_iconify_frame (struct frame *f)
1187 /* --------------------------------------------------------------------------
1188      External: Iconify window
1189    -------------------------------------------------------------------------- */
1191   NSView *view;
1192   struct ns_display_info *dpyinfo;
1194   NSTRACE (x_iconify_frame);
1195   check_window_system (f);
1196   view = FRAME_NS_VIEW (f);
1197   dpyinfo = FRAME_DISPLAY_INFO (f);
1199   if (dpyinfo->x_highlight_frame == f)
1200     dpyinfo->x_highlight_frame = 0;
1202   if ([[view window] windowNumber] <= 0)
1203     {
1204       /* the window is still deferred.  Make it very small, bring it
1205          on screen and order it out. */
1206       NSRect s = { { 100, 100}, {0, 0} };
1207       NSRect t;
1208       t = [[view window] frame];
1209       [[view window] setFrame: s display: NO];
1210       [[view window] orderBack: NSApp];
1211       [[view window] orderOut: NSApp];
1212       [[view window] setFrame: t display: NO];
1213     }
1214   [[view window] miniaturize: NSApp];
1217 /* Free X resources of frame F.  */
1219 void
1220 x_free_frame_resources (struct frame *f)
1222   NSView *view;
1223   struct ns_display_info *dpyinfo;
1224   Mouse_HLInfo *hlinfo;
1226   NSTRACE (x_free_frame_resources);
1227   check_window_system (f);
1228   view = FRAME_NS_VIEW (f);
1229   dpyinfo = FRAME_DISPLAY_INFO (f);
1230   hlinfo = MOUSE_HL_INFO (f);
1232   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1234   block_input ();
1236   free_frame_menubar (f);
1237   free_frame_faces (f);
1239   if (f == dpyinfo->x_focus_frame)
1240     dpyinfo->x_focus_frame = 0;
1241   if (f == dpyinfo->x_highlight_frame)
1242     dpyinfo->x_highlight_frame = 0;
1243   if (f == hlinfo->mouse_face_mouse_frame)
1244     reset_mouse_highlight (hlinfo);
1246   if (f->output_data.ns->miniimage != nil)
1247     [f->output_data.ns->miniimage release];
1249   [[view window] close];
1250   [view release];
1252   xfree (f->output_data.ns);
1254   unblock_input ();
1257 void
1258 x_destroy_window (struct frame *f)
1259 /* --------------------------------------------------------------------------
1260      External: Delete the window
1261    -------------------------------------------------------------------------- */
1263   NSTRACE (x_destroy_window);
1264   check_window_system (f);
1265   x_free_frame_resources (f);
1266   ns_window_num--;
1270 void
1271 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1272 /* --------------------------------------------------------------------------
1273      External: Position the window
1274    -------------------------------------------------------------------------- */
1276   NSView *view = FRAME_NS_VIEW (f);
1277   NSArray *screens = [NSScreen screens];
1278   NSScreen *fscreen = [screens objectAtIndex: 0];
1279   NSScreen *screen = [[view window] screen];
1281   NSTRACE (x_set_offset);
1283   block_input ();
1285   f->left_pos = xoff;
1286   f->top_pos = yoff;
1288   if (view != nil && screen && fscreen)
1289     {
1290       f->left_pos = f->size_hint_flags & XNegative
1291         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1292         : f->left_pos;
1293       /* We use visibleFrame here to take menu bar into account.
1294          Ideally we should also adjust left/top with visibleFrame.origin.  */
1296       f->top_pos = f->size_hint_flags & YNegative
1297         ? ([screen visibleFrame].size.height + f->top_pos
1298            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1299            - FRAME_TOOLBAR_HEIGHT (f))
1300         : f->top_pos;
1301 #ifdef NS_IMPL_GNUSTEP
1302       if (f->left_pos < 100)
1303         f->left_pos = 100;  /* don't overlap menu */
1304 #endif
1305       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1306          menu bar.  */
1307       [[view window] setFrameTopLeftPoint:
1308                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1309                                     SCREENMAXBOUND ([fscreen frame].size.height
1310                                                     - NS_TOP_POS (f)))];
1311       f->size_hint_flags &= ~(XNegative|YNegative);
1312     }
1314   unblock_input ();
1318 void
1319 x_set_window_size (struct frame *f,
1320                    bool change_gravity,
1321                    int width,
1322                    int height,
1323                    bool pixelwise)
1324 /* --------------------------------------------------------------------------
1325      Adjust window pixel size based on given character grid size
1326      Impl is a bit more complex than other terms, need to do some
1327      internal clipping.
1328    -------------------------------------------------------------------------- */
1330   EmacsView *view = FRAME_NS_VIEW (f);
1331   NSWindow *window = [view window];
1332   NSRect wr = [window frame];
1333   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1334   int pixelwidth, pixelheight;
1335   int rows, cols;
1336   int orig_height = wr.size.height;
1338   NSTRACE (x_set_window_size);
1340   if (view == nil)
1341     return;
1343 /*fprintf (stderr, "\tsetWindowSize: %d x %d, pixelwise %d, font size %d x %d\n", width, height, pixelwise, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));*/
1345   block_input ();
1347   if (pixelwise)
1348     {
1349       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1350       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1351       cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1352       rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1353     }
1354   else
1355     {
1356       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1357       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1358       cols = width;
1359       rows = height;
1360     }
1362   /* If we have a toolbar, take its height into account. */
1363   if (tb && ! [view isFullscreen])
1364     {
1365     /* NOTE: previously this would generate wrong result if toolbar not
1366              yet displayed and fixing toolbar_height=32 helped, but
1367              now (200903) seems no longer needed */
1368     FRAME_TOOLBAR_HEIGHT (f) =
1369       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1370         - FRAME_NS_TITLEBAR_HEIGHT (f);
1371 #ifdef NS_IMPL_GNUSTEP
1372       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1373 #endif
1374     }
1375   else
1376     FRAME_TOOLBAR_HEIGHT (f) = 0;
1378   wr.size.width = pixelwidth + f->border_width;
1379   wr.size.height = pixelheight;
1380   if (! [view isFullscreen])
1381     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1382       + FRAME_TOOLBAR_HEIGHT (f);
1384   /* Do not try to constrain to this screen.  We may have multiple
1385      screens, and want Emacs to span those.  Constraining to screen
1386      prevents that, and that is not nice to the user.  */
1387  if (f->output_data.ns->zooming)
1388    f->output_data.ns->zooming = 0;
1389  else
1390    wr.origin.y += orig_height - wr.size.height;
1392   [view setRows: rows andColumns: cols];
1393   [window setFrame: wr display: YES];
1395   /* This is a trick to compensate for Emacs' managing the scrollbar area
1396      as a fixed number of standard character columns.  Instead of leaving
1397      blank space for the extra, we chopped it off above.  Now for
1398      left-hand scrollbars, we shift all rendering to the left by the
1399      difference between the real width and Emacs' imagined one.  For
1400      right-hand bars, don't worry about it since the extra is never used.
1401      (Obviously doesn't work for vertically split windows tho..) */
1402   {
1403     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1404       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1405                      - NS_SCROLL_BAR_WIDTH (f), 0)
1406       : NSMakePoint (0, 0);
1407     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1408     [view setBoundsOrigin: origin];
1409   }
1411   [view updateFrameSize: NO];
1412   unblock_input ();
1416 static void
1417 ns_fullscreen_hook (struct frame *f)
1419   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1421   if (!FRAME_VISIBLE_P (f))
1422     return;
1424    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1425     {
1426       /* Old style fs don't initiate correctly if created from
1427          init/default-frame alist, so use a timer (not nice...).
1428       */
1429       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1430                                      selector: @selector (handleFS)
1431                                      userInfo: nil repeats: NO];
1432       return;
1433     }
1435   block_input ();
1436   [view handleFS];
1437   unblock_input ();
1440 /* ==========================================================================
1442     Color management
1444    ========================================================================== */
1447 NSColor *
1448 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1450   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1451   if (idx < 1 || idx >= color_table->avail)
1452     return nil;
1453   return color_table->colors[idx];
1457 unsigned long
1458 ns_index_color (NSColor *color, struct frame *f)
1460   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1461   ptrdiff_t idx;
1462   ptrdiff_t i;
1464   if (!color_table->colors)
1465     {
1466       color_table->size = NS_COLOR_CAPACITY;
1467       color_table->avail = 1; /* skip idx=0 as marker */
1468       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1469       color_table->colors[0] = nil;
1470       color_table->empty_indices = [[NSMutableSet alloc] init];
1471     }
1473   /* Do we already have this color?  */
1474   for (i = 1; i < color_table->avail; i++)
1475     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1476       return i;
1478   if ([color_table->empty_indices count] > 0)
1479     {
1480       NSNumber *index = [color_table->empty_indices anyObject];
1481       [color_table->empty_indices removeObject: index];
1482       idx = [index unsignedLongValue];
1483     }
1484   else
1485     {
1486       if (color_table->avail == color_table->size)
1487         color_table->colors =
1488           xpalloc (color_table->colors, &color_table->size, 1,
1489                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1490       idx = color_table->avail++;
1491     }
1493   color_table->colors[idx] = color;
1494   [color retain];
1495 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1496   return idx;
1500 void
1501 ns_free_indexed_color (unsigned long idx, struct frame *f)
1503   struct ns_color_table *color_table;
1504   NSColor *color;
1505   NSNumber *index;
1507   if (!f)
1508     return;
1510   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1512   if (idx <= 0 || idx >= color_table->size) {
1513     message1 ("ns_free_indexed_color: Color index out of range.\n");
1514     return;
1515   }
1517   index = [NSNumber numberWithUnsignedInt: idx];
1518   if ([color_table->empty_indices containsObject: index]) {
1519     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1520     return;
1521   }
1523   color = color_table->colors[idx];
1524   [color release];
1525   color_table->colors[idx] = nil;
1526   [color_table->empty_indices addObject: index];
1527 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1531 static int
1532 ns_get_color (const char *name, NSColor **col)
1533 /* --------------------------------------------------------------------------
1534      Parse a color name
1535    -------------------------------------------------------------------------- */
1536 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1537    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1538    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1540   NSColor *new = nil;
1541   static char hex[20];
1542   int scaling = 0;
1543   float r = -1.0, g, b;
1544   NSString *nsname = [NSString stringWithUTF8String: name];
1546 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1547   block_input ();
1549   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1550     {
1551 #ifdef NS_IMPL_COCOA
1552       NSString *defname = [[NSUserDefaults standardUserDefaults]
1553                             stringForKey: @"AppleHighlightColor"];
1554       if (defname != nil)
1555         nsname = defname;
1556       else
1557 #endif
1558       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1559         {
1560           *col = [new colorUsingDefaultColorSpace];
1561           unblock_input ();
1562           return 0;
1563         }
1564       else
1565         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1567       name = [nsname UTF8String];
1568     }
1569   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1570     {
1571       /* NOTE: OSX applications normally don't set foreground selection, but
1572          text may be unreadable if we don't.
1573       */
1574       if ((new = [NSColor selectedTextColor]) != nil)
1575         {
1576           *col = [new colorUsingDefaultColorSpace];
1577           unblock_input ();
1578           return 0;
1579         }
1581       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1582       name = [nsname UTF8String];
1583     }
1585   /* First, check for some sort of numeric specification. */
1586   hex[0] = '\0';
1588   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1589     {
1590       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1591       [scanner scanFloat: &r];
1592       [scanner scanFloat: &g];
1593       [scanner scanFloat: &b];
1594     }
1595   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1596     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1597   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1598     {
1599       int len = (strlen(name) - 1);
1600       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1601       int i;
1602       scaling = strlen(name+start) / 3;
1603       for (i = 0; i < 3; i++)
1604         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1605                  name + start + i * scaling);
1606       hex[3 * (scaling + 1) - 1] = '\0';
1607     }
1609   if (hex[0])
1610     {
1611       int rr, gg, bb;
1612       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1613       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1614         {
1615           r = rr / fscale;
1616           g = gg / fscale;
1617           b = bb / fscale;
1618         }
1619     }
1621   if (r >= 0.0F)
1622     {
1623       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1624       unblock_input ();
1625       return 0;
1626     }
1628   /* Otherwise, color is expected to be from a list */
1629   {
1630     NSEnumerator *lenum, *cenum;
1631     NSString *name;
1632     NSColorList *clist;
1634 #ifdef NS_IMPL_GNUSTEP
1635     /* XXX: who is wrong, the requestor or the implementation? */
1636     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1637         == NSOrderedSame)
1638       nsname = @"highlightColor";
1639 #endif
1641     lenum = [[NSColorList availableColorLists] objectEnumerator];
1642     while ( (clist = [lenum nextObject]) && new == nil)
1643       {
1644         cenum = [[clist allKeys] objectEnumerator];
1645         while ( (name = [cenum nextObject]) && new == nil )
1646           {
1647             if ([name compare: nsname
1648                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1649               new = [clist colorWithKey: name];
1650           }
1651       }
1652   }
1654   if (new)
1655     *col = [new colorUsingDefaultColorSpace];
1656   unblock_input ();
1657   return new ? 0 : 1;
1662 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1663 /* --------------------------------------------------------------------------
1664      Convert a Lisp string object to a NS color
1665    -------------------------------------------------------------------------- */
1667   NSTRACE (ns_lisp_to_color);
1668   if (STRINGP (color))
1669     return ns_get_color (SSDATA (color), col);
1670   else if (SYMBOLP (color))
1671     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1672   return 1;
1676 Lisp_Object
1677 ns_color_to_lisp (NSColor *col)
1678 /* --------------------------------------------------------------------------
1679      Convert a color to a lisp string with the RGB equivalent
1680    -------------------------------------------------------------------------- */
1682   EmacsCGFloat red, green, blue, alpha, gray;
1683   char buf[1024];
1684   const char *str;
1685   NSTRACE (ns_color_to_lisp);
1687   block_input ();
1688   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1690       if ((str =[[col colorNameComponent] UTF8String]))
1691         {
1692           unblock_input ();
1693           return build_string ((char *)str);
1694         }
1696     [[col colorUsingDefaultColorSpace]
1697         getRed: &red green: &green blue: &blue alpha: &alpha];
1698   if (red == green && red == blue)
1699     {
1700       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1701             getWhite: &gray alpha: &alpha];
1702       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1703                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1704       unblock_input ();
1705       return build_string (buf);
1706     }
1708   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1709             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1711   unblock_input ();
1712   return build_string (buf);
1716 void
1717 ns_query_color(void *col, XColor *color_def, int setPixel)
1718 /* --------------------------------------------------------------------------
1719          Get ARGB values out of NSColor col and put them into color_def.
1720          If setPixel, set the pixel to a concatenated version.
1721          and set color_def pixel to the resulting index.
1722    -------------------------------------------------------------------------- */
1724   EmacsCGFloat r, g, b, a;
1726   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1727   color_def->red   = r * 65535;
1728   color_def->green = g * 65535;
1729   color_def->blue  = b * 65535;
1731   if (setPixel == YES)
1732     color_def->pixel
1733       = ARGB_TO_ULONG((int)(a*255),
1734                       (int)(r*255), (int)(g*255), (int)(b*255));
1738 bool
1739 ns_defined_color (struct frame *f,
1740                   const char *name,
1741                   XColor *color_def,
1742                   bool alloc,
1743                   bool makeIndex)
1744 /* --------------------------------------------------------------------------
1745          Return true if named color found, and set color_def rgb accordingly.
1746          If makeIndex and alloc are nonzero put the color in the color_table,
1747          and set color_def pixel to the resulting index.
1748          If makeIndex is zero, set color_def pixel to ARGB.
1749          Return false if not found
1750    -------------------------------------------------------------------------- */
1752   NSColor *col;
1753   NSTRACE (ns_defined_color);
1755   block_input ();
1756   if (ns_get_color (name, &col) != 0) /* Color not found  */
1757     {
1758       unblock_input ();
1759       return 0;
1760     }
1761   if (makeIndex && alloc)
1762     color_def->pixel = ns_index_color (col, f);
1763   ns_query_color (col, color_def, !makeIndex);
1764   unblock_input ();
1765   return 1;
1769 void
1770 x_set_frame_alpha (struct frame *f)
1771 /* --------------------------------------------------------------------------
1772      change the entire-frame transparency
1773    -------------------------------------------------------------------------- */
1775   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1776   double alpha = 1.0;
1777   double alpha_min = 1.0;
1779   if (dpyinfo->x_highlight_frame == f)
1780     alpha = f->alpha[0];
1781   else
1782     alpha = f->alpha[1];
1784   if (FLOATP (Vframe_alpha_lower_limit))
1785     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1786   else if (INTEGERP (Vframe_alpha_lower_limit))
1787     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1789   if (alpha < 0.0)
1790     return;
1791   else if (1.0 < alpha)
1792     alpha = 1.0;
1793   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1794     alpha = alpha_min;
1796 #ifdef NS_IMPL_COCOA
1797   {
1798     EmacsView *view = FRAME_NS_VIEW (f);
1799   [[view window] setAlphaValue: alpha];
1800   }
1801 #endif
1805 /* ==========================================================================
1807     Mouse handling
1809    ========================================================================== */
1812 void
1813 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1814 /* --------------------------------------------------------------------------
1815      Programmatically reposition mouse pointer in pixel coordinates
1816    -------------------------------------------------------------------------- */
1818   NSTRACE (frame_set_mouse_pixel_position);
1819   ns_raise_frame (f);
1820 #if 0
1821   /* FIXME: this does not work, and what about GNUstep? */
1822 #ifdef NS_IMPL_COCOA
1823   [FRAME_NS_VIEW (f) lockFocus];
1824   PSsetmouse ((float)pix_x, (float)pix_y);
1825   [FRAME_NS_VIEW (f) unlockFocus];
1826 #endif
1827 #endif
1830 static int
1831 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1832 /*   ------------------------------------------------------------------------
1833      Called by EmacsView on mouseMovement events.  Passes on
1834      to emacs mainstream code if we moved off of a rect of interest
1835      known as last_mouse_glyph.
1836      ------------------------------------------------------------------------ */
1838   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1839   NSRect *r;
1841 //  NSTRACE (note_mouse_movement);
1843   dpyinfo->last_mouse_motion_frame = frame;
1844   r = &dpyinfo->last_mouse_glyph;
1846   /* Note, this doesn't get called for enter/leave, since we don't have a
1847      position.  Those are taken care of in the corresponding NSView methods. */
1849   /* has movement gone beyond last rect we were tracking? */
1850   if (x < r->origin.x || x >= r->origin.x + r->size.width
1851       || y < r->origin.y || y >= r->origin.y + r->size.height)
1852     {
1853       ns_update_begin (frame);
1854       frame->mouse_moved = 1;
1855       note_mouse_highlight (frame, x, y);
1856       remember_mouse_glyph (frame, x, y, r);
1857       ns_update_end (frame);
1858       return 1;
1859     }
1861   return 0;
1865 static void
1866 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1867                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1868                    Time *time)
1869 /* --------------------------------------------------------------------------
1870     External (hook): inform emacs about mouse position and hit parts.
1871     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1872     x & y should be position in the scrollbar (the whole bar, not the handle)
1873     and length of scrollbar respectively
1874    -------------------------------------------------------------------------- */
1876   id view;
1877   NSPoint position;
1878   Lisp_Object frame, tail;
1879   struct frame *f;
1880   struct ns_display_info *dpyinfo;
1882   NSTRACE (ns_mouse_position);
1884   if (*fp == NULL)
1885     {
1886       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1887       return;
1888     }
1890   dpyinfo = FRAME_DISPLAY_INFO (*fp);
1892   block_input ();
1894   /* Clear the mouse-moved flag for every frame on this display.  */
1895   FOR_EACH_FRAME (tail, frame)
1896     if (FRAME_NS_P (XFRAME (frame))
1897         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1898       XFRAME (frame)->mouse_moved = 0;
1900   dpyinfo->last_mouse_scroll_bar = nil;
1901   if (dpyinfo->last_mouse_frame
1902       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
1903     f = dpyinfo->last_mouse_frame;
1904   else
1905     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
1907   if (f && FRAME_NS_P (f))
1908     {
1909       view = FRAME_NS_VIEW (*fp);
1911       position = [[view window] mouseLocationOutsideOfEventStream];
1912       position = [view convertPoint: position fromView: nil];
1913       remember_mouse_glyph (f, position.x, position.y,
1914                             &dpyinfo->last_mouse_glyph);
1915 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1917       if (bar_window) *bar_window = Qnil;
1918       if (part) *part = scroll_bar_above_handle;
1920       if (x) XSETINT (*x, lrint (position.x));
1921       if (y) XSETINT (*y, lrint (position.y));
1922       if (time)
1923         *time = dpyinfo->last_mouse_movement_time;
1924       *fp = f;
1925     }
1927   unblock_input ();
1931 static void
1932 ns_frame_up_to_date (struct frame *f)
1933 /* --------------------------------------------------------------------------
1934     External (hook): Fix up mouse highlighting right after a full update.
1935     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1936    -------------------------------------------------------------------------- */
1938   NSTRACE (ns_frame_up_to_date);
1940   if (FRAME_NS_P (f))
1941     {
1942       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1943       if (f == hlinfo->mouse_face_mouse_frame)
1944         {
1945           block_input ();
1946           ns_update_begin(f);
1947           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1948                                 hlinfo->mouse_face_mouse_x,
1949                                 hlinfo->mouse_face_mouse_y);
1950           ns_update_end(f);
1951           unblock_input ();
1952         }
1953     }
1957 static void
1958 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1959 /* --------------------------------------------------------------------------
1960     External (RIF): set frame mouse pointer type.
1961    -------------------------------------------------------------------------- */
1963   NSTRACE (ns_define_frame_cursor);
1964   if (FRAME_POINTER_TYPE (f) != cursor)
1965     {
1966       EmacsView *view = FRAME_NS_VIEW (f);
1967       FRAME_POINTER_TYPE (f) = cursor;
1968       [[view window] invalidateCursorRectsForView: view];
1969       /* Redisplay assumes this function also draws the changed frame
1970          cursor, but this function doesn't, so do it explicitly.  */
1971       x_update_cursor (f, 1);
1972     }
1977 /* ==========================================================================
1979     Keyboard handling
1981    ========================================================================== */
1984 static unsigned
1985 ns_convert_key (unsigned code)
1986 /* --------------------------------------------------------------------------
1987     Internal call used by NSView-keyDown.
1988    -------------------------------------------------------------------------- */
1990   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
1991   unsigned keysym;
1992   /* An array would be faster, but less easy to read. */
1993   for (keysym = 0; keysym < last_keysym; keysym += 2)
1994     if (code == convert_ns_to_X_keysym[keysym])
1995       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1996   return 0;
1997 /* if decide to use keyCode and Carbon table, use this line:
1998      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2002 char *
2003 x_get_keysym_name (int keysym)
2004 /* --------------------------------------------------------------------------
2005     Called by keyboard.c.  Not sure if the return val is important, except
2006     that it be unique.
2007    -------------------------------------------------------------------------- */
2009   static char value[16];
2010   NSTRACE (x_get_keysym_name);
2011   sprintf (value, "%d", keysym);
2012   return value;
2017 /* ==========================================================================
2019     Block drawing operations
2021    ========================================================================== */
2024 static void
2025 ns_redraw_scroll_bars (struct frame *f)
2027   int i;
2028   id view;
2029   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2030   NSTRACE (ns_redraw_scroll_bars);
2031   for (i =[subviews count]-1; i >= 0; i--)
2032     {
2033       view = [subviews objectAtIndex: i];
2034       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2035       [view display];
2036     }
2040 void
2041 ns_clear_frame (struct frame *f)
2042 /* --------------------------------------------------------------------------
2043       External (hook): Erase the entire frame
2044    -------------------------------------------------------------------------- */
2046   NSView *view = FRAME_NS_VIEW (f);
2047   NSRect r;
2049   NSTRACE (ns_clear_frame);
2051  /* comes on initial frame because we have
2052     after-make-frame-functions = select-frame */
2053  if (!FRAME_DEFAULT_FACE (f))
2054    return;
2056   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2058   r = [view bounds];
2060   block_input ();
2061   ns_focus (f, &r, 1);
2062   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2063   NSRectFill (r);
2064   ns_unfocus (f);
2066   /* as of 2006/11 or so this is now needed */
2067   ns_redraw_scroll_bars (f);
2068   unblock_input ();
2072 static void
2073 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2074 /* --------------------------------------------------------------------------
2075     External (RIF):  Clear section of frame
2076    -------------------------------------------------------------------------- */
2078   NSRect r = NSMakeRect (x, y, width, height);
2079   NSView *view = FRAME_NS_VIEW (f);
2080   struct face *face = FRAME_DEFAULT_FACE (f);
2082   if (!view || !face)
2083     return;
2085   NSTRACE (ns_clear_frame_area);
2087   r = NSIntersectionRect (r, [view frame]);
2088   ns_focus (f, &r, 1);
2089   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2091   NSRectFill (r);
2093   ns_unfocus (f);
2094   return;
2097 static void
2098 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2100   if (FRAME_NS_VIEW (f))
2101     {
2102       ns_focus (f, &dest, 1);
2103       [FRAME_NS_VIEW (f) scrollRect: src
2104                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2105                                                  dest.origin.y - src.origin.y)];
2106       ns_unfocus (f);
2107     }
2110 static void
2111 ns_scroll_run (struct window *w, struct run *run)
2112 /* --------------------------------------------------------------------------
2113     External (RIF):  Insert or delete n lines at line vpos
2114    -------------------------------------------------------------------------- */
2116   struct frame *f = XFRAME (w->frame);
2117   int x, y, width, height, from_y, to_y, bottom_y;
2119   NSTRACE (ns_scroll_run);
2121   /* begin copy from other terms */
2122   /* Get frame-relative bounding box of the text display area of W,
2123      without mode lines.  Include in this box the left and right
2124      fringe of W.  */
2125   window_box (w, ANY_AREA, &x, &y, &width, &height);
2127   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2128   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2129   bottom_y = y + height;
2131   if (to_y < from_y)
2132     {
2133       /* Scrolling up.  Make sure we don't copy part of the mode
2134          line at the bottom.  */
2135       if (from_y + run->height > bottom_y)
2136         height = bottom_y - from_y;
2137       else
2138         height = run->height;
2139     }
2140   else
2141     {
2142       /* Scrolling down.  Make sure we don't copy over the mode line.
2143          at the bottom.  */
2144       if (to_y + run->height > bottom_y)
2145         height = bottom_y - to_y;
2146       else
2147         height = run->height;
2148     }
2149   /* end copy from other terms */
2151   if (height == 0)
2152       return;
2154   block_input ();
2156   x_clear_cursor (w);
2158   {
2159     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2160     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2162     ns_copy_bits (f, srcRect , dstRect);
2163   }
2165   unblock_input ();
2169 static void
2170 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2171 /* --------------------------------------------------------------------------
2172     External (RIF): preparatory to fringe update after text was updated
2173    -------------------------------------------------------------------------- */
2175   struct frame *f;
2176   int width, height;
2178   NSTRACE (ns_after_update_window_line);
2180   /* begin copy from other terms */
2181   eassert (w);
2183   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2184     desired_row->redraw_fringe_bitmaps_p = 1;
2186   /* When a window has disappeared, make sure that no rest of
2187      full-width rows stays visible in the internal border.  */
2188   if (windows_or_buffers_changed
2189       && desired_row->full_width_p
2190       && (f = XFRAME (w->frame),
2191           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2192           width != 0)
2193       && (height = desired_row->visible_height,
2194           height > 0))
2195     {
2196       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2198       block_input ();
2199       ns_clear_frame_area (f, 0, y, width, height);
2200       ns_clear_frame_area (f,
2201                            FRAME_PIXEL_WIDTH (f) - width,
2202                            y, width, height);
2203       unblock_input ();
2204     }
2208 static void
2209 ns_shift_glyphs_for_insert (struct frame *f,
2210                            int x, int y, int width, int height,
2211                            int shift_by)
2212 /* --------------------------------------------------------------------------
2213     External (RIF): copy an area horizontally, don't worry about clearing src
2214    -------------------------------------------------------------------------- */
2216   NSRect srcRect = NSMakeRect (x, y, width, height);
2217   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2219   NSTRACE (ns_shift_glyphs_for_insert);
2221   ns_copy_bits (f, srcRect, dstRect);
2226 /* ==========================================================================
2228     Character encoding and metrics
2230    ========================================================================== */
2233 static void
2234 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2235 /* --------------------------------------------------------------------------
2236      External (RIF); compute left/right overhang of whole string and set in s
2237    -------------------------------------------------------------------------- */
2239   struct font *font = s->font;
2241   if (s->char2b)
2242     {
2243       struct font_metrics metrics;
2244       unsigned int codes[2];
2245       codes[0] = *(s->char2b);
2246       codes[1] = *(s->char2b + s->nchars - 1);
2248       font->driver->text_extents (font, codes, 2, &metrics);
2249       s->left_overhang = -metrics.lbearing;
2250       s->right_overhang
2251         = metrics.rbearing > metrics.width
2252         ? metrics.rbearing - metrics.width : 0;
2253     }
2254   else
2255     {
2256       s->left_overhang = 0;
2257       if (EQ (font->driver->type, Qns))
2258         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2259           FONT_HEIGHT (font) * 0.2 : 0;
2260       else
2261         s->right_overhang = 0;
2262     }
2267 /* ==========================================================================
2269     Fringe and cursor drawing
2271    ========================================================================== */
2274 extern int max_used_fringe_bitmap;
2275 static void
2276 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2277                       struct draw_fringe_bitmap_params *p)
2278 /* --------------------------------------------------------------------------
2279     External (RIF); fringe-related
2280    -------------------------------------------------------------------------- */
2282   struct frame *f = XFRAME (WINDOW_FRAME (w));
2283   struct face *face = p->face;
2284   static EmacsImage **bimgs = NULL;
2285   static int nBimgs = 0;
2287   /* grow bimgs if needed */
2288   if (nBimgs < max_used_fringe_bitmap)
2289     {
2290       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2291       memset (bimgs + nBimgs, 0,
2292               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2293       nBimgs = max_used_fringe_bitmap;
2294     }
2296   /* Must clip because of partially visible lines.  */
2297   ns_clip_to_row (w, row, ANY_AREA, YES);
2299   if (!p->overlay_p)
2300     {
2301       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2303       if (bx >= 0 && nx > 0)
2304         {
2305           NSRect r = NSMakeRect (bx, by, nx, ny);
2306           NSRectClip (r);
2307           [ns_lookup_indexed_color (face->background, f) set];
2308           NSRectFill (r);
2309         }
2310     }
2312   if (p->which)
2313     {
2314       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2315       EmacsImage *img = bimgs[p->which - 1];
2317       if (!img)
2318         {
2319           unsigned short *bits = p->bits + p->dh;
2320           int len = p->h;
2321           int i;
2322           unsigned char *cbits = xmalloc (len);
2324           for (i = 0; i < len; i++)
2325             cbits[i] = ~(bits[i] & 0xff);
2326           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2327                                              fg: 0 bg: 0];
2328           bimgs[p->which - 1] = img;
2329           xfree (cbits);
2330         }
2332       NSRectClip (r);
2333       /* Since we composite the bitmap instead of just blitting it, we need
2334          to erase the whole background. */
2335       [ns_lookup_indexed_color(face->background, f) set];
2336       NSRectFill (r);
2338       {
2339         NSColor *bm_color;
2340         if (!p->cursor_p)
2341           bm_color = ns_lookup_indexed_color(face->foreground, f);
2342         else if (p->overlay_p)
2343           bm_color = ns_lookup_indexed_color(face->background, f);
2344         else
2345           bm_color = f->output_data.ns->cursor_color;
2346         [img setXBMColor: bm_color];
2347       }
2349 #ifdef NS_IMPL_COCOA
2350       [img drawInRect: r
2351               fromRect: NSZeroRect
2352              operation: NSCompositeSourceOver
2353               fraction: 1.0
2354            respectFlipped: YES
2355                 hints: nil];
2356 #else
2357       {
2358         NSPoint pt = r.origin;
2359         pt.y += p->h;
2360         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2361       }
2362 #endif
2363     }
2364   ns_unfocus (f);
2368 static void
2369 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2370                        int x, int y, enum text_cursor_kinds cursor_type,
2371                        int cursor_width, bool on_p, bool active_p)
2372 /* --------------------------------------------------------------------------
2373      External call (RIF): draw cursor.
2374      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2375    -------------------------------------------------------------------------- */
2377   NSRect r, s;
2378   int fx, fy, h, cursor_height;
2379   struct frame *f = WINDOW_XFRAME (w);
2380   struct glyph *phys_cursor_glyph;
2381   struct glyph *cursor_glyph;
2382   struct face *face;
2383   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2385   /* If cursor is out of bounds, don't draw garbage.  This can happen
2386      in mini-buffer windows when switching between echo area glyphs
2387      and mini-buffer.  */
2389   NSTRACE (dumpcursor);
2391   if (!on_p)
2392     return;
2394   w->phys_cursor_type = cursor_type;
2395   w->phys_cursor_on_p = on_p;
2397   if (cursor_type == NO_CURSOR)
2398     {
2399       w->phys_cursor_width = 0;
2400       return;
2401     }
2403   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2404     {
2405       if (glyph_row->exact_window_width_line_p
2406           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2407         {
2408           glyph_row->cursor_in_fringe_p = 1;
2409           draw_fringe_bitmap (w, glyph_row, 0);
2410         }
2411       return;
2412     }
2414   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2415      (other terminals do it the other way round).  We must set
2416      w->phys_cursor_width to the cursor width.  For bar cursors, that
2417      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2418   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2420   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2421      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2422   if (cursor_type == BAR_CURSOR)
2423     {
2424       if (cursor_width < 1)
2425         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2426       w->phys_cursor_width = cursor_width;
2427     }
2428   /* If we have an HBAR, "cursor_width" MAY specify height. */
2429   else if (cursor_type == HBAR_CURSOR)
2430     {
2431       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2432       if (cursor_height > glyph_row->height)
2433         cursor_height = glyph_row->height;
2434       if (h > cursor_height) // Cursor smaller than line height, move down
2435         fy += h - cursor_height;
2436       h = cursor_height;
2437     }
2439   r.origin.x = fx, r.origin.y = fy;
2440   r.size.height = h;
2441   r.size.width = w->phys_cursor_width;
2443   /* TODO: only needed in rare cases with last-resort font in HELLO..
2444      should we do this more efficiently? */
2445   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2448   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2449   if (face && NS_FACE_BACKGROUND (face)
2450       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2451     {
2452       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2453       hollow_color = FRAME_CURSOR_COLOR (f);
2454     }
2455   else
2456     [FRAME_CURSOR_COLOR (f) set];
2458 #ifdef NS_IMPL_COCOA
2459   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2460            atomic.  Cleaner ways of doing this should be investigated.
2461            One way would be to set a global variable DRAWING_CURSOR
2462            when making the call to draw_phys..(), don't focus in that
2463            case, then move the ns_unfocus() here after that call. */
2464   NSDisableScreenUpdates ();
2465 #endif
2467   switch (cursor_type)
2468     {
2469     case DEFAULT_CURSOR:
2470     case NO_CURSOR:
2471       break;
2472     case FILLED_BOX_CURSOR:
2473       NSRectFill (r);
2474       break;
2475     case HOLLOW_BOX_CURSOR:
2476       NSRectFill (r);
2477       [hollow_color set];
2478       NSRectFill (NSInsetRect (r, 1, 1));
2479       [FRAME_CURSOR_COLOR (f) set];
2480       break;
2481     case HBAR_CURSOR:
2482       NSRectFill (r);
2483       break;
2484     case BAR_CURSOR:
2485       s = r;
2486       /* If the character under cursor is R2L, draw the bar cursor
2487          on the right of its glyph, rather than on the left.  */
2488       cursor_glyph = get_phys_cursor_glyph (w);
2489       if ((cursor_glyph->resolved_level & 1) != 0)
2490         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2492       NSRectFill (s);
2493       break;
2494     }
2495   ns_unfocus (f);
2497   /* draw the character under the cursor */
2498   if (cursor_type != NO_CURSOR)
2499     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2501 #ifdef NS_IMPL_COCOA
2502   NSEnableScreenUpdates ();
2503 #endif
2508 static void
2509 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2510 /* --------------------------------------------------------------------------
2511      External (RIF): Draw a vertical line.
2512    -------------------------------------------------------------------------- */
2514   struct frame *f = XFRAME (WINDOW_FRAME (w));
2515   struct face *face;
2516   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2518   NSTRACE (ns_draw_vertical_window_border);
2520   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2521   if (face)
2522       [ns_lookup_indexed_color(face->foreground, f) set];
2524   ns_focus (f, &r, 1);
2525   NSRectFill(r);
2526   ns_unfocus (f);
2530 static void
2531 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2532 /* --------------------------------------------------------------------------
2533      External (RIF): Draw a window divider.
2534    -------------------------------------------------------------------------- */
2536   struct frame *f = XFRAME (WINDOW_FRAME (w));
2537   struct face *face;
2538   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2540   NSTRACE (ns_draw_window_divider);
2542   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2543   if (face)
2544       [ns_lookup_indexed_color(face->foreground, f) set];
2546   ns_focus (f, &r, 1);
2547   NSRectFill(r);
2548   ns_unfocus (f);
2551 static void
2552 ns_show_hourglass (struct frame *f)
2554   /* TODO: add NSProgressIndicator to all frames.  */
2557 static void
2558 ns_hide_hourglass (struct frame *f)
2560   /* TODO: remove NSProgressIndicator from all frames.  */
2563 /* ==========================================================================
2565     Glyph drawing operations
2567    ========================================================================== */
2569 static int
2570 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2571 /* --------------------------------------------------------------------------
2572     Wrapper utility to account for internal border width on full-width lines,
2573     and allow top full-width rows to hit the frame top.  nr should be pointer
2574     to two successive NSRects.  Number of rects actually used is returned.
2575    -------------------------------------------------------------------------- */
2577   int n = get_glyph_string_clip_rects (s, nr, 2);
2578   return n;
2581 /* --------------------------------------------------------------------
2582    Draw a wavy line under glyph string s. The wave fills wave_height
2583    pixels from y.
2585                     x          wave_length = 2
2586                                  --
2587                 y    *   *   *   *   *
2588                      |* * * * * * * * *
2589     wave_height = 3  | *   *   *   *
2590   --------------------------------------------------------------------- */
2592 static void
2593 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2595   int wave_height = 3, wave_length = 2;
2596   int y, dx, dy, odd, xmax;
2597   NSPoint a, b;
2598   NSRect waveClip;
2600   dx = wave_length;
2601   dy = wave_height - 1;
2602   y =  s->ybase - wave_height + 3;
2603   xmax = x + width;
2605   /* Find and set clipping rectangle */
2606   waveClip = NSMakeRect (x, y, width, wave_height);
2607   [[NSGraphicsContext currentContext] saveGraphicsState];
2608   NSRectClip (waveClip);
2610   /* Draw the waves */
2611   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2612   b.x = a.x + dx;
2613   odd = (int)(a.x/dx) % 2;
2614   a.y = b.y = y + 0.5;
2616   if (odd)
2617     a.y += dy;
2618   else
2619     b.y += dy;
2621   while (a.x <= xmax)
2622     {
2623       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2624       a.x = b.x, a.y = b.y;
2625       b.x += dx, b.y = y + 0.5 + odd*dy;
2626       odd = !odd;
2627     }
2629   /* Restore previous clipping rectangle(s) */
2630   [[NSGraphicsContext currentContext] restoreGraphicsState];
2635 void
2636 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2637                          NSColor *defaultCol, CGFloat width, CGFloat x)
2638 /* --------------------------------------------------------------------------
2639    Draw underline, overline, and strike-through on glyph string s.
2640    -------------------------------------------------------------------------- */
2642   if (s->for_overlaps)
2643     return;
2645   /* Do underline. */
2646   if (face->underline_p)
2647     {
2648       if (s->face->underline_type == FACE_UNDER_WAVE)
2649         {
2650           if (face->underline_defaulted_p)
2651             [defaultCol set];
2652           else
2653             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2655           ns_draw_underwave (s, width, x);
2656         }
2657       else if (s->face->underline_type == FACE_UNDER_LINE)
2658         {
2660           NSRect r;
2661           unsigned long thickness, position;
2663           /* If the prev was underlined, match its appearance. */
2664           if (s->prev && s->prev->face->underline_p
2665               && s->prev->face->underline_type == FACE_UNDER_LINE
2666               && s->prev->underline_thickness > 0)
2667             {
2668               thickness = s->prev->underline_thickness;
2669               position = s->prev->underline_position;
2670             }
2671           else
2672             {
2673               struct font *font;
2674               unsigned long descent;
2676               font=s->font;
2677               descent = s->y + s->height - s->ybase;
2679               /* Use underline thickness of font, defaulting to 1. */
2680               thickness = (font && font->underline_thickness > 0)
2681                 ? font->underline_thickness : 1;
2683               /* Determine the offset of underlining from the baseline. */
2684               if (x_underline_at_descent_line)
2685                 position = descent - thickness;
2686               else if (x_use_underline_position_properties
2687                        && font && font->underline_position >= 0)
2688                 position = font->underline_position;
2689               else if (font)
2690                 position = lround (font->descent / 2);
2691               else
2692                 position = underline_minimum_offset;
2694               position = max (position, underline_minimum_offset);
2696               /* Ensure underlining is not cropped. */
2697               if (descent <= position)
2698                 {
2699                   position = descent - 1;
2700                   thickness = 1;
2701                 }
2702               else if (descent < position + thickness)
2703                 thickness = 1;
2704             }
2706           s->underline_thickness = thickness;
2707           s->underline_position = position;
2709           r = NSMakeRect (x, s->ybase + position, width, thickness);
2711           if (face->underline_defaulted_p)
2712             [defaultCol set];
2713           else
2714             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2715           NSRectFill (r);
2716         }
2717     }
2718   /* Do overline. We follow other terms in using a thickness of 1
2719      and ignoring overline_margin. */
2720   if (face->overline_p)
2721     {
2722       NSRect r;
2723       r = NSMakeRect (x, s->y, width, 1);
2725       if (face->overline_color_defaulted_p)
2726         [defaultCol set];
2727       else
2728         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2729       NSRectFill (r);
2730     }
2732   /* Do strike-through.  We follow other terms for thickness and
2733      vertical position.*/
2734   if (face->strike_through_p)
2735     {
2736       NSRect r;
2737       unsigned long dy;
2739       dy = lrint ((s->height - 1) / 2);
2740       r = NSMakeRect (x, s->y + dy, width, 1);
2742       if (face->strike_through_color_defaulted_p)
2743         [defaultCol set];
2744       else
2745         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2746       NSRectFill (r);
2747     }
2750 static void
2751 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2752              char left_p, char right_p)
2753 /* --------------------------------------------------------------------------
2754     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2755     Note we can't just use an NSDrawRect command, because of the possibility
2756     of some sides not being drawn, and because the rect will be filled.
2757    -------------------------------------------------------------------------- */
2759   NSRect s = r;
2760   [col set];
2762   /* top, bottom */
2763   s.size.height = thickness;
2764   NSRectFill (s);
2765   s.origin.y += r.size.height - thickness;
2766   NSRectFill (s);
2768   s.size.height = r.size.height;
2769   s.origin.y = r.origin.y;
2771   /* left, right (optional) */
2772   s.size.width = thickness;
2773   if (left_p)
2774     NSRectFill (s);
2775   if (right_p)
2776     {
2777       s.origin.x += r.size.width - thickness;
2778       NSRectFill (s);
2779     }
2783 static void
2784 ns_draw_relief (NSRect r, int thickness, char raised_p,
2785                char top_p, char bottom_p, char left_p, char right_p,
2786                struct glyph_string *s)
2787 /* --------------------------------------------------------------------------
2788     Draw a relief rect inside r, optionally leaving some sides open.
2789     Note we can't just use an NSDrawBezel command, because of the possibility
2790     of some sides not being drawn, and because the rect will be filled.
2791    -------------------------------------------------------------------------- */
2793   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2794   NSColor *newBaseCol = nil;
2795   NSRect sr = r;
2797   NSTRACE (ns_draw_relief);
2799   /* set up colors */
2801   if (s->face->use_box_color_for_shadows_p)
2802     {
2803       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2804     }
2805 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2806            && s->img->pixmap
2807            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2808        {
2809          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2810        } */
2811   else
2812     {
2813       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2814     }
2816   if (newBaseCol == nil)
2817     newBaseCol = [NSColor grayColor];
2819   if (newBaseCol != baseCol)  /* TODO: better check */
2820     {
2821       [baseCol release];
2822       baseCol = [newBaseCol retain];
2823       [lightCol release];
2824       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2825       [darkCol release];
2826       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2827     }
2829   [(raised_p ? lightCol : darkCol) set];
2831   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2833   /* top */
2834   sr.size.height = thickness;
2835   if (top_p) NSRectFill (sr);
2837   /* left */
2838   sr.size.height = r.size.height;
2839   sr.size.width = thickness;
2840   if (left_p) NSRectFill (sr);
2842   [(raised_p ? darkCol : lightCol) set];
2844   /* bottom */
2845   sr.size.width = r.size.width;
2846   sr.size.height = thickness;
2847   sr.origin.y += r.size.height - thickness;
2848   if (bottom_p) NSRectFill (sr);
2850   /* right */
2851   sr.size.height = r.size.height;
2852   sr.origin.y = r.origin.y;
2853   sr.size.width = thickness;
2854   sr.origin.x += r.size.width - thickness;
2855   if (right_p) NSRectFill (sr);
2859 static void
2860 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2861 /* --------------------------------------------------------------------------
2862       Function modeled after x_draw_glyph_string_box ().
2863       Sets up parameters for drawing.
2864    -------------------------------------------------------------------------- */
2866   int right_x, last_x;
2867   char left_p, right_p;
2868   struct glyph *last_glyph;
2869   NSRect r;
2870   int thickness;
2871   struct face *face;
2873   if (s->hl == DRAW_MOUSE_FACE)
2874     {
2875       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2876       if (!face)
2877         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2878     }
2879   else
2880     face = s->face;
2882   thickness = face->box_line_width;
2884   NSTRACE (ns_dumpglyphs_box_or_relief);
2886   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2887             ? WINDOW_RIGHT_EDGE_X (s->w)
2888             : window_box_right (s->w, s->area));
2889   last_glyph = (s->cmp || s->img
2890                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2892   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2893               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2895   left_p = (s->first_glyph->left_box_line_p
2896             || (s->hl == DRAW_MOUSE_FACE
2897                 && (s->prev == NULL || s->prev->hl != s->hl)));
2898   right_p = (last_glyph->right_box_line_p
2899              || (s->hl == DRAW_MOUSE_FACE
2900                  && (s->next == NULL || s->next->hl != s->hl)));
2902   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2904   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2905   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2906     {
2907       ns_draw_box (r, abs (thickness),
2908                    ns_lookup_indexed_color (face->box_color, s->f),
2909                   left_p, right_p);
2910     }
2911   else
2912     {
2913       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2914                      1, 1, left_p, right_p, s);
2915     }
2919 static void
2920 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2921 /* --------------------------------------------------------------------------
2922       Modeled after x_draw_glyph_string_background, which draws BG in
2923       certain cases.  Others are left to the text rendering routine.
2924    -------------------------------------------------------------------------- */
2926   NSTRACE (ns_maybe_dumpglyphs_background);
2928   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2929     {
2930       int box_line_width = max (s->face->box_line_width, 0);
2931       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2932           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
2933              dimensions, since the actual glyphs might be much
2934              smaller.  So in that case we always clear the rectangle
2935              with background color.  */
2936           || FONT_TOO_HIGH (s->font)
2937           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2938         {
2939           struct face *face;
2940           if (s->hl == DRAW_MOUSE_FACE)
2941             {
2942               face = FACE_FROM_ID (s->f,
2943                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2944               if (!face)
2945                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2946             }
2947           else
2948             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2949           if (!face->stipple)
2950             [(NS_FACE_BACKGROUND (face) != 0
2951               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2952               : FRAME_BACKGROUND_COLOR (s->f)) set];
2953           else
2954             {
2955               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
2956               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2957             }
2959           if (s->hl != DRAW_CURSOR)
2960             {
2961               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2962                                     s->background_width,
2963                                     s->height-2*box_line_width);
2964               NSRectFill (r);
2965             }
2967           s->background_filled_p = 1;
2968         }
2969     }
2973 static void
2974 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2975 /* --------------------------------------------------------------------------
2976       Renders an image and associated borders.
2977    -------------------------------------------------------------------------- */
2979   EmacsImage *img = s->img->pixmap;
2980   int box_line_vwidth = max (s->face->box_line_width, 0);
2981   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2982   int bg_x, bg_y, bg_height;
2983   int th;
2984   char raised_p;
2985   NSRect br;
2986   struct face *face;
2987   NSColor *tdCol;
2989   NSTRACE (ns_dumpglyphs_image);
2991   if (s->face->box != FACE_NO_BOX
2992       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2993     x += abs (s->face->box_line_width);
2995   bg_x = x;
2996   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2997   bg_height = s->height;
2998   /* other terms have this, but was causing problems w/tabbar mode */
2999   /* - 2 * box_line_vwidth; */
3001   if (s->slice.x == 0) x += s->img->hmargin;
3002   if (s->slice.y == 0) y += s->img->vmargin;
3004   /* Draw BG: if we need larger area than image itself cleared, do that,
3005      otherwise, since we composite the image under NS (instead of mucking
3006      with its background color), we must clear just the image area. */
3007   if (s->hl == DRAW_MOUSE_FACE)
3008     {
3009       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3010       if (!face)
3011        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3012     }
3013   else
3014     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3016   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3018   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3019       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3020     {
3021       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3022       s->background_filled_p = 1;
3023     }
3024   else
3025     {
3026       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3027     }
3029   NSRectFill (br);
3031   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3032   if (img != nil)
3033     {
3034 #ifdef NS_IMPL_COCOA
3035       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3036       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3037                               s->slice.width, s->slice.height);
3038       [img drawInRect: dr
3039              fromRect: ir
3040              operation: NSCompositeSourceOver
3041               fraction: 1.0
3042            respectFlipped: YES
3043                 hints: nil];
3044 #else
3045       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3046                   operation: NSCompositeSourceOver];
3047 #endif
3048     }
3050   if (s->hl == DRAW_CURSOR)
3051     {
3052     [FRAME_CURSOR_COLOR (s->f) set];
3053     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3054       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3055     else
3056       /* Currently on NS img->mask is always 0. Since
3057          get_window_cursor_type specifies a hollow box cursor when on
3058          a non-masked image we never reach this clause. But we put it
3059          in in anticipation of better support for image masks on
3060          NS. */
3061       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3062     }
3063   else
3064     {
3065       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3066     }
3068   /* Draw underline, overline, strike-through. */
3069   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3071   /* Draw relief, if requested */
3072   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3073     {
3074       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3075         {
3076           th = tool_bar_button_relief >= 0 ?
3077             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3078           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3079         }
3080       else
3081         {
3082           th = abs (s->img->relief);
3083           raised_p = (s->img->relief > 0);
3084         }
3086       r.origin.x = x - th;
3087       r.origin.y = y - th;
3088       r.size.width = s->slice.width + 2*th-1;
3089       r.size.height = s->slice.height + 2*th-1;
3090       ns_draw_relief (r, th, raised_p,
3091                       s->slice.y == 0,
3092                       s->slice.y + s->slice.height == s->img->height,
3093                       s->slice.x == 0,
3094                       s->slice.x + s->slice.width == s->img->width, s);
3095     }
3097   /* If there is no mask, the background won't be seen,
3098      so draw a rectangle on the image for the cursor.
3099      Do this for all images, getting transparency right is not reliable.  */
3100   if (s->hl == DRAW_CURSOR)
3101     {
3102       int thickness = abs (s->img->relief);
3103       if (thickness == 0) thickness = 1;
3104       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3105     }
3109 static void
3110 ns_dumpglyphs_stretch (struct glyph_string *s)
3112   NSRect r[2];
3113   int n, i;
3114   struct face *face;
3115   NSColor *fgCol, *bgCol;
3117   if (!s->background_filled_p)
3118     {
3119       n = ns_get_glyph_string_clip_rect (s, r);
3120       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3122       ns_focus (s->f, r, n);
3124       if (s->hl == DRAW_MOUSE_FACE)
3125        {
3126          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3127          if (!face)
3128            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3129        }
3130       else
3131        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3133       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3134       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3136       for (i = 0; i < n; ++i)
3137         {
3138           if (!s->row->full_width_p)
3139             {
3140               int overrun, leftoverrun;
3142               /* truncate to avoid overwriting fringe and/or scrollbar */
3143               overrun = max (0, (s->x + s->background_width)
3144                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3145                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3146               r[i].size.width -= overrun;
3148               /* truncate to avoid overwriting to left of the window box */
3149               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3150                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3152               if (leftoverrun > 0)
3153                 {
3154                   r[i].origin.x += leftoverrun;
3155                   r[i].size.width -= leftoverrun;
3156                 }
3158               /* XXX: Try to work between problem where a stretch glyph on
3159                  a partially-visible bottom row will clear part of the
3160                  modeline, and another where list-buffers headers and similar
3161                  rows erroneously have visible_height set to 0.  Not sure
3162                  where this is coming from as other terms seem not to show. */
3163               r[i].size.height = min (s->height, s->row->visible_height);
3164             }
3166           [bgCol set];
3168           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3169              overwriting cursor (usually when cursor on a tab) */
3170           if (s->hl == DRAW_CURSOR)
3171             {
3172               CGFloat x, width;
3174               x = r[i].origin.x;
3175               width = s->w->phys_cursor_width;
3176               r[i].size.width -= width;
3177               r[i].origin.x += width;
3179               NSRectFill (r[i]);
3181               /* Draw overlining, etc. on the cursor. */
3182               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3183                 ns_draw_text_decoration (s, face, bgCol, width, x);
3184               else
3185                 ns_draw_text_decoration (s, face, fgCol, width, x);
3186             }
3187           else
3188             {
3189               NSRectFill (r[i]);
3190             }
3192           /* Draw overlining, etc. on the stretch glyph (or the part
3193              of the stretch glyph after the cursor). */
3194           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3195                                    r[i].origin.x);
3196         }
3197       ns_unfocus (s->f);
3198       s->background_filled_p = 1;
3199     }
3203 static void
3204 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3206   int i, j, x;
3207   struct font *font = s->font;
3209   /* If first glyph of S has a left box line, start drawing the text
3210      of S to the right of that box line.  */
3211   if (s->face && s->face->box != FACE_NO_BOX
3212       && s->first_glyph->left_box_line_p)
3213     x = s->x + eabs (s->face->box_line_width);
3214   else
3215     x = s->x;
3217   /* S is a glyph string for a composition.  S->cmp_from is the index
3218      of the first character drawn for glyphs of this composition.
3219      S->cmp_from == 0 means we are drawing the very first character of
3220      this composition.  */
3222   /* Draw a rectangle for the composition if the font for the very
3223      first character of the composition could not be loaded.  */
3224   if (s->font_not_found_p)
3225     {
3226       if (s->cmp_from == 0)
3227         {
3228           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3229           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3230         }
3231     }
3232   else if (! s->first_glyph->u.cmp.automatic)
3233     {
3234       int y = s->ybase;
3236       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3237         /* TAB in a composition means display glyphs with padding
3238            space on the left or right.  */
3239         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3240           {
3241             int xx = x + s->cmp->offsets[j * 2];
3242             int yy = y - s->cmp->offsets[j * 2 + 1];
3244             font->driver->draw (s, j, j + 1, xx, yy, false);
3245             if (s->face->overstrike)
3246               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3247           }
3248     }
3249   else
3250     {
3251       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3252       Lisp_Object glyph;
3253       int y = s->ybase;
3254       int width = 0;
3256       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3257         {
3258           glyph = LGSTRING_GLYPH (gstring, i);
3259           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3260             width += LGLYPH_WIDTH (glyph);
3261           else
3262             {
3263               int xoff, yoff, wadjust;
3265               if (j < i)
3266                 {
3267                   font->driver->draw (s, j, i, x, y, false);
3268                   if (s->face->overstrike)
3269                     font->driver->draw (s, j, i, x + 1, y, false);
3270                   x += width;
3271                 }
3272               xoff = LGLYPH_XOFF (glyph);
3273               yoff = LGLYPH_YOFF (glyph);
3274               wadjust = LGLYPH_WADJUST (glyph);
3275               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3276               if (s->face->overstrike)
3277                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3278                                     false);
3279               x += wadjust;
3280               j = i + 1;
3281               width = 0;
3282             }
3283         }
3284       if (j < i)
3285         {
3286           font->driver->draw (s, j, i, x, y, false);
3287           if (s->face->overstrike)
3288             font->driver->draw (s, j, i, x + 1, y, false);
3289         }
3290     }
3293 static void
3294 ns_draw_glyph_string (struct glyph_string *s)
3295 /* --------------------------------------------------------------------------
3296       External (RIF): Main draw-text call.
3297    -------------------------------------------------------------------------- */
3299   /* TODO (optimize): focus for box and contents draw */
3300   NSRect r[2];
3301   int n, flags;
3302   char box_drawn_p = 0;
3303   struct font *font = s->face->font;
3304   if (! font) font = FRAME_FONT (s->f);
3306   NSTRACE (ns_draw_glyph_string);
3308   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3309     {
3310       int width;
3311       struct glyph_string *next;
3313       for (width = 0, next = s->next;
3314            next && width < s->right_overhang;
3315            width += next->width, next = next->next)
3316         if (next->first_glyph->type != IMAGE_GLYPH)
3317           {
3318             if (next->first_glyph->type != STRETCH_GLYPH)
3319               {
3320                 n = ns_get_glyph_string_clip_rect (s->next, r);
3321                 ns_focus (s->f, r, n);
3322                 ns_maybe_dumpglyphs_background (s->next, 1);
3323                 ns_unfocus (s->f);
3324               }
3325             else
3326               {
3327                 ns_dumpglyphs_stretch (s->next);
3328               }
3329             next->num_clips = 0;
3330           }
3331     }
3333   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3334         && (s->first_glyph->type == CHAR_GLYPH
3335             || s->first_glyph->type == COMPOSITE_GLYPH))
3336     {
3337       n = ns_get_glyph_string_clip_rect (s, r);
3338       ns_focus (s->f, r, n);
3339       ns_maybe_dumpglyphs_background (s, 1);
3340       ns_dumpglyphs_box_or_relief (s);
3341       ns_unfocus (s->f);
3342       box_drawn_p = 1;
3343     }
3345   switch (s->first_glyph->type)
3346     {
3348     case IMAGE_GLYPH:
3349       n = ns_get_glyph_string_clip_rect (s, r);
3350       ns_focus (s->f, r, n);
3351       ns_dumpglyphs_image (s, r[0]);
3352       ns_unfocus (s->f);
3353       break;
3355     case STRETCH_GLYPH:
3356       ns_dumpglyphs_stretch (s);
3357       break;
3359     case CHAR_GLYPH:
3360     case COMPOSITE_GLYPH:
3361       n = ns_get_glyph_string_clip_rect (s, r);
3362       ns_focus (s->f, r, n);
3364       if (s->for_overlaps || (s->cmp_from > 0
3365                               && ! s->first_glyph->u.cmp.automatic))
3366         s->background_filled_p = 1;
3367       else
3368         ns_maybe_dumpglyphs_background
3369           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3371       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3372         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3373          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3374           NS_DUMPGLYPH_NORMAL));
3376       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3377         {
3378           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3379           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3380           NS_FACE_FOREGROUND (s->face) = tmp;
3381         }
3383       {
3384         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3386         if (isComposite)
3387           ns_draw_composite_glyph_string_foreground (s);
3388         else
3389           font->driver->draw
3390             (s, s->cmp_from, s->nchars, s->x, s->ybase,
3391              (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3392              || flags == NS_DUMPGLYPH_MOUSEFACE);
3393       }
3395       {
3396         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3397                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3398                                                    s->f)
3399                         : FRAME_FOREGROUND_COLOR (s->f));
3400         [col set];
3402         /* Draw underline, overline, strike-through. */
3403         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3404       }
3406       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3407         {
3408           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3409           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3410           NS_FACE_FOREGROUND (s->face) = tmp;
3411         }
3413       ns_unfocus (s->f);
3414       break;
3416     case GLYPHLESS_GLYPH:
3417       n = ns_get_glyph_string_clip_rect (s, r);
3418       ns_focus (s->f, r, n);
3420       if (s->for_overlaps || (s->cmp_from > 0
3421                               && ! s->first_glyph->u.cmp.automatic))
3422         s->background_filled_p = 1;
3423       else
3424         ns_maybe_dumpglyphs_background
3425           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3426       /* ... */
3427       /* Not yet implemented.  */
3428       /* ... */
3429       ns_unfocus (s->f);
3430       break;
3432     default:
3433       emacs_abort ();
3434     }
3436   /* Draw box if not done already. */
3437   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3438     {
3439       n = ns_get_glyph_string_clip_rect (s, r);
3440       ns_focus (s->f, r, n);
3441       ns_dumpglyphs_box_or_relief (s);
3442       ns_unfocus (s->f);
3443     }
3445   s->num_clips = 0;
3450 /* ==========================================================================
3452     Event loop
3454    ========================================================================== */
3457 static void
3458 ns_send_appdefined (int value)
3459 /* --------------------------------------------------------------------------
3460     Internal: post an appdefined event which EmacsApp-sendEvent will
3461               recognize and take as a command to halt the event loop.
3462    -------------------------------------------------------------------------- */
3464   /*NSTRACE (ns_send_appdefined); */
3466 #ifdef NS_IMPL_GNUSTEP
3467   // GNUstep needs postEvent to happen on the main thread.
3468   if (! [[NSThread currentThread] isMainThread])
3469     {
3470       EmacsApp *app = (EmacsApp *)NSApp;
3471       app->nextappdefined = value;
3472       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3473                             withObject:nil
3474                          waitUntilDone:YES];
3475       return;
3476     }
3477 #endif
3479   /* Only post this event if we haven't already posted one.  This will end
3480        the [NXApp run] main loop after having processed all events queued at
3481        this moment.  */
3483 #ifdef NS_IMPL_COCOA
3484   if (! send_appdefined)
3485     {
3486       /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3487          in certain situations (rapid incoming events).
3488          So check if we have one, if not add one.  */
3489       NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3490                                           untilDate:[NSDate distantPast]
3491                                              inMode:NSDefaultRunLoopMode
3492                                             dequeue:NO];
3493       if (! appev) send_appdefined = YES;
3494     }
3495 #endif
3497   if (send_appdefined)
3498     {
3499       NSEvent *nxev;
3501       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3502       send_appdefined = NO;
3504       /* Don't need wakeup timer any more */
3505       if (timed_entry)
3506         {
3507           [timed_entry invalidate];
3508           [timed_entry release];
3509           timed_entry = nil;
3510         }
3512       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3513                                 location: NSMakePoint (0, 0)
3514                            modifierFlags: 0
3515                                timestamp: 0
3516                             windowNumber: [[NSApp mainWindow] windowNumber]
3517                                  context: [NSApp context]
3518                                  subtype: 0
3519                                    data1: value
3520                                    data2: 0];
3522       /* Post an application defined event on the event queue.  When this is
3523          received the [NXApp run] will return, thus having processed all
3524          events which are currently queued.  */
3525       [NSApp postEvent: nxev atStart: NO];
3526     }
3529 #ifdef HAVE_NATIVE_FS
3530 static void
3531 check_native_fs ()
3533   Lisp_Object frame, tail;
3535   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3536     return;
3538   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3540   FOR_EACH_FRAME (tail, frame)
3541     {
3542       struct frame *f = XFRAME (frame);
3543       if (FRAME_NS_P (f))
3544         {
3545           EmacsView *view = FRAME_NS_VIEW (f);
3546           [view updateCollectionBehavior];
3547         }
3548     }
3550 #endif
3552 /* GNUstep does not have cancelTracking.  */
3553 #ifdef NS_IMPL_COCOA
3554 /* Check if menu open should be canceled or continued as normal.  */
3555 void
3556 ns_check_menu_open (NSMenu *menu)
3558   /* Click in menu bar? */
3559   NSArray *a = [[NSApp mainMenu] itemArray];
3560   int i;
3561   BOOL found = NO;
3563   if (menu == nil) // Menu tracking ended.
3564     {
3565       if (menu_will_open_state == MENU_OPENING)
3566         menu_will_open_state = MENU_NONE;
3567       return;
3568     }
3570   for (i = 0; ! found && i < [a count]; i++)
3571     found = menu == [[a objectAtIndex:i] submenu];
3572   if (found)
3573     {
3574       if (menu_will_open_state == MENU_NONE && emacs_event)
3575         {
3576           NSEvent *theEvent = [NSApp currentEvent];
3577           struct frame *emacsframe = SELECTED_FRAME ();
3579           [menu cancelTracking];
3580           menu_will_open_state = MENU_PENDING;
3581           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3582           EV_TRAILER (theEvent);
3584           CGEventRef ourEvent = CGEventCreate (NULL);
3585           menu_mouse_point = CGEventGetLocation (ourEvent);
3586           CFRelease (ourEvent);
3587         }
3588       else if (menu_will_open_state == MENU_OPENING)
3589         {
3590           menu_will_open_state = MENU_NONE;
3591         }
3592     }
3595 /* Redo saved menu click if state is MENU_PENDING.  */
3596 void
3597 ns_check_pending_open_menu ()
3599   if (menu_will_open_state == MENU_PENDING)
3600     {
3601       CGEventSourceRef source
3602         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3604       CGEventRef event = CGEventCreateMouseEvent (source,
3605                                                   kCGEventLeftMouseDown,
3606                                                   menu_mouse_point,
3607                                                   kCGMouseButtonLeft);
3608       CGEventSetType (event, kCGEventLeftMouseDown);
3609       CGEventPost (kCGHIDEventTap, event);
3610       CFRelease (event);
3611       CFRelease (source);
3613       menu_will_open_state = MENU_OPENING;
3614     }
3616 #endif /* NS_IMPL_COCOA */
3618 static void
3619 unwind_apploopnr (Lisp_Object not_used)
3621   --apploopnr;
3622   n_emacs_events_pending = 0;
3623   ns_finish_events ();
3624   q_event_ptr = NULL;
3627 static int
3628 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3629 /* --------------------------------------------------------------------------
3630      External (hook): Post an event to ourself and keep reading events until
3631      we read it back again.  In effect process all events which were waiting.
3632      From 21+ we have to manage the event buffer ourselves.
3633    -------------------------------------------------------------------------- */
3635   struct input_event ev;
3636   int nevents;
3638 /* NSTRACE (ns_read_socket); */
3640 #ifdef HAVE_NATIVE_FS
3641   check_native_fs ();
3642 #endif
3644   if ([NSApp modalWindow] != nil)
3645     return -1;
3647   if (hold_event_q.nr > 0)
3648     {
3649       int i;
3650       for (i = 0; i < hold_event_q.nr; ++i)
3651         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3652       hold_event_q.nr = 0;
3653       return i;
3654     }
3656   block_input ();
3657   n_emacs_events_pending = 0;
3658   ns_init_events (&ev);
3659   q_event_ptr = hold_quit;
3661   /* we manage autorelease pools by allocate/reallocate each time around
3662      the loop; strict nesting is occasionally violated but seems not to
3663      matter.. earlier methods using full nesting caused major memory leaks */
3664   [outerpool release];
3665   outerpool = [[NSAutoreleasePool alloc] init];
3667   /* If have pending open-file requests, attend to the next one of those. */
3668   if (ns_pending_files && [ns_pending_files count] != 0
3669       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3670     {
3671       [ns_pending_files removeObjectAtIndex: 0];
3672     }
3673   /* Deal with pending service requests. */
3674   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3675     && [(EmacsApp *)
3676          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3677                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3678     {
3679       [ns_pending_service_names removeObjectAtIndex: 0];
3680       [ns_pending_service_args removeObjectAtIndex: 0];
3681     }
3682   else
3683     {
3684       ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3685       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3686          to ourself, otherwise [NXApp run] will never exit.  */
3687       send_appdefined = YES;
3688       ns_send_appdefined (-1);
3690       if (++apploopnr != 1)
3691         {
3692           emacs_abort ();
3693         }
3694       record_unwind_protect (unwind_apploopnr, Qt);
3695       [NSApp run];
3696       unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
3697     }
3699   nevents = n_emacs_events_pending;
3700   n_emacs_events_pending = 0;
3701   ns_finish_events ();
3702   q_event_ptr = NULL;
3703   unblock_input ();
3705   return nevents;
3710 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3711            fd_set *exceptfds, struct timespec const *timeout,
3712            sigset_t const *sigmask)
3713 /* --------------------------------------------------------------------------
3714      Replacement for select, checking for events
3715    -------------------------------------------------------------------------- */
3717   int result;
3718   int t, k, nr = 0;
3719   struct input_event event;
3720   char c;
3722 /*  NSTRACE (ns_select); */
3724 #ifdef HAVE_NATIVE_FS
3725   check_native_fs ();
3726 #endif
3728   if (hold_event_q.nr > 0)
3729     {
3730       /* We already have events pending. */
3731       raise (SIGIO);
3732       errno = EINTR;
3733       return -1;
3734     }
3736   for (k = 0; k < nfds+1; k++)
3737     {
3738       if (readfds && FD_ISSET(k, readfds)) ++nr;
3739       if (writefds && FD_ISSET(k, writefds)) ++nr;
3740     }
3742   if (NSApp == nil
3743       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3744     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3746   [outerpool release];
3747   outerpool = [[NSAutoreleasePool alloc] init];
3750   send_appdefined = YES;
3751   if (nr > 0)
3752     {
3753       pthread_mutex_lock (&select_mutex);
3754       select_nfds = nfds;
3755       select_valid = 0;
3756       if (readfds)
3757         {
3758           select_readfds = *readfds;
3759           select_valid += SELECT_HAVE_READ;
3760         }
3761       if (writefds)
3762         {
3763           select_writefds = *writefds;
3764           select_valid += SELECT_HAVE_WRITE;
3765         }
3767       if (timeout)
3768         {
3769           select_timeout = *timeout;
3770           select_valid += SELECT_HAVE_TMO;
3771         }
3773       pthread_mutex_unlock (&select_mutex);
3775       /* Inform fd_handler that select should be called */
3776       c = 'g';
3777       emacs_write_sig (selfds[1], &c, 1);
3778     }
3779   else if (nr == 0 && timeout)
3780     {
3781       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3782       double time = timespectod (*timeout);
3783       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3784                                                       target: NSApp
3785                                                     selector:
3786                                   @selector (timeout_handler:)
3787                                                     userInfo: 0
3788                                                      repeats: NO]
3789                       retain];
3790     }
3791   else /* No timeout and no file descriptors, can this happen?  */
3792     {
3793       /* Send appdefined so we exit from the loop */
3794       ns_send_appdefined (-1);
3795     }
3797   block_input ();
3798   ns_init_events (&event);
3799   if (++apploopnr != 1)
3800     {
3801       emacs_abort ();
3802     }
3804   {
3805     ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3806     record_unwind_protect (unwind_apploopnr, Qt);
3807     [NSApp run];
3808     unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
3809   }
3811   ns_finish_events ();
3812   if (nr > 0 && readfds)
3813     {
3814       c = 's';
3815       emacs_write_sig (selfds[1], &c, 1);
3816     }
3817   unblock_input ();
3819   t = last_appdefined_event_data;
3821   if (t != NO_APPDEFINED_DATA)
3822     {
3823       last_appdefined_event_data = NO_APPDEFINED_DATA;
3825       if (t == -2)
3826         {
3827           /* The NX_APPDEFINED event we received was a timeout. */
3828           result = 0;
3829         }
3830       else if (t == -1)
3831         {
3832           /* The NX_APPDEFINED event we received was the result of
3833              at least one real input event arriving.  */
3834           errno = EINTR;
3835           result = -1;
3836         }
3837       else
3838         {
3839           /* Received back from select () in fd_handler; copy the results */
3840           pthread_mutex_lock (&select_mutex);
3841           if (readfds) *readfds = select_readfds;
3842           if (writefds) *writefds = select_writefds;
3843           pthread_mutex_unlock (&select_mutex);
3844           result = t;
3845         }
3846     }
3847   else
3848     {
3849       errno = EINTR;
3850       result = -1;
3851     }
3853   return result;
3858 /* ==========================================================================
3860     Scrollbar handling
3862    ========================================================================== */
3865 static void
3866 ns_set_vertical_scroll_bar (struct window *window,
3867                            int portion, int whole, int position)
3868 /* --------------------------------------------------------------------------
3869       External (hook): Update or add scrollbar
3870    -------------------------------------------------------------------------- */
3872   Lisp_Object win;
3873   NSRect r, v;
3874   struct frame *f = XFRAME (WINDOW_FRAME (window));
3875   EmacsView *view = FRAME_NS_VIEW (f);
3876   EmacsScroller *bar;
3877   int window_y, window_height;
3878   int top, left, height, width;
3879   BOOL update_p = YES;
3881   /* optimization; display engine sends WAY too many of these.. */
3882   if (!NILP (window->vertical_scroll_bar))
3883     {
3884       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3885       if ([bar checkSamePosition: position portion: portion whole: whole])
3886         {
3887           if (view->scrollbarsNeedingUpdate == 0)
3888             {
3889               if (!windows_or_buffers_changed)
3890                   return;
3891             }
3892           else
3893             view->scrollbarsNeedingUpdate--;
3894           update_p = NO;
3895         }
3896     }
3898   NSTRACE (ns_set_vertical_scroll_bar);
3900   /* Get dimensions.  */
3901   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3902   top = window_y;
3903   height = window_height;
3904   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3905   left = WINDOW_SCROLL_BAR_AREA_X (window);
3907   r = NSMakeRect (left, top, width, height);
3908   /* the parent view is flipped, so we need to flip y value */
3909   v = [view frame];
3910   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3912   XSETWINDOW (win, window);
3913   block_input ();
3915   /* we want at least 5 lines to display a scrollbar */
3916   if (WINDOW_TOTAL_LINES (window) < 5)
3917     {
3918       if (!NILP (window->vertical_scroll_bar))
3919         {
3920           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3921           [bar removeFromSuperview];
3922           wset_vertical_scroll_bar (window, Qnil);
3923           [bar release];
3924         }
3925       ns_clear_frame_area (f, left, top, width, height);
3926       unblock_input ();
3927       return;
3928     }
3930   if (NILP (window->vertical_scroll_bar))
3931     {
3932       if (width > 0 && height > 0)
3933         ns_clear_frame_area (f, left, top, width, height);
3935       bar = [[EmacsScroller alloc] initFrame: r window: win];
3936       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3937       update_p = YES;
3938     }
3939   else
3940     {
3941       NSRect oldRect;
3942       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3943       oldRect = [bar frame];
3944       r.size.width = oldRect.size.width;
3945       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3946         {
3947           if (oldRect.origin.x != r.origin.x)
3948               ns_clear_frame_area (f, left, top, width, height);
3949           [bar setFrame: r];
3950         }
3951     }
3953   if (update_p)
3954     [bar setPosition: position portion: portion whole: whole];
3955   unblock_input ();
3959 static void
3960 ns_set_horizontal_scroll_bar (struct window *window,
3961                               int portion, int whole, int position)
3962 /* --------------------------------------------------------------------------
3963       External (hook): Update or add scrollbar
3964    -------------------------------------------------------------------------- */
3966   Lisp_Object win;
3967   NSRect r, v;
3968   struct frame *f = XFRAME (WINDOW_FRAME (window));
3969   EmacsView *view = FRAME_NS_VIEW (f);
3970   EmacsScroller *bar;
3971   int top, height, left, width;
3972   int window_x, window_width;
3973   BOOL update_p = YES;
3975   /* optimization; display engine sends WAY too many of these.. */
3976   if (!NILP (window->horizontal_scroll_bar))
3977     {
3978       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
3979       if ([bar checkSamePosition: position portion: portion whole: whole])
3980         {
3981           if (view->scrollbarsNeedingUpdate == 0)
3982             {
3983               if (!windows_or_buffers_changed)
3984                   return;
3985             }
3986           else
3987             view->scrollbarsNeedingUpdate--;
3988           update_p = NO;
3989         }
3990     }
3992   NSTRACE (ns_set_horizontal_scroll_bar);
3994   /* Get dimensions.  */
3995   window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
3996   left = window_x;
3997   width = window_width;
3998   height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
3999   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4001   r = NSMakeRect (left, top, width, height);
4002   /* the parent view is flipped, so we need to flip y value */
4003   v = [view frame];
4004   /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
4005   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4007   XSETWINDOW (win, window);
4008   block_input ();
4010   if (WINDOW_TOTAL_COLS (window) < 5)
4011     {
4012       if (!NILP (window->horizontal_scroll_bar))
4013         {
4014           bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4015           [bar removeFromSuperview];
4016           wset_horizontal_scroll_bar (window, Qnil);
4017         }
4018       ns_clear_frame_area (f, left, top, width, height);
4019       unblock_input ();
4020       return;
4021     }
4023   if (NILP (window->horizontal_scroll_bar))
4024     {
4025       if (width > 0 && height > 0)
4026         ns_clear_frame_area (f, left, top, width, height);
4028       bar = [[EmacsScroller alloc] initFrame: r window: win];
4029       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4030       update_p = YES;
4031     }
4032   else
4033     {
4034       NSRect oldRect;
4035       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4036       oldRect = [bar frame];
4037       r.size.width = oldRect.size.width;
4038       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4039         {
4040           if (oldRect.origin.x != r.origin.x)
4041               ns_clear_frame_area (f, left, top, width, height);
4042           [bar setFrame: r];
4043           update_p = YES;
4044         }
4045     }
4047   if (update_p)
4048     [bar setPosition: position portion: portion whole: whole];
4049   unblock_input ();
4053 static void
4054 ns_condemn_scroll_bars (struct frame *f)
4055 /* --------------------------------------------------------------------------
4056      External (hook): arrange for all frame's scrollbars to be removed
4057      at next call to judge_scroll_bars, except for those redeemed.
4058    -------------------------------------------------------------------------- */
4060   int i;
4061   id view;
4062   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4064   NSTRACE (ns_condemn_scroll_bars);
4066   for (i =[subviews count]-1; i >= 0; i--)
4067     {
4068       view = [subviews objectAtIndex: i];
4069       if ([view isKindOfClass: [EmacsScroller class]])
4070         [view condemn];
4071     }
4075 static void
4076 ns_redeem_scroll_bar (struct window *window)
4077 /* --------------------------------------------------------------------------
4078      External (hook): arrange to spare this window's scrollbar
4079      at next call to judge_scroll_bars.
4080    -------------------------------------------------------------------------- */
4082   id bar;
4083   NSTRACE (ns_redeem_scroll_bar);
4084   if (!NILP (window->vertical_scroll_bar))
4085     {
4086       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4087       [bar reprieve];
4088     }
4090   if (!NILP (window->horizontal_scroll_bar))
4091     {
4092       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4093       [bar reprieve];
4094     }
4098 static void
4099 ns_judge_scroll_bars (struct frame *f)
4100 /* --------------------------------------------------------------------------
4101      External (hook): destroy all scrollbars on frame that weren't
4102      redeemed after call to condemn_scroll_bars.
4103    -------------------------------------------------------------------------- */
4105   int i;
4106   id view;
4107   EmacsView *eview = FRAME_NS_VIEW (f);
4108   NSArray *subviews = [[eview superview] subviews];
4109   BOOL removed = NO;
4111   NSTRACE (ns_judge_scroll_bars);
4112   for (i = [subviews count]-1; i >= 0; --i)
4113     {
4114       view = [subviews objectAtIndex: i];
4115       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4116       if ([view judge])
4117         removed = YES;
4118     }
4120   if (removed)
4121     [eview updateFrameSize: NO];
4124 /* ==========================================================================
4126     Initialization
4128    ========================================================================== */
4131 x_display_pixel_height (struct ns_display_info *dpyinfo)
4133   NSArray *screens = [NSScreen screens];
4134   NSEnumerator *enumerator = [screens objectEnumerator];
4135   NSScreen *screen;
4136   NSRect frame;
4138   frame = NSZeroRect;
4139   while ((screen = [enumerator nextObject]) != nil)
4140     frame = NSUnionRect (frame, [screen frame]);
4142   return NSHeight (frame);
4146 x_display_pixel_width (struct ns_display_info *dpyinfo)
4148   NSArray *screens = [NSScreen screens];
4149   NSEnumerator *enumerator = [screens objectEnumerator];
4150   NSScreen *screen;
4151   NSRect frame;
4153   frame = NSZeroRect;
4154   while ((screen = [enumerator nextObject]) != nil)
4155     frame = NSUnionRect (frame, [screen frame]);
4157   return NSWidth (frame);
4161 static Lisp_Object ns_string_to_lispmod (const char *s)
4162 /* --------------------------------------------------------------------------
4163      Convert modifier name to lisp symbol
4164    -------------------------------------------------------------------------- */
4166   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4167     return Qmeta;
4168   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4169     return Qsuper;
4170   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4171     return Qcontrol;
4172   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4173     return Qalt;
4174   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4175     return Qhyper;
4176   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4177     return Qnone;
4178   else
4179     return Qnil;
4183 static void
4184 ns_default (const char *parameter, Lisp_Object *result,
4185            Lisp_Object yesval, Lisp_Object noval,
4186            BOOL is_float, BOOL is_modstring)
4187 /* --------------------------------------------------------------------------
4188       Check a parameter value in user's preferences
4189    -------------------------------------------------------------------------- */
4191   const char *value = ns_get_defaults_value (parameter);
4193   if (value)
4194     {
4195       double f;
4196       char *pos;
4197       if (c_strcasecmp (value, "YES") == 0)
4198         *result = yesval;
4199       else if (c_strcasecmp (value, "NO") == 0)
4200         *result = noval;
4201       else if (is_float && (f = strtod (value, &pos), pos != value))
4202         *result = make_float (f);
4203       else if (is_modstring && value)
4204         *result = ns_string_to_lispmod (value);
4205       else fprintf (stderr,
4206                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4207     }
4211 static void
4212 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4213 /* --------------------------------------------------------------------------
4214       Initialize global info and storage for display.
4215    -------------------------------------------------------------------------- */
4217     NSScreen *screen = [NSScreen mainScreen];
4218     NSWindowDepth depth = [screen depth];
4220     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4221     dpyinfo->resy = 72.27;
4222     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4223                                                   NSColorSpaceFromDepth (depth)]
4224                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4225                                                  NSColorSpaceFromDepth (depth)];
4226     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4227     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4228     dpyinfo->color_table->colors = NULL;
4229     dpyinfo->root_window = 42; /* a placeholder.. */
4230     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4231     dpyinfo->n_fonts = 0;
4232     dpyinfo->smallest_font_height = 1;
4233     dpyinfo->smallest_char_width = 1;
4235     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4239 /* This and next define (many of the) public functions in this file. */
4240 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4241          with using despite presence in the "system dependent" redisplay
4242          interface.  In addition, many of the ns_ methods have code that is
4243          shared with all terms, indicating need for further refactoring. */
4244 extern frame_parm_handler ns_frame_parm_handlers[];
4245 static struct redisplay_interface ns_redisplay_interface =
4247   ns_frame_parm_handlers,
4248   x_produce_glyphs,
4249   x_write_glyphs,
4250   x_insert_glyphs,
4251   x_clear_end_of_line,
4252   ns_scroll_run,
4253   ns_after_update_window_line,
4254   ns_update_window_begin,
4255   ns_update_window_end,
4256   0, /* flush_display */
4257   x_clear_window_mouse_face,
4258   x_get_glyph_overhangs,
4259   x_fix_overlapping_area,
4260   ns_draw_fringe_bitmap,
4261   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4262   0, /* destroy_fringe_bitmap */
4263   ns_compute_glyph_string_overhangs,
4264   ns_draw_glyph_string,
4265   ns_define_frame_cursor,
4266   ns_clear_frame_area,
4267   ns_draw_window_cursor,
4268   ns_draw_vertical_window_border,
4269   ns_draw_window_divider,
4270   ns_shift_glyphs_for_insert,
4271   ns_show_hourglass,
4272   ns_hide_hourglass
4276 static void
4277 ns_delete_display (struct ns_display_info *dpyinfo)
4279   /* TODO... */
4283 /* This function is called when the last frame on a display is deleted. */
4284 static void
4285 ns_delete_terminal (struct terminal *terminal)
4287   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4289   /* Protect against recursive calls.  delete_frame in
4290      delete_terminal calls us back when it deletes our last frame.  */
4291   if (!terminal->name)
4292     return;
4294   block_input ();
4296   x_destroy_all_bitmaps (dpyinfo);
4297   ns_delete_display (dpyinfo);
4298   unblock_input ();
4302 static struct terminal *
4303 ns_create_terminal (struct ns_display_info *dpyinfo)
4304 /* --------------------------------------------------------------------------
4305       Set up use of NS before we make the first connection.
4306    -------------------------------------------------------------------------- */
4308   struct terminal *terminal;
4310   NSTRACE (ns_create_terminal);
4312   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4314   terminal->display_info.ns = dpyinfo;
4315   dpyinfo->terminal = terminal;
4317   terminal->clear_frame_hook = ns_clear_frame;
4318   terminal->ring_bell_hook = ns_ring_bell;
4319   terminal->update_begin_hook = ns_update_begin;
4320   terminal->update_end_hook = ns_update_end;
4321   terminal->read_socket_hook = ns_read_socket;
4322   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4323   terminal->mouse_position_hook = ns_mouse_position;
4324   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4325   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4326   terminal->fullscreen_hook = ns_fullscreen_hook;
4327   terminal->menu_show_hook = ns_menu_show;
4328   terminal->popup_dialog_hook = ns_popup_dialog;
4329   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4330   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4331   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4332   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4333   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4334   terminal->delete_frame_hook = x_destroy_window;
4335   terminal->delete_terminal_hook = ns_delete_terminal;
4336   /* Other hooks are NULL by default.  */
4338   return terminal;
4342 struct ns_display_info *
4343 ns_term_init (Lisp_Object display_name)
4344 /* --------------------------------------------------------------------------
4345      Start the Application and get things rolling.
4346    -------------------------------------------------------------------------- */
4348   struct terminal *terminal;
4349   struct ns_display_info *dpyinfo;
4350   static int ns_initialized = 0;
4351   Lisp_Object tmp;
4353   if (ns_initialized) return x_display_list;
4354   ns_initialized = 1;
4356   NSTRACE (ns_term_init);
4358   [outerpool release];
4359   outerpool = [[NSAutoreleasePool alloc] init];
4361   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4362   /*GSDebugAllocationActive (YES); */
4363   block_input ();
4365   baud_rate = 38400;
4366   Fset_input_interrupt_mode (Qnil);
4368   if (selfds[0] == -1)
4369     {
4370       if (emacs_pipe (selfds) != 0)
4371         {
4372           fprintf (stderr, "Failed to create pipe: %s\n",
4373                    emacs_strerror (errno));
4374           emacs_abort ();
4375         }
4377       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4378       FD_ZERO (&select_readfds);
4379       FD_ZERO (&select_writefds);
4380       pthread_mutex_init (&select_mutex, NULL);
4381     }
4383   ns_pending_files = [[NSMutableArray alloc] init];
4384   ns_pending_service_names = [[NSMutableArray alloc] init];
4385   ns_pending_service_args = [[NSMutableArray alloc] init];
4387 /* Start app and create the main menu, window, view.
4388      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4389      The view will then ask the NSApp to stop and return to Emacs. */
4390   [EmacsApp sharedApplication];
4391   if (NSApp == nil)
4392     return NULL;
4393   [NSApp setDelegate: NSApp];
4395   /* Start the select thread.  */
4396   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4397                            toTarget:NSApp
4398                          withObject:nil];
4400   /* debugging: log all notifications */
4401   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4402                                          selector: @selector (logNotification:)
4403                                              name: nil object: nil]; */
4405   dpyinfo = xzalloc (sizeof *dpyinfo);
4407   ns_initialize_display_info (dpyinfo);
4408   terminal = ns_create_terminal (dpyinfo);
4410   terminal->kboard = allocate_kboard (Qns);
4411   /* Don't let the initial kboard remain current longer than necessary.
4412      That would cause problems if a file loaded on startup tries to
4413      prompt in the mini-buffer.  */
4414   if (current_kboard == initial_kboard)
4415     current_kboard = terminal->kboard;
4416   terminal->kboard->reference_count++;
4418   dpyinfo->next = x_display_list;
4419   x_display_list = dpyinfo;
4421   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4423   terminal->name = xlispstrdup (display_name);
4425   unblock_input ();
4427   if (!inhibit_x_resources)
4428     {
4429       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4430                  Qt, Qnil, NO, NO);
4431       tmp = Qnil;
4432       /* this is a standard variable */
4433       ns_default ("AppleAntiAliasingThreshold", &tmp,
4434                  make_float (10.0), make_float (6.0), YES, NO);
4435       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4436     }
4438   {
4439     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4441     if ( cl == nil )
4442       {
4443         Lisp_Object color_file, color_map, color;
4444         unsigned long c;
4445         char *name;
4447         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4448                          Fsymbol_value (intern ("data-directory")));
4450         color_map = Fx_load_color_file (color_file);
4451         if (NILP (color_map))
4452           fatal ("Could not read %s.\n", SDATA (color_file));
4454         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4455         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4456           {
4457             color = XCAR (color_map);
4458             name = SSDATA (XCAR (color));
4459             c = XINT (XCDR (color));
4460             [cl setColor:
4461                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4462                                       green: GREEN_FROM_ULONG (c) / 255.0
4463                                        blue: BLUE_FROM_ULONG (c) / 255.0
4464                                       alpha: 1.0]
4465                   forKey: [NSString stringWithUTF8String: name]];
4466           }
4467         [cl writeToFile: nil];
4468       }
4469   }
4471   {
4472 #ifdef NS_IMPL_GNUSTEP
4473     Vwindow_system_version = build_string (gnustep_base_version);
4474 #else
4475     /*PSnextrelease (128, c); */
4476     char c[DBL_BUFSIZE_BOUND];
4477     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4478     Vwindow_system_version = make_unibyte_string (c, len);
4479 #endif
4480   }
4482   delete_keyboard_wait_descriptor (0);
4484   ns_app_name = [[NSProcessInfo processInfo] processName];
4486 /* Set up OS X app menu */
4487 #ifdef NS_IMPL_COCOA
4488   {
4489     NSMenu *appMenu;
4490     NSMenuItem *item;
4491     /* set up the application menu */
4492     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4493     [svcsMenu setAutoenablesItems: NO];
4494     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4495     [appMenu setAutoenablesItems: NO];
4496     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4497     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4499     [appMenu insertItemWithTitle: @"About Emacs"
4500                           action: @selector (orderFrontStandardAboutPanel:)
4501                    keyEquivalent: @""
4502                          atIndex: 0];
4503     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4504     [appMenu insertItemWithTitle: @"Preferences..."
4505                           action: @selector (showPreferencesWindow:)
4506                    keyEquivalent: @","
4507                          atIndex: 2];
4508     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4509     item = [appMenu insertItemWithTitle: @"Services"
4510                                  action: @selector (menuDown:)
4511                           keyEquivalent: @""
4512                                 atIndex: 4];
4513     [appMenu setSubmenu: svcsMenu forItem: item];
4514     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4515     [appMenu insertItemWithTitle: @"Hide Emacs"
4516                           action: @selector (hide:)
4517                    keyEquivalent: @"h"
4518                          atIndex: 6];
4519     item =  [appMenu insertItemWithTitle: @"Hide Others"
4520                           action: @selector (hideOtherApplications:)
4521                    keyEquivalent: @"h"
4522                          atIndex: 7];
4523     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4524     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4525     [appMenu insertItemWithTitle: @"Quit Emacs"
4526                           action: @selector (terminate:)
4527                    keyEquivalent: @"q"
4528                          atIndex: 9];
4530     item = [mainMenu insertItemWithTitle: ns_app_name
4531                                   action: @selector (menuDown:)
4532                            keyEquivalent: @""
4533                                  atIndex: 0];
4534     [mainMenu setSubmenu: appMenu forItem: item];
4535     [dockMenu insertItemWithTitle: @"New Frame"
4536                            action: @selector (newFrame:)
4537                     keyEquivalent: @""
4538                           atIndex: 0];
4540     [NSApp setMainMenu: mainMenu];
4541     [NSApp setAppleMenu: appMenu];
4542     [NSApp setServicesMenu: svcsMenu];
4543     /* Needed at least on Cocoa, to get dock menu to show windows */
4544     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4546     [[NSNotificationCenter defaultCenter]
4547       addObserver: mainMenu
4548          selector: @selector (trackingNotification:)
4549              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4550     [[NSNotificationCenter defaultCenter]
4551       addObserver: mainMenu
4552          selector: @selector (trackingNotification:)
4553              name: NSMenuDidEndTrackingNotification object: mainMenu];
4554   }
4555 #endif /* MAC OS X menu setup */
4557   /* Register our external input/output types, used for determining
4558      applicable services and also drag/drop eligibility. */
4559   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4560   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4561                       retain];
4562   ns_drag_types = [[NSArray arrayWithObjects:
4563                             NSStringPboardType,
4564                             NSTabularTextPboardType,
4565                             NSFilenamesPboardType,
4566                             NSURLPboardType, nil] retain];
4568   /* If fullscreen is in init/default-frame-alist, focus isn't set
4569      right for fullscreen windows, so set this.  */
4570   [NSApp activateIgnoringOtherApps:YES];
4572   [NSApp run];
4573   ns_do_open_file = YES;
4575 #ifdef NS_IMPL_GNUSTEP
4576   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4577      We must re-catch it so subprocess works.  */
4578   catch_child_signal ();
4579 #endif
4580   return dpyinfo;
4584 void
4585 ns_term_shutdown (int sig)
4587   [[NSUserDefaults standardUserDefaults] synchronize];
4589   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4590   if (STRINGP (Vauto_save_list_file_name))
4591     unlink (SSDATA (Vauto_save_list_file_name));
4593   if (sig == 0 || sig == SIGTERM)
4594     {
4595       [NSApp terminate: NSApp];
4596     }
4597   else // force a stack trace to happen
4598     {
4599       emacs_abort ();
4600     }
4604 /* ==========================================================================
4606     EmacsApp implementation
4608    ========================================================================== */
4611 @implementation EmacsApp
4613 - (id)init
4615   if ((self = [super init]))
4616     {
4617 #ifdef NS_IMPL_COCOA
4618       self->isFirst = YES;
4619 #endif
4620 #ifdef NS_IMPL_GNUSTEP
4621       self->applicationDidFinishLaunchingCalled = NO;
4622 #endif
4623     }
4625   return self;
4628 #ifdef NS_IMPL_COCOA
4629 - (void)run
4631 #ifndef NSAppKitVersionNumber10_9
4632 #define NSAppKitVersionNumber10_9 1265
4633 #endif
4635     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
4636       {
4637         [super run];
4638         return;
4639       }
4641   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4643   if (isFirst) [self finishLaunching];
4644   isFirst = NO;
4646   shouldKeepRunning = YES;
4647   do
4648     {
4649       [pool release];
4650       pool = [[NSAutoreleasePool alloc] init];
4652       NSEvent *event =
4653         [self nextEventMatchingMask:NSAnyEventMask
4654                           untilDate:[NSDate distantFuture]
4655                              inMode:NSDefaultRunLoopMode
4656                             dequeue:YES];
4658       [self sendEvent:event];
4659       [self updateWindows];
4660     } while (shouldKeepRunning);
4662   [pool release];
4665 - (void)stop: (id)sender
4667     shouldKeepRunning = NO;
4668     // Stop possible dialog also.  Noop if no dialog present.
4669     // The file dialog still leaks 7k - 10k on 10.9 though.
4670     [super stop:sender];
4672 #endif /* NS_IMPL_COCOA */
4674 - (void)logNotification: (NSNotification *)notification
4676   const char *name = [[notification name] UTF8String];
4677   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4678       && !strstr (name, "WindowNumber"))
4679     NSLog (@"notification: '%@'", [notification name]);
4683 - (void)sendEvent: (NSEvent *)theEvent
4684 /* --------------------------------------------------------------------------
4685      Called when NSApp is running for each event received.  Used to stop
4686      the loop when we choose, since there's no way to just run one iteration.
4687    -------------------------------------------------------------------------- */
4689   int type = [theEvent type];
4690   NSWindow *window = [theEvent window];
4692 /*  NSTRACE (sendEvent); */
4693 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4695 #ifdef NS_IMPL_GNUSTEP
4696   // Keyboard events aren't propagated to file dialogs for some reason.
4697   if ([NSApp modalWindow] != nil &&
4698       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4699     {
4700       [[NSApp modalWindow] sendEvent: theEvent];
4701       return;
4702     }
4703 #endif
4705   if (represented_filename != nil && represented_frame)
4706     {
4707       NSString *fstr = represented_filename;
4708       NSView *view = FRAME_NS_VIEW (represented_frame);
4709 #ifdef NS_IMPL_COCOA
4710       /* work around a bug observed on 10.3 and later where
4711          setTitleWithRepresentedFilename does not clear out previous state
4712          if given filename does not exist */
4713       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
4714         [[view window] setRepresentedFilename: @""];
4715 #endif
4716       [[view window] setRepresentedFilename: fstr];
4717       [represented_filename release];
4718       represented_filename = nil;
4719       represented_frame = NULL;
4720     }
4722   if (type == NSApplicationDefined)
4723     {
4724       switch ([theEvent data2])
4725         {
4726 #ifdef NS_IMPL_COCOA
4727         case NSAPP_DATA2_RUNASSCRIPT:
4728           ns_run_ascript ();
4729           [self stop: self];
4730           return;
4731 #endif
4732         case NSAPP_DATA2_RUNFILEDIALOG:
4733           ns_run_file_dialog ();
4734           [self stop: self];
4735           return;
4736         }
4737     }
4739   if (type == NSCursorUpdate && window == nil)
4740     {
4741       fprintf (stderr, "Dropping external cursor update event.\n");
4742       return;
4743     }
4745   if (type == NSApplicationDefined)
4746     {
4747       /* Events posted by ns_send_appdefined interrupt the run loop here.
4748          But, if a modal window is up, an appdefined can still come through,
4749          (e.g., from a makeKeyWindow event) but stopping self also stops the
4750          modal loop. Just defer it until later. */
4751       if ([NSApp modalWindow] == nil)
4752         {
4753           last_appdefined_event_data = [theEvent data1];
4754           [self stop: self];
4755         }
4756       else
4757         {
4758           send_appdefined = YES;
4759         }
4760     }
4763 #ifdef NS_IMPL_COCOA
4764   /* If no dialog and none of our frames have focus and it is a move, skip it.
4765      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4766      such as Wifi, sound, date or similar.
4767      This prevents "spooky" highlighting in the frame under the menu.  */
4768   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4769     {
4770       struct ns_display_info *di;
4771       BOOL has_focus = NO;
4772       for (di = x_display_list; ! has_focus && di; di = di->next)
4773         has_focus = di->x_focus_frame != 0;
4774       if (! has_focus)
4775         return;
4776     }
4777 #endif
4779   [super sendEvent: theEvent];
4783 - (void)showPreferencesWindow: (id)sender
4785   struct frame *emacsframe = SELECTED_FRAME ();
4786   NSEvent *theEvent = [NSApp currentEvent];
4788   if (!emacs_event)
4789     return;
4790   emacs_event->kind = NS_NONKEY_EVENT;
4791   emacs_event->code = KEY_NS_SHOW_PREFS;
4792   emacs_event->modifiers = 0;
4793   EV_TRAILER (theEvent);
4797 - (void)newFrame: (id)sender
4799   struct frame *emacsframe = SELECTED_FRAME ();
4800   NSEvent *theEvent = [NSApp currentEvent];
4802   if (!emacs_event)
4803     return;
4804   emacs_event->kind = NS_NONKEY_EVENT;
4805   emacs_event->code = KEY_NS_NEW_FRAME;
4806   emacs_event->modifiers = 0;
4807   EV_TRAILER (theEvent);
4811 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4812 - (BOOL) openFile: (NSString *)fileName
4814   struct frame *emacsframe = SELECTED_FRAME ();
4815   NSEvent *theEvent = [NSApp currentEvent];
4817   if (!emacs_event)
4818     return NO;
4820   emacs_event->kind = NS_NONKEY_EVENT;
4821   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4822   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4823   ns_input_line = Qnil; /* can be start or cons start,end */
4824   emacs_event->modifiers =0;
4825   EV_TRAILER (theEvent);
4827   return YES;
4831 /* **************************************************************************
4833       EmacsApp delegate implementation
4835    ************************************************************************** */
4837 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4838 /* --------------------------------------------------------------------------
4839      When application is loaded, terminate event loop in ns_term_init
4840    -------------------------------------------------------------------------- */
4842   NSTRACE (applicationDidFinishLaunching);
4843 #ifdef NS_IMPL_GNUSTEP
4844   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
4845 #endif
4846   [NSApp setServicesProvider: NSApp];
4848   [self antialiasThresholdDidChange:nil];
4849 #ifdef NS_IMPL_COCOA
4850   [[NSNotificationCenter defaultCenter]
4851     addObserver:self
4852        selector:@selector(antialiasThresholdDidChange:)
4853            name:NSAntialiasThresholdChangedNotification
4854          object:nil];
4855 #endif
4857   ns_send_appdefined (-2);
4860 - (void)antialiasThresholdDidChange:(NSNotification *)notification
4862 #ifdef NS_IMPL_COCOA
4863   macfont_update_antialias_threshold ();
4864 #endif
4868 /* Termination sequences:
4869     C-x C-c:
4870     Cmd-Q:
4871     MenuBar | File | Exit:
4872     Select Quit from App menubar:
4873         -terminate
4874         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4875         ns_term_shutdown()
4877     Select Quit from Dock menu:
4878     Logout attempt:
4879         -appShouldTerminate
4880           Cancel -> Nothing else
4881           Accept ->
4883           -terminate
4884           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4885           ns_term_shutdown()
4889 - (void) terminate: (id)sender
4891   struct frame *emacsframe = SELECTED_FRAME ();
4893   if (!emacs_event)
4894     return;
4896   emacs_event->kind = NS_NONKEY_EVENT;
4897   emacs_event->code = KEY_NS_POWER_OFF;
4898   emacs_event->arg = Qt; /* mark as non-key event */
4899   EV_TRAILER ((id)nil);
4902 static bool
4903 runAlertPanel(NSString *title,
4904               NSString *msgFormat,
4905               NSString *defaultButton,
4906               NSString *alternateButton)
4908 #if !defined (NS_IMPL_COCOA) || \
4909   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
4910   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
4911     == NSAlertDefaultReturn;
4912 #else
4913   NSAlert *alert = [[NSAlert alloc] init];
4914   [alert setAlertStyle: NSCriticalAlertStyle];
4915   [alert setMessageText: msgFormat];
4916   [alert addButtonWithTitle: defaultButton];
4917   [alert addButtonWithTitle: alternateButton];
4918   NSInteger ret = [alert runModal];
4919   [alert release];
4920   return ret == NSAlertFirstButtonReturn;
4921 #endif
4925 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4927   bool ret;
4929   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4930     return NSTerminateNow;
4932     ret = runAlertPanel(ns_app_name,
4933                         @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4934                         @"Save Buffers and Exit", @"Cancel");
4936     if (ret)
4937         return NSTerminateNow;
4938     else
4939         return NSTerminateCancel;
4940     return NSTerminateNow;  /* just in case */
4943 static int
4944 not_in_argv (NSString *arg)
4946   int k;
4947   const char *a = [arg UTF8String];
4948   for (k = 1; k < initial_argc; ++k)
4949     if (strcmp (a, initial_argv[k]) == 0) return 0;
4950   return 1;
4953 /*   Notification from the Workspace to open a file */
4954 - (BOOL)application: sender openFile: (NSString *)file
4956   if (ns_do_open_file || not_in_argv (file))
4957     [ns_pending_files addObject: file];
4958   return YES;
4962 /*   Open a file as a temporary file */
4963 - (BOOL)application: sender openTempFile: (NSString *)file
4965   if (ns_do_open_file || not_in_argv (file))
4966     [ns_pending_files addObject: file];
4967   return YES;
4971 /*   Notification from the Workspace to open a file noninteractively (?) */
4972 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4974   if (ns_do_open_file || not_in_argv (file))
4975     [ns_pending_files addObject: file];
4976   return YES;
4979 /*   Notification from the Workspace to open multiple files */
4980 - (void)application: sender openFiles: (NSArray *)fileList
4982   NSEnumerator *files = [fileList objectEnumerator];
4983   NSString *file;
4984   /* Don't open files from the command line unconditionally,
4985      Cocoa parses the command line wrong, --option value tries to open value
4986      if --option is the last option.  */
4987   while ((file = [files nextObject]) != nil)
4988     if (ns_do_open_file || not_in_argv (file))
4989       [ns_pending_files addObject: file];
4991   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4996 /* Handle dock menu requests.  */
4997 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4999   return dockMenu;
5003 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5004 - (void)applicationWillBecomeActive: (NSNotification *)notification
5006   //ns_app_active=YES;
5008 - (void)applicationDidBecomeActive: (NSNotification *)notification
5010   NSTRACE (applicationDidBecomeActive);
5012 #ifdef NS_IMPL_GNUSTEP
5013   if (! applicationDidFinishLaunchingCalled)
5014     [self applicationDidFinishLaunching:notification];
5015 #endif
5016   //ns_app_active=YES;
5018   ns_update_auto_hide_menu_bar ();
5019   // No constraining takes place when the application is not active.
5020   ns_constrain_all_frames ();
5022 - (void)applicationDidResignActive: (NSNotification *)notification
5024   //ns_app_active=NO;
5025   ns_send_appdefined (-1);
5030 /* ==========================================================================
5032     EmacsApp aux handlers for managing event loop
5034    ========================================================================== */
5037 - (void)timeout_handler: (NSTimer *)timedEntry
5038 /* --------------------------------------------------------------------------
5039      The timeout specified to ns_select has passed.
5040    -------------------------------------------------------------------------- */
5042   /*NSTRACE (timeout_handler); */
5043   ns_send_appdefined (-2);
5046 #ifdef NS_IMPL_GNUSTEP
5047 - (void)sendFromMainThread:(id)unused
5049   ns_send_appdefined (nextappdefined);
5051 #endif
5053 - (void)fd_handler:(id)unused
5054 /* --------------------------------------------------------------------------
5055      Check data waiting on file descriptors and terminate if so
5056    -------------------------------------------------------------------------- */
5058   int result;
5059   int waiting = 1, nfds;
5060   char c;
5062   fd_set readfds, writefds, *wfds;
5063   struct timespec timeout, *tmo;
5064   NSAutoreleasePool *pool = nil;
5066   /* NSTRACE (fd_handler); */
5068   for (;;)
5069     {
5070       [pool release];
5071       pool = [[NSAutoreleasePool alloc] init];
5073       if (waiting)
5074         {
5075           fd_set fds;
5076           FD_ZERO (&fds);
5077           FD_SET (selfds[0], &fds);
5078           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5079           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5080             waiting = 0;
5081         }
5082       else
5083         {
5084           pthread_mutex_lock (&select_mutex);
5085           nfds = select_nfds;
5087           if (select_valid & SELECT_HAVE_READ)
5088             readfds = select_readfds;
5089           else
5090             FD_ZERO (&readfds);
5092           if (select_valid & SELECT_HAVE_WRITE)
5093             {
5094               writefds = select_writefds;
5095               wfds = &writefds;
5096             }
5097           else
5098             wfds = NULL;
5099           if (select_valid & SELECT_HAVE_TMO)
5100             {
5101               timeout = select_timeout;
5102               tmo = &timeout;
5103             }
5104           else
5105             tmo = NULL;
5107           pthread_mutex_unlock (&select_mutex);
5109           FD_SET (selfds[0], &readfds);
5110           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5112           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5114           if (result == 0)
5115             ns_send_appdefined (-2);
5116           else if (result > 0)
5117             {
5118               if (FD_ISSET (selfds[0], &readfds))
5119                 {
5120                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5121                     waiting = 1;
5122                 }
5123               else
5124                 {
5125                   pthread_mutex_lock (&select_mutex);
5126                   if (select_valid & SELECT_HAVE_READ)
5127                     select_readfds = readfds;
5128                   if (select_valid & SELECT_HAVE_WRITE)
5129                     select_writefds = writefds;
5130                   if (select_valid & SELECT_HAVE_TMO)
5131                     select_timeout = timeout;
5132                   pthread_mutex_unlock (&select_mutex);
5134                   ns_send_appdefined (result);
5135                 }
5136             }
5137           waiting = 1;
5138         }
5139     }
5144 /* ==========================================================================
5146     Service provision
5148    ========================================================================== */
5150 /* called from system: queue for next pass through event loop */
5151 - (void)requestService: (NSPasteboard *)pboard
5152               userData: (NSString *)userData
5153                  error: (NSString **)error
5155   [ns_pending_service_names addObject: userData];
5156   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5157       SSDATA (ns_string_from_pasteboard (pboard))]];
5161 /* called from ns_read_socket to clear queue */
5162 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5164   struct frame *emacsframe = SELECTED_FRAME ();
5165   NSEvent *theEvent = [NSApp currentEvent];
5167   if (!emacs_event)
5168     return NO;
5170   emacs_event->kind = NS_NONKEY_EVENT;
5171   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5172   ns_input_spi_name = build_string ([name UTF8String]);
5173   ns_input_spi_arg = build_string ([arg UTF8String]);
5174   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5175   EV_TRAILER (theEvent);
5177   return YES;
5181 @end  /* EmacsApp */
5185 /* ==========================================================================
5187     EmacsView implementation
5189    ========================================================================== */
5192 @implementation EmacsView
5194 /* needed to inform when window closed from LISP */
5195 - (void) setWindowClosing: (BOOL)closing
5197   windowClosing = closing;
5201 - (void)dealloc
5203   NSTRACE (EmacsView_dealloc);
5204   [toolbar release];
5205   if (fs_state == FULLSCREEN_BOTH)
5206     [nonfs_window release];
5207   [super dealloc];
5211 /* called on font panel selection */
5212 - (void)changeFont: (id)sender
5214   NSEvent *e = [[self window] currentEvent];
5215   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5216   struct font *font = face->font;
5217   id newFont;
5218   CGFloat size;
5219   NSFont *nsfont;
5221   NSTRACE (changeFont);
5223   if (!emacs_event)
5224     return;
5226 #ifdef NS_IMPL_GNUSTEP
5227   nsfont = ((struct nsfont_info *)font)->nsfont;
5228 #endif
5229 #ifdef NS_IMPL_COCOA
5230   nsfont = (NSFont *) macfont_get_nsctfont (font);
5231 #endif
5233   if ((newFont = [sender convertFont: nsfont]))
5234     {
5235       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5237       emacs_event->kind = NS_NONKEY_EVENT;
5238       emacs_event->modifiers = 0;
5239       emacs_event->code = KEY_NS_CHANGE_FONT;
5241       size = [newFont pointSize];
5242       ns_input_fontsize = make_number (lrint (size));
5243       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5244       EV_TRAILER (e);
5245     }
5249 - (BOOL)acceptsFirstResponder
5251   NSTRACE (acceptsFirstResponder);
5252   return YES;
5256 - (void)resetCursorRects
5258   NSRect visible = [self visibleRect];
5259   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5260   NSTRACE (resetCursorRects);
5262   if (currentCursor == nil)
5263     currentCursor = [NSCursor arrowCursor];
5265   if (!NSIsEmptyRect (visible))
5266     [self addCursorRect: visible cursor: currentCursor];
5267   [currentCursor setOnMouseEntered: YES];
5272 /*****************************************************************************/
5273 /* Keyboard handling. */
5274 #define NS_KEYLOG 0
5276 - (void)keyDown: (NSEvent *)theEvent
5278   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5279   int code;
5280   unsigned fnKeysym = 0;
5281   static NSMutableArray *nsEvArray;
5282   int left_is_none;
5283   unsigned int flags = [theEvent modifierFlags];
5285   NSTRACE (keyDown);
5287   /* Rhapsody and OS X give up and down events for the arrow keys */
5288   if (ns_fake_keydown == YES)
5289     ns_fake_keydown = NO;
5290   else if ([theEvent type] != NSKeyDown)
5291     return;
5293   if (!emacs_event)
5294     return;
5296  if (![[self window] isKeyWindow]
5297      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5298      /* we must avoid an infinite loop here. */
5299      && (EmacsView *)[[theEvent window] delegate] != self)
5300    {
5301      /* XXX: There is an occasional condition in which, when Emacs display
5302          updates a different frame from the current one, and temporarily
5303          selects it, then processes some interrupt-driven input
5304          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5305          for some reason that window has its first responder set to the NSView
5306          most recently updated (I guess), which is not the correct one. */
5307      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5308      return;
5309    }
5311   if (nsEvArray == nil)
5312     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5314   [NSCursor setHiddenUntilMouseMoves: YES];
5316   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5317     {
5318       clear_mouse_face (hlinfo);
5319       hlinfo->mouse_face_hidden = 1;
5320     }
5322   if (!processingCompose)
5323     {
5324       /* When using screen sharing, no left or right information is sent,
5325          so use Left key in those cases.  */
5326       int is_left_key, is_right_key;
5328       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5329         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5331       /* (Carbon way: [theEvent keyCode]) */
5333       /* is it a "function key"? */
5334       /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5335          flag set (this is probably a bug in the OS).
5336       */
5337       if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5338         {
5339           fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5340         }
5341       if (fnKeysym == 0)
5342         {
5343           fnKeysym = ns_convert_key (code);
5344         }
5346       if (fnKeysym)
5347         {
5348           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5349              because Emacs treats Delete and KP-Delete same (in simple.el). */
5350           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5351 #ifdef NS_IMPL_GNUSTEP
5352               /*  GNUstep uses incompatible keycodes, even for those that are
5353                   supposed to be hardware independent.  Just check for delete.
5354                   Keypad delete does not have keysym 0xFFFF.
5355                   See http://savannah.gnu.org/bugs/?25395
5356               */
5357               || (fnKeysym == 0xFFFF && code == 127)
5358 #endif
5359             )
5360             code = 0xFF08; /* backspace */
5361           else
5362             code = fnKeysym;
5363         }
5365       /* are there modifiers? */
5366       emacs_event->modifiers = 0;
5368       if (flags & NSHelpKeyMask)
5369           emacs_event->modifiers |= hyper_modifier;
5371       if (flags & NSShiftKeyMask)
5372         emacs_event->modifiers |= shift_modifier;
5374       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5375       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5376         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5378       if (is_right_key)
5379         emacs_event->modifiers |= parse_solitary_modifier
5380           (EQ (ns_right_command_modifier, Qleft)
5381            ? ns_command_modifier
5382            : ns_right_command_modifier);
5384       if (is_left_key)
5385         {
5386           emacs_event->modifiers |= parse_solitary_modifier
5387             (ns_command_modifier);
5389           /* if super (default), take input manager's word so things like
5390              dvorak / qwerty layout work */
5391           if (EQ (ns_command_modifier, Qsuper)
5392               && !fnKeysym
5393               && [[theEvent characters] length] != 0)
5394             {
5395               /* XXX: the code we get will be unshifted, so if we have
5396                  a shift modifier, must convert ourselves */
5397               if (!(flags & NSShiftKeyMask))
5398                 code = [[theEvent characters] characterAtIndex: 0];
5399 #if 0
5400               /* this is ugly and also requires linking w/Carbon framework
5401                  (for LMGetKbdType) so for now leave this rare (?) case
5402                  undealt with.. in future look into CGEvent methods */
5403               else
5404                 {
5405                   long smv = GetScriptManagerVariable (smKeyScript);
5406                   Handle uchrHandle = GetResource
5407                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5408                   UInt32 dummy = 0;
5409                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5410                                  [[theEvent characters] characterAtIndex: 0],
5411                                  kUCKeyActionDisplay,
5412                                  (flags & ~NSCommandKeyMask) >> 8,
5413                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5414                                  &dummy, 1, &dummy, &code);
5415                   code &= 0xFF;
5416                 }
5417 #endif
5418             }
5419         }
5421       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5422       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5423         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5425       if (is_right_key)
5426           emacs_event->modifiers |= parse_solitary_modifier
5427               (EQ (ns_right_control_modifier, Qleft)
5428                ? ns_control_modifier
5429                : ns_right_control_modifier);
5431       if (is_left_key)
5432         emacs_event->modifiers |= parse_solitary_modifier
5433           (ns_control_modifier);
5435       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5436           emacs_event->modifiers |=
5437             parse_solitary_modifier (ns_function_modifier);
5439       left_is_none = NILP (ns_alternate_modifier)
5440         || EQ (ns_alternate_modifier, Qnone);
5442       is_right_key = (flags & NSRightAlternateKeyMask)
5443         == NSRightAlternateKeyMask;
5444       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5445         || (! is_right_key
5446             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5448       if (is_right_key)
5449         {
5450           if ((NILP (ns_right_alternate_modifier)
5451                || EQ (ns_right_alternate_modifier, Qnone)
5452                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5453               && !fnKeysym)
5454             {   /* accept pre-interp alt comb */
5455               if ([[theEvent characters] length] > 0)
5456                 code = [[theEvent characters] characterAtIndex: 0];
5457               /*HACK: clear lone shift modifier to stop next if from firing */
5458               if (emacs_event->modifiers == shift_modifier)
5459                 emacs_event->modifiers = 0;
5460             }
5461           else
5462             emacs_event->modifiers |= parse_solitary_modifier
5463               (EQ (ns_right_alternate_modifier, Qleft)
5464                ? ns_alternate_modifier
5465                : ns_right_alternate_modifier);
5466         }
5468       if (is_left_key) /* default = meta */
5469         {
5470           if (left_is_none && !fnKeysym)
5471             {   /* accept pre-interp alt comb */
5472               if ([[theEvent characters] length] > 0)
5473                 code = [[theEvent characters] characterAtIndex: 0];
5474               /*HACK: clear lone shift modifier to stop next if from firing */
5475               if (emacs_event->modifiers == shift_modifier)
5476                 emacs_event->modifiers = 0;
5477             }
5478           else
5479               emacs_event->modifiers |=
5480                 parse_solitary_modifier (ns_alternate_modifier);
5481         }
5483   if (NS_KEYLOG)
5484     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5485              code, fnKeysym, flags, emacs_event->modifiers);
5487       /* if it was a function key or had modifiers, pass it directly to emacs */
5488       if (fnKeysym || (emacs_event->modifiers
5489                        && (emacs_event->modifiers != shift_modifier)
5490                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5491 /*[[theEvent characters] length] */
5492         {
5493           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5494           if (code < 0x20)
5495             code |= (1<<28)|(3<<16);
5496           else if (code == 0x7f)
5497             code |= (1<<28)|(3<<16);
5498           else if (!fnKeysym)
5499             emacs_event->kind = code > 0xFF
5500               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5502           emacs_event->code = code;
5503           EV_TRAILER (theEvent);
5504           processingCompose = NO;
5505           return;
5506         }
5507     }
5510   if (NS_KEYLOG && !processingCompose)
5511     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5513   processingCompose = YES;
5514   [nsEvArray addObject: theEvent];
5515   [self interpretKeyEvents: nsEvArray];
5516   [nsEvArray removeObject: theEvent];
5520 #ifdef NS_IMPL_COCOA
5521 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5522    decided not to send key-down for.
5523    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5524    This only applies on Tiger and earlier.
5525    If it matches one of these, send it on to keyDown. */
5526 -(void)keyUp: (NSEvent *)theEvent
5528   int flags = [theEvent modifierFlags];
5529   int code = [theEvent keyCode];
5530   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5531       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5532     {
5533       if (NS_KEYLOG)
5534         fprintf (stderr, "keyUp: passed test");
5535       ns_fake_keydown = YES;
5536       [self keyDown: theEvent];
5537     }
5539 #endif
5542 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5545 /* <NSTextInput>: called when done composing;
5546    NOTE: also called when we delete over working text, followed immed.
5547          by doCommandBySelector: deleteBackward: */
5548 - (void)insertText: (id)aString
5550   int code;
5551   int len = [(NSString *)aString length];
5552   int i;
5554   if (NS_KEYLOG)
5555     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5556   processingCompose = NO;
5558   if (!emacs_event)
5559     return;
5561   /* first, clear any working text */
5562   if (workingText != nil)
5563     [self deleteWorkingText];
5565   /* now insert the string as keystrokes */
5566   for (i =0; i<len; i++)
5567     {
5568       code = [aString characterAtIndex: i];
5569       /* TODO: still need this? */
5570       if (code == 0x2DC)
5571         code = '~'; /* 0x7E */
5572       if (code != 32) /* Space */
5573         emacs_event->modifiers = 0;
5574       emacs_event->kind
5575         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5576       emacs_event->code = code;
5577       EV_TRAILER ((id)nil);
5578     }
5582 /* <NSTextInput>: inserts display of composing characters */
5583 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5585   NSString *str = [aString respondsToSelector: @selector (string)] ?
5586     [aString string] : aString;
5587   if (NS_KEYLOG)
5588     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5589            str, (unsigned long)[str length],
5590            (unsigned long)selRange.length,
5591            (unsigned long)selRange.location);
5593   if (workingText != nil)
5594     [self deleteWorkingText];
5595   if ([str length] == 0)
5596     return;
5598   if (!emacs_event)
5599     return;
5601   processingCompose = YES;
5602   workingText = [str copy];
5603   ns_working_text = build_string ([workingText UTF8String]);
5605   emacs_event->kind = NS_TEXT_EVENT;
5606   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5607   EV_TRAILER ((id)nil);
5611 /* delete display of composing characters [not in <NSTextInput>] */
5612 - (void)deleteWorkingText
5614   if (workingText == nil)
5615     return;
5616   if (NS_KEYLOG)
5617     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5618   [workingText release];
5619   workingText = nil;
5620   processingCompose = NO;
5622   if (!emacs_event)
5623     return;
5625   emacs_event->kind = NS_TEXT_EVENT;
5626   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5627   EV_TRAILER ((id)nil);
5631 - (BOOL)hasMarkedText
5633   return workingText != nil;
5637 - (NSRange)markedRange
5639   NSRange rng = workingText != nil
5640     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5641   if (NS_KEYLOG)
5642     NSLog (@"markedRange request");
5643   return rng;
5647 - (void)unmarkText
5649   if (NS_KEYLOG)
5650     NSLog (@"unmark (accept) text");
5651   [self deleteWorkingText];
5652   processingCompose = NO;
5656 /* used to position char selection windows, etc. */
5657 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5659   NSRect rect;
5660   NSPoint pt;
5661   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5662   if (NS_KEYLOG)
5663     NSLog (@"firstRectForCharRange request");
5665   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5666   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5667   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5668   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5669                                        +FRAME_LINE_HEIGHT (emacsframe));
5671   pt = [self convertPoint: pt toView: nil];
5672   pt = [[self window] convertBaseToScreen: pt];
5673   rect.origin = pt;
5674   return rect;
5678 - (NSInteger)conversationIdentifier
5680   return (NSInteger)self;
5684 - (void)doCommandBySelector: (SEL)aSelector
5686   if (NS_KEYLOG)
5687     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5689   processingCompose = NO;
5690   if (aSelector == @selector (deleteBackward:))
5691     {
5692       /* happens when user backspaces over an ongoing composition:
5693          throw a 'delete' into the event queue */
5694       if (!emacs_event)
5695         return;
5696       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5697       emacs_event->code = 0xFF08;
5698       EV_TRAILER ((id)nil);
5699     }
5702 - (NSArray *)validAttributesForMarkedText
5704   static NSArray *arr = nil;
5705   if (arr == nil) arr = [NSArray new];
5706  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5707   return arr;
5710 - (NSRange)selectedRange
5712   if (NS_KEYLOG)
5713     NSLog (@"selectedRange request");
5714   return NSMakeRange (NSNotFound, 0);
5717 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5718     GNUSTEP_GUI_MINOR_VERSION > 22
5719 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5720 #else
5721 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5722 #endif
5724   if (NS_KEYLOG)
5725     NSLog (@"characterIndexForPoint request");
5726   return 0;
5729 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5731   static NSAttributedString *str = nil;
5732   if (str == nil) str = [NSAttributedString new];
5733   if (NS_KEYLOG)
5734     NSLog (@"attributedSubstringFromRange request");
5735   return str;
5738 /* End <NSTextInput> impl. */
5739 /*****************************************************************************/
5742 /* This is what happens when the user presses a mouse button.  */
5743 - (void)mouseDown: (NSEvent *)theEvent
5745   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5746   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5748   NSTRACE (mouseDown);
5750   [self deleteWorkingText];
5752   if (!emacs_event)
5753     return;
5755   dpyinfo->last_mouse_frame = emacsframe;
5756   /* appears to be needed to prevent spurious movement events generated on
5757      button clicks */
5758   emacsframe->mouse_moved = 0;
5760   if ([theEvent type] == NSScrollWheel)
5761     {
5762       CGFloat delta = [theEvent deltaY];
5763       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5764       if (delta == 0)
5765         {
5766           delta = [theEvent deltaX];
5767           if (delta == 0)
5768             {
5769               NSTRACE (deltaIsZero);
5770               return;
5771             }
5772           emacs_event->kind = HORIZ_WHEEL_EVENT;
5773         }
5774       else
5775         emacs_event->kind = WHEEL_EVENT;
5777       emacs_event->code = 0;
5778       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5779         ((delta > 0) ? up_modifier : down_modifier);
5780     }
5781   else
5782     {
5783       emacs_event->kind = MOUSE_CLICK_EVENT;
5784       emacs_event->code = EV_BUTTON (theEvent);
5785       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5786                              | EV_UDMODIFIERS (theEvent);
5787     }
5788   XSETINT (emacs_event->x, lrint (p.x));
5789   XSETINT (emacs_event->y, lrint (p.y));
5790   EV_TRAILER (theEvent);
5794 - (void)rightMouseDown: (NSEvent *)theEvent
5796   NSTRACE (rightMouseDown);
5797   [self mouseDown: theEvent];
5801 - (void)otherMouseDown: (NSEvent *)theEvent
5803   NSTRACE (otherMouseDown);
5804   [self mouseDown: theEvent];
5808 - (void)mouseUp: (NSEvent *)theEvent
5810   NSTRACE (mouseUp);
5811   [self mouseDown: theEvent];
5815 - (void)rightMouseUp: (NSEvent *)theEvent
5817   NSTRACE (rightMouseUp);
5818   [self mouseDown: theEvent];
5822 - (void)otherMouseUp: (NSEvent *)theEvent
5824   NSTRACE (otherMouseUp);
5825   [self mouseDown: theEvent];
5829 - (void) scrollWheel: (NSEvent *)theEvent
5831   NSTRACE (scrollWheel);
5832   [self mouseDown: theEvent];
5836 /* Tell emacs the mouse has moved. */
5837 - (void)mouseMoved: (NSEvent *)e
5839   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5840   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
5841   Lisp_Object frame;
5842   NSPoint pt;
5844 //  NSTRACE (mouseMoved);
5846   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
5847   pt = [self convertPoint: [e locationInWindow] fromView: nil];
5848   dpyinfo->last_mouse_motion_x = pt.x;
5849   dpyinfo->last_mouse_motion_y = pt.y;
5851   /* update any mouse face */
5852   if (hlinfo->mouse_face_hidden)
5853     {
5854       hlinfo->mouse_face_hidden = 0;
5855       clear_mouse_face (hlinfo);
5856     }
5858   /* tooltip handling */
5859   previous_help_echo_string = help_echo_string;
5860   help_echo_string = Qnil;
5862   if (!NILP (Vmouse_autoselect_window))
5863     {
5864       NSTRACE (mouse_autoselect_window);
5865       static Lisp_Object last_mouse_window;
5866       Lisp_Object window
5867         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
5869       if (WINDOWP (window)
5870           && !EQ (window, last_mouse_window)
5871           && !EQ (window, selected_window)
5872           && (focus_follows_mouse
5873               || (EQ (XWINDOW (window)->frame,
5874                       XWINDOW (selected_window)->frame))))
5875         {
5876           NSTRACE (in_window);
5877           emacs_event->kind = SELECT_WINDOW_EVENT;
5878           emacs_event->frame_or_window = window;
5879           EV_TRAILER2 (e);
5880         }
5881       /* Remember the last window where we saw the mouse.  */
5882       last_mouse_window = window;
5883     }
5885   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
5886     help_echo_string = previous_help_echo_string;
5888   XSETFRAME (frame, emacsframe);
5889   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5890     {
5891       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5892          (note_mouse_highlight), which is called through the
5893          note_mouse_movement () call above */
5894       any_help_event_p = YES;
5895       gen_help_event (help_echo_string, frame, help_echo_window,
5896                       help_echo_object, help_echo_pos);
5897     }
5899   if (emacsframe->mouse_moved && send_appdefined)
5900     ns_send_appdefined (-1);
5904 - (void)mouseDragged: (NSEvent *)e
5906   NSTRACE (mouseDragged);
5907   [self mouseMoved: e];
5911 - (void)rightMouseDragged: (NSEvent *)e
5913   NSTRACE (rightMouseDragged);
5914   [self mouseMoved: e];
5918 - (void)otherMouseDragged: (NSEvent *)e
5920   NSTRACE (otherMouseDragged);
5921   [self mouseMoved: e];
5925 - (BOOL)windowShouldClose: (id)sender
5927   NSEvent *e =[[self window] currentEvent];
5929   NSTRACE (windowShouldClose);
5930   windowClosing = YES;
5931   if (!emacs_event)
5932     return NO;
5933   emacs_event->kind = DELETE_WINDOW_EVENT;
5934   emacs_event->modifiers = 0;
5935   emacs_event->code = 0;
5936   EV_TRAILER (e);
5937   /* Don't close this window, let this be done from lisp code.  */
5938   return NO;
5941 - (void) updateFrameSize: (BOOL) delay;
5943   NSWindow *window = [self window];
5944   NSRect wr = [window frame];
5945   int extra = 0;
5946   int oldc = cols, oldr = rows;
5947   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
5948   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5949   int neww, newh;
5951   NSTRACE (updateFrameSize);
5952   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
5954   if (! [self isFullscreen])
5955     {
5956 #ifdef NS_IMPL_GNUSTEP
5957       // GNUstep does not always update the tool bar height.  Force it.
5958       if (toolbar && [toolbar isVisible])
5959           update_frame_tool_bar (emacsframe);
5960 #endif
5962       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5963         + FRAME_TOOLBAR_HEIGHT (emacsframe);
5964     }
5966   if (wait_for_tool_bar)
5967     {
5968       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
5969         return;
5970       wait_for_tool_bar = NO;
5971     }
5973   neww = (int)wr.size.width - emacsframe->border_width;
5974   newh = (int)wr.size.height - extra;
5976   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
5977   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
5979   if (cols < MINWIDTH)
5980     cols = MINWIDTH;
5982   if (rows < MINHEIGHT)
5983     rows = MINHEIGHT;
5985   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5986     {
5987       NSView *view = FRAME_NS_VIEW (emacsframe);
5988       NSWindow *win = [view window];
5989       NSSize sz = [win resizeIncrements];
5991       change_frame_size (emacsframe,
5992                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
5993                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
5994                          0, delay, 0, 1);
5995       SET_FRAME_GARBAGED (emacsframe);
5996       cancel_mouse_face (emacsframe);
5998       // Did resize increments change because of a font change?
5999       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
6000           sz.height != FRAME_LINE_HEIGHT (emacsframe) ||
6001           (frame_resize_pixelwise && sz.width != 1))
6002         {
6003           sz.width = frame_resize_pixelwise
6004             ? 1 : FRAME_COLUMN_WIDTH (emacsframe);
6005           sz.height = frame_resize_pixelwise
6006             ? 1 : FRAME_LINE_HEIGHT (emacsframe);
6007           [win setResizeIncrements: sz];
6009           NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6010         }
6012       [view setFrame: NSMakeRect (0, 0, neww, newh)];
6013       [self windowDidMove:nil];   // Update top/left.
6014     }
6017 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6018 /* normalize frame to gridded text size */
6020   int extra = 0;
6022   NSTRACE (windowWillResize);
6023   NSTRACE_SIZE ("Original size", frameSize);
6024 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
6026   if (fs_state == FULLSCREEN_MAXIMIZED
6027       && (maximized_width != (int)frameSize.width
6028           || maximized_height != (int)frameSize.height))
6029     [self setFSValue: FULLSCREEN_NONE];
6030   else if (fs_state == FULLSCREEN_WIDTH
6031            && maximized_width != (int)frameSize.width)
6032     [self setFSValue: FULLSCREEN_NONE];
6033   else if (fs_state == FULLSCREEN_HEIGHT
6034            && maximized_height != (int)frameSize.height)
6035     [self setFSValue: FULLSCREEN_NONE];
6036   if (fs_state == FULLSCREEN_NONE)
6037     maximized_width = maximized_height = -1;
6039   if (! [self isFullscreen])
6040     {
6041       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6042         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6043     }
6045   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6046   if (cols < MINWIDTH)
6047     cols = MINWIDTH;
6049   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6050                                            frameSize.height - extra);
6051   if (rows < MINHEIGHT)
6052     rows = MINHEIGHT;
6053 #ifdef NS_IMPL_COCOA
6054   {
6055     /* this sets window title to have size in it; the wm does this under GS */
6056     NSRect r = [[self window] frame];
6057     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6058       {
6059         if (old_title != 0)
6060           {
6061             xfree (old_title);
6062             old_title = 0;
6063           }
6064       }
6065     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6066       {
6067         char *size_title;
6068         NSWindow *window = [self window];
6069         if (old_title == 0)
6070           {
6071             char *t = strdup ([[[self window] title] UTF8String]);
6072             char *pos = strstr (t, "  â€”  ");
6073             if (pos)
6074               *pos = '\0';
6075             old_title = t;
6076           }
6077         size_title = xmalloc (strlen (old_title) + 40);
6078         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6079         [window setTitle: [NSString stringWithUTF8String: size_title]];
6080         [window display];
6081         xfree (size_title);
6082       }
6083   }
6084 #endif /* NS_IMPL_COCOA */
6085 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
6087   return frameSize;
6091 - (void)windowDidResize: (NSNotification *)notification
6093   if (! [self fsIsNative])
6094     {
6095       NSWindow *theWindow = [notification object];
6096       /* We can get notification on the non-FS window when in
6097          fullscreen mode.  */
6098       if ([self window] != theWindow) return;
6099     }
6101 #ifdef NS_IMPL_GNUSTEP
6102   NSWindow *theWindow = [notification object];
6104    /* In GNUstep, at least currently, it's possible to get a didResize
6105       without getting a willResize.. therefore we need to act as if we got
6106       the willResize now */
6107   NSSize sz = [theWindow frame].size;
6108   sz = [self windowWillResize: theWindow toSize: sz];
6109 #endif /* NS_IMPL_GNUSTEP */
6111   NSTRACE (windowDidResize);
6112 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
6114 if (cols > 0 && rows > 0)
6115     {
6116       [self updateFrameSize: YES];
6117     }
6119   ns_send_appdefined (-1);
6122 #ifdef NS_IMPL_COCOA
6123 - (void)viewDidEndLiveResize
6125   [super viewDidEndLiveResize];
6126   if (old_title != 0)
6127     {
6128       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6129       xfree (old_title);
6130       old_title = 0;
6131     }
6132   maximizing_resize = NO;
6134 #endif /* NS_IMPL_COCOA */
6137 - (void)windowDidBecomeKey: (NSNotification *)notification
6138 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6140   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6141   struct frame *old_focus = dpyinfo->x_focus_frame;
6143   NSTRACE (windowDidBecomeKey);
6145   if (emacsframe != old_focus)
6146     dpyinfo->x_focus_frame = emacsframe;
6148   ns_frame_rehighlight (emacsframe);
6150   if (emacs_event)
6151     {
6152       emacs_event->kind = FOCUS_IN_EVENT;
6153       EV_TRAILER ((id)nil);
6154     }
6158 - (void)windowDidResignKey: (NSNotification *)notification
6159 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6161   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6162   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6163   NSTRACE (windowDidResignKey);
6165   if (is_focus_frame)
6166     dpyinfo->x_focus_frame = 0;
6168   emacsframe->mouse_moved = 0;
6169   ns_frame_rehighlight (emacsframe);
6171   /* FIXME: for some reason needed on second and subsequent clicks away
6172             from sole-frame Emacs to get hollow box to show */
6173   if (!windowClosing && [[self window] isVisible] == YES)
6174     {
6175       x_update_cursor (emacsframe, 1);
6176       x_set_frame_alpha (emacsframe);
6177     }
6179   if (any_help_event_p)
6180     {
6181       Lisp_Object frame;
6182       XSETFRAME (frame, emacsframe);
6183       help_echo_string = Qnil;
6184       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6185     }
6187   if (emacs_event && is_focus_frame)
6188     {
6189       [self deleteWorkingText];
6190       emacs_event->kind = FOCUS_OUT_EVENT;
6191       EV_TRAILER ((id)nil);
6192     }
6196 - (void)windowWillMiniaturize: sender
6198   NSTRACE (windowWillMiniaturize);
6202 - (BOOL)isFlipped
6204   return YES;
6208 - (BOOL)isOpaque
6210   return NO;
6214 - initFrameFromEmacs: (struct frame *)f
6216   NSRect r, wr;
6217   Lisp_Object tem;
6218   NSWindow *win;
6219   NSSize sz;
6220   NSColor *col;
6221   NSString *name;
6223   NSTRACE (initFrameFromEmacs);
6225   windowClosing = NO;
6226   processingCompose = NO;
6227   scrollbarsNeedingUpdate = 0;
6228   fs_state = FULLSCREEN_NONE;
6229   fs_before_fs = next_maximized = -1;
6230 #ifdef HAVE_NATIVE_FS
6231   fs_is_native = ns_use_native_fullscreen;
6232 #else
6233   fs_is_native = NO;
6234 #endif
6235   maximized_width = maximized_height = -1;
6236   nonfs_window = nil;
6238 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
6240   ns_userRect = NSMakeRect (0, 0, 0, 0);
6241   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6242                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6243   [self initWithFrame: r];
6244   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6246   FRAME_NS_VIEW (f) = self;
6247   emacsframe = f;
6248 #ifdef NS_IMPL_COCOA
6249   old_title = 0;
6250   maximizing_resize = NO;
6251 #endif
6253   win = [[EmacsWindow alloc]
6254             initWithContentRect: r
6255                       styleMask: (NSResizableWindowMask |
6256 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6257                                   NSTitledWindowMask |
6258 #endif
6259                                   NSMiniaturizableWindowMask |
6260                                   NSClosableWindowMask)
6261                         backing: NSBackingStoreBuffered
6262                           defer: YES];
6264 #ifdef HAVE_NATIVE_FS
6265     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6266 #endif
6268   wr = [win frame];
6269   bwidth = f->border_width = wr.size.width - r.size.width;
6270   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6272   [win setAcceptsMouseMovedEvents: YES];
6273   [win setDelegate: self];
6274 #if !defined (NS_IMPL_COCOA) || \
6275   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6276   [win useOptimizedDrawing: YES];
6277 #endif
6278   sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6279   sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6280   [win setResizeIncrements: sz];
6282   [[win contentView] addSubview: self];
6284   if (ns_drag_types)
6285     [self registerForDraggedTypes: ns_drag_types];
6287   tem = f->name;
6288   name = [NSString stringWithUTF8String:
6289                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6290   [win setTitle: name];
6292   /* toolbar support */
6293   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6294                          [NSString stringWithFormat: @"Emacs Frame %d",
6295                                    ns_window_num]];
6296   [win setToolbar: toolbar];
6297   [toolbar setVisible: NO];
6299   /* Don't set frame garbaged until tool bar is up to date?
6300      This avoids an extra clear and redraw (flicker) at frame creation.  */
6301   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6302   else wait_for_tool_bar = NO;
6305 #ifdef NS_IMPL_COCOA
6306   {
6307     NSButton *toggleButton;
6308   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6309   [toggleButton setTarget: self];
6310   [toggleButton setAction: @selector (toggleToolbar: )];
6311   }
6312 #endif
6313   FRAME_TOOLBAR_HEIGHT (f) = 0;
6315   tem = f->icon_name;
6316   if (!NILP (tem))
6317     [win setMiniwindowTitle:
6318            [NSString stringWithUTF8String: SSDATA (tem)]];
6320   {
6321     NSScreen *screen = [win screen];
6323     if (screen != 0)
6324       [win setFrameTopLeftPoint: NSMakePoint
6325            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6326             IN_BOUND (-SCREENMAX,
6327                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
6328   }
6330   [win makeFirstResponder: self];
6332   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6333                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6334   [win setBackgroundColor: col];
6335   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6336     [win setOpaque: NO];
6338 #if !defined (NS_IMPL_COCOA) || \
6339   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6340   [self allocateGState];
6341 #endif
6342   [NSApp registerServicesMenuSendTypes: ns_send_types
6343                            returnTypes: nil];
6345   ns_window_num++;
6346   return self;
6350 - (void)windowDidMove: sender
6352   NSWindow *win = [self window];
6353   NSRect r = [win frame];
6354   NSArray *screens = [NSScreen screens];
6355   NSScreen *screen = [screens objectAtIndex: 0];
6357   NSTRACE (windowDidMove);
6359   if (!emacsframe->output_data.ns)
6360     return;
6361   if (screen != nil)
6362     {
6363       emacsframe->left_pos = r.origin.x;
6364       emacsframe->top_pos =
6365         [screen frame].size.height - (r.origin.y + r.size.height);
6366     }
6370 /* Called AFTER method below, but before our windowWillResize call there leads
6371    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6372    location so set_window_size moves the frame. */
6373 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6375   emacsframe->output_data.ns->zooming = 1;
6376   return YES;
6380 /* Override to do something slightly nonstandard, but nice.  First click on
6381    zoom button will zoom vertically.  Second will zoom completely.  Third
6382    returns to original. */
6383 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6384                         defaultFrame:(NSRect)defaultFrame
6386   NSRect result = [sender frame];
6388   NSTRACE (windowWillUseStandardFrame);
6390   if (fs_before_fs != -1) /* Entering fullscreen */
6391       {
6392         result = defaultFrame;
6393       }
6394   else if (next_maximized == FULLSCREEN_HEIGHT
6395       || (next_maximized == -1
6396           && abs ((int)(defaultFrame.size.height - result.size.height))
6397           > FRAME_LINE_HEIGHT (emacsframe)))
6398     {
6399       /* first click */
6400       ns_userRect = result;
6401       maximized_height = result.size.height = defaultFrame.size.height;
6402       maximized_width = -1;
6403       result.origin.y = defaultFrame.origin.y;
6404       [self setFSValue: FULLSCREEN_HEIGHT];
6405 #ifdef NS_IMPL_COCOA
6406       maximizing_resize = YES;
6407 #endif
6408     }
6409   else if (next_maximized == FULLSCREEN_WIDTH)
6410     {
6411       ns_userRect = result;
6412       maximized_width = result.size.width = defaultFrame.size.width;
6413       maximized_height = -1;
6414       result.origin.x = defaultFrame.origin.x;
6415       [self setFSValue: FULLSCREEN_WIDTH];
6416     }
6417   else if (next_maximized == FULLSCREEN_MAXIMIZED
6418            || (next_maximized == -1
6419                && abs ((int)(defaultFrame.size.width - result.size.width))
6420                > FRAME_COLUMN_WIDTH (emacsframe)))
6421     {
6422       result = defaultFrame;  /* second click */
6423       maximized_width = result.size.width;
6424       maximized_height = result.size.height;
6425       [self setFSValue: FULLSCREEN_MAXIMIZED];
6426 #ifdef NS_IMPL_COCOA
6427       maximizing_resize = YES;
6428 #endif
6429     }
6430   else
6431     {
6432       /* restore */
6433       result = ns_userRect.size.height ? ns_userRect : result;
6434       ns_userRect = NSMakeRect (0, 0, 0, 0);
6435 #ifdef NS_IMPL_COCOA
6436       maximizing_resize = fs_state != FULLSCREEN_NONE;
6437 #endif
6438       [self setFSValue: FULLSCREEN_NONE];
6439       maximized_width = maximized_height = -1;
6440     }
6442   if (fs_before_fs == -1) next_maximized = -1;
6443   [self windowWillResize: sender toSize: result.size];
6444   return result;
6448 - (void)windowDidDeminiaturize: sender
6450   NSTRACE (windowDidDeminiaturize);
6451   if (!emacsframe->output_data.ns)
6452     return;
6454   SET_FRAME_ICONIFIED (emacsframe, 0);
6455   SET_FRAME_VISIBLE (emacsframe, 1);
6456   windows_or_buffers_changed = 63;
6458   if (emacs_event)
6459     {
6460       emacs_event->kind = DEICONIFY_EVENT;
6461       EV_TRAILER ((id)nil);
6462     }
6466 - (void)windowDidExpose: sender
6468   NSTRACE (windowDidExpose);
6469   if (!emacsframe->output_data.ns)
6470     return;
6472   SET_FRAME_VISIBLE (emacsframe, 1);
6473   SET_FRAME_GARBAGED (emacsframe);
6475   if (send_appdefined)
6476     ns_send_appdefined (-1);
6480 - (void)windowDidMiniaturize: sender
6482   NSTRACE (windowDidMiniaturize);
6483   if (!emacsframe->output_data.ns)
6484     return;
6486   SET_FRAME_ICONIFIED (emacsframe, 1);
6487   SET_FRAME_VISIBLE (emacsframe, 0);
6489   if (emacs_event)
6490     {
6491       emacs_event->kind = ICONIFY_EVENT;
6492       EV_TRAILER ((id)nil);
6493     }
6496 #ifdef HAVE_NATIVE_FS
6497 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6498       willUseFullScreenPresentationOptions:
6499   (NSApplicationPresentationOptions)proposedOptions
6501   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6503 #endif
6505 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6507   fs_before_fs = fs_state;
6510 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6512   [self setFSValue: FULLSCREEN_BOTH];
6513   if (! [self fsIsNative])
6514     {
6515       [self windowDidBecomeKey:notification];
6516       [nonfs_window orderOut:self];
6517     }
6518   else
6519     {
6520       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6521 #ifdef NS_IMPL_COCOA
6522 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6523       unsigned val = (unsigned)[NSApp presentationOptions];
6525       // OSX 10.7 bug fix, the menu won't appear without this.
6526       // val is non-zero on other OSX versions.
6527       if (val == 0)
6528         {
6529           NSApplicationPresentationOptions options
6530             = NSApplicationPresentationAutoHideDock
6531             | NSApplicationPresentationAutoHideMenuBar
6532             | NSApplicationPresentationFullScreen
6533             | NSApplicationPresentationAutoHideToolbar;
6535           [NSApp setPresentationOptions: options];
6536         }
6537 #endif
6538 #endif
6539       [toolbar setVisible:tbar_visible];
6540     }
6543 - (void)windowWillExitFullScreen:(NSNotification *)notification
6545   if (next_maximized != -1)
6546     fs_before_fs = next_maximized;
6549 - (void)windowDidExitFullScreen:(NSNotification *)notification
6551   [self setFSValue: fs_before_fs];
6552   fs_before_fs = -1;
6553 #ifdef HAVE_NATIVE_FS
6554   [self updateCollectionBehavior];
6555 #endif
6556   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6557     {
6558       [toolbar setVisible:YES];
6559       update_frame_tool_bar (emacsframe);
6560       [self updateFrameSize:YES];
6561       [[self window] display];
6562     }
6563   else
6564     [toolbar setVisible:NO];
6566   if (next_maximized != -1)
6567     [[self window] performZoom:self];
6570 - (BOOL)fsIsNative
6572   return fs_is_native;
6575 - (BOOL)isFullscreen
6577   if (! fs_is_native) return nonfs_window != nil;
6578 #ifdef HAVE_NATIVE_FS
6579   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6580 #else
6581   return NO;
6582 #endif
6585 #ifdef HAVE_NATIVE_FS
6586 - (void)updateCollectionBehavior
6588   if (! [self isFullscreen])
6589     {
6590       NSWindow *win = [self window];
6591       NSWindowCollectionBehavior b = [win collectionBehavior];
6592       if (ns_use_native_fullscreen)
6593         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6594       else
6595         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6597       [win setCollectionBehavior: b];
6598       fs_is_native = ns_use_native_fullscreen;
6599     }
6601 #endif
6603 - (void)toggleFullScreen: (id)sender
6605   NSWindow *w, *fw;
6606   BOOL onFirstScreen;
6607   struct frame *f;
6608   NSSize sz;
6609   NSRect r, wr;
6610   NSColor *col;
6612   if (fs_is_native)
6613     {
6614 #ifdef HAVE_NATIVE_FS
6615       [[self window] toggleFullScreen:sender];
6616 #endif
6617       return;
6618     }
6620   w = [self window];
6621   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6622   f = emacsframe;
6623   wr = [w frame];
6624   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6625                                  (FRAME_DEFAULT_FACE (f)),
6626                                  f);
6628   sz.width = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
6629   sz.height = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
6631   if (fs_state != FULLSCREEN_BOTH)
6632     {
6633       NSScreen *screen = [w screen];
6635 #if defined (NS_IMPL_COCOA) && \
6636   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
6637       /* Hide ghost menu bar on secondary monitor? */
6638       if (! onFirstScreen)
6639         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
6640 #endif
6641       /* Hide dock and menubar if we are on the primary screen.  */
6642       if (onFirstScreen)
6643         {
6644 #ifdef NS_IMPL_COCOA
6645           NSApplicationPresentationOptions options
6646             = NSApplicationPresentationAutoHideDock
6647             | NSApplicationPresentationAutoHideMenuBar;
6649           [NSApp setPresentationOptions: options];
6650 #else
6651           [NSMenu setMenuBarVisible:NO];
6652 #endif
6653         }
6655       fw = [[EmacsFSWindow alloc]
6656                        initWithContentRect:[w contentRectForFrameRect:wr]
6657                                  styleMask:NSBorderlessWindowMask
6658                                    backing:NSBackingStoreBuffered
6659                                      defer:YES
6660                                     screen:screen];
6662       [fw setContentView:[w contentView]];
6663       [fw setTitle:[w title]];
6664       [fw setDelegate:self];
6665       [fw setAcceptsMouseMovedEvents: YES];
6666 #if !defined (NS_IMPL_COCOA) || \
6667   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6668       [fw useOptimizedDrawing: YES];
6669 #endif
6670       [fw setResizeIncrements: sz];
6671       [fw setBackgroundColor: col];
6672       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6673         [fw setOpaque: NO];
6675       f->border_width = 0;
6676       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6677       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6678       FRAME_TOOLBAR_HEIGHT (f) = 0;
6680       nonfs_window = w;
6682       [self windowWillEnterFullScreen:nil];
6683       [fw makeKeyAndOrderFront:NSApp];
6684       [fw makeFirstResponder:self];
6685       [w orderOut:self];
6686       r = [fw frameRectForContentRect:[screen frame]];
6687       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
6688       [self windowDidEnterFullScreen:nil];
6689       [fw display];
6690     }
6691   else
6692     {
6693       fw = w;
6694       w = nonfs_window;
6695       nonfs_window = nil;
6697       if (onFirstScreen)
6698         {
6699 #ifdef NS_IMPL_COCOA
6700           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6701 #else
6702           [NSMenu setMenuBarVisible:YES];
6703 #endif
6704         }
6706       [w setContentView:[fw contentView]];
6707       [w setResizeIncrements: sz];
6708       [w setBackgroundColor: col];
6709       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6710         [w setOpaque: NO];
6712       f->border_width = bwidth;
6713       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6714       if (FRAME_EXTERNAL_TOOL_BAR (f))
6715         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6717       [self windowWillExitFullScreen:nil];
6718       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
6719       [fw close];
6720       [w makeKeyAndOrderFront:NSApp];
6721       [self windowDidExitFullScreen:nil];
6722       [self updateFrameSize:YES];
6723     }
6726 - (void)handleFS
6728   if (fs_state != emacsframe->want_fullscreen)
6729     {
6730       if (fs_state == FULLSCREEN_BOTH)
6731         {
6732           [self toggleFullScreen:self];
6733         }
6735       switch (emacsframe->want_fullscreen)
6736         {
6737         case FULLSCREEN_BOTH:
6738           [self toggleFullScreen:self];
6739           break;
6740         case FULLSCREEN_WIDTH:
6741           next_maximized = FULLSCREEN_WIDTH;
6742           if (fs_state != FULLSCREEN_BOTH)
6743             [[self window] performZoom:self];
6744           break;
6745         case FULLSCREEN_HEIGHT:
6746           next_maximized = FULLSCREEN_HEIGHT;
6747           if (fs_state != FULLSCREEN_BOTH)
6748             [[self window] performZoom:self];
6749           break;
6750         case FULLSCREEN_MAXIMIZED:
6751           next_maximized = FULLSCREEN_MAXIMIZED;
6752           if (fs_state != FULLSCREEN_BOTH)
6753             [[self window] performZoom:self];
6754           break;
6755         case FULLSCREEN_NONE:
6756           if (fs_state != FULLSCREEN_BOTH)
6757             {
6758               next_maximized = FULLSCREEN_NONE;
6759               [[self window] performZoom:self];
6760             }
6761           break;
6762         }
6764       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6765     }
6769 - (void) setFSValue: (int)value
6771   Lisp_Object lval = Qnil;
6772   switch (value)
6773     {
6774     case FULLSCREEN_BOTH:
6775       lval = Qfullboth;
6776       break;
6777     case FULLSCREEN_WIDTH:
6778       lval = Qfullwidth;
6779       break;
6780     case FULLSCREEN_HEIGHT:
6781       lval = Qfullheight;
6782       break;
6783     case FULLSCREEN_MAXIMIZED:
6784       lval = Qmaximized;
6785       break;
6786     }
6787   store_frame_param (emacsframe, Qfullscreen, lval);
6788   fs_state = value;
6791 - (void)mouseEntered: (NSEvent *)theEvent
6793   NSTRACE (mouseEntered);
6794   if (emacsframe)
6795     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6796       = EV_TIMESTAMP (theEvent);
6800 - (void)mouseExited: (NSEvent *)theEvent
6802   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6804   NSTRACE (mouseExited);
6806   if (!hlinfo)
6807     return;
6809   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
6810     = EV_TIMESTAMP (theEvent);
6812   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6813     {
6814       clear_mouse_face (hlinfo);
6815       hlinfo->mouse_face_mouse_frame = 0;
6816     }
6820 - menuDown: sender
6822   NSTRACE (menuDown);
6823   if (context_menu_value == -1)
6824     context_menu_value = [sender tag];
6825   else
6826     {
6827       NSInteger tag = [sender tag];
6828       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6829                                     emacsframe->menu_bar_vector,
6830                                     (void *)tag);
6831     }
6833   ns_send_appdefined (-1);
6834   return self;
6838 - (EmacsToolbar *)toolbar
6840   return toolbar;
6844 /* this gets called on toolbar button click */
6845 - toolbarClicked: (id)item
6847   NSEvent *theEvent;
6848   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6850   NSTRACE (toolbarClicked);
6852   if (!emacs_event)
6853     return self;
6855   /* send first event (for some reason two needed) */
6856   theEvent = [[self window] currentEvent];
6857   emacs_event->kind = TOOL_BAR_EVENT;
6858   XSETFRAME (emacs_event->arg, emacsframe);
6859   EV_TRAILER (theEvent);
6861   emacs_event->kind = TOOL_BAR_EVENT;
6862 /*   XSETINT (emacs_event->code, 0); */
6863   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6864                            idx + TOOL_BAR_ITEM_KEY);
6865   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6866   EV_TRAILER (theEvent);
6867   return self;
6871 - toggleToolbar: (id)sender
6873   if (!emacs_event)
6874     return self;
6876   emacs_event->kind = NS_NONKEY_EVENT;
6877   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6878   EV_TRAILER ((id)nil);
6879   return self;
6883 - (void)drawRect: (NSRect)rect
6885   int x = NSMinX (rect), y = NSMinY (rect);
6886   int width = NSWidth (rect), height = NSHeight (rect);
6888   NSTRACE (drawRect);
6890   if (!emacsframe || !emacsframe->output_data.ns)
6891     return;
6893   ns_clear_frame_area (emacsframe, x, y, width, height);
6894   block_input ();
6895   expose_frame (emacsframe, x, y, width, height);
6896   unblock_input ();
6898   /*
6899     drawRect: may be called (at least in OS X 10.5) for invisible
6900     views as well for some reason.  Thus, do not infer visibility
6901     here.
6903     emacsframe->async_visible = 1;
6904     emacsframe->async_iconified = 0;
6905   */
6909 /* NSDraggingDestination protocol methods.  Actually this is not really a
6910    protocol, but a category of Object.  O well...  */
6912 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
6914   NSTRACE (draggingEntered);
6915   return NSDragOperationGeneric;
6919 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6921   return YES;
6925 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6927   id pb;
6928   int x, y;
6929   NSString *type;
6930   NSEvent *theEvent = [[self window] currentEvent];
6931   NSPoint position;
6932   NSDragOperation op = [sender draggingSourceOperationMask];
6933   int modifiers = 0;
6935   NSTRACE (performDragOperation);
6937   if (!emacs_event)
6938     return NO;
6940   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6941   x = lrint (position.x);  y = lrint (position.y);
6943   pb = [sender draggingPasteboard];
6944   type = [pb availableTypeFromArray: ns_drag_types];
6946   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
6947       // URL drags contain all operations (0xf), don't allow all to be set.
6948       (op & 0xf) != 0xf)
6949     {
6950       if (op & NSDragOperationLink)
6951         modifiers |= NSControlKeyMask;
6952       if (op & NSDragOperationCopy)
6953         modifiers |= NSAlternateKeyMask;
6954       if (op & NSDragOperationGeneric)
6955         modifiers |= NSCommandKeyMask;
6956     }
6958   modifiers = EV_MODIFIERS2 (modifiers);
6959   if (type == 0)
6960     {
6961       return NO;
6962     }
6963   else if ([type isEqualToString: NSFilenamesPboardType])
6964     {
6965       NSArray *files;
6966       NSEnumerator *fenum;
6967       NSString *file;
6969       if (!(files = [pb propertyListForType: type]))
6970         return NO;
6972       fenum = [files objectEnumerator];
6973       while ( (file = [fenum nextObject]) )
6974         {
6975           emacs_event->kind = DRAG_N_DROP_EVENT;
6976           XSETINT (emacs_event->x, x);
6977           XSETINT (emacs_event->y, y);
6978           ns_input_file = append2 (ns_input_file,
6979                                    build_string ([file UTF8String]));
6980           emacs_event->modifiers = modifiers;
6981           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
6982           EV_TRAILER (theEvent);
6983         }
6984       return YES;
6985     }
6986   else if ([type isEqualToString: NSURLPboardType])
6987     {
6988       NSURL *url = [NSURL URLFromPasteboard: pb];
6989       if (url == nil) return NO;
6991       emacs_event->kind = DRAG_N_DROP_EVENT;
6992       XSETINT (emacs_event->x, x);
6993       XSETINT (emacs_event->y, y);
6994       emacs_event->modifiers = modifiers;
6995       emacs_event->arg =  list2 (Qurl,
6996                                  build_string ([[url absoluteString]
6997                                                  UTF8String]));
6998       EV_TRAILER (theEvent);
7000       if ([url isFileURL] != NO)
7001         {
7002           NSString *file = [url path];
7003           ns_input_file = append2 (ns_input_file,
7004                                    build_string ([file UTF8String]));
7005         }
7006       return YES;
7007     }
7008   else if ([type isEqualToString: NSStringPboardType]
7009            || [type isEqualToString: NSTabularTextPboardType])
7010     {
7011       NSString *data;
7013       if (! (data = [pb stringForType: type]))
7014         return NO;
7016       emacs_event->kind = DRAG_N_DROP_EVENT;
7017       XSETINT (emacs_event->x, x);
7018       XSETINT (emacs_event->y, y);
7019       emacs_event->modifiers = modifiers;
7020       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
7021       EV_TRAILER (theEvent);
7022       return YES;
7023     }
7024   else
7025     {
7026       fprintf (stderr, "Invalid data type in dragging pasteboard");
7027       return NO;
7028     }
7032 - (id) validRequestorForSendType: (NSString *)typeSent
7033                       returnType: (NSString *)typeReturned
7035   NSTRACE (validRequestorForSendType);
7036   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7037       && typeReturned == nil)
7038     {
7039       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7040         return self;
7041     }
7043   return [super validRequestorForSendType: typeSent
7044                                returnType: typeReturned];
7048 /* The next two methods are part of NSServicesRequests informal protocol,
7049    supposedly called when a services menu item is chosen from this app.
7050    But this should not happen because we override the services menu with our
7051    own entries which call ns-perform-service.
7052    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7053    So let's at least stub them out until further investigation can be done. */
7055 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7057   /* we could call ns_string_from_pasteboard(pboard) here but then it should
7058      be written into the buffer in place of the existing selection..
7059      ordinary service calls go through functions defined in ns-win.el */
7060   return NO;
7063 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7065   NSArray *typesDeclared;
7066   Lisp_Object val;
7068   /* We only support NSStringPboardType */
7069   if ([types containsObject:NSStringPboardType] == NO) {
7070     return NO;
7071   }
7073   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7074   if (CONSP (val) && SYMBOLP (XCAR (val)))
7075     {
7076       val = XCDR (val);
7077       if (CONSP (val) && NILP (XCDR (val)))
7078         val = XCAR (val);
7079     }
7080   if (! STRINGP (val))
7081     return NO;
7083   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7084   [pb declareTypes:typesDeclared owner:nil];
7085   ns_string_to_pasteboard (pb, val);
7086   return YES;
7090 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7091    (gives a miniaturized version of the window); currently we use the latter for
7092    frames whose active buffer doesn't correspond to any file
7093    (e.g., '*scratch*') */
7094 - setMiniwindowImage: (BOOL) setMini
7096   id image = [[self window] miniwindowImage];
7097   NSTRACE (setMiniwindowImage);
7099   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7100      about "AppleDockIconEnabled" notwithstanding, however the set message
7101      below has its effect nonetheless. */
7102   if (image != emacsframe->output_data.ns->miniimage)
7103     {
7104       if (image && [image isKindOfClass: [EmacsImage class]])
7105         [image release];
7106       [[self window] setMiniwindowImage:
7107                        setMini ? emacsframe->output_data.ns->miniimage : nil];
7108     }
7110   return self;
7114 - (void) setRows: (int) r andColumns: (int) c
7116   rows = r;
7117   cols = c;
7120 @end  /* EmacsView */
7124 /* ==========================================================================
7126     EmacsWindow implementation
7128    ========================================================================== */
7130 @implementation EmacsWindow
7132 #ifdef NS_IMPL_COCOA
7133 - (id)accessibilityAttributeValue:(NSString *)attribute
7135   Lisp_Object str = Qnil;
7136   struct frame *f = SELECTED_FRAME ();
7137   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7139   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7140     return NSAccessibilityTextFieldRole;
7142   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7143       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7144     {
7145       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7146     }
7147   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7148     {
7149       if (! NILP (BVAR (curbuf, mark_active)))
7150           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7152       if (NILP (str))
7153         {
7154           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7155           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7156           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7158           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7159             str = make_uninit_multibyte_string (range, byte_range);
7160           else
7161             str = make_uninit_string (range);
7162           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7163              Is this a problem?  */
7164           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7165         }
7166     }
7169   if (! NILP (str))
7170     {
7171       if (CONSP (str) && SYMBOLP (XCAR (str)))
7172         {
7173           str = XCDR (str);
7174           if (CONSP (str) && NILP (XCDR (str)))
7175             str = XCAR (str);
7176         }
7177       if (STRINGP (str))
7178         {
7179           const char *utfStr = SSDATA (str);
7180           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7181           return nsStr;
7182         }
7183     }
7185   return [super accessibilityAttributeValue:attribute];
7187 #endif /* NS_IMPL_COCOA */
7189 /* If we have multiple monitors, one above the other, we don't want to
7190    restrict the height to just one monitor.  So we override this.  */
7191 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7193   /* When making the frame visible for the first time or if there is just
7194      one screen, we want to constrain.  Other times not.  */
7195   NSArray *screens = [NSScreen screens];
7196   NSUInteger nr_screens = [screens count], nr_eff_screens = 0, i;
7197   NSTRACE (constrainFrameRect);
7198   NSTRACE_RECT ("input", frameRect);
7200   if (ns_menu_bar_should_be_hidden ())
7201     return frameRect;
7203   if (nr_screens == 1)
7204     return [super constrainFrameRect:frameRect toScreen:screen];
7206 #ifdef NS_IMPL_COCOA
7207 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7208   // If separate spaces is on, it is like each screen is independent.  There is
7209   // no spanning of frames across screens.
7210   if ([NSScreen screensHaveSeparateSpaces])
7211     return [super constrainFrameRect:frameRect toScreen:screen];
7212 #endif
7213 #endif
7215   for (i = 0; i < nr_screens; ++i)
7216     {
7217       NSScreen *s = [screens objectAtIndex: i];
7218       NSRect scrrect = [s frame];
7219       NSRect intersect = NSIntersectionRect (frameRect, scrrect);
7221       if (intersect.size.width > 0 || intersect.size.height > 0)
7222         ++nr_eff_screens;
7223     }
7225   if (nr_eff_screens == 1)
7226     return [super constrainFrameRect:frameRect toScreen:screen];
7228   /* The default implementation does two things 1) ensure that the top
7229      of the rectangle is below the menu bar (or below the top of the
7230      screen) and 2) resizes windows larger than the screen. As we
7231      don't want the latter, a smaller rectangle is used. */
7232 #define FAKE_HEIGHT 64
7233   float old_top = frameRect.origin.y + frameRect.size.height;
7234   NSRect r;
7235   r.size.height = FAKE_HEIGHT;
7236   r.size.width = frameRect.size.width;
7237   r.origin.x = frameRect.origin.x;
7238   r.origin.y = old_top - FAKE_HEIGHT;
7240   NSTRACE_RECT ("input to super", r);
7242   r = [super constrainFrameRect:r toScreen:screen];
7244   NSTRACE_RECT ("output from super", r);
7246   float new_top = r.origin.y + FAKE_HEIGHT;
7247   if (new_top < old_top)
7248   {
7249     frameRect.origin.y = new_top - frameRect.size.height;
7250   }
7252   NSTRACE_RECT ("output", frameRect);
7254   return frameRect;
7255 #undef FAKE_HEIGHT
7258 @end /* EmacsWindow */
7261 @implementation EmacsFSWindow
7263 - (BOOL)canBecomeKeyWindow
7265   return YES;
7268 - (BOOL)canBecomeMainWindow
7270   return YES;
7273 @end
7275 /* ==========================================================================
7277     EmacsScroller implementation
7279    ========================================================================== */
7282 @implementation EmacsScroller
7284 /* for repeat button push */
7285 #define SCROLL_BAR_FIRST_DELAY 0.5
7286 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7288 + (CGFloat) scrollerWidth
7290   /* TODO: if we want to allow variable widths, this is the place to do it,
7291            however neither GNUstep nor Cocoa support it very well */
7292   CGFloat r;
7293 #if !defined (NS_IMPL_COCOA) || \
7294   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
7295   r = [NSScroller scrollerWidth];
7296 #else
7297   r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
7298                                 scrollerStyle: NSScrollerStyleLegacy];
7299 #endif
7300   return r;
7304 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7306   NSTRACE (EmacsScroller_initFrame);
7308   r.size.width = [EmacsScroller scrollerWidth];
7309   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7310   [self setContinuous: YES];
7311   [self setEnabled: YES];
7313   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7314      locked against the top and bottom edges, and right edge on OS X, where
7315      scrollers are on right. */
7316 #ifdef NS_IMPL_GNUSTEP
7317   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7318 #else
7319   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7320 #endif
7322   window = XWINDOW (nwin);
7323   condemned = NO;
7324   pixel_height = NSHeight (r);
7325   if (pixel_height == 0) pixel_height = 1;
7326   min_portion = 20 / pixel_height;
7328   frame = XFRAME (window->frame);
7329   if (FRAME_LIVE_P (frame))
7330     {
7331       int i;
7332       EmacsView *view = FRAME_NS_VIEW (frame);
7333       NSView *sview = [[view window] contentView];
7334       NSArray *subs = [sview subviews];
7336       /* disable optimization stopping redraw of other scrollbars */
7337       view->scrollbarsNeedingUpdate = 0;
7338       for (i =[subs count]-1; i >= 0; i--)
7339         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7340           view->scrollbarsNeedingUpdate++;
7341       [sview addSubview: self];
7342     }
7344 /*  [self setFrame: r]; */
7346   return self;
7350 - (void)setFrame: (NSRect)newRect
7352   NSTRACE (EmacsScroller_setFrame);
7353 /*  block_input (); */
7354   pixel_height = NSHeight (newRect);
7355   if (pixel_height == 0) pixel_height = 1;
7356   min_portion = 20 / pixel_height;
7357   [super setFrame: newRect];
7358 /*  unblock_input (); */
7362 - (void)dealloc
7364   NSTRACE (EmacsScroller_dealloc);
7365   if (window)
7366     wset_vertical_scroll_bar (window, Qnil);
7367   window = 0;
7368   [super dealloc];
7372 - condemn
7374   NSTRACE (condemn);
7375   condemned =YES;
7376   return self;
7380 - reprieve
7382   NSTRACE (reprieve);
7383   condemned =NO;
7384   return self;
7388 -(bool)judge
7390   NSTRACE (judge);
7391   bool ret = condemned;
7392   if (condemned)
7393     {
7394       EmacsView *view;
7395       block_input ();
7396       /* ensure other scrollbar updates after deletion */
7397       view = (EmacsView *)FRAME_NS_VIEW (frame);
7398       if (view != nil)
7399         view->scrollbarsNeedingUpdate++;
7400       if (window)
7401         wset_vertical_scroll_bar (window, Qnil);
7402       window = 0;
7403       [self removeFromSuperview];
7404       [self release];
7405       unblock_input ();
7406     }
7407   return ret;
7411 - (void)resetCursorRects
7413   NSRect visible = [self visibleRect];
7414   NSTRACE (resetCursorRects);
7416   if (!NSIsEmptyRect (visible))
7417     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7418   [[NSCursor arrowCursor] setOnMouseEntered: YES];
7422 - (int) checkSamePosition: (int) position portion: (int) portion
7423                     whole: (int) whole
7425   return em_position ==position && em_portion ==portion && em_whole ==whole
7426     && portion != whole; /* needed for resize empty buf */
7430 - setPosition: (int)position portion: (int)portion whole: (int)whole
7432   NSTRACE (setPosition);
7434   em_position = position;
7435   em_portion = portion;
7436   em_whole = whole;
7438   if (portion >= whole)
7439     {
7440 #ifdef NS_IMPL_COCOA
7441       [self setKnobProportion: 1.0];
7442       [self setDoubleValue: 1.0];
7443 #else
7444       [self setFloatValue: 0.0 knobProportion: 1.0];
7445 #endif
7446     }
7447   else
7448     {
7449       float pos;
7450       CGFloat por;
7451       portion = max ((float)whole*min_portion/pixel_height, portion);
7452       pos = (float)position / (whole - portion);
7453       por = (CGFloat)portion/whole;
7454 #ifdef NS_IMPL_COCOA
7455       [self setKnobProportion: por];
7456       [self setDoubleValue: pos];
7457 #else
7458       [self setFloatValue: pos knobProportion: por];
7459 #endif
7460     }
7462   return self;
7465 /* set up emacs_event */
7466 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7468   Lisp_Object win;
7469   if (!emacs_event)
7470     return;
7472   emacs_event->part = last_hit_part;
7473   emacs_event->code = 0;
7474   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7475   XSETWINDOW (win, window);
7476   emacs_event->frame_or_window = win;
7477   emacs_event->timestamp = EV_TIMESTAMP (e);
7478   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7479   emacs_event->arg = Qnil;
7480   XSETINT (emacs_event->x, loc * pixel_height);
7481   XSETINT (emacs_event->y, pixel_height-20);
7483   if (q_event_ptr)
7484     {
7485       n_emacs_events_pending++;
7486       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7487     }
7488   else
7489     hold_event (emacs_event);
7490   EVENT_INIT (*emacs_event);
7491   ns_send_appdefined (-1);
7495 /* called manually thru timer to implement repeated button action w/hold-down */
7496 - repeatScroll: (NSTimer *)scrollEntry
7498   NSEvent *e = [[self window] currentEvent];
7499   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7500   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7502   /* clear timer if need be */
7503   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7504     {
7505         [scroll_repeat_entry invalidate];
7506         [scroll_repeat_entry release];
7507         scroll_repeat_entry = nil;
7509         if (inKnob)
7510           return self;
7512         scroll_repeat_entry
7513           = [[NSTimer scheduledTimerWithTimeInterval:
7514                         SCROLL_BAR_CONTINUOUS_DELAY
7515                                             target: self
7516                                           selector: @selector (repeatScroll:)
7517                                           userInfo: 0
7518                                            repeats: YES]
7519               retain];
7520     }
7522   [self sendScrollEventAtLoc: 0 fromEvent: e];
7523   return self;
7527 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7528    mouseDragged events without going into a modal loop. */
7529 - (void)mouseDown: (NSEvent *)e
7531   NSRect sr, kr;
7532   /* hitPart is only updated AFTER event is passed on */
7533   NSScrollerPart part = [self testPart: [e locationInWindow]];
7534   CGFloat inc = 0.0, loc, kloc, pos;
7535   int edge = 0;
7537   NSTRACE (EmacsScroller_mouseDown);
7539   switch (part)
7540     {
7541     case NSScrollerDecrementPage:
7542         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7543     case NSScrollerIncrementPage:
7544         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7545     case NSScrollerDecrementLine:
7546       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7547     case NSScrollerIncrementLine:
7548       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7549     case NSScrollerKnob:
7550       last_hit_part = scroll_bar_handle; break;
7551     case NSScrollerKnobSlot:  /* GNUstep-only */
7552       last_hit_part = scroll_bar_move_ratio; break;
7553     default:  /* NSScrollerNoPart? */
7554       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7555                (long) part);
7556       return;
7557     }
7559   if (inc != 0.0)
7560     {
7561       pos = 0;      /* ignored */
7563       /* set a timer to repeat, as we can't let superclass do this modally */
7564       scroll_repeat_entry
7565         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7566                                             target: self
7567                                           selector: @selector (repeatScroll:)
7568                                           userInfo: 0
7569                                            repeats: YES]
7570             retain];
7571     }
7572   else
7573     {
7574       /* handle, or on GNUstep possibly slot */
7575       NSEvent *fake_event;
7577       /* compute float loc in slot and mouse offset on knob */
7578       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7579                       toView: nil];
7580       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7581       if (loc <= 0.0)
7582         {
7583           loc = 0.0;
7584           edge = -1;
7585         }
7586       else if (loc >= NSHeight (sr))
7587         {
7588           loc = NSHeight (sr);
7589           edge = 1;
7590         }
7592       if (edge)
7593         kloc = 0.5 * edge;
7594       else
7595         {
7596           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7597                           toView: nil];
7598           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7599         }
7600       last_mouse_offset = kloc;
7602       /* if knob, tell emacs a location offset by knob pos
7603          (to indicate top of handle) */
7604       if (part == NSScrollerKnob)
7605           pos = (loc - last_mouse_offset) / NSHeight (sr);
7606       else
7607         /* else this is a slot click on GNUstep: go straight there */
7608         pos = loc / NSHeight (sr);
7610       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7611       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7612                                       location: [e locationInWindow]
7613                                  modifierFlags: [e modifierFlags]
7614                                      timestamp: [e timestamp]
7615                                   windowNumber: [e windowNumber]
7616                                        context: [e context]
7617                                    eventNumber: [e eventNumber]
7618                                     clickCount: [e clickCount]
7619                                       pressure: [e pressure]];
7620       [super mouseUp: fake_event];
7621     }
7623   if (part != NSScrollerKnob)
7624     [self sendScrollEventAtLoc: pos fromEvent: e];
7628 /* Called as we manually track scroller drags, rather than superclass. */
7629 - (void)mouseDragged: (NSEvent *)e
7631     NSRect sr;
7632     double loc, pos;
7634     NSTRACE (EmacsScroller_mouseDragged);
7636       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7637                       toView: nil];
7638       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7640       if (loc <= 0.0)
7641         {
7642           loc = 0.0;
7643         }
7644       else if (loc >= NSHeight (sr) + last_mouse_offset)
7645         {
7646           loc = NSHeight (sr) + last_mouse_offset;
7647         }
7649       pos = (loc - last_mouse_offset) / NSHeight (sr);
7650       [self sendScrollEventAtLoc: pos fromEvent: e];
7654 - (void)mouseUp: (NSEvent *)e
7656   if (scroll_repeat_entry)
7657     {
7658       [scroll_repeat_entry invalidate];
7659       [scroll_repeat_entry release];
7660       scroll_repeat_entry = nil;
7661     }
7662   last_hit_part = scroll_bar_above_handle;
7666 /* treat scrollwheel events in the bar as though they were in the main window */
7667 - (void) scrollWheel: (NSEvent *)theEvent
7669   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7670   [view mouseDown: theEvent];
7673 @end  /* EmacsScroller */
7676 #ifdef NS_IMPL_GNUSTEP
7677 /* Dummy class to get rid of startup warnings.  */
7678 @implementation EmacsDocument
7680 @end
7681 #endif
7684 /* ==========================================================================
7686    Font-related functions; these used to be in nsfaces.m
7688    ========================================================================== */
7691 Lisp_Object
7692 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7694   struct font *font = XFONT_OBJECT (font_object);
7695   EmacsView *view = FRAME_NS_VIEW (f);
7696   int font_ascent, font_descent;
7698   if (fontset < 0)
7699     fontset = fontset_from_font (font_object);
7700   FRAME_FONTSET (f) = fontset;
7702   if (FRAME_FONT (f) == font)
7703     /* This font is already set in frame F.  There's nothing more to
7704        do.  */
7705     return font_object;
7707   FRAME_FONT (f) = font;
7709   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7710   FRAME_COLUMN_WIDTH (f) = font->average_width;
7711   get_font_ascent_descent (font, &font_ascent, &font_descent);
7712   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
7714   /* Compute the scroll bar width in character columns.  */
7715   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7716     {
7717       int wid = FRAME_COLUMN_WIDTH (f);
7718       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7719         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7720     }
7721   else
7722     {
7723       int wid = FRAME_COLUMN_WIDTH (f);
7724       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7725     }
7727   /* Compute the scroll bar height in character lines.  */
7728   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
7729     {
7730       int height = FRAME_LINE_HEIGHT (f);
7731       FRAME_CONFIG_SCROLL_BAR_LINES (f)
7732         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
7733     }
7734   else
7735     {
7736       int height = FRAME_LINE_HEIGHT (f);
7737       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
7738     }
7740   /* Now make the frame display the given font.  */
7741   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
7742     x_set_window_size (f, false, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
7743                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), true);
7745   return font_object;
7749 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7750 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7751          in 1.43. */
7753 const char *
7754 ns_xlfd_to_fontname (const char *xlfd)
7755 /* --------------------------------------------------------------------------
7756     Convert an X font name (XLFD) to an NS font name.
7757     Only family is used.
7758     The string returned is temporarily allocated.
7759    -------------------------------------------------------------------------- */
7761   char *name = xmalloc (180);
7762   int i, len;
7763   const char *ret;
7765   if (!strncmp (xlfd, "--", 2))
7766     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7767   else
7768     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7770   /* stopgap for malformed XLFD input */
7771   if (strlen (name) == 0)
7772     strcpy (name, "Monaco");
7774   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7775      also uppercase after '-' or ' ' */
7776   name[0] = c_toupper (name[0]);
7777   for (len =strlen (name), i =0; i<len; i++)
7778     {
7779       if (name[i] == '$')
7780         {
7781           name[i] = '-';
7782           if (i+1<len)
7783             name[i+1] = c_toupper (name[i+1]);
7784         }
7785       else if (name[i] == '_')
7786         {
7787           name[i] = ' ';
7788           if (i+1<len)
7789             name[i+1] = c_toupper (name[i+1]);
7790         }
7791     }
7792 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7793   ret = [[NSString stringWithUTF8String: name] UTF8String];
7794   xfree (name);
7795   return ret;
7799 void
7800 syms_of_nsterm (void)
7802   NSTRACE (syms_of_nsterm);
7804   ns_antialias_threshold = 10.0;
7806   /* from 23+ we need to tell emacs what modifiers there are.. */
7807   DEFSYM (Qmodifier_value, "modifier-value");
7808   DEFSYM (Qalt, "alt");
7809   DEFSYM (Qhyper, "hyper");
7810   DEFSYM (Qmeta, "meta");
7811   DEFSYM (Qsuper, "super");
7812   DEFSYM (Qcontrol, "control");
7813   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7815   DEFSYM (Qfile, "file");
7816   DEFSYM (Qurl, "url");
7818   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7819   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7820   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7821   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7822   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7824   DEFVAR_LISP ("ns-input-file", ns_input_file,
7825               "The file specified in the last NS event.");
7826   ns_input_file =Qnil;
7828   DEFVAR_LISP ("ns-working-text", ns_working_text,
7829               "String for visualizing working composition sequence.");
7830   ns_working_text =Qnil;
7832   DEFVAR_LISP ("ns-input-font", ns_input_font,
7833               "The font specified in the last NS event.");
7834   ns_input_font =Qnil;
7836   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7837               "The fontsize specified in the last NS event.");
7838   ns_input_fontsize =Qnil;
7840   DEFVAR_LISP ("ns-input-line", ns_input_line,
7841                "The line specified in the last NS event.");
7842   ns_input_line =Qnil;
7844   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7845                "The service name specified in the last NS event.");
7846   ns_input_spi_name =Qnil;
7848   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7849                "The service argument specified in the last NS event.");
7850   ns_input_spi_arg =Qnil;
7852   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7853                "This variable describes the behavior of the alternate or option key.\n\
7854 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7855 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7856 at all, allowing it to be used at a lower level for accented character entry.");
7857   ns_alternate_modifier = Qmeta;
7859   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7860                "This variable describes the behavior of the right alternate or option key.\n\
7861 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7862 Set to left means be the same key as `ns-alternate-modifier'.\n\
7863 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7864 at all, allowing it to be used at a lower level for accented character entry.");
7865   ns_right_alternate_modifier = Qleft;
7867   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7868                "This variable describes the behavior of the command key.\n\
7869 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7870   ns_command_modifier = Qsuper;
7872   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7873                "This variable describes the behavior of the right command key.\n\
7874 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7875 Set to left means be the same key as `ns-command-modifier'.\n\
7876 Set to none means that the command / option key is not interpreted by Emacs\n\
7877 at all, allowing it to be used at a lower level for accented character entry.");
7878   ns_right_command_modifier = Qleft;
7880   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7881                "This variable describes the behavior of the control key.\n\
7882 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7883   ns_control_modifier = Qcontrol;
7885   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7886                "This variable describes the behavior of the right control key.\n\
7887 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7888 Set to left means be the same key as `ns-control-modifier'.\n\
7889 Set to none means that the control / option key is not interpreted by Emacs\n\
7890 at all, allowing it to be used at a lower level for accented character entry.");
7891   ns_right_control_modifier = Qleft;
7893   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7894                "This variable describes the behavior of the function key (on laptops).\n\
7895 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7896 Set to none means that the function key is not interpreted by Emacs at all,\n\
7897 allowing it to be used at a lower level for accented character entry.");
7898   ns_function_modifier = Qnone;
7900   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7901                "Non-nil (the default) means to render text antialiased.");
7902   ns_antialias_text = Qt;
7904   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7905                "Whether to confirm application quit using dialog.");
7906   ns_confirm_quit = Qnil;
7908   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7909                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7910 Only works on OSX 10.6 or later.  */);
7911   ns_auto_hide_menu_bar = Qnil;
7913   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7914      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7915 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7916 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7917 Default is t for OSX >= 10.7, nil otherwise.  */);
7918 #ifdef HAVE_NATIVE_FS
7919   ns_use_native_fullscreen = YES;
7920 #else
7921   ns_use_native_fullscreen = NO;
7922 #endif
7923   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7925   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
7926      doc: /*Non-nil means use animation on non-native fullscreen.
7927 For native fullscreen, this does nothing.
7928 Default is nil.  */);
7929   ns_use_fullscreen_animation = NO;
7931   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
7932      doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
7933 Note that this does not apply to images.
7934 This variable is ignored on OSX < 10.7 and GNUstep.  */);
7935   ns_use_srgb_colorspace = YES;
7937   /* TODO: move to common code */
7938   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7939                doc: /* Which toolkit scroll bars Emacs uses, if any.
7940 A value of nil means Emacs doesn't use toolkit scroll bars.
7941 With the X Window system, the value is a symbol describing the
7942 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7943 With MS Windows or Nextstep, the value is t.  */);
7944   Vx_toolkit_scroll_bars = Qt;
7946   DEFVAR_BOOL ("x-use-underline-position-properties",
7947                x_use_underline_position_properties,
7948      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7949 A value of nil means ignore them.  If you encounter fonts with bogus
7950 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7951 to 4.1, set this to nil. */);
7952   x_use_underline_position_properties = 0;
7954   DEFVAR_BOOL ("x-underline-at-descent-line",
7955                x_underline_at_descent_line,
7956      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7957 A value of nil means to draw the underline according to the value of the
7958 variable `x-use-underline-position-properties', which is usually at the
7959 baseline level.  The default value is nil.  */);
7960   x_underline_at_descent_line = 0;
7962   /* Tell Emacs about this window system.  */
7963   Fprovide (Qns, Qnil);
7965   DEFSYM (Qcocoa, "cocoa");
7966   DEFSYM (Qgnustep, "gnustep");
7968 #ifdef NS_IMPL_COCOA
7969   Fprovide (Qcocoa, Qnil);
7970   syms_of_macfont ();
7971 #else
7972   Fprovide (Qgnustep, Qnil);
7973   syms_of_nsfont ();
7974 #endif