* src/minibuf.c (read_minibuf): Use CONSP instead of Fconsp.
[emacs.git] / src / nsterm.m
blob1d48c041bad7bf2f0f910b63c16466869d386b39
1 /* NeXT/Open/GNUstep / MacOSX communication module.      -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2016 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or (at
11 your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 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
72 extern NSString *NSMenuDidBeginTrackingNotification;
75 /* ==========================================================================
77    NSTRACE, Trace support.
79    ========================================================================== */
81 #if NSTRACE_ENABLED
83 /* The following use "volatile" since they can be accessed from
84    parallel threads. */
85 volatile int nstrace_num = 0;
86 volatile int nstrace_depth = 0;
88 /* When 0, no trace is emitted.  This is used by NSTRACE_WHEN and
89    NSTRACE_UNLESS to silence functions called.
91    TODO: This should really be a thread-local variable, to avoid that
92    a function with disabled trace thread silence trace output in
93    another.  However, in practice this seldom is a problem. */
94 volatile int nstrace_enabled_global = 1;
96 /* Called when nstrace_enabled goes out of scope. */
97 void nstrace_leave(int * pointer_to_nstrace_enabled)
99   if (*pointer_to_nstrace_enabled)
100     {
101       --nstrace_depth;
102     }
106 /* Called when nstrace_saved_enabled_global goes out of scope. */
107 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
109   nstrace_enabled_global = *pointer_to_saved_enabled_global;
113 char const * nstrace_fullscreen_type_name (int fs_type)
115   switch (fs_type)
116     {
117     case -1:                   return "-1";
118     case FULLSCREEN_NONE:      return "FULLSCREEN_NONE";
119     case FULLSCREEN_WIDTH:     return "FULLSCREEN_WIDTH";
120     case FULLSCREEN_HEIGHT:    return "FULLSCREEN_HEIGHT";
121     case FULLSCREEN_BOTH:      return "FULLSCREEN_BOTH";
122     case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
123     default:                   return "FULLSCREEN_?????";
124     }
126 #endif
129 /* ==========================================================================
131    NSColor, EmacsColor category.
133    ========================================================================== */
134 @implementation NSColor (EmacsColor)
135 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
136                          blue:(CGFloat)blue alpha:(CGFloat)alpha
138 #ifdef NS_IMPL_COCOA
139 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
140   if (ns_use_srgb_colorspace)
141       return [NSColor colorWithSRGBRed: red
142                                  green: green
143                                   blue: blue
144                                  alpha: alpha];
145 #endif
146 #endif
147   return [NSColor colorWithCalibratedRed: red
148                                    green: green
149                                     blue: blue
150                                    alpha: alpha];
153 - (NSColor *)colorUsingDefaultColorSpace
155 #ifdef NS_IMPL_COCOA
156 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
157   if (ns_use_srgb_colorspace)
158     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
159 #endif
160 #endif
161   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
164 @end
166 /* ==========================================================================
168     Local declarations
170    ========================================================================== */
172 /* Convert a symbol indexed with an NSxxx value to a value as defined
173    in keyboard.c (lispy_function_key). I hope this is a correct way
174    of doing things... */
175 static unsigned convert_ns_to_X_keysym[] =
177   NSHomeFunctionKey,            0x50,
178   NSLeftArrowFunctionKey,       0x51,
179   NSUpArrowFunctionKey,         0x52,
180   NSRightArrowFunctionKey,      0x53,
181   NSDownArrowFunctionKey,       0x54,
182   NSPageUpFunctionKey,          0x55,
183   NSPageDownFunctionKey,        0x56,
184   NSEndFunctionKey,             0x57,
185   NSBeginFunctionKey,           0x58,
186   NSSelectFunctionKey,          0x60,
187   NSPrintFunctionKey,           0x61,
188   NSClearLineFunctionKey,       0x0B,
189   NSExecuteFunctionKey,         0x62,
190   NSInsertFunctionKey,          0x63,
191   NSUndoFunctionKey,            0x65,
192   NSRedoFunctionKey,            0x66,
193   NSMenuFunctionKey,            0x67,
194   NSFindFunctionKey,            0x68,
195   NSHelpFunctionKey,            0x6A,
196   NSBreakFunctionKey,           0x6B,
198   NSF1FunctionKey,              0xBE,
199   NSF2FunctionKey,              0xBF,
200   NSF3FunctionKey,              0xC0,
201   NSF4FunctionKey,              0xC1,
202   NSF5FunctionKey,              0xC2,
203   NSF6FunctionKey,              0xC3,
204   NSF7FunctionKey,              0xC4,
205   NSF8FunctionKey,              0xC5,
206   NSF9FunctionKey,              0xC6,
207   NSF10FunctionKey,             0xC7,
208   NSF11FunctionKey,             0xC8,
209   NSF12FunctionKey,             0xC9,
210   NSF13FunctionKey,             0xCA,
211   NSF14FunctionKey,             0xCB,
212   NSF15FunctionKey,             0xCC,
213   NSF16FunctionKey,             0xCD,
214   NSF17FunctionKey,             0xCE,
215   NSF18FunctionKey,             0xCF,
216   NSF19FunctionKey,             0xD0,
217   NSF20FunctionKey,             0xD1,
218   NSF21FunctionKey,             0xD2,
219   NSF22FunctionKey,             0xD3,
220   NSF23FunctionKey,             0xD4,
221   NSF24FunctionKey,             0xD5,
223   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
224   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
225   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
227   NSTabCharacter,               0x09,
228   0x19,                         0x09,  /* left tab->regular since pass shift */
229   NSCarriageReturnCharacter,    0x0D,
230   NSNewlineCharacter,           0x0D,
231   NSEnterCharacter,             0x8D,
233   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
234   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
235   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
236   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
237   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
238   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
239   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
240   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
241   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
242   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
243   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
244   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
245   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
246   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
247   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
248   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
250   0x1B,                         0x1B   /* escape */
253 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
254    the maximum font size to NOT antialias.  On GNUstep there is currently
255    no way to control this behavior. */
256 float ns_antialias_threshold;
258 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
259 NSString *ns_app_name = @"Emacs";  /* default changed later */
261 /* Display variables */
262 struct ns_display_info *x_display_list; /* Chain of existing displays */
263 long context_menu_value = 0;
265 /* display update */
266 static struct frame *ns_updating_frame;
267 static NSView *focus_view = NULL;
268 static int ns_window_num = 0;
269 #ifdef NS_IMPL_GNUSTEP
270 static NSRect uRect;            // TODO: This is dead, remove it?
271 #endif
272 static BOOL gsaved = NO;
273 static BOOL ns_fake_keydown = NO;
274 #ifdef NS_IMPL_COCOA
275 static BOOL ns_menu_bar_is_hidden = NO;
276 #endif
277 /*static int debug_lock = 0; */
279 /* event loop */
280 static BOOL send_appdefined = YES;
281 #define NO_APPDEFINED_DATA (-8)
282 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
283 static NSTimer *timed_entry = 0;
284 static NSTimer *scroll_repeat_entry = nil;
285 static fd_set select_readfds, select_writefds;
286 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
287 static int select_nfds = 0, select_valid = 0;
288 static struct timespec select_timeout = { 0, 0 };
289 static int selfds[2] = { -1, -1 };
290 static pthread_mutex_t select_mutex;
291 static int apploopnr = 0;
292 static NSAutoreleasePool *outerpool;
293 static struct input_event *emacs_event = NULL;
294 static struct input_event *q_event_ptr = NULL;
295 static int n_emacs_events_pending = 0;
296 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
297   *ns_pending_service_args;
298 static BOOL ns_do_open_file = NO;
299 static BOOL ns_last_use_native_fullscreen;
301 /* Non-zero means that a HELP_EVENT has been generated since Emacs
302    start.  */
304 static BOOL any_help_event_p = NO;
306 static struct {
307   struct input_event *q;
308   int nr, cap;
309 } hold_event_q = {
310   NULL, 0, 0
313 static NSString *represented_filename = nil;
314 static struct frame *represented_frame = 0;
316 #ifdef NS_IMPL_COCOA
318  * State for pending menu activation:
319  * MENU_NONE     Normal state
320  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
321  *               run lisp to update the menu.
322  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
323  *               will open.
324  */
325 #define MENU_NONE 0
326 #define MENU_PENDING 1
327 #define MENU_OPENING 2
328 static int menu_will_open_state = MENU_NONE;
330 /* Saved position for menu click.  */
331 static CGPoint menu_mouse_point;
332 #endif
334 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
335 #define NS_FUNCTION_KEY_MASK 0x800000
336 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
337 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
338 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
339 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
340 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
341 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
342 #define EV_MODIFIERS2(flags)                          \
343     (((flags & NSHelpKeyMask) ?           \
344            hyper_modifier : 0)                        \
345      | (!EQ (ns_right_alternate_modifier, Qleft) && \
346         ((flags & NSRightAlternateKeyMask) \
347          == NSRightAlternateKeyMask) ? \
348            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
349      | ((flags & NSAlternateKeyMask) ?                 \
350            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
351      | ((flags & NSShiftKeyMask) ?     \
352            shift_modifier : 0)                        \
353      | (!EQ (ns_right_control_modifier, Qleft) && \
354         ((flags & NSRightControlKeyMask) \
355          == NSRightControlKeyMask) ? \
356            parse_solitary_modifier (ns_right_control_modifier) : 0) \
357      | ((flags & NSControlKeyMask) ?      \
358            parse_solitary_modifier (ns_control_modifier) : 0)     \
359      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
360            parse_solitary_modifier (ns_function_modifier) : 0)    \
361      | (!EQ (ns_right_command_modifier, Qleft) && \
362         ((flags & NSRightCommandKeyMask) \
363          == NSRightCommandKeyMask) ? \
364            parse_solitary_modifier (ns_right_command_modifier) : 0) \
365      | ((flags & NSCommandKeyMask) ?      \
366            parse_solitary_modifier (ns_command_modifier):0))
367 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
369 #define EV_UDMODIFIERS(e)                                      \
370     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
371      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
372      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
373      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
374      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
375      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
376      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
377      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
378      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
380 #define EV_BUTTON(e)                                                         \
381     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
382       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
383      [e buttonNumber] - 1)
385 /* Convert the time field to a timestamp in milliseconds. */
386 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
388 /* This is a piece of code which is common to all the event handling
389    methods.  Maybe it should even be a function.  */
390 #define EV_TRAILER(e)                                                   \
391   {                                                                     \
392     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
393     EV_TRAILER2 (e);                                                    \
394   }
396 #define EV_TRAILER2(e)                                                  \
397   {                                                                     \
398       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
399       if (q_event_ptr)                                                  \
400         {                                                               \
401           Lisp_Object tem = Vinhibit_quit;                              \
402           Vinhibit_quit = Qt;                                           \
403           n_emacs_events_pending++;                                     \
404           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
405           Vinhibit_quit = tem;                                          \
406         }                                                               \
407       else                                                              \
408         hold_event (emacs_event);                                       \
409       EVENT_INIT (*emacs_event);                                        \
410       ns_send_appdefined (-1);                                          \
411     }
413 /* TODO: get rid of need for these forward declarations */
414 static void ns_condemn_scroll_bars (struct frame *f);
415 static void ns_judge_scroll_bars (struct frame *f);
416 void x_set_frame_alpha (struct frame *f);
419 /* ==========================================================================
421     Utilities
423    ========================================================================== */
425 void
426 ns_set_represented_filename (NSString* fstr, struct frame *f)
428   represented_filename = [fstr retain];
429   represented_frame = f;
432 void
433 ns_init_events (struct input_event* ev)
435   EVENT_INIT (*ev);
436   emacs_event = ev;
439 void
440 ns_finish_events ()
442   emacs_event = NULL;
445 static void
446 hold_event (struct input_event *event)
448   if (hold_event_q.nr == hold_event_q.cap)
449     {
450       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
451       else hold_event_q.cap *= 2;
452       hold_event_q.q =
453         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
454     }
456   hold_event_q.q[hold_event_q.nr++] = *event;
457   /* Make sure ns_read_socket is called, i.e. we have input.  */
458   raise (SIGIO);
459   send_appdefined = YES;
462 static Lisp_Object
463 append2 (Lisp_Object list, Lisp_Object item)
464 /* --------------------------------------------------------------------------
465    Utility to append to a list
466    -------------------------------------------------------------------------- */
468   return CALLN (Fnconc, list, list1 (item));
472 const char *
473 ns_etc_directory (void)
474 /* If running as a self-contained app bundle, return as a string the
475    filename of the etc directory, if present; else nil.  */
477   NSBundle *bundle = [NSBundle mainBundle];
478   NSString *resourceDir = [bundle resourcePath];
479   NSString *resourcePath;
480   NSFileManager *fileManager = [NSFileManager defaultManager];
481   BOOL isDir;
483   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
484   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
485     {
486       if (isDir) return [resourcePath UTF8String];
487     }
488   return NULL;
492 const char *
493 ns_exec_path (void)
494 /* If running as a self-contained app bundle, return as a path string
495    the filenames of the libexec and bin directories, ie libexec:bin.
496    Otherwise, return nil.
497    Normally, Emacs does not add its own bin/ directory to the PATH.
498    However, a self-contained NS build has a different layout, with
499    bin/ and libexec/ subdirectories in the directory that contains
500    Emacs.app itself.
501    We put libexec first, because init_callproc_1 uses the first
502    element to initialize exec-directory.  An alternative would be
503    for init_callproc to check for invocation-directory/libexec.
506   NSBundle *bundle = [NSBundle mainBundle];
507   NSString *resourceDir = [bundle resourcePath];
508   NSString *binDir = [bundle bundlePath];
509   NSString *resourcePath, *resourcePaths;
510   NSRange range;
511   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
512   NSFileManager *fileManager = [NSFileManager defaultManager];
513   NSArray *paths;
514   NSEnumerator *pathEnum;
515   BOOL isDir;
517   range = [resourceDir rangeOfString: @"Contents"];
518   if (range.location != NSNotFound)
519     {
520       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
521 #ifdef NS_IMPL_COCOA
522       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
523 #endif
524     }
526   paths = [binDir stringsByAppendingPaths:
527                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
528   pathEnum = [paths objectEnumerator];
529   resourcePaths = @"";
531   while ((resourcePath = [pathEnum nextObject]))
532     {
533       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
534         if (isDir)
535           {
536             if ([resourcePaths length] > 0)
537               resourcePaths
538                 = [resourcePaths stringByAppendingString: pathSeparator];
539             resourcePaths
540               = [resourcePaths stringByAppendingString: resourcePath];
541           }
542     }
543   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
545   return NULL;
549 const char *
550 ns_load_path (void)
551 /* If running as a self-contained app bundle, return as a path string
552    the filenames of the site-lisp and lisp directories.
553    Ie, site-lisp:lisp.  Otherwise, return nil.  */
555   NSBundle *bundle = [NSBundle mainBundle];
556   NSString *resourceDir = [bundle resourcePath];
557   NSString *resourcePath, *resourcePaths;
558   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
559   NSFileManager *fileManager = [NSFileManager defaultManager];
560   BOOL isDir;
561   NSArray *paths = [resourceDir stringsByAppendingPaths:
562                               [NSArray arrayWithObjects:
563                                          @"site-lisp", @"lisp", nil]];
564   NSEnumerator *pathEnum = [paths objectEnumerator];
565   resourcePaths = @"";
567   /* Hack to skip site-lisp.  */
568   if (no_site_lisp) resourcePath = [pathEnum nextObject];
570   while ((resourcePath = [pathEnum nextObject]))
571     {
572       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
573         if (isDir)
574           {
575             if ([resourcePaths length] > 0)
576               resourcePaths
577                 = [resourcePaths stringByAppendingString: pathSeparator];
578             resourcePaths
579               = [resourcePaths stringByAppendingString: resourcePath];
580           }
581     }
582   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
584   return NULL;
588 void
589 ns_init_locale (void)
590 /* OS X doesn't set any environment variables for the locale when run
591    from the GUI. Get the locale from the OS and set LANG. */
593   NSLocale *locale = [NSLocale currentLocale];
595   NSTRACE ("ns_init_locale");
597   @try
598     {
599       /* It seems OS X should probably use UTF-8 everywhere.
600          'localeIdentifier' does not specify the encoding, and I can't
601          find any way to get the OS to tell us which encoding to use,
602          so hard-code '.UTF-8'. */
603       NSString *localeID = [NSString stringWithFormat:@"%@.UTF-8",
604                                      [locale localeIdentifier]];
606       /* Set LANG to locale, but not if LANG is already set. */
607       setenv("LANG", [localeID UTF8String], 0);
608     }
609   @catch (NSException *e)
610     {
611       NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
612     }
616 void
617 ns_release_object (void *obj)
618 /* --------------------------------------------------------------------------
619     Release an object (callable from C)
620    -------------------------------------------------------------------------- */
622     [(id)obj release];
626 void
627 ns_retain_object (void *obj)
628 /* --------------------------------------------------------------------------
629     Retain an object (callable from C)
630    -------------------------------------------------------------------------- */
632     [(id)obj retain];
636 void *
637 ns_alloc_autorelease_pool (void)
638 /* --------------------------------------------------------------------------
639      Allocate a pool for temporary objects (callable from C)
640    -------------------------------------------------------------------------- */
642   return [[NSAutoreleasePool alloc] init];
646 void
647 ns_release_autorelease_pool (void *pool)
648 /* --------------------------------------------------------------------------
649      Free a pool and temporary objects it refers to (callable from C)
650    -------------------------------------------------------------------------- */
652   ns_release_object (pool);
656 static BOOL
657 ns_menu_bar_should_be_hidden (void)
658 /* True, if the menu bar should be hidden.  */
660   return !NILP (ns_auto_hide_menu_bar)
661     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
665 struct EmacsMargins
667   CGFloat top;
668   CGFloat bottom;
669   CGFloat left;
670   CGFloat right;
674 static struct EmacsMargins
675 ns_screen_margins (NSScreen *screen)
676 /* The parts of SCREEN used by the operating system.  */
678   NSTRACE ("ns_screen_margins");
680   struct EmacsMargins margins;
682   NSRect screenFrame = [screen frame];
683   NSRect screenVisibleFrame = [screen visibleFrame];
685   /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
686      menu bar, check this explicitly.  */
687   if (ns_menu_bar_should_be_hidden())
688     {
689       margins.top = 0;
690     }
691   else
692     {
693       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
694       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
695                                  + screenVisibleFrame.size.height);
697       margins.top = frameTop - visibleFrameTop;
698     }
700   {
701     CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
702     CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
703                                  + screenVisibleFrame.size.width);
704     margins.right = frameRight - visibleFrameRight;
705   }
707   margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
708   margins.left   = screenVisibleFrame.origin.x - screenFrame.origin.x;
710   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
711                margins.left,
712                margins.right,
713                margins.top,
714                margins.bottom);
716   return margins;
720 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
721    assumed to contain a hidden dock.  OS X currently use 4 pixels for
722    this, however, to be future compatible, a larger value is used.  */
723 #define DOCK_IGNORE_LIMIT 6
725 static struct EmacsMargins
726 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
727 /* The parts of SCREEN used by the operating system, excluding the parts
728 reserved for an hidden dock.  */
730   NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
732   struct EmacsMargins margins = ns_screen_margins(screen);
734   /* OS X (currently) reserved 4 pixels along the edge where a hidden
735      dock is located.  Unfortunately, it's not possible to find the
736      location and information about if the dock is hidden.  Instead,
737      it is assumed that if the margin of an edge is less than
738      DOCK_IGNORE_LIMIT, it contains a hidden dock.  */
739   if (margins.left <= DOCK_IGNORE_LIMIT)
740     {
741       margins.left = 0;
742     }
743   if (margins.right <= DOCK_IGNORE_LIMIT)
744     {
745       margins.right = 0;
746     }
747   if (margins.top <= DOCK_IGNORE_LIMIT)
748     {
749       margins.top = 0;
750     }
751   /* Note: This doesn't occur in current versions of OS X, but
752      included for completeness and future compatibility.  */
753   if (margins.bottom <= DOCK_IGNORE_LIMIT)
754     {
755       margins.bottom = 0;
756     }
758   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
759                margins.left,
760                margins.right,
761                margins.top,
762                margins.bottom);
764   return margins;
768 static CGFloat
769 ns_menu_bar_height (NSScreen *screen)
770 /* The height of the menu bar, if visible.
772    Note: Don't use this when fullscreen is enabled -- the screen
773    sometimes includes, sometimes excludes the menu bar area.  */
775   struct EmacsMargins margins = ns_screen_margins(screen);
777   CGFloat res = margins.top;
779   NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
781   return res;
785 /* ==========================================================================
787     Focus (clipping) and screen update
789    ========================================================================== */
792 // Window constraining
793 // -------------------
795 // To ensure that the windows are not placed under the menu bar, they
796 // are typically moved by the call-back constrainFrameRect. However,
797 // by overriding it, it's possible to inhibit this, leaving the window
798 // in it's original position.
800 // It's possible to hide the menu bar. However, technically, it's only
801 // possible to hide it when the application is active. To ensure that
802 // this work properly, the menu bar and window constraining are
803 // deferred until the application becomes active.
805 // Even though it's not possible to manually move a window above the
806 // top of the screen, it is allowed if it's done programmatically,
807 // when the menu is hidden. This allows the editable area to cover the
808 // full screen height.
810 // Test cases
811 // ----------
813 // Use the following extra files:
815 //    init.el:
816 //       ;; Hide menu and place frame slightly above the top of the screen.
817 //       (setq ns-auto-hide-menu-bar t)
818 //       (set-frame-position (selected-frame) 0 -20)
820 // Test 1:
822 //    emacs -Q -l init.el
824 //    Result: No menu bar, and the title bar should be above the screen.
826 // Test 2:
828 //    emacs -Q
830 //    Result: Menu bar visible, frame placed immediately below the menu.
833 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
835   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
836              NSTRACE_ARG_RECT (frameRect));
838   // --------------------
839   // Collect information about the screen the frame is covering.
840   //
842   NSArray *screens = [NSScreen screens];
843   NSUInteger nr_screens = [screens count];
845   int i;
847   // The height of the menu bar, if present in any screen the frame is
848   // displayed in.
849   int menu_bar_height = 0;
851   // A rectangle covering all the screen the frame is displayed in.
852   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
853   for (i = 0; i < nr_screens; ++i )
854     {
855       NSScreen *s = [screens objectAtIndex: i];
856       NSRect scrRect = [s frame];
858       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
859                    i, NSTRACE_ARG_RECT (scrRect));
861       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
862         {
863           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
865           if (!isFullscreen)
866             {
867               CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
868               menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
869             }
870         }
871     }
873   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
875   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
877   if (multiscreenRect.size.width == 0
878       || multiscreenRect.size.height == 0)
879     {
880       // Failed to find any monitor, give up.
881       NSTRACE_MSG ("multiscreenRect empty");
882       NSTRACE_RETURN_RECT (frameRect);
883       return frameRect;
884     }
887   // --------------------
888   // Find a suitable placement.
889   //
891   if (ns_menu_bar_should_be_hidden())
892     {
893       // When the menu bar is hidden, the user may place part of the
894       // frame above the top of the screen, for example to hide the
895       // title bar.
896       //
897       // Hence, keep the original position.
898     }
899   else
900     {
901       // Ensure that the frame is below the menu bar, or below the top
902       // of the screen.
903       //
904       // This assume that the menu bar is placed at the top in the
905       // rectangle that covers the monitors.  (It doesn't have to be,
906       // but if it's not it's hard to do anything useful.)
907       CGFloat topOfWorkArea = (multiscreenRect.origin.y
908                                + multiscreenRect.size.height
909                                - menu_bar_height);
911       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
912       if (topOfFrame > topOfWorkArea)
913         {
914           frameRect.origin.y -= topOfFrame - topOfWorkArea;
915           NSTRACE_RECT ("After placement adjust", frameRect);
916         }
917     }
919   // Include the following section to restrict frame to the screens.
920   // (If so, update it to allow the frame to stretch down below the
921   // screen.)
922 #if 0
923   // --------------------
924   // Ensure frame doesn't stretch below the screens.
925   //
927   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
929   if (diff > 0)
930     {
931       frameRect.origin.y = multiscreenRect.origin.y;
932       frameRect.size.height -= diff;
933     }
934 #endif
936   NSTRACE_RETURN_RECT (frameRect);
937   return frameRect;
941 static void
942 ns_constrain_all_frames (void)
943 /* --------------------------------------------------------------------------
944      Ensure that the menu bar doesn't cover any frames.
945    -------------------------------------------------------------------------- */
947   Lisp_Object tail, frame;
949   NSTRACE ("ns_constrain_all_frames");
951   block_input ();
953   FOR_EACH_FRAME (tail, frame)
954     {
955       struct frame *f = XFRAME (frame);
956       if (FRAME_NS_P (f))
957         {
958           EmacsView *view = FRAME_NS_VIEW (f);
960           if (![view isFullscreen])
961             {
962               [[view window]
963                 setFrame:constrain_frame_rect([[view window] frame], false)
964                  display:NO];
965             }
966         }
967     }
969   unblock_input ();
973 static void
974 ns_update_auto_hide_menu_bar (void)
975 /* --------------------------------------------------------------------------
976      Show or hide the menu bar, based on user setting.
977    -------------------------------------------------------------------------- */
979 #ifdef NS_IMPL_COCOA
980   NSTRACE ("ns_update_auto_hide_menu_bar");
982   block_input ();
984   if (NSApp != nil && [NSApp isActive])
985     {
986       // Note, "setPresentationOptions" triggers an error unless the
987       // application is active.
988       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
990       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
991         {
992           NSApplicationPresentationOptions options
993             = NSApplicationPresentationDefault;
995           if (menu_bar_should_be_hidden)
996             options |= NSApplicationPresentationAutoHideMenuBar
997               | NSApplicationPresentationAutoHideDock;
999           [NSApp setPresentationOptions: options];
1001           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
1003           if (!ns_menu_bar_is_hidden)
1004             {
1005               ns_constrain_all_frames ();
1006             }
1007         }
1008     }
1010   unblock_input ();
1011 #endif
1015 static void
1016 ns_update_begin (struct frame *f)
1017 /* --------------------------------------------------------------------------
1018    Prepare for a grouped sequence of drawing calls
1019    external (RIF) call; whole frame, called before update_window_begin
1020    -------------------------------------------------------------------------- */
1022   EmacsView *view = FRAME_NS_VIEW (f);
1023   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1025   ns_update_auto_hide_menu_bar ();
1027 #ifdef NS_IMPL_COCOA
1028   if ([view isFullscreen] && [view fsIsNative])
1029   {
1030     // Fix reappearing tool bar in fullscreen for OSX 10.7
1031     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1032     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1033     if (! tbar_visible != ! [toolbar isVisible])
1034       [toolbar setVisible: tbar_visible];
1035   }
1036 #endif
1038   ns_updating_frame = f;
1039   [view lockFocus];
1041   /* drawRect may have been called for say the minibuffer, and then clip path
1042      is for the minibuffer.  But the display engine may draw more because
1043      we have set the frame as garbaged.  So reset clip path to the whole
1044      view.  */
1045 #ifdef NS_IMPL_COCOA
1046   {
1047     NSBezierPath *bp;
1048     NSRect r = [view frame];
1049     NSRect cr = [[view window] frame];
1050     /* If a large frame size is set, r may be larger than the window frame
1051        before constrained.  In that case don't change the clip path, as we
1052        will clear in to the tool bar and title bar.  */
1053     if (r.size.height
1054         + FRAME_NS_TITLEBAR_HEIGHT (f)
1055         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1056       {
1057         bp = [[NSBezierPath bezierPathWithRect: r] retain];
1058         [bp setClip];
1059         [bp release];
1060       }
1061   }
1062 #endif
1064 #ifdef NS_IMPL_GNUSTEP
1065   uRect = NSMakeRect (0, 0, 0, 0);
1066 #endif
1070 static void
1071 ns_update_window_begin (struct window *w)
1072 /* --------------------------------------------------------------------------
1073    Prepare for a grouped sequence of drawing calls
1074    external (RIF) call; for one window, called after update_begin
1075    -------------------------------------------------------------------------- */
1077   struct frame *f = XFRAME (WINDOW_FRAME (w));
1078   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1080   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1081   w->output_cursor = w->cursor;
1083   block_input ();
1085   if (f == hlinfo->mouse_face_mouse_frame)
1086     {
1087       /* Don't do highlighting for mouse motion during the update.  */
1088       hlinfo->mouse_face_defer = 1;
1090         /* If the frame needs to be redrawn,
1091            simply forget about any prior mouse highlighting.  */
1092       if (FRAME_GARBAGED_P (f))
1093         hlinfo->mouse_face_window = Qnil;
1095       /* (further code for mouse faces ifdef'd out in other terms elided) */
1096     }
1098   unblock_input ();
1102 static void
1103 ns_update_window_end (struct window *w, bool cursor_on_p,
1104                       bool mouse_face_overwritten_p)
1105 /* --------------------------------------------------------------------------
1106    Finished a grouped sequence of drawing calls
1107    external (RIF) call; for one window called before update_end
1108    -------------------------------------------------------------------------- */
1110   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1112   /* note: this fn is nearly identical in all terms */
1113   if (!w->pseudo_window_p)
1114     {
1115       block_input ();
1117       if (cursor_on_p)
1118         display_and_set_cursor (w, 1,
1119                                 w->output_cursor.hpos, w->output_cursor.vpos,
1120                                 w->output_cursor.x, w->output_cursor.y);
1122       if (draw_window_fringes (w, 1))
1123         {
1124           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1125             x_draw_right_divider (w);
1126           else
1127             x_draw_vertical_border (w);
1128         }
1130       unblock_input ();
1131     }
1133   /* If a row with mouse-face was overwritten, arrange for
1134      frame_up_to_date to redisplay the mouse highlight.  */
1135   if (mouse_face_overwritten_p)
1136     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1140 static void
1141 ns_update_end (struct frame *f)
1142 /* --------------------------------------------------------------------------
1143    Finished a grouped sequence of drawing calls
1144    external (RIF) call; for whole frame, called after update_window_end
1145    -------------------------------------------------------------------------- */
1147   EmacsView *view = FRAME_NS_VIEW (f);
1149   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1151 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1152   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1154   block_input ();
1156   [view unlockFocus];
1157   [[view window] flushWindow];
1159   unblock_input ();
1160   ns_updating_frame = NULL;
1163 static void
1164 ns_focus (struct frame *f, NSRect *r, int n)
1165 /* --------------------------------------------------------------------------
1166    Internal: Focus on given frame.  During small local updates this is used to
1167      draw, however during large updates, ns_update_begin and ns_update_end are
1168      called to wrap the whole thing, in which case these calls are stubbed out.
1169      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1170      the back end won't do this automatically, and will just end up flushing
1171      the entire window.
1172    -------------------------------------------------------------------------- */
1174   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1175   if (r != NULL)
1176     {
1177       NSTRACE_RECT ("r", *r);
1178     }
1180   if (f != ns_updating_frame)
1181     {
1182       NSView *view = FRAME_NS_VIEW (f);
1183       if (view != focus_view)
1184         {
1185           if (focus_view != NULL)
1186             {
1187               [focus_view unlockFocus];
1188               [[focus_view window] flushWindow];
1189 /*debug_lock--; */
1190             }
1192           if (view)
1193             [view lockFocus];
1194           focus_view = view;
1195 /*if (view) debug_lock++; */
1196         }
1197     }
1199   /* clipping */
1200   if (r)
1201     {
1202       [[NSGraphicsContext currentContext] saveGraphicsState];
1203       if (n == 2)
1204         NSRectClipList (r, 2);
1205       else
1206         NSRectClip (*r);
1207       gsaved = YES;
1208     }
1212 static void
1213 ns_unfocus (struct frame *f)
1214 /* --------------------------------------------------------------------------
1215      Internal: Remove focus on given frame
1216    -------------------------------------------------------------------------- */
1218   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1220   if (gsaved)
1221     {
1222       [[NSGraphicsContext currentContext] restoreGraphicsState];
1223       gsaved = NO;
1224     }
1226   if (f != ns_updating_frame)
1227     {
1228       if (focus_view != NULL)
1229         {
1230           [focus_view unlockFocus];
1231           [[focus_view window] flushWindow];
1232           focus_view = NULL;
1233 /*debug_lock--; */
1234         }
1235     }
1239 static void
1240 ns_clip_to_row (struct window *w, struct glyph_row *row,
1241                 enum glyph_row_area area, BOOL gc)
1242 /* --------------------------------------------------------------------------
1243      Internal (but parallels other terms): Focus drawing on given row
1244    -------------------------------------------------------------------------- */
1246   struct frame *f = XFRAME (WINDOW_FRAME (w));
1247   NSRect clip_rect;
1248   int window_x, window_y, window_width;
1250   window_box (w, area, &window_x, &window_y, &window_width, 0);
1252   clip_rect.origin.x = window_x;
1253   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1254   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1255   clip_rect.size.width = window_width;
1256   clip_rect.size.height = row->visible_height;
1258   ns_focus (f, &clip_rect, 1);
1262 /* ==========================================================================
1264     Visible bell and beep.
1266    ========================================================================== */
1269 // This bell implementation shows the visual bell image asynchronously
1270 // from the rest of Emacs. This is done by adding a NSView to the
1271 // superview of the Emacs window and removing it using a timer.
1273 // Unfortunately, some Emacs operations, like scrolling, is done using
1274 // low-level primitives that copy the content of the window, including
1275 // the bell image. To some extent, this is handled by removing the
1276 // image prior to scrolling and marking that the window is in need for
1277 // redisplay.
1279 // To test this code, make sure that there is no artifacts of the bell
1280 // image in the following situations. Use a non-empty buffer (like the
1281 // tutorial) to ensure that a scroll is performed:
1283 // * Single-window: C-g C-v
1285 // * Side-by-windows: C-x 3 C-g C-v
1287 // * Windows above each other: C-x 2 C-g C-v
1289 @interface EmacsBell : NSImageView
1291   // Number of currently active bell:s.
1292   unsigned int nestCount;
1293   NSView * mView;
1294   bool isAttached;
1296 - (void)show:(NSView *)view;
1297 - (void)hide;
1298 - (void)remove;
1299 @end
1301 @implementation EmacsBell
1303 - (id)init;
1305   NSTRACE ("[EmacsBell init]");
1306   if ((self = [super init]))
1307     {
1308       nestCount = 0;
1309       isAttached = false;
1310 #ifdef NS_IMPL_GNUSTEP
1311       // GNUstep doesn't provide named images.  This was reported in
1312       // 2011, see https://savannah.gnu.org/bugs/?33396
1313       //
1314       // As a drop in replacement, a semitransparent gray square is used.
1315       self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1316       [self.image lockFocus];
1317       [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1318       NSRectFill(NSMakeRect(0, 0, 32, 32));
1319       [self.image unlockFocus];
1320 #else
1321       self.image = [NSImage imageNamed:NSImageNameCaution];
1322       [self.image setSize:NSMakeSize(self.image.size.width * 5,
1323                                      self.image.size.height * 5)];
1324 #endif
1325     }
1326   return self;
1329 - (void)show:(NSView *)view
1331   NSTRACE ("[EmacsBell show:]");
1332   NSTRACE_MSG ("nestCount: %u", nestCount);
1334   // Show the image, unless it's already shown.
1335   if (nestCount == 0)
1336     {
1337       NSRect rect = [view bounds];
1338       NSPoint pos;
1339       pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
1340       pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1342       [self setFrameOrigin:pos];
1343       [self setFrameSize:self.image.size];
1345       isAttached = true;
1346       mView = view;
1347       [[[view window] contentView] addSubview:self
1348                                    positioned:NSWindowAbove
1349                                    relativeTo:nil];
1350     }
1352   ++nestCount;
1354   [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1358 - (void)hide
1360   // Note: Trace output from this method isn't shown, reason unknown.
1361   // NSTRACE ("[EmacsBell hide]");
1363   if (nestCount > 0)
1364     --nestCount;
1366   // Remove the image once the last bell became inactive.
1367   if (nestCount == 0)
1368     {
1369       [self remove];
1370     }
1374 -(void)remove
1376   NSTRACE ("[EmacsBell remove]");
1377   if (isAttached)
1378     {
1379       NSTRACE_MSG ("removeFromSuperview");
1380       [self removeFromSuperview];
1381       mView.needsDisplay = YES;
1382       isAttached = false;
1383     }
1386 @end
1389 static EmacsBell * bell_view = nil;
1391 static void
1392 ns_ring_bell (struct frame *f)
1393 /* --------------------------------------------------------------------------
1394      "Beep" routine
1395    -------------------------------------------------------------------------- */
1397   NSTRACE ("ns_ring_bell");
1398   if (visible_bell)
1399     {
1400       struct frame *frame = SELECTED_FRAME ();
1401       NSView *view;
1403       if (bell_view == nil)
1404         {
1405           bell_view = [[EmacsBell alloc] init];
1406           [bell_view retain];
1407         }
1409       block_input ();
1411       view = FRAME_NS_VIEW (frame);
1412       if (view != nil)
1413         {
1414           [bell_view show:view];
1415         }
1417       unblock_input ();
1418     }
1419   else
1420     {
1421       NSBeep ();
1422     }
1426 static void hide_bell ()
1427 /* --------------------------------------------------------------------------
1428      Ensure the bell is hidden.
1429    -------------------------------------------------------------------------- */
1431   NSTRACE ("hide_bell");
1433   if (bell_view != nil)
1434     {
1435       [bell_view remove];
1436     }
1440 /* ==========================================================================
1442     Frame / window manager related functions
1444    ========================================================================== */
1447 static void
1448 ns_raise_frame (struct frame *f)
1449 /* --------------------------------------------------------------------------
1450      Bring window to foreground and make it active
1451    -------------------------------------------------------------------------- */
1453   NSView *view;
1455   check_window_system (f);
1456   view = FRAME_NS_VIEW (f);
1457   block_input ();
1458   if (FRAME_VISIBLE_P (f))
1459     [[view window] makeKeyAndOrderFront: NSApp];
1460   unblock_input ();
1464 static void
1465 ns_lower_frame (struct frame *f)
1466 /* --------------------------------------------------------------------------
1467      Send window to back
1468    -------------------------------------------------------------------------- */
1470   NSView *view;
1472   check_window_system (f);
1473   view = FRAME_NS_VIEW (f);
1474   block_input ();
1475   [[view window] orderBack: NSApp];
1476   unblock_input ();
1480 static void
1481 ns_frame_raise_lower (struct frame *f, bool raise)
1482 /* --------------------------------------------------------------------------
1483      External (hook)
1484    -------------------------------------------------------------------------- */
1486   NSTRACE ("ns_frame_raise_lower");
1488   if (raise)
1489     ns_raise_frame (f);
1490   else
1491     ns_lower_frame (f);
1495 static void
1496 ns_frame_rehighlight (struct frame *frame)
1497 /* --------------------------------------------------------------------------
1498      External (hook): called on things like window switching within frame
1499    -------------------------------------------------------------------------- */
1501   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1502   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1504   NSTRACE ("ns_frame_rehighlight");
1505   if (dpyinfo->x_focus_frame)
1506     {
1507       dpyinfo->x_highlight_frame
1508         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1509            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1510            : dpyinfo->x_focus_frame);
1511       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1512         {
1513           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1514           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1515         }
1516     }
1517   else
1518       dpyinfo->x_highlight_frame = 0;
1520   if (dpyinfo->x_highlight_frame &&
1521          dpyinfo->x_highlight_frame != old_highlight)
1522     {
1523       if (old_highlight)
1524         {
1525           x_update_cursor (old_highlight, 1);
1526           x_set_frame_alpha (old_highlight);
1527         }
1528       if (dpyinfo->x_highlight_frame)
1529         {
1530           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1531           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1532         }
1533     }
1537 void
1538 x_make_frame_visible (struct frame *f)
1539 /* --------------------------------------------------------------------------
1540      External: Show the window (X11 semantics)
1541    -------------------------------------------------------------------------- */
1543   NSTRACE ("x_make_frame_visible");
1544   /* XXX: at some points in past this was not needed, as the only place that
1545      called this (frame.c:Fraise_frame ()) also called raise_lower;
1546      if this ends up the case again, comment this out again. */
1547   if (!FRAME_VISIBLE_P (f))
1548     {
1549       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1551       SET_FRAME_VISIBLE (f, 1);
1552       ns_raise_frame (f);
1554       /* Making a new frame from a fullscreen frame will make the new frame
1555          fullscreen also.  So skip handleFS as this will print an error.  */
1556       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1557           && [view isFullscreen])
1558         return;
1560       if (f->want_fullscreen != FULLSCREEN_NONE)
1561         {
1562           block_input ();
1563           [view handleFS];
1564           unblock_input ();
1565         }
1566     }
1570 void
1571 x_make_frame_invisible (struct frame *f)
1572 /* --------------------------------------------------------------------------
1573      External: Hide the window (X11 semantics)
1574    -------------------------------------------------------------------------- */
1576   NSView *view;
1577   NSTRACE ("x_make_frame_invisible");
1578   check_window_system (f);
1579   view = FRAME_NS_VIEW (f);
1580   [[view window] orderOut: NSApp];
1581   SET_FRAME_VISIBLE (f, 0);
1582   SET_FRAME_ICONIFIED (f, 0);
1586 void
1587 x_iconify_frame (struct frame *f)
1588 /* --------------------------------------------------------------------------
1589      External: Iconify window
1590    -------------------------------------------------------------------------- */
1592   NSView *view;
1593   struct ns_display_info *dpyinfo;
1595   NSTRACE ("x_iconify_frame");
1596   check_window_system (f);
1597   view = FRAME_NS_VIEW (f);
1598   dpyinfo = FRAME_DISPLAY_INFO (f);
1600   if (dpyinfo->x_highlight_frame == f)
1601     dpyinfo->x_highlight_frame = 0;
1603   if ([[view window] windowNumber] <= 0)
1604     {
1605       /* the window is still deferred.  Make it very small, bring it
1606          on screen and order it out. */
1607       NSRect s = { { 100, 100}, {0, 0} };
1608       NSRect t;
1609       t = [[view window] frame];
1610       [[view window] setFrame: s display: NO];
1611       [[view window] orderBack: NSApp];
1612       [[view window] orderOut: NSApp];
1613       [[view window] setFrame: t display: NO];
1614     }
1615   [[view window] miniaturize: NSApp];
1618 /* Free X resources of frame F.  */
1620 void
1621 x_free_frame_resources (struct frame *f)
1623   NSView *view;
1624   struct ns_display_info *dpyinfo;
1625   Mouse_HLInfo *hlinfo;
1627   NSTRACE ("x_free_frame_resources");
1628   check_window_system (f);
1629   view = FRAME_NS_VIEW (f);
1630   dpyinfo = FRAME_DISPLAY_INFO (f);
1631   hlinfo = MOUSE_HL_INFO (f);
1633   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1635   block_input ();
1637   free_frame_menubar (f);
1638   free_frame_faces (f);
1640   if (f == dpyinfo->x_focus_frame)
1641     dpyinfo->x_focus_frame = 0;
1642   if (f == dpyinfo->x_highlight_frame)
1643     dpyinfo->x_highlight_frame = 0;
1644   if (f == hlinfo->mouse_face_mouse_frame)
1645     reset_mouse_highlight (hlinfo);
1647   if (f->output_data.ns->miniimage != nil)
1648     [f->output_data.ns->miniimage release];
1650   [[view window] close];
1651   [view release];
1653   xfree (f->output_data.ns);
1655   unblock_input ();
1658 void
1659 x_destroy_window (struct frame *f)
1660 /* --------------------------------------------------------------------------
1661      External: Delete the window
1662    -------------------------------------------------------------------------- */
1664   NSTRACE ("x_destroy_window");
1665   check_window_system (f);
1666   x_free_frame_resources (f);
1667   ns_window_num--;
1671 void
1672 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1673 /* --------------------------------------------------------------------------
1674      External: Position the window
1675    -------------------------------------------------------------------------- */
1677   NSView *view = FRAME_NS_VIEW (f);
1678   NSArray *screens = [NSScreen screens];
1679   NSScreen *fscreen = [screens objectAtIndex: 0];
1680   NSScreen *screen = [[view window] screen];
1682   NSTRACE ("x_set_offset");
1684   block_input ();
1686   f->left_pos = xoff;
1687   f->top_pos = yoff;
1689   if (view != nil && screen && fscreen)
1690     {
1691       f->left_pos = f->size_hint_flags & XNegative
1692         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1693         : f->left_pos;
1694       /* We use visibleFrame here to take menu bar into account.
1695          Ideally we should also adjust left/top with visibleFrame.origin.  */
1697       f->top_pos = f->size_hint_flags & YNegative
1698         ? ([screen visibleFrame].size.height + f->top_pos
1699            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1700            - FRAME_TOOLBAR_HEIGHT (f))
1701         : f->top_pos;
1702 #ifdef NS_IMPL_GNUSTEP
1703       if (f->left_pos < 100)
1704         f->left_pos = 100;  /* don't overlap menu */
1705 #endif
1706       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1707          menu bar.  */
1708       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
1709                                 SCREENMAXBOUND ([fscreen frame].size.height
1710                                                 - NS_TOP_POS (f)));
1711       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1712       [[view window] setFrameTopLeftPoint: pt];
1713       f->size_hint_flags &= ~(XNegative|YNegative);
1714     }
1716   unblock_input ();
1720 void
1721 x_set_window_size (struct frame *f,
1722                    bool change_gravity,
1723                    int width,
1724                    int height,
1725                    bool pixelwise)
1726 /* --------------------------------------------------------------------------
1727      Adjust window pixel size based on given character grid size
1728      Impl is a bit more complex than other terms, need to do some
1729      internal clipping.
1730    -------------------------------------------------------------------------- */
1732   EmacsView *view = FRAME_NS_VIEW (f);
1733   NSWindow *window = [view window];
1734   NSRect wr = [window frame];
1735   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1736   int pixelwidth, pixelheight;
1737   int orig_height = wr.size.height;
1739   NSTRACE ("x_set_window_size");
1741   if (view == nil)
1742     return;
1744   NSTRACE_RECT ("current", wr);
1745   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1746   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1748   block_input ();
1750   if (pixelwise)
1751     {
1752       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1753       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1754     }
1755   else
1756     {
1757       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1758       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1759     }
1761   /* If we have a toolbar, take its height into account. */
1762   if (tb && ! [view isFullscreen])
1763     {
1764     /* NOTE: previously this would generate wrong result if toolbar not
1765              yet displayed and fixing toolbar_height=32 helped, but
1766              now (200903) seems no longer needed */
1767     FRAME_TOOLBAR_HEIGHT (f) =
1768       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1769         - FRAME_NS_TITLEBAR_HEIGHT (f);
1770 #if 0
1771       /* Only breaks things here, removed by martin 2015-09-30.  */
1772 #ifdef NS_IMPL_GNUSTEP
1773       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1774 #endif
1775 #endif
1776     }
1777   else
1778     FRAME_TOOLBAR_HEIGHT (f) = 0;
1780   wr.size.width = pixelwidth + f->border_width;
1781   wr.size.height = pixelheight;
1782   if (! [view isFullscreen])
1783     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1784       + FRAME_TOOLBAR_HEIGHT (f);
1786   /* Do not try to constrain to this screen.  We may have multiple
1787      screens, and want Emacs to span those.  Constraining to screen
1788      prevents that, and that is not nice to the user.  */
1789  if (f->output_data.ns->zooming)
1790    f->output_data.ns->zooming = 0;
1791  else
1792    wr.origin.y += orig_height - wr.size.height;
1794  frame_size_history_add
1795    (f, Qx_set_window_size_1, width, height,
1796     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1797            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1798            make_number (f->border_width),
1799            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1800            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1802   [window setFrame: wr display: YES];
1804   [view updateFrameSize: NO];
1805   unblock_input ();
1809 static void
1810 ns_fullscreen_hook (struct frame *f)
1812   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1814   NSTRACE ("ns_fullscreen_hook");
1816   if (!FRAME_VISIBLE_P (f))
1817     return;
1819    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1820     {
1821       /* Old style fs don't initiate correctly if created from
1822          init/default-frame alist, so use a timer (not nice...).
1823       */
1824       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1825                                      selector: @selector (handleFS)
1826                                      userInfo: nil repeats: NO];
1827       return;
1828     }
1830   block_input ();
1831   [view handleFS];
1832   unblock_input ();
1835 /* ==========================================================================
1837     Color management
1839    ========================================================================== */
1842 NSColor *
1843 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1845   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1846   if (idx < 1 || idx >= color_table->avail)
1847     return nil;
1848   return color_table->colors[idx];
1852 unsigned long
1853 ns_index_color (NSColor *color, struct frame *f)
1855   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1856   ptrdiff_t idx;
1857   ptrdiff_t i;
1859   if (!color_table->colors)
1860     {
1861       color_table->size = NS_COLOR_CAPACITY;
1862       color_table->avail = 1; /* skip idx=0 as marker */
1863       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1864       color_table->colors[0] = nil;
1865       color_table->empty_indices = [[NSMutableSet alloc] init];
1866     }
1868   /* Do we already have this color?  */
1869   for (i = 1; i < color_table->avail; i++)
1870     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1871       return i;
1873   if ([color_table->empty_indices count] > 0)
1874     {
1875       NSNumber *index = [color_table->empty_indices anyObject];
1876       [color_table->empty_indices removeObject: index];
1877       idx = [index unsignedLongValue];
1878     }
1879   else
1880     {
1881       if (color_table->avail == color_table->size)
1882         color_table->colors =
1883           xpalloc (color_table->colors, &color_table->size, 1,
1884                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1885       idx = color_table->avail++;
1886     }
1888   color_table->colors[idx] = color;
1889   [color retain];
1890 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1891   return idx;
1895 void
1896 ns_free_indexed_color (unsigned long idx, struct frame *f)
1898   struct ns_color_table *color_table;
1899   NSColor *color;
1900   NSNumber *index;
1902   if (!f)
1903     return;
1905   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1907   if (idx <= 0 || idx >= color_table->size) {
1908     message1 ("ns_free_indexed_color: Color index out of range.\n");
1909     return;
1910   }
1912   index = [NSNumber numberWithUnsignedInt: idx];
1913   if ([color_table->empty_indices containsObject: index]) {
1914     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1915     return;
1916   }
1918   color = color_table->colors[idx];
1919   [color release];
1920   color_table->colors[idx] = nil;
1921   [color_table->empty_indices addObject: index];
1922 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1926 static int
1927 ns_get_color (const char *name, NSColor **col)
1928 /* --------------------------------------------------------------------------
1929      Parse a color name
1930    -------------------------------------------------------------------------- */
1931 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1932    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1933    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1935   NSColor *new = nil;
1936   static char hex[20];
1937   int scaling = 0;
1938   float r = -1.0, g, b;
1939   NSString *nsname = [NSString stringWithUTF8String: name];
1941   NSTRACE ("ns_get_color(%s, **)", name);
1943   block_input ();
1945   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1946     {
1947 #ifdef NS_IMPL_COCOA
1948       NSString *defname = [[NSUserDefaults standardUserDefaults]
1949                             stringForKey: @"AppleHighlightColor"];
1950       if (defname != nil)
1951         nsname = defname;
1952       else
1953 #endif
1954       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1955         {
1956           *col = [new colorUsingDefaultColorSpace];
1957           unblock_input ();
1958           return 0;
1959         }
1960       else
1961         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1963       name = [nsname UTF8String];
1964     }
1965   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1966     {
1967       /* NOTE: OSX applications normally don't set foreground selection, but
1968          text may be unreadable if we don't.
1969       */
1970       if ((new = [NSColor selectedTextColor]) != nil)
1971         {
1972           *col = [new colorUsingDefaultColorSpace];
1973           unblock_input ();
1974           return 0;
1975         }
1977       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1978       name = [nsname UTF8String];
1979     }
1981   /* First, check for some sort of numeric specification. */
1982   hex[0] = '\0';
1984   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1985     {
1986       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1987       [scanner scanFloat: &r];
1988       [scanner scanFloat: &g];
1989       [scanner scanFloat: &b];
1990     }
1991   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1992     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1993   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1994     {
1995       int len = (strlen(name) - 1);
1996       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1997       int i;
1998       scaling = strlen(name+start) / 3;
1999       for (i = 0; i < 3; i++)
2000         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2001                  name + start + i * scaling);
2002       hex[3 * (scaling + 1) - 1] = '\0';
2003     }
2005   if (hex[0])
2006     {
2007       int rr, gg, bb;
2008       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2009       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2010         {
2011           r = rr / fscale;
2012           g = gg / fscale;
2013           b = bb / fscale;
2014         }
2015     }
2017   if (r >= 0.0F)
2018     {
2019       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2020       unblock_input ();
2021       return 0;
2022     }
2024   /* Otherwise, color is expected to be from a list */
2025   {
2026     NSEnumerator *lenum, *cenum;
2027     NSString *name;
2028     NSColorList *clist;
2030 #ifdef NS_IMPL_GNUSTEP
2031     /* XXX: who is wrong, the requestor or the implementation? */
2032     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2033         == NSOrderedSame)
2034       nsname = @"highlightColor";
2035 #endif
2037     lenum = [[NSColorList availableColorLists] objectEnumerator];
2038     while ( (clist = [lenum nextObject]) && new == nil)
2039       {
2040         cenum = [[clist allKeys] objectEnumerator];
2041         while ( (name = [cenum nextObject]) && new == nil )
2042           {
2043             if ([name compare: nsname
2044                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
2045               new = [clist colorWithKey: name];
2046           }
2047       }
2048   }
2050   if (new)
2051     *col = [new colorUsingDefaultColorSpace];
2052   unblock_input ();
2053   return new ? 0 : 1;
2058 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2059 /* --------------------------------------------------------------------------
2060      Convert a Lisp string object to a NS color
2061    -------------------------------------------------------------------------- */
2063   NSTRACE ("ns_lisp_to_color");
2064   if (STRINGP (color))
2065     return ns_get_color (SSDATA (color), col);
2066   else if (SYMBOLP (color))
2067     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2068   return 1;
2072 Lisp_Object
2073 ns_color_to_lisp (NSColor *col)
2074 /* --------------------------------------------------------------------------
2075      Convert a color to a lisp string with the RGB equivalent
2076    -------------------------------------------------------------------------- */
2078   EmacsCGFloat red, green, blue, alpha, gray;
2079   char buf[1024];
2080   const char *str;
2081   NSTRACE ("ns_color_to_lisp");
2083   block_input ();
2084   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
2086       if ((str =[[col colorNameComponent] UTF8String]))
2087         {
2088           unblock_input ();
2089           return build_string ((char *)str);
2090         }
2092     [[col colorUsingDefaultColorSpace]
2093         getRed: &red green: &green blue: &blue alpha: &alpha];
2094   if (red == green && red == blue)
2095     {
2096       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
2097             getWhite: &gray alpha: &alpha];
2098       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
2099                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
2100       unblock_input ();
2101       return build_string (buf);
2102     }
2104   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
2105             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
2107   unblock_input ();
2108   return build_string (buf);
2112 void
2113 ns_query_color(void *col, XColor *color_def, int setPixel)
2114 /* --------------------------------------------------------------------------
2115          Get ARGB values out of NSColor col and put them into color_def.
2116          If setPixel, set the pixel to a concatenated version.
2117          and set color_def pixel to the resulting index.
2118    -------------------------------------------------------------------------- */
2120   EmacsCGFloat r, g, b, a;
2122   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2123   color_def->red   = r * 65535;
2124   color_def->green = g * 65535;
2125   color_def->blue  = b * 65535;
2127   if (setPixel == YES)
2128     color_def->pixel
2129       = ARGB_TO_ULONG((int)(a*255),
2130                       (int)(r*255), (int)(g*255), (int)(b*255));
2134 bool
2135 ns_defined_color (struct frame *f,
2136                   const char *name,
2137                   XColor *color_def,
2138                   bool alloc,
2139                   bool makeIndex)
2140 /* --------------------------------------------------------------------------
2141          Return true if named color found, and set color_def rgb accordingly.
2142          If makeIndex and alloc are nonzero put the color in the color_table,
2143          and set color_def pixel to the resulting index.
2144          If makeIndex is zero, set color_def pixel to ARGB.
2145          Return false if not found
2146    -------------------------------------------------------------------------- */
2148   NSColor *col;
2149   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2151   block_input ();
2152   if (ns_get_color (name, &col) != 0) /* Color not found  */
2153     {
2154       unblock_input ();
2155       return 0;
2156     }
2157   if (makeIndex && alloc)
2158     color_def->pixel = ns_index_color (col, f);
2159   ns_query_color (col, color_def, !makeIndex);
2160   unblock_input ();
2161   return 1;
2165 void
2166 x_set_frame_alpha (struct frame *f)
2167 /* --------------------------------------------------------------------------
2168      change the entire-frame transparency
2169    -------------------------------------------------------------------------- */
2171   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2172   double alpha = 1.0;
2173   double alpha_min = 1.0;
2175   NSTRACE ("x_set_frame_alpha");
2177   if (dpyinfo->x_highlight_frame == f)
2178     alpha = f->alpha[0];
2179   else
2180     alpha = f->alpha[1];
2182   if (FLOATP (Vframe_alpha_lower_limit))
2183     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2184   else if (INTEGERP (Vframe_alpha_lower_limit))
2185     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2187   if (alpha < 0.0)
2188     return;
2189   else if (1.0 < alpha)
2190     alpha = 1.0;
2191   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2192     alpha = alpha_min;
2194 #ifdef NS_IMPL_COCOA
2195   {
2196     EmacsView *view = FRAME_NS_VIEW (f);
2197   [[view window] setAlphaValue: alpha];
2198   }
2199 #endif
2203 /* ==========================================================================
2205     Mouse handling
2207    ========================================================================== */
2210 void
2211 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2212 /* --------------------------------------------------------------------------
2213      Programmatically reposition mouse pointer in pixel coordinates
2214    -------------------------------------------------------------------------- */
2216   NSTRACE ("frame_set_mouse_pixel_position");
2217   ns_raise_frame (f);
2218 #if 0
2219   /* FIXME: this does not work, and what about GNUstep? */
2220 #ifdef NS_IMPL_COCOA
2221   [FRAME_NS_VIEW (f) lockFocus];
2222   PSsetmouse ((float)pix_x, (float)pix_y);
2223   [FRAME_NS_VIEW (f) unlockFocus];
2224 #endif
2225 #endif
2228 static int
2229 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2230 /*   ------------------------------------------------------------------------
2231      Called by EmacsView on mouseMovement events.  Passes on
2232      to emacs mainstream code if we moved off of a rect of interest
2233      known as last_mouse_glyph.
2234      ------------------------------------------------------------------------ */
2236   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2237   NSRect *r;
2239 //  NSTRACE ("note_mouse_movement");
2241   dpyinfo->last_mouse_motion_frame = frame;
2242   r = &dpyinfo->last_mouse_glyph;
2244   /* Note, this doesn't get called for enter/leave, since we don't have a
2245      position.  Those are taken care of in the corresponding NSView methods. */
2247   /* has movement gone beyond last rect we were tracking? */
2248   if (x < r->origin.x || x >= r->origin.x + r->size.width
2249       || y < r->origin.y || y >= r->origin.y + r->size.height)
2250     {
2251       ns_update_begin (frame);
2252       frame->mouse_moved = 1;
2253       note_mouse_highlight (frame, x, y);
2254       remember_mouse_glyph (frame, x, y, r);
2255       ns_update_end (frame);
2256       return 1;
2257     }
2259   return 0;
2263 static void
2264 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2265                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2266                    Time *time)
2267 /* --------------------------------------------------------------------------
2268     External (hook): inform emacs about mouse position and hit parts.
2269     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2270     x & y should be position in the scrollbar (the whole bar, not the handle)
2271     and length of scrollbar respectively
2272    -------------------------------------------------------------------------- */
2274   id view;
2275   NSPoint position;
2276   Lisp_Object frame, tail;
2277   struct frame *f;
2278   struct ns_display_info *dpyinfo;
2280   NSTRACE ("ns_mouse_position");
2282   if (*fp == NULL)
2283     {
2284       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2285       return;
2286     }
2288   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2290   block_input ();
2292   /* Clear the mouse-moved flag for every frame on this display.  */
2293   FOR_EACH_FRAME (tail, frame)
2294     if (FRAME_NS_P (XFRAME (frame))
2295         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2296       XFRAME (frame)->mouse_moved = 0;
2298   dpyinfo->last_mouse_scroll_bar = nil;
2299   if (dpyinfo->last_mouse_frame
2300       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2301     f = dpyinfo->last_mouse_frame;
2302   else
2303     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2305   if (f && FRAME_NS_P (f))
2306     {
2307       view = FRAME_NS_VIEW (*fp);
2309       position = [[view window] mouseLocationOutsideOfEventStream];
2310       position = [view convertPoint: position fromView: nil];
2311       remember_mouse_glyph (f, position.x, position.y,
2312                             &dpyinfo->last_mouse_glyph);
2313       NSTRACE_POINT ("position", position);
2315       if (bar_window) *bar_window = Qnil;
2316       if (part) *part = scroll_bar_above_handle;
2318       if (x) XSETINT (*x, lrint (position.x));
2319       if (y) XSETINT (*y, lrint (position.y));
2320       if (time)
2321         *time = dpyinfo->last_mouse_movement_time;
2322       *fp = f;
2323     }
2325   unblock_input ();
2329 static void
2330 ns_frame_up_to_date (struct frame *f)
2331 /* --------------------------------------------------------------------------
2332     External (hook): Fix up mouse highlighting right after a full update.
2333     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2334    -------------------------------------------------------------------------- */
2336   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2338   if (FRAME_NS_P (f))
2339     {
2340       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2341       if (f == hlinfo->mouse_face_mouse_frame)
2342         {
2343           block_input ();
2344           ns_update_begin(f);
2345           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2346                                 hlinfo->mouse_face_mouse_x,
2347                                 hlinfo->mouse_face_mouse_y);
2348           ns_update_end(f);
2349           unblock_input ();
2350         }
2351     }
2355 static void
2356 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2357 /* --------------------------------------------------------------------------
2358     External (RIF): set frame mouse pointer type.
2359    -------------------------------------------------------------------------- */
2361   NSTRACE ("ns_define_frame_cursor");
2362   if (FRAME_POINTER_TYPE (f) != cursor)
2363     {
2364       EmacsView *view = FRAME_NS_VIEW (f);
2365       FRAME_POINTER_TYPE (f) = cursor;
2366       [[view window] invalidateCursorRectsForView: view];
2367       /* Redisplay assumes this function also draws the changed frame
2368          cursor, but this function doesn't, so do it explicitly.  */
2369       x_update_cursor (f, 1);
2370     }
2375 /* ==========================================================================
2377     Keyboard handling
2379    ========================================================================== */
2382 static unsigned
2383 ns_convert_key (unsigned code)
2384 /* --------------------------------------------------------------------------
2385     Internal call used by NSView-keyDown.
2386    -------------------------------------------------------------------------- */
2388   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2389   unsigned keysym;
2390   /* An array would be faster, but less easy to read. */
2391   for (keysym = 0; keysym < last_keysym; keysym += 2)
2392     if (code == convert_ns_to_X_keysym[keysym])
2393       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2394   return 0;
2395 /* if decide to use keyCode and Carbon table, use this line:
2396      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2400 char *
2401 x_get_keysym_name (int keysym)
2402 /* --------------------------------------------------------------------------
2403     Called by keyboard.c.  Not sure if the return val is important, except
2404     that it be unique.
2405    -------------------------------------------------------------------------- */
2407   static char value[16];
2408   NSTRACE ("x_get_keysym_name");
2409   sprintf (value, "%d", keysym);
2410   return value;
2415 /* ==========================================================================
2417     Block drawing operations
2419    ========================================================================== */
2422 static void
2423 ns_redraw_scroll_bars (struct frame *f)
2425   int i;
2426   id view;
2427   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2428   NSTRACE ("ns_redraw_scroll_bars");
2429   for (i =[subviews count]-1; i >= 0; i--)
2430     {
2431       view = [subviews objectAtIndex: i];
2432       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2433       [view display];
2434     }
2438 void
2439 ns_clear_frame (struct frame *f)
2440 /* --------------------------------------------------------------------------
2441       External (hook): Erase the entire frame
2442    -------------------------------------------------------------------------- */
2444   NSView *view = FRAME_NS_VIEW (f);
2445   NSRect r;
2447   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2449  /* comes on initial frame because we have
2450     after-make-frame-functions = select-frame */
2451  if (!FRAME_DEFAULT_FACE (f))
2452    return;
2454   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2456   r = [view bounds];
2458   block_input ();
2459   ns_focus (f, &r, 1);
2460   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2461   NSRectFill (r);
2462   ns_unfocus (f);
2464   /* as of 2006/11 or so this is now needed */
2465   ns_redraw_scroll_bars (f);
2466   unblock_input ();
2470 static void
2471 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2472 /* --------------------------------------------------------------------------
2473     External (RIF):  Clear section of frame
2474    -------------------------------------------------------------------------- */
2476   NSRect r = NSMakeRect (x, y, width, height);
2477   NSView *view = FRAME_NS_VIEW (f);
2478   struct face *face = FRAME_DEFAULT_FACE (f);
2480   if (!view || !face)
2481     return;
2483   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2485   r = NSIntersectionRect (r, [view frame]);
2486   ns_focus (f, &r, 1);
2487   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2489   NSRectFill (r);
2491   ns_unfocus (f);
2492   return;
2495 static void
2496 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2498   NSTRACE ("ns_copy_bits");
2500   if (FRAME_NS_VIEW (f))
2501     {
2502       hide_bell();              // Ensure the bell image isn't scrolled.
2504       ns_focus (f, &dest, 1);
2505       [FRAME_NS_VIEW (f) scrollRect: src
2506                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2507                                                  dest.origin.y - src.origin.y)];
2508       ns_unfocus (f);
2509     }
2512 static void
2513 ns_scroll_run (struct window *w, struct run *run)
2514 /* --------------------------------------------------------------------------
2515     External (RIF):  Insert or delete n lines at line vpos
2516    -------------------------------------------------------------------------- */
2518   struct frame *f = XFRAME (w->frame);
2519   int x, y, width, height, from_y, to_y, bottom_y;
2521   NSTRACE ("ns_scroll_run");
2523   /* begin copy from other terms */
2524   /* Get frame-relative bounding box of the text display area of W,
2525      without mode lines.  Include in this box the left and right
2526      fringe of W.  */
2527   window_box (w, ANY_AREA, &x, &y, &width, &height);
2529   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2530   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2531   bottom_y = y + height;
2533   if (to_y < from_y)
2534     {
2535       /* Scrolling up.  Make sure we don't copy part of the mode
2536          line at the bottom.  */
2537       if (from_y + run->height > bottom_y)
2538         height = bottom_y - from_y;
2539       else
2540         height = run->height;
2541     }
2542   else
2543     {
2544       /* Scrolling down.  Make sure we don't copy over the mode line.
2545          at the bottom.  */
2546       if (to_y + run->height > bottom_y)
2547         height = bottom_y - to_y;
2548       else
2549         height = run->height;
2550     }
2551   /* end copy from other terms */
2553   if (height == 0)
2554       return;
2556   block_input ();
2558   x_clear_cursor (w);
2560   {
2561     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2562     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2564     ns_copy_bits (f, srcRect , dstRect);
2565   }
2567   unblock_input ();
2571 static void
2572 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2573 /* --------------------------------------------------------------------------
2574     External (RIF): preparatory to fringe update after text was updated
2575    -------------------------------------------------------------------------- */
2577   struct frame *f;
2578   int width, height;
2580   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2582   /* begin copy from other terms */
2583   eassert (w);
2585   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2586     desired_row->redraw_fringe_bitmaps_p = 1;
2588   /* When a window has disappeared, make sure that no rest of
2589      full-width rows stays visible in the internal border.  */
2590   if (windows_or_buffers_changed
2591       && desired_row->full_width_p
2592       && (f = XFRAME (w->frame),
2593           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2594           width != 0)
2595       && (height = desired_row->visible_height,
2596           height > 0))
2597     {
2598       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2600       block_input ();
2601       ns_clear_frame_area (f, 0, y, width, height);
2602       ns_clear_frame_area (f,
2603                            FRAME_PIXEL_WIDTH (f) - width,
2604                            y, width, height);
2605       unblock_input ();
2606     }
2610 static void
2611 ns_shift_glyphs_for_insert (struct frame *f,
2612                            int x, int y, int width, int height,
2613                            int shift_by)
2614 /* --------------------------------------------------------------------------
2615     External (RIF): copy an area horizontally, don't worry about clearing src
2616    -------------------------------------------------------------------------- */
2618   NSRect srcRect = NSMakeRect (x, y, width, height);
2619   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2621   NSTRACE ("ns_shift_glyphs_for_insert");
2623   ns_copy_bits (f, srcRect, dstRect);
2628 /* ==========================================================================
2630     Character encoding and metrics
2632    ========================================================================== */
2635 static void
2636 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2637 /* --------------------------------------------------------------------------
2638      External (RIF); compute left/right overhang of whole string and set in s
2639    -------------------------------------------------------------------------- */
2641   struct font *font = s->font;
2643   if (s->char2b)
2644     {
2645       struct font_metrics metrics;
2646       unsigned int codes[2];
2647       codes[0] = *(s->char2b);
2648       codes[1] = *(s->char2b + s->nchars - 1);
2650       font->driver->text_extents (font, codes, 2, &metrics);
2651       s->left_overhang = -metrics.lbearing;
2652       s->right_overhang
2653         = metrics.rbearing > metrics.width
2654         ? metrics.rbearing - metrics.width : 0;
2655     }
2656   else
2657     {
2658       s->left_overhang = 0;
2659       if (EQ (font->driver->type, Qns))
2660         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2661           FONT_HEIGHT (font) * 0.2 : 0;
2662       else
2663         s->right_overhang = 0;
2664     }
2669 /* ==========================================================================
2671     Fringe and cursor drawing
2673    ========================================================================== */
2676 extern int max_used_fringe_bitmap;
2677 static void
2678 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2679                       struct draw_fringe_bitmap_params *p)
2680 /* --------------------------------------------------------------------------
2681     External (RIF); fringe-related
2682    -------------------------------------------------------------------------- */
2684   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2685      periodic bitmap is used to create a continuous pattern.  Since a
2686      bitmap is rendered one text line at a time, the start offset (dh)
2687      of the bitmap varies.  Concretely, this is used for the empty
2688      line indicator.
2690      For a bitmap, "h + dh" is the full height and is always
2691      invariant.  For a normal bitmap "dh" is zero.
2693      For example, when the period is three and the full height is 72
2694      the following combinations exists:
2696        h=72 dh=0
2697        h=71 dh=1
2698        h=70 dh=2 */
2700   struct frame *f = XFRAME (WINDOW_FRAME (w));
2701   struct face *face = p->face;
2702   static EmacsImage **bimgs = NULL;
2703   static int nBimgs = 0;
2705   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2706   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2707                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2709   /* grow bimgs if needed */
2710   if (nBimgs < max_used_fringe_bitmap)
2711     {
2712       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2713       memset (bimgs + nBimgs, 0,
2714               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2715       nBimgs = max_used_fringe_bitmap;
2716     }
2718   /* Must clip because of partially visible lines.  */
2719   ns_clip_to_row (w, row, ANY_AREA, YES);
2721   if (!p->overlay_p)
2722     {
2723       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2725       if (bx >= 0 && nx > 0)
2726         {
2727           NSRect r = NSMakeRect (bx, by, nx, ny);
2728           NSRectClip (r);
2729           [ns_lookup_indexed_color (face->background, f) set];
2730           NSRectFill (r);
2731         }
2732     }
2734   if (p->which)
2735     {
2736       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2737       EmacsImage *img = bimgs[p->which - 1];
2739       if (!img)
2740         {
2741           // Note: For "periodic" images, allocate one EmacsImage for
2742           // the base image, and use it for all dh:s.
2743           unsigned short *bits = p->bits;
2744           int full_height = p->h + p->dh;
2745           int i;
2746           unsigned char *cbits = xmalloc (full_height);
2748           for (i = 0; i < full_height; i++)
2749             cbits[i] = bits[i];
2750           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2751                                          height: full_height
2752                                              fg: 0 bg: 0];
2753           bimgs[p->which - 1] = img;
2754           xfree (cbits);
2755         }
2757       NSTRACE_RECT ("r", r);
2759       NSRectClip (r);
2760       /* Since we composite the bitmap instead of just blitting it, we need
2761          to erase the whole background. */
2762       [ns_lookup_indexed_color(face->background, f) set];
2763       NSRectFill (r);
2765       {
2766         NSColor *bm_color;
2767         if (!p->cursor_p)
2768           bm_color = ns_lookup_indexed_color(face->foreground, f);
2769         else if (p->overlay_p)
2770           bm_color = ns_lookup_indexed_color(face->background, f);
2771         else
2772           bm_color = f->output_data.ns->cursor_color;
2773         [img setXBMColor: bm_color];
2774       }
2776 #ifdef NS_IMPL_COCOA
2777       // Note: For periodic images, the full image height is "h + hd".
2778       // By using the height h, a suitable part of the image is used.
2779       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2781       NSTRACE_RECT ("fromRect", fromRect);
2783       [img drawInRect: r
2784               fromRect: fromRect
2785              operation: NSCompositeSourceOver
2786               fraction: 1.0
2787            respectFlipped: YES
2788                 hints: nil];
2789 #else
2790       {
2791         NSPoint pt = r.origin;
2792         pt.y += p->h;
2793         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2794       }
2795 #endif
2796     }
2797   ns_unfocus (f);
2801 static void
2802 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2803                        int x, int y, enum text_cursor_kinds cursor_type,
2804                        int cursor_width, bool on_p, bool active_p)
2805 /* --------------------------------------------------------------------------
2806      External call (RIF): draw cursor.
2807      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2808    -------------------------------------------------------------------------- */
2810   NSRect r, s;
2811   int fx, fy, h, cursor_height;
2812   struct frame *f = WINDOW_XFRAME (w);
2813   struct glyph *phys_cursor_glyph;
2814   struct glyph *cursor_glyph;
2815   struct face *face;
2816   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2818   /* If cursor is out of bounds, don't draw garbage.  This can happen
2819      in mini-buffer windows when switching between echo area glyphs
2820      and mini-buffer.  */
2822   NSTRACE ("ns_draw_window_cursor");
2824   if (!on_p)
2825     return;
2827   w->phys_cursor_type = cursor_type;
2828   w->phys_cursor_on_p = on_p;
2830   if (cursor_type == NO_CURSOR)
2831     {
2832       w->phys_cursor_width = 0;
2833       return;
2834     }
2836   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2837     {
2838       if (glyph_row->exact_window_width_line_p
2839           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2840         {
2841           glyph_row->cursor_in_fringe_p = 1;
2842           draw_fringe_bitmap (w, glyph_row, 0);
2843         }
2844       return;
2845     }
2847   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2848      (other terminals do it the other way round).  We must set
2849      w->phys_cursor_width to the cursor width.  For bar cursors, that
2850      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2851   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2853   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2854      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2855   if (cursor_type == BAR_CURSOR)
2856     {
2857       if (cursor_width < 1)
2858         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2859       w->phys_cursor_width = cursor_width;
2860     }
2861   /* If we have an HBAR, "cursor_width" MAY specify height. */
2862   else if (cursor_type == HBAR_CURSOR)
2863     {
2864       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2865       if (cursor_height > glyph_row->height)
2866         cursor_height = glyph_row->height;
2867       if (h > cursor_height) // Cursor smaller than line height, move down
2868         fy += h - cursor_height;
2869       h = cursor_height;
2870     }
2872   r.origin.x = fx, r.origin.y = fy;
2873   r.size.height = h;
2874   r.size.width = w->phys_cursor_width;
2876   /* TODO: only needed in rare cases with last-resort font in HELLO..
2877      should we do this more efficiently? */
2878   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2881   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2882   if (face && NS_FACE_BACKGROUND (face)
2883       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2884     {
2885       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2886       hollow_color = FRAME_CURSOR_COLOR (f);
2887     }
2888   else
2889     [FRAME_CURSOR_COLOR (f) set];
2891 #ifdef NS_IMPL_COCOA
2892   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2893            atomic.  Cleaner ways of doing this should be investigated.
2894            One way would be to set a global variable DRAWING_CURSOR
2895            when making the call to draw_phys..(), don't focus in that
2896            case, then move the ns_unfocus() here after that call. */
2897   NSDisableScreenUpdates ();
2898 #endif
2900   switch (cursor_type)
2901     {
2902     case DEFAULT_CURSOR:
2903     case NO_CURSOR:
2904       break;
2905     case FILLED_BOX_CURSOR:
2906       NSRectFill (r);
2907       break;
2908     case HOLLOW_BOX_CURSOR:
2909       NSRectFill (r);
2910       [hollow_color set];
2911       NSRectFill (NSInsetRect (r, 1, 1));
2912       [FRAME_CURSOR_COLOR (f) set];
2913       break;
2914     case HBAR_CURSOR:
2915       NSRectFill (r);
2916       break;
2917     case BAR_CURSOR:
2918       s = r;
2919       /* If the character under cursor is R2L, draw the bar cursor
2920          on the right of its glyph, rather than on the left.  */
2921       cursor_glyph = get_phys_cursor_glyph (w);
2922       if ((cursor_glyph->resolved_level & 1) != 0)
2923         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2925       NSRectFill (s);
2926       break;
2927     }
2928   ns_unfocus (f);
2930   /* draw the character under the cursor */
2931   if (cursor_type != NO_CURSOR)
2932     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2934 #ifdef NS_IMPL_COCOA
2935   NSEnableScreenUpdates ();
2936 #endif
2941 static void
2942 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2943 /* --------------------------------------------------------------------------
2944      External (RIF): Draw a vertical line.
2945    -------------------------------------------------------------------------- */
2947   struct frame *f = XFRAME (WINDOW_FRAME (w));
2948   struct face *face;
2949   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2951   NSTRACE ("ns_draw_vertical_window_border");
2953   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2954   if (face)
2955       [ns_lookup_indexed_color(face->foreground, f) set];
2957   ns_focus (f, &r, 1);
2958   NSRectFill(r);
2959   ns_unfocus (f);
2963 static void
2964 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2965 /* --------------------------------------------------------------------------
2966      External (RIF): Draw a window divider.
2967    -------------------------------------------------------------------------- */
2969   struct frame *f = XFRAME (WINDOW_FRAME (w));
2970   struct face *face;
2971   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2973   NSTRACE ("ns_draw_window_divider");
2975   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2976   if (face)
2977       [ns_lookup_indexed_color(face->foreground, f) set];
2979   ns_focus (f, &r, 1);
2980   NSRectFill(r);
2981   ns_unfocus (f);
2984 static void
2985 ns_show_hourglass (struct frame *f)
2987   /* TODO: add NSProgressIndicator to all frames.  */
2990 static void
2991 ns_hide_hourglass (struct frame *f)
2993   /* TODO: remove NSProgressIndicator from all frames.  */
2996 /* ==========================================================================
2998     Glyph drawing operations
3000    ========================================================================== */
3002 static int
3003 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3004 /* --------------------------------------------------------------------------
3005     Wrapper utility to account for internal border width on full-width lines,
3006     and allow top full-width rows to hit the frame top.  nr should be pointer
3007     to two successive NSRects.  Number of rects actually used is returned.
3008    -------------------------------------------------------------------------- */
3010   int n = get_glyph_string_clip_rects (s, nr, 2);
3011   return n;
3014 /* --------------------------------------------------------------------
3015    Draw a wavy line under glyph string s. The wave fills wave_height
3016    pixels from y.
3018                     x          wave_length = 2
3019                                  --
3020                 y    *   *   *   *   *
3021                      |* * * * * * * * *
3022     wave_height = 3  | *   *   *   *
3023   --------------------------------------------------------------------- */
3025 static void
3026 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3028   int wave_height = 3, wave_length = 2;
3029   int y, dx, dy, odd, xmax;
3030   NSPoint a, b;
3031   NSRect waveClip;
3033   dx = wave_length;
3034   dy = wave_height - 1;
3035   y =  s->ybase - wave_height + 3;
3036   xmax = x + width;
3038   /* Find and set clipping rectangle */
3039   waveClip = NSMakeRect (x, y, width, wave_height);
3040   [[NSGraphicsContext currentContext] saveGraphicsState];
3041   NSRectClip (waveClip);
3043   /* Draw the waves */
3044   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3045   b.x = a.x + dx;
3046   odd = (int)(a.x/dx) % 2;
3047   a.y = b.y = y + 0.5;
3049   if (odd)
3050     a.y += dy;
3051   else
3052     b.y += dy;
3054   while (a.x <= xmax)
3055     {
3056       [NSBezierPath strokeLineFromPoint:a toPoint:b];
3057       a.x = b.x, a.y = b.y;
3058       b.x += dx, b.y = y + 0.5 + odd*dy;
3059       odd = !odd;
3060     }
3062   /* Restore previous clipping rectangle(s) */
3063   [[NSGraphicsContext currentContext] restoreGraphicsState];
3068 void
3069 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3070                          NSColor *defaultCol, CGFloat width, CGFloat x)
3071 /* --------------------------------------------------------------------------
3072    Draw underline, overline, and strike-through on glyph string s.
3073    -------------------------------------------------------------------------- */
3075   if (s->for_overlaps)
3076     return;
3078   /* Do underline. */
3079   if (face->underline_p)
3080     {
3081       if (s->face->underline_type == FACE_UNDER_WAVE)
3082         {
3083           if (face->underline_defaulted_p)
3084             [defaultCol set];
3085           else
3086             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3088           ns_draw_underwave (s, width, x);
3089         }
3090       else if (s->face->underline_type == FACE_UNDER_LINE)
3091         {
3093           NSRect r;
3094           unsigned long thickness, position;
3096           /* If the prev was underlined, match its appearance. */
3097           if (s->prev && s->prev->face->underline_p
3098               && s->prev->face->underline_type == FACE_UNDER_LINE
3099               && s->prev->underline_thickness > 0)
3100             {
3101               thickness = s->prev->underline_thickness;
3102               position = s->prev->underline_position;
3103             }
3104           else
3105             {
3106               struct font *font;
3107               unsigned long descent;
3109               font=s->font;
3110               descent = s->y + s->height - s->ybase;
3112               /* Use underline thickness of font, defaulting to 1. */
3113               thickness = (font && font->underline_thickness > 0)
3114                 ? font->underline_thickness : 1;
3116               /* Determine the offset of underlining from the baseline. */
3117               if (x_underline_at_descent_line)
3118                 position = descent - thickness;
3119               else if (x_use_underline_position_properties
3120                        && font && font->underline_position >= 0)
3121                 position = font->underline_position;
3122               else if (font)
3123                 position = lround (font->descent / 2);
3124               else
3125                 position = underline_minimum_offset;
3127               position = max (position, underline_minimum_offset);
3129               /* Ensure underlining is not cropped. */
3130               if (descent <= position)
3131                 {
3132                   position = descent - 1;
3133                   thickness = 1;
3134                 }
3135               else if (descent < position + thickness)
3136                 thickness = 1;
3137             }
3139           s->underline_thickness = thickness;
3140           s->underline_position = position;
3142           r = NSMakeRect (x, s->ybase + position, width, thickness);
3144           if (face->underline_defaulted_p)
3145             [defaultCol set];
3146           else
3147             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3148           NSRectFill (r);
3149         }
3150     }
3151   /* Do overline. We follow other terms in using a thickness of 1
3152      and ignoring overline_margin. */
3153   if (face->overline_p)
3154     {
3155       NSRect r;
3156       r = NSMakeRect (x, s->y, width, 1);
3158       if (face->overline_color_defaulted_p)
3159         [defaultCol set];
3160       else
3161         [ns_lookup_indexed_color (face->overline_color, s->f) set];
3162       NSRectFill (r);
3163     }
3165   /* Do strike-through.  We follow other terms for thickness and
3166      vertical position.*/
3167   if (face->strike_through_p)
3168     {
3169       NSRect r;
3170       unsigned long dy;
3172       dy = lrint ((s->height - 1) / 2);
3173       r = NSMakeRect (x, s->y + dy, width, 1);
3175       if (face->strike_through_color_defaulted_p)
3176         [defaultCol set];
3177       else
3178         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3179       NSRectFill (r);
3180     }
3183 static void
3184 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3185              char left_p, char right_p)
3186 /* --------------------------------------------------------------------------
3187     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3188     Note we can't just use an NSDrawRect command, because of the possibility
3189     of some sides not being drawn, and because the rect will be filled.
3190    -------------------------------------------------------------------------- */
3192   NSRect s = r;
3193   [col set];
3195   /* top, bottom */
3196   s.size.height = thickness;
3197   NSRectFill (s);
3198   s.origin.y += r.size.height - thickness;
3199   NSRectFill (s);
3201   s.size.height = r.size.height;
3202   s.origin.y = r.origin.y;
3204   /* left, right (optional) */
3205   s.size.width = thickness;
3206   if (left_p)
3207     NSRectFill (s);
3208   if (right_p)
3209     {
3210       s.origin.x += r.size.width - thickness;
3211       NSRectFill (s);
3212     }
3216 static void
3217 ns_draw_relief (NSRect r, int thickness, char raised_p,
3218                char top_p, char bottom_p, char left_p, char right_p,
3219                struct glyph_string *s)
3220 /* --------------------------------------------------------------------------
3221     Draw a relief rect inside r, optionally leaving some sides open.
3222     Note we can't just use an NSDrawBezel command, because of the possibility
3223     of some sides not being drawn, and because the rect will be filled.
3224    -------------------------------------------------------------------------- */
3226   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3227   NSColor *newBaseCol = nil;
3228   NSRect sr = r;
3230   NSTRACE ("ns_draw_relief");
3232   /* set up colors */
3234   if (s->face->use_box_color_for_shadows_p)
3235     {
3236       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3237     }
3238 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3239            && s->img->pixmap
3240            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3241        {
3242          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3243        } */
3244   else
3245     {
3246       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3247     }
3249   if (newBaseCol == nil)
3250     newBaseCol = [NSColor grayColor];
3252   if (newBaseCol != baseCol)  /* TODO: better check */
3253     {
3254       [baseCol release];
3255       baseCol = [newBaseCol retain];
3256       [lightCol release];
3257       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3258       [darkCol release];
3259       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3260     }
3262   [(raised_p ? lightCol : darkCol) set];
3264   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3266   /* top */
3267   sr.size.height = thickness;
3268   if (top_p) NSRectFill (sr);
3270   /* left */
3271   sr.size.height = r.size.height;
3272   sr.size.width = thickness;
3273   if (left_p) NSRectFill (sr);
3275   [(raised_p ? darkCol : lightCol) set];
3277   /* bottom */
3278   sr.size.width = r.size.width;
3279   sr.size.height = thickness;
3280   sr.origin.y += r.size.height - thickness;
3281   if (bottom_p) NSRectFill (sr);
3283   /* right */
3284   sr.size.height = r.size.height;
3285   sr.origin.y = r.origin.y;
3286   sr.size.width = thickness;
3287   sr.origin.x += r.size.width - thickness;
3288   if (right_p) NSRectFill (sr);
3292 static void
3293 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3294 /* --------------------------------------------------------------------------
3295       Function modeled after x_draw_glyph_string_box ().
3296       Sets up parameters for drawing.
3297    -------------------------------------------------------------------------- */
3299   int right_x, last_x;
3300   char left_p, right_p;
3301   struct glyph *last_glyph;
3302   NSRect r;
3303   int thickness;
3304   struct face *face;
3306   if (s->hl == DRAW_MOUSE_FACE)
3307     {
3308       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3309       if (!face)
3310         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3311     }
3312   else
3313     face = s->face;
3315   thickness = face->box_line_width;
3317   NSTRACE ("ns_dumpglyphs_box_or_relief");
3319   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3320             ? WINDOW_RIGHT_EDGE_X (s->w)
3321             : window_box_right (s->w, s->area));
3322   last_glyph = (s->cmp || s->img
3323                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3325   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3326               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3328   left_p = (s->first_glyph->left_box_line_p
3329             || (s->hl == DRAW_MOUSE_FACE
3330                 && (s->prev == NULL || s->prev->hl != s->hl)));
3331   right_p = (last_glyph->right_box_line_p
3332              || (s->hl == DRAW_MOUSE_FACE
3333                  && (s->next == NULL || s->next->hl != s->hl)));
3335   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3337   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3338   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3339     {
3340       ns_draw_box (r, abs (thickness),
3341                    ns_lookup_indexed_color (face->box_color, s->f),
3342                   left_p, right_p);
3343     }
3344   else
3345     {
3346       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3347                      1, 1, left_p, right_p, s);
3348     }
3352 static void
3353 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3354 /* --------------------------------------------------------------------------
3355       Modeled after x_draw_glyph_string_background, which draws BG in
3356       certain cases.  Others are left to the text rendering routine.
3357    -------------------------------------------------------------------------- */
3359   NSTRACE ("ns_maybe_dumpglyphs_background");
3361   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3362     {
3363       int box_line_width = max (s->face->box_line_width, 0);
3364       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3365           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3366              dimensions, since the actual glyphs might be much
3367              smaller.  So in that case we always clear the rectangle
3368              with background color.  */
3369           || FONT_TOO_HIGH (s->font)
3370           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3371         {
3372           struct face *face;
3373           if (s->hl == DRAW_MOUSE_FACE)
3374             {
3375               face = FACE_FROM_ID (s->f,
3376                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3377               if (!face)
3378                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3379             }
3380           else
3381             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3382           if (!face->stipple)
3383             [(NS_FACE_BACKGROUND (face) != 0
3384               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3385               : FRAME_BACKGROUND_COLOR (s->f)) set];
3386           else
3387             {
3388               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3389               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3390             }
3392           if (s->hl != DRAW_CURSOR)
3393             {
3394               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3395                                     s->background_width,
3396                                     s->height-2*box_line_width);
3397               NSRectFill (r);
3398             }
3400           s->background_filled_p = 1;
3401         }
3402     }
3406 static void
3407 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3408 /* --------------------------------------------------------------------------
3409       Renders an image and associated borders.
3410    -------------------------------------------------------------------------- */
3412   EmacsImage *img = s->img->pixmap;
3413   int box_line_vwidth = max (s->face->box_line_width, 0);
3414   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3415   int bg_x, bg_y, bg_height;
3416   int th;
3417   char raised_p;
3418   NSRect br;
3419   struct face *face;
3420   NSColor *tdCol;
3422   NSTRACE ("ns_dumpglyphs_image");
3424   if (s->face->box != FACE_NO_BOX
3425       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3426     x += abs (s->face->box_line_width);
3428   bg_x = x;
3429   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3430   bg_height = s->height;
3431   /* other terms have this, but was causing problems w/tabbar mode */
3432   /* - 2 * box_line_vwidth; */
3434   if (s->slice.x == 0) x += s->img->hmargin;
3435   if (s->slice.y == 0) y += s->img->vmargin;
3437   /* Draw BG: if we need larger area than image itself cleared, do that,
3438      otherwise, since we composite the image under NS (instead of mucking
3439      with its background color), we must clear just the image area. */
3440   if (s->hl == DRAW_MOUSE_FACE)
3441     {
3442       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3443       if (!face)
3444        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3445     }
3446   else
3447     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3449   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3451   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3452       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3453     {
3454       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3455       s->background_filled_p = 1;
3456     }
3457   else
3458     {
3459       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3460     }
3462   NSRectFill (br);
3464   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3465   if (img != nil)
3466     {
3467 #ifdef NS_IMPL_COCOA
3468       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3469       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3470                               s->slice.width, s->slice.height);
3471       [img drawInRect: dr
3472              fromRect: ir
3473              operation: NSCompositeSourceOver
3474               fraction: 1.0
3475            respectFlipped: YES
3476                 hints: nil];
3477 #else
3478       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3479                   operation: NSCompositeSourceOver];
3480 #endif
3481     }
3483   if (s->hl == DRAW_CURSOR)
3484     {
3485     [FRAME_CURSOR_COLOR (s->f) set];
3486     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3487       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3488     else
3489       /* Currently on NS img->mask is always 0. Since
3490          get_window_cursor_type specifies a hollow box cursor when on
3491          a non-masked image we never reach this clause. But we put it
3492          in in anticipation of better support for image masks on
3493          NS. */
3494       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3495     }
3496   else
3497     {
3498       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3499     }
3501   /* Draw underline, overline, strike-through. */
3502   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3504   /* Draw relief, if requested */
3505   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3506     {
3507       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3508         {
3509           th = tool_bar_button_relief >= 0 ?
3510             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3511           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3512         }
3513       else
3514         {
3515           th = abs (s->img->relief);
3516           raised_p = (s->img->relief > 0);
3517         }
3519       r.origin.x = x - th;
3520       r.origin.y = y - th;
3521       r.size.width = s->slice.width + 2*th-1;
3522       r.size.height = s->slice.height + 2*th-1;
3523       ns_draw_relief (r, th, raised_p,
3524                       s->slice.y == 0,
3525                       s->slice.y + s->slice.height == s->img->height,
3526                       s->slice.x == 0,
3527                       s->slice.x + s->slice.width == s->img->width, s);
3528     }
3530   /* If there is no mask, the background won't be seen,
3531      so draw a rectangle on the image for the cursor.
3532      Do this for all images, getting transparency right is not reliable.  */
3533   if (s->hl == DRAW_CURSOR)
3534     {
3535       int thickness = abs (s->img->relief);
3536       if (thickness == 0) thickness = 1;
3537       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3538     }
3542 static void
3543 ns_dumpglyphs_stretch (struct glyph_string *s)
3545   NSRect r[2];
3546   int n, i;
3547   struct face *face;
3548   NSColor *fgCol, *bgCol;
3550   if (!s->background_filled_p)
3551     {
3552       n = ns_get_glyph_string_clip_rect (s, r);
3553       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3555       ns_focus (s->f, r, n);
3557       if (s->hl == DRAW_MOUSE_FACE)
3558        {
3559          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3560          if (!face)
3561            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3562        }
3563       else
3564        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3566       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3567       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3569       for (i = 0; i < n; ++i)
3570         {
3571           if (!s->row->full_width_p)
3572             {
3573               int overrun, leftoverrun;
3575               /* truncate to avoid overwriting fringe and/or scrollbar */
3576               overrun = max (0, (s->x + s->background_width)
3577                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3578                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3579               r[i].size.width -= overrun;
3581               /* truncate to avoid overwriting to left of the window box */
3582               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3583                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3585               if (leftoverrun > 0)
3586                 {
3587                   r[i].origin.x += leftoverrun;
3588                   r[i].size.width -= leftoverrun;
3589                 }
3591               /* XXX: Try to work between problem where a stretch glyph on
3592                  a partially-visible bottom row will clear part of the
3593                  modeline, and another where list-buffers headers and similar
3594                  rows erroneously have visible_height set to 0.  Not sure
3595                  where this is coming from as other terms seem not to show. */
3596               r[i].size.height = min (s->height, s->row->visible_height);
3597             }
3599           [bgCol set];
3601           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3602              overwriting cursor (usually when cursor on a tab) */
3603           if (s->hl == DRAW_CURSOR)
3604             {
3605               CGFloat x, width;
3607               x = r[i].origin.x;
3608               width = s->w->phys_cursor_width;
3609               r[i].size.width -= width;
3610               r[i].origin.x += width;
3612               NSRectFill (r[i]);
3614               /* Draw overlining, etc. on the cursor. */
3615               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3616                 ns_draw_text_decoration (s, face, bgCol, width, x);
3617               else
3618                 ns_draw_text_decoration (s, face, fgCol, width, x);
3619             }
3620           else
3621             {
3622               NSRectFill (r[i]);
3623             }
3625           /* Draw overlining, etc. on the stretch glyph (or the part
3626              of the stretch glyph after the cursor). */
3627           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3628                                    r[i].origin.x);
3629         }
3630       ns_unfocus (s->f);
3631       s->background_filled_p = 1;
3632     }
3636 static void
3637 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3639   int i, j, x;
3640   struct font *font = s->font;
3642   /* If first glyph of S has a left box line, start drawing the text
3643      of S to the right of that box line.  */
3644   if (s->face && s->face->box != FACE_NO_BOX
3645       && s->first_glyph->left_box_line_p)
3646     x = s->x + eabs (s->face->box_line_width);
3647   else
3648     x = s->x;
3650   /* S is a glyph string for a composition.  S->cmp_from is the index
3651      of the first character drawn for glyphs of this composition.
3652      S->cmp_from == 0 means we are drawing the very first character of
3653      this composition.  */
3655   /* Draw a rectangle for the composition if the font for the very
3656      first character of the composition could not be loaded.  */
3657   if (s->font_not_found_p)
3658     {
3659       if (s->cmp_from == 0)
3660         {
3661           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3662           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3663         }
3664     }
3665   else if (! s->first_glyph->u.cmp.automatic)
3666     {
3667       int y = s->ybase;
3669       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3670         /* TAB in a composition means display glyphs with padding
3671            space on the left or right.  */
3672         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3673           {
3674             int xx = x + s->cmp->offsets[j * 2];
3675             int yy = y - s->cmp->offsets[j * 2 + 1];
3677             font->driver->draw (s, j, j + 1, xx, yy, false);
3678             if (s->face->overstrike)
3679               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3680           }
3681     }
3682   else
3683     {
3684       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3685       Lisp_Object glyph;
3686       int y = s->ybase;
3687       int width = 0;
3689       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3690         {
3691           glyph = LGSTRING_GLYPH (gstring, i);
3692           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3693             width += LGLYPH_WIDTH (glyph);
3694           else
3695             {
3696               int xoff, yoff, wadjust;
3698               if (j < i)
3699                 {
3700                   font->driver->draw (s, j, i, x, y, false);
3701                   if (s->face->overstrike)
3702                     font->driver->draw (s, j, i, x + 1, y, false);
3703                   x += width;
3704                 }
3705               xoff = LGLYPH_XOFF (glyph);
3706               yoff = LGLYPH_YOFF (glyph);
3707               wadjust = LGLYPH_WADJUST (glyph);
3708               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3709               if (s->face->overstrike)
3710                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3711                                     false);
3712               x += wadjust;
3713               j = i + 1;
3714               width = 0;
3715             }
3716         }
3717       if (j < i)
3718         {
3719           font->driver->draw (s, j, i, x, y, false);
3720           if (s->face->overstrike)
3721             font->driver->draw (s, j, i, x + 1, y, false);
3722         }
3723     }
3726 static void
3727 ns_draw_glyph_string (struct glyph_string *s)
3728 /* --------------------------------------------------------------------------
3729       External (RIF): Main draw-text call.
3730    -------------------------------------------------------------------------- */
3732   /* TODO (optimize): focus for box and contents draw */
3733   NSRect r[2];
3734   int n, flags;
3735   char box_drawn_p = 0;
3736   struct font *font = s->face->font;
3737   if (! font) font = FRAME_FONT (s->f);
3739   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3741   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3742     {
3743       int width;
3744       struct glyph_string *next;
3746       for (width = 0, next = s->next;
3747            next && width < s->right_overhang;
3748            width += next->width, next = next->next)
3749         if (next->first_glyph->type != IMAGE_GLYPH)
3750           {
3751             if (next->first_glyph->type != STRETCH_GLYPH)
3752               {
3753                 n = ns_get_glyph_string_clip_rect (s->next, r);
3754                 ns_focus (s->f, r, n);
3755                 ns_maybe_dumpglyphs_background (s->next, 1);
3756                 ns_unfocus (s->f);
3757               }
3758             else
3759               {
3760                 ns_dumpglyphs_stretch (s->next);
3761               }
3762             next->num_clips = 0;
3763           }
3764     }
3766   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3767         && (s->first_glyph->type == CHAR_GLYPH
3768             || s->first_glyph->type == COMPOSITE_GLYPH))
3769     {
3770       n = ns_get_glyph_string_clip_rect (s, r);
3771       ns_focus (s->f, r, n);
3772       ns_maybe_dumpglyphs_background (s, 1);
3773       ns_dumpglyphs_box_or_relief (s);
3774       ns_unfocus (s->f);
3775       box_drawn_p = 1;
3776     }
3778   switch (s->first_glyph->type)
3779     {
3781     case IMAGE_GLYPH:
3782       n = ns_get_glyph_string_clip_rect (s, r);
3783       ns_focus (s->f, r, n);
3784       ns_dumpglyphs_image (s, r[0]);
3785       ns_unfocus (s->f);
3786       break;
3788     case STRETCH_GLYPH:
3789       ns_dumpglyphs_stretch (s);
3790       break;
3792     case CHAR_GLYPH:
3793     case COMPOSITE_GLYPH:
3794       n = ns_get_glyph_string_clip_rect (s, r);
3795       ns_focus (s->f, r, n);
3797       if (s->for_overlaps || (s->cmp_from > 0
3798                               && ! s->first_glyph->u.cmp.automatic))
3799         s->background_filled_p = 1;
3800       else
3801         ns_maybe_dumpglyphs_background
3802           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3804       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3805         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3806          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3807           NS_DUMPGLYPH_NORMAL));
3809       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3810         {
3811           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3812           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3813           NS_FACE_FOREGROUND (s->face) = tmp;
3814         }
3816       {
3817         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3819         if (isComposite)
3820           ns_draw_composite_glyph_string_foreground (s);
3821         else
3822           font->driver->draw
3823             (s, s->cmp_from, s->nchars, s->x, s->ybase,
3824              (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3825              || flags == NS_DUMPGLYPH_MOUSEFACE);
3826       }
3828       {
3829         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3830                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3831                                                    s->f)
3832                         : FRAME_FOREGROUND_COLOR (s->f));
3833         [col set];
3835         /* Draw underline, overline, strike-through. */
3836         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3837       }
3839       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3840         {
3841           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3842           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3843           NS_FACE_FOREGROUND (s->face) = tmp;
3844         }
3846       ns_unfocus (s->f);
3847       break;
3849     case GLYPHLESS_GLYPH:
3850       n = ns_get_glyph_string_clip_rect (s, r);
3851       ns_focus (s->f, r, n);
3853       if (s->for_overlaps || (s->cmp_from > 0
3854                               && ! s->first_glyph->u.cmp.automatic))
3855         s->background_filled_p = 1;
3856       else
3857         ns_maybe_dumpglyphs_background
3858           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3859       /* ... */
3860       /* Not yet implemented.  */
3861       /* ... */
3862       ns_unfocus (s->f);
3863       break;
3865     default:
3866       emacs_abort ();
3867     }
3869   /* Draw box if not done already. */
3870   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3871     {
3872       n = ns_get_glyph_string_clip_rect (s, r);
3873       ns_focus (s->f, r, n);
3874       ns_dumpglyphs_box_or_relief (s);
3875       ns_unfocus (s->f);
3876     }
3878   s->num_clips = 0;
3883 /* ==========================================================================
3885     Event loop
3887    ========================================================================== */
3890 static void
3891 ns_send_appdefined (int value)
3892 /* --------------------------------------------------------------------------
3893     Internal: post an appdefined event which EmacsApp-sendEvent will
3894               recognize and take as a command to halt the event loop.
3895    -------------------------------------------------------------------------- */
3897   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
3899 #ifdef NS_IMPL_GNUSTEP
3900   // GNUstep needs postEvent to happen on the main thread.
3901   if (! [[NSThread currentThread] isMainThread])
3902     {
3903       EmacsApp *app = (EmacsApp *)NSApp;
3904       app->nextappdefined = value;
3905       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3906                             withObject:nil
3907                          waitUntilDone:YES];
3908       return;
3909     }
3910 #endif
3912   /* Only post this event if we haven't already posted one.  This will end
3913        the [NXApp run] main loop after having processed all events queued at
3914        this moment.  */
3916 #ifdef NS_IMPL_COCOA
3917   if (! send_appdefined)
3918     {
3919       /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3920          in certain situations (rapid incoming events).
3921          So check if we have one, if not add one.  */
3922       NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3923                                           untilDate:[NSDate distantPast]
3924                                              inMode:NSDefaultRunLoopMode
3925                                             dequeue:NO];
3926       if (! appev) send_appdefined = YES;
3927     }
3928 #endif
3930   if (send_appdefined)
3931     {
3932       NSEvent *nxev;
3934       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3935       send_appdefined = NO;
3937       /* Don't need wakeup timer any more */
3938       if (timed_entry)
3939         {
3940           [timed_entry invalidate];
3941           [timed_entry release];
3942           timed_entry = nil;
3943         }
3945       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3946                                 location: NSMakePoint (0, 0)
3947                            modifierFlags: 0
3948                                timestamp: 0
3949                             windowNumber: [[NSApp mainWindow] windowNumber]
3950                                  context: [NSApp context]
3951                                  subtype: 0
3952                                    data1: value
3953                                    data2: 0];
3955       /* Post an application defined event on the event queue.  When this is
3956          received the [NXApp run] will return, thus having processed all
3957          events which are currently queued.  */
3958       [NSApp postEvent: nxev atStart: NO];
3959     }
3962 #ifdef HAVE_NATIVE_FS
3963 static void
3964 check_native_fs ()
3966   Lisp_Object frame, tail;
3968   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3969     return;
3971   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3973   FOR_EACH_FRAME (tail, frame)
3974     {
3975       struct frame *f = XFRAME (frame);
3976       if (FRAME_NS_P (f))
3977         {
3978           EmacsView *view = FRAME_NS_VIEW (f);
3979           [view updateCollectionBehavior];
3980         }
3981     }
3983 #endif
3985 /* GNUstep does not have cancelTracking.  */
3986 #ifdef NS_IMPL_COCOA
3987 /* Check if menu open should be canceled or continued as normal.  */
3988 void
3989 ns_check_menu_open (NSMenu *menu)
3991   /* Click in menu bar? */
3992   NSArray *a = [[NSApp mainMenu] itemArray];
3993   int i;
3994   BOOL found = NO;
3996   if (menu == nil) // Menu tracking ended.
3997     {
3998       if (menu_will_open_state == MENU_OPENING)
3999         menu_will_open_state = MENU_NONE;
4000       return;
4001     }
4003   for (i = 0; ! found && i < [a count]; i++)
4004     found = menu == [[a objectAtIndex:i] submenu];
4005   if (found)
4006     {
4007       if (menu_will_open_state == MENU_NONE && emacs_event)
4008         {
4009           NSEvent *theEvent = [NSApp currentEvent];
4010           struct frame *emacsframe = SELECTED_FRAME ();
4012           [menu cancelTracking];
4013           menu_will_open_state = MENU_PENDING;
4014           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4015           EV_TRAILER (theEvent);
4017           CGEventRef ourEvent = CGEventCreate (NULL);
4018           menu_mouse_point = CGEventGetLocation (ourEvent);
4019           CFRelease (ourEvent);
4020         }
4021       else if (menu_will_open_state == MENU_OPENING)
4022         {
4023           menu_will_open_state = MENU_NONE;
4024         }
4025     }
4028 /* Redo saved menu click if state is MENU_PENDING.  */
4029 void
4030 ns_check_pending_open_menu ()
4032   if (menu_will_open_state == MENU_PENDING)
4033     {
4034       CGEventSourceRef source
4035         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4037       CGEventRef event = CGEventCreateMouseEvent (source,
4038                                                   kCGEventLeftMouseDown,
4039                                                   menu_mouse_point,
4040                                                   kCGMouseButtonLeft);
4041       CGEventSetType (event, kCGEventLeftMouseDown);
4042       CGEventPost (kCGHIDEventTap, event);
4043       CFRelease (event);
4044       CFRelease (source);
4046       menu_will_open_state = MENU_OPENING;
4047     }
4049 #endif /* NS_IMPL_COCOA */
4051 static void
4052 unwind_apploopnr (Lisp_Object not_used)
4054   --apploopnr;
4055   n_emacs_events_pending = 0;
4056   ns_finish_events ();
4057   q_event_ptr = NULL;
4060 static int
4061 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4062 /* --------------------------------------------------------------------------
4063      External (hook): Post an event to ourself and keep reading events until
4064      we read it back again.  In effect process all events which were waiting.
4065      From 21+ we have to manage the event buffer ourselves.
4066    -------------------------------------------------------------------------- */
4068   struct input_event ev;
4069   int nevents;
4071   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4073 #ifdef HAVE_NATIVE_FS
4074   check_native_fs ();
4075 #endif
4077   if ([NSApp modalWindow] != nil)
4078     return -1;
4080   if (hold_event_q.nr > 0)
4081     {
4082       int i;
4083       for (i = 0; i < hold_event_q.nr; ++i)
4084         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4085       hold_event_q.nr = 0;
4086       return i;
4087     }
4089   block_input ();
4090   n_emacs_events_pending = 0;
4091   ns_init_events (&ev);
4092   q_event_ptr = hold_quit;
4094   /* we manage autorelease pools by allocate/reallocate each time around
4095      the loop; strict nesting is occasionally violated but seems not to
4096      matter.. earlier methods using full nesting caused major memory leaks */
4097   [outerpool release];
4098   outerpool = [[NSAutoreleasePool alloc] init];
4100   /* If have pending open-file requests, attend to the next one of those. */
4101   if (ns_pending_files && [ns_pending_files count] != 0
4102       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4103     {
4104       [ns_pending_files removeObjectAtIndex: 0];
4105     }
4106   /* Deal with pending service requests. */
4107   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4108     && [(EmacsApp *)
4109          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4110                       withArg: [ns_pending_service_args objectAtIndex: 0]])
4111     {
4112       [ns_pending_service_names removeObjectAtIndex: 0];
4113       [ns_pending_service_args removeObjectAtIndex: 0];
4114     }
4115   else
4116     {
4117       ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4118       /* Run and wait for events.  We must always send one NX_APPDEFINED event
4119          to ourself, otherwise [NXApp run] will never exit.  */
4120       send_appdefined = YES;
4121       ns_send_appdefined (-1);
4123       if (++apploopnr != 1)
4124         {
4125           emacs_abort ();
4126         }
4127       record_unwind_protect (unwind_apploopnr, Qt);
4128       [NSApp run];
4129       unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
4130     }
4132   nevents = n_emacs_events_pending;
4133   n_emacs_events_pending = 0;
4134   ns_finish_events ();
4135   q_event_ptr = NULL;
4136   unblock_input ();
4138   return nevents;
4143 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4144            fd_set *exceptfds, struct timespec const *timeout,
4145            sigset_t const *sigmask)
4146 /* --------------------------------------------------------------------------
4147      Replacement for select, checking for events
4148    -------------------------------------------------------------------------- */
4150   int result;
4151   int t, k, nr = 0;
4152   struct input_event event;
4153   char c;
4155   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4157 #ifdef HAVE_NATIVE_FS
4158   check_native_fs ();
4159 #endif
4161   if (hold_event_q.nr > 0)
4162     {
4163       /* We already have events pending. */
4164       raise (SIGIO);
4165       errno = EINTR;
4166       return -1;
4167     }
4169   for (k = 0; k < nfds+1; k++)
4170     {
4171       if (readfds && FD_ISSET(k, readfds)) ++nr;
4172       if (writefds && FD_ISSET(k, writefds)) ++nr;
4173     }
4175   if (NSApp == nil
4176       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4177     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
4179   [outerpool release];
4180   outerpool = [[NSAutoreleasePool alloc] init];
4183   send_appdefined = YES;
4184   if (nr > 0)
4185     {
4186       pthread_mutex_lock (&select_mutex);
4187       select_nfds = nfds;
4188       select_valid = 0;
4189       if (readfds)
4190         {
4191           select_readfds = *readfds;
4192           select_valid += SELECT_HAVE_READ;
4193         }
4194       if (writefds)
4195         {
4196           select_writefds = *writefds;
4197           select_valid += SELECT_HAVE_WRITE;
4198         }
4200       if (timeout)
4201         {
4202           select_timeout = *timeout;
4203           select_valid += SELECT_HAVE_TMO;
4204         }
4206       pthread_mutex_unlock (&select_mutex);
4208       /* Inform fd_handler that select should be called */
4209       c = 'g';
4210       emacs_write_sig (selfds[1], &c, 1);
4211     }
4212   else if (nr == 0 && timeout)
4213     {
4214       /* No file descriptor, just a timeout, no need to wake fd_handler  */
4215       double time = timespectod (*timeout);
4216       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4217                                                       target: NSApp
4218                                                     selector:
4219                                   @selector (timeout_handler:)
4220                                                     userInfo: 0
4221                                                      repeats: NO]
4222                       retain];
4223     }
4224   else /* No timeout and no file descriptors, can this happen?  */
4225     {
4226       /* Send appdefined so we exit from the loop */
4227       ns_send_appdefined (-1);
4228     }
4230   block_input ();
4231   ns_init_events (&event);
4232   if (++apploopnr != 1)
4233     {
4234       emacs_abort ();
4235     }
4237   {
4238     ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4239     record_unwind_protect (unwind_apploopnr, Qt);
4240     [NSApp run];
4241     unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
4242   }
4244   ns_finish_events ();
4245   if (nr > 0 && readfds)
4246     {
4247       c = 's';
4248       emacs_write_sig (selfds[1], &c, 1);
4249     }
4250   unblock_input ();
4252   t = last_appdefined_event_data;
4254   if (t != NO_APPDEFINED_DATA)
4255     {
4256       last_appdefined_event_data = NO_APPDEFINED_DATA;
4258       if (t == -2)
4259         {
4260           /* The NX_APPDEFINED event we received was a timeout. */
4261           result = 0;
4262         }
4263       else if (t == -1)
4264         {
4265           /* The NX_APPDEFINED event we received was the result of
4266              at least one real input event arriving.  */
4267           errno = EINTR;
4268           result = -1;
4269         }
4270       else
4271         {
4272           /* Received back from select () in fd_handler; copy the results */
4273           pthread_mutex_lock (&select_mutex);
4274           if (readfds) *readfds = select_readfds;
4275           if (writefds) *writefds = select_writefds;
4276           pthread_mutex_unlock (&select_mutex);
4277           result = t;
4278         }
4279     }
4280   else
4281     {
4282       errno = EINTR;
4283       result = -1;
4284     }
4286   return result;
4291 /* ==========================================================================
4293     Scrollbar handling
4295    ========================================================================== */
4298 static void
4299 ns_set_vertical_scroll_bar (struct window *window,
4300                            int portion, int whole, int position)
4301 /* --------------------------------------------------------------------------
4302       External (hook): Update or add scrollbar
4303    -------------------------------------------------------------------------- */
4305   Lisp_Object win;
4306   NSRect r, v;
4307   struct frame *f = XFRAME (WINDOW_FRAME (window));
4308   EmacsView *view = FRAME_NS_VIEW (f);
4309   EmacsScroller *bar;
4310   int window_y, window_height;
4311   int top, left, height, width;
4312   BOOL update_p = YES;
4314   /* optimization; display engine sends WAY too many of these.. */
4315   if (!NILP (window->vertical_scroll_bar))
4316     {
4317       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4318       if ([bar checkSamePosition: position portion: portion whole: whole])
4319         {
4320           if (view->scrollbarsNeedingUpdate == 0)
4321             {
4322               if (!windows_or_buffers_changed)
4323                   return;
4324             }
4325           else
4326             view->scrollbarsNeedingUpdate--;
4327           update_p = NO;
4328         }
4329     }
4331   NSTRACE ("ns_set_vertical_scroll_bar");
4333   /* Get dimensions.  */
4334   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4335   top = window_y;
4336   height = window_height;
4337   width = NS_SCROLL_BAR_WIDTH (f);
4338   left = WINDOW_SCROLL_BAR_AREA_X (window);
4340   r = NSMakeRect (left, top, width, height);
4341   /* the parent view is flipped, so we need to flip y value */
4342   v = [view frame];
4343   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4345   XSETWINDOW (win, window);
4346   block_input ();
4348   /* we want at least 5 lines to display a scrollbar */
4349   if (WINDOW_TOTAL_LINES (window) < 5)
4350     {
4351       if (!NILP (window->vertical_scroll_bar))
4352         {
4353           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4354           [bar removeFromSuperview];
4355           wset_vertical_scroll_bar (window, Qnil);
4356           [bar release];
4357         }
4358       ns_clear_frame_area (f, left, top, width, height);
4359       unblock_input ();
4360       return;
4361     }
4363   if (NILP (window->vertical_scroll_bar))
4364     {
4365       if (width > 0 && height > 0)
4366         ns_clear_frame_area (f, left, top, width, height);
4368       bar = [[EmacsScroller alloc] initFrame: r window: win];
4369       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4370       update_p = YES;
4371     }
4372   else
4373     {
4374       NSRect oldRect;
4375       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4376       oldRect = [bar frame];
4377       r.size.width = oldRect.size.width;
4378       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4379         {
4380           if (oldRect.origin.x != r.origin.x)
4381               ns_clear_frame_area (f, left, top, width, height);
4382           [bar setFrame: r];
4383         }
4384     }
4386   if (update_p)
4387     [bar setPosition: position portion: portion whole: whole];
4388   unblock_input ();
4392 static void
4393 ns_set_horizontal_scroll_bar (struct window *window,
4394                               int portion, int whole, int position)
4395 /* --------------------------------------------------------------------------
4396       External (hook): Update or add scrollbar
4397    -------------------------------------------------------------------------- */
4399   Lisp_Object win;
4400   NSRect r, v;
4401   struct frame *f = XFRAME (WINDOW_FRAME (window));
4402   EmacsView *view = FRAME_NS_VIEW (f);
4403   EmacsScroller *bar;
4404   int top, height, left, width;
4405   int window_x, window_width;
4406   BOOL update_p = YES;
4408   /* optimization; display engine sends WAY too many of these.. */
4409   if (!NILP (window->horizontal_scroll_bar))
4410     {
4411       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4412       if ([bar checkSamePosition: position portion: portion whole: whole])
4413         {
4414           if (view->scrollbarsNeedingUpdate == 0)
4415             {
4416               if (!windows_or_buffers_changed)
4417                   return;
4418             }
4419           else
4420             view->scrollbarsNeedingUpdate--;
4421           update_p = NO;
4422         }
4423     }
4425   NSTRACE ("ns_set_horizontal_scroll_bar");
4427   /* Get dimensions.  */
4428   window_box (window, ANY_AREA, &window_x, 0, &window_width, 0);
4429   left = window_x;
4430   width = window_width;
4431   height = NS_SCROLL_BAR_HEIGHT (f);
4432   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4434   r = NSMakeRect (left, top, width, height);
4435   /* the parent view is flipped, so we need to flip y value */
4436   v = [view frame];
4437   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4439   XSETWINDOW (win, window);
4440   block_input ();
4442   if (NILP (window->horizontal_scroll_bar))
4443     {
4444       if (width > 0 && height > 0)
4445         ns_clear_frame_area (f, left, top, width, height);
4447       bar = [[EmacsScroller alloc] initFrame: r window: win];
4448       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4449       update_p = YES;
4450     }
4451   else
4452     {
4453       NSRect oldRect;
4454       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4455       oldRect = [bar frame];
4456       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4457         {
4458           if (oldRect.origin.y != r.origin.y)
4459             ns_clear_frame_area (f, left, top, width, height);
4460           [bar setFrame: r];
4461           update_p = YES;
4462         }
4463     }
4465   /* If there are both horizontal and vertical scroll-bars they leave
4466      a square that belongs to neither. We need to clear it otherwise
4467      it fills with junk. */
4468   if (!NILP (window->vertical_scroll_bar))
4469     ns_clear_frame_area (f, WINDOW_SCROLL_BAR_AREA_X (window), top,
4470                          NS_SCROLL_BAR_HEIGHT (f), height);
4472   if (update_p)
4473     [bar setPosition: position portion: portion whole: whole];
4474   unblock_input ();
4478 static void
4479 ns_condemn_scroll_bars (struct frame *f)
4480 /* --------------------------------------------------------------------------
4481      External (hook): arrange for all frame's scrollbars to be removed
4482      at next call to judge_scroll_bars, except for those redeemed.
4483    -------------------------------------------------------------------------- */
4485   int i;
4486   id view;
4487   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4489   NSTRACE ("ns_condemn_scroll_bars");
4491   for (i =[subviews count]-1; i >= 0; i--)
4492     {
4493       view = [subviews objectAtIndex: i];
4494       if ([view isKindOfClass: [EmacsScroller class]])
4495         [view condemn];
4496     }
4500 static void
4501 ns_redeem_scroll_bar (struct window *window)
4502 /* --------------------------------------------------------------------------
4503      External (hook): arrange to spare this window's scrollbar
4504      at next call to judge_scroll_bars.
4505    -------------------------------------------------------------------------- */
4507   id bar;
4508   NSTRACE ("ns_redeem_scroll_bar");
4509   if (!NILP (window->vertical_scroll_bar)
4510       && WINDOW_HAS_VERTICAL_SCROLL_BAR (window))
4511     {
4512       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4513       [bar reprieve];
4514     }
4516   if (!NILP (window->horizontal_scroll_bar)
4517       && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (window))
4518     {
4519       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4520       [bar reprieve];
4521     }
4525 static void
4526 ns_judge_scroll_bars (struct frame *f)
4527 /* --------------------------------------------------------------------------
4528      External (hook): destroy all scrollbars on frame that weren't
4529      redeemed after call to condemn_scroll_bars.
4530    -------------------------------------------------------------------------- */
4532   int i;
4533   id view;
4534   EmacsView *eview = FRAME_NS_VIEW (f);
4535   NSArray *subviews = [[eview superview] subviews];
4536   BOOL removed = NO;
4538   NSTRACE ("ns_judge_scroll_bars");
4539   for (i = [subviews count]-1; i >= 0; --i)
4540     {
4541       view = [subviews objectAtIndex: i];
4542       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4543       if ([view judge])
4544         removed = YES;
4545     }
4547   if (removed)
4548     [eview updateFrameSize: NO];
4551 /* ==========================================================================
4553     Initialization
4555    ========================================================================== */
4558 x_display_pixel_height (struct ns_display_info *dpyinfo)
4560   NSArray *screens = [NSScreen screens];
4561   NSEnumerator *enumerator = [screens objectEnumerator];
4562   NSScreen *screen;
4563   NSRect frame;
4565   frame = NSZeroRect;
4566   while ((screen = [enumerator nextObject]) != nil)
4567     frame = NSUnionRect (frame, [screen frame]);
4569   return NSHeight (frame);
4573 x_display_pixel_width (struct ns_display_info *dpyinfo)
4575   NSArray *screens = [NSScreen screens];
4576   NSEnumerator *enumerator = [screens objectEnumerator];
4577   NSScreen *screen;
4578   NSRect frame;
4580   frame = NSZeroRect;
4581   while ((screen = [enumerator nextObject]) != nil)
4582     frame = NSUnionRect (frame, [screen frame]);
4584   return NSWidth (frame);
4588 static Lisp_Object ns_string_to_lispmod (const char *s)
4589 /* --------------------------------------------------------------------------
4590      Convert modifier name to lisp symbol
4591    -------------------------------------------------------------------------- */
4593   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4594     return Qmeta;
4595   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4596     return Qsuper;
4597   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4598     return Qcontrol;
4599   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4600     return Qalt;
4601   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4602     return Qhyper;
4603   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4604     return Qnone;
4605   else
4606     return Qnil;
4610 static void
4611 ns_default (const char *parameter, Lisp_Object *result,
4612            Lisp_Object yesval, Lisp_Object noval,
4613            BOOL is_float, BOOL is_modstring)
4614 /* --------------------------------------------------------------------------
4615       Check a parameter value in user's preferences
4616    -------------------------------------------------------------------------- */
4618   const char *value = ns_get_defaults_value (parameter);
4620   if (value)
4621     {
4622       double f;
4623       char *pos;
4624       if (c_strcasecmp (value, "YES") == 0)
4625         *result = yesval;
4626       else if (c_strcasecmp (value, "NO") == 0)
4627         *result = noval;
4628       else if (is_float && (f = strtod (value, &pos), pos != value))
4629         *result = make_float (f);
4630       else if (is_modstring && value)
4631         *result = ns_string_to_lispmod (value);
4632       else fprintf (stderr,
4633                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4634     }
4638 static void
4639 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4640 /* --------------------------------------------------------------------------
4641       Initialize global info and storage for display.
4642    -------------------------------------------------------------------------- */
4644     NSScreen *screen = [NSScreen mainScreen];
4645     NSWindowDepth depth = [screen depth];
4647     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4648     dpyinfo->resy = 72.27;
4649     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4650                                                   NSColorSpaceFromDepth (depth)]
4651                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4652                                                  NSColorSpaceFromDepth (depth)];
4653     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4654     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4655     dpyinfo->color_table->colors = NULL;
4656     dpyinfo->root_window = 42; /* a placeholder.. */
4657     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4658     dpyinfo->n_fonts = 0;
4659     dpyinfo->smallest_font_height = 1;
4660     dpyinfo->smallest_char_width = 1;
4662     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4666 /* This and next define (many of the) public functions in this file. */
4667 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4668          with using despite presence in the "system dependent" redisplay
4669          interface.  In addition, many of the ns_ methods have code that is
4670          shared with all terms, indicating need for further refactoring. */
4671 extern frame_parm_handler ns_frame_parm_handlers[];
4672 static struct redisplay_interface ns_redisplay_interface =
4674   ns_frame_parm_handlers,
4675   x_produce_glyphs,
4676   x_write_glyphs,
4677   x_insert_glyphs,
4678   x_clear_end_of_line,
4679   ns_scroll_run,
4680   ns_after_update_window_line,
4681   ns_update_window_begin,
4682   ns_update_window_end,
4683   0, /* flush_display */
4684   x_clear_window_mouse_face,
4685   x_get_glyph_overhangs,
4686   x_fix_overlapping_area,
4687   ns_draw_fringe_bitmap,
4688   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4689   0, /* destroy_fringe_bitmap */
4690   ns_compute_glyph_string_overhangs,
4691   ns_draw_glyph_string,
4692   ns_define_frame_cursor,
4693   ns_clear_frame_area,
4694   ns_draw_window_cursor,
4695   ns_draw_vertical_window_border,
4696   ns_draw_window_divider,
4697   ns_shift_glyphs_for_insert,
4698   ns_show_hourglass,
4699   ns_hide_hourglass
4703 static void
4704 ns_delete_display (struct ns_display_info *dpyinfo)
4706   /* TODO... */
4710 /* This function is called when the last frame on a display is deleted. */
4711 static void
4712 ns_delete_terminal (struct terminal *terminal)
4714   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4716   NSTRACE ("ns_delete_terminal");
4718   /* Protect against recursive calls.  delete_frame in
4719      delete_terminal calls us back when it deletes our last frame.  */
4720   if (!terminal->name)
4721     return;
4723   block_input ();
4725   x_destroy_all_bitmaps (dpyinfo);
4726   ns_delete_display (dpyinfo);
4727   unblock_input ();
4731 static struct terminal *
4732 ns_create_terminal (struct ns_display_info *dpyinfo)
4733 /* --------------------------------------------------------------------------
4734       Set up use of NS before we make the first connection.
4735    -------------------------------------------------------------------------- */
4737   struct terminal *terminal;
4739   NSTRACE ("ns_create_terminal");
4741   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4743   terminal->display_info.ns = dpyinfo;
4744   dpyinfo->terminal = terminal;
4746   terminal->clear_frame_hook = ns_clear_frame;
4747   terminal->ring_bell_hook = ns_ring_bell;
4748   terminal->update_begin_hook = ns_update_begin;
4749   terminal->update_end_hook = ns_update_end;
4750   terminal->read_socket_hook = ns_read_socket;
4751   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4752   terminal->mouse_position_hook = ns_mouse_position;
4753   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4754   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4755   terminal->fullscreen_hook = ns_fullscreen_hook;
4756   terminal->menu_show_hook = ns_menu_show;
4757   terminal->popup_dialog_hook = ns_popup_dialog;
4758   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4759   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4760   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4761   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4762   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4763   terminal->delete_frame_hook = x_destroy_window;
4764   terminal->delete_terminal_hook = ns_delete_terminal;
4765   /* Other hooks are NULL by default.  */
4767   return terminal;
4771 struct ns_display_info *
4772 ns_term_init (Lisp_Object display_name)
4773 /* --------------------------------------------------------------------------
4774      Start the Application and get things rolling.
4775    -------------------------------------------------------------------------- */
4777   struct terminal *terminal;
4778   struct ns_display_info *dpyinfo;
4779   static int ns_initialized = 0;
4780   Lisp_Object tmp;
4782   if (ns_initialized) return x_display_list;
4783   ns_initialized = 1;
4785   block_input ();
4787   NSTRACE ("ns_term_init");
4789   [outerpool release];
4790   outerpool = [[NSAutoreleasePool alloc] init];
4792   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4793   /*GSDebugAllocationActive (YES); */
4794   block_input ();
4796   baud_rate = 38400;
4797   Fset_input_interrupt_mode (Qnil);
4799   if (selfds[0] == -1)
4800     {
4801       if (emacs_pipe (selfds) != 0)
4802         {
4803           fprintf (stderr, "Failed to create pipe: %s\n",
4804                    emacs_strerror (errno));
4805           emacs_abort ();
4806         }
4808       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4809       FD_ZERO (&select_readfds);
4810       FD_ZERO (&select_writefds);
4811       pthread_mutex_init (&select_mutex, NULL);
4812     }
4814   ns_pending_files = [[NSMutableArray alloc] init];
4815   ns_pending_service_names = [[NSMutableArray alloc] init];
4816   ns_pending_service_args = [[NSMutableArray alloc] init];
4818 /* Start app and create the main menu, window, view.
4819      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4820      The view will then ask the NSApp to stop and return to Emacs. */
4821   [EmacsApp sharedApplication];
4822   if (NSApp == nil)
4823     return NULL;
4824   [NSApp setDelegate: NSApp];
4826   /* Start the select thread.  */
4827   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4828                            toTarget:NSApp
4829                          withObject:nil];
4831   /* debugging: log all notifications */
4832   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4833                                          selector: @selector (logNotification:)
4834                                              name: nil object: nil]; */
4836   dpyinfo = xzalloc (sizeof *dpyinfo);
4838   ns_initialize_display_info (dpyinfo);
4839   terminal = ns_create_terminal (dpyinfo);
4841   terminal->kboard = allocate_kboard (Qns);
4842   /* Don't let the initial kboard remain current longer than necessary.
4843      That would cause problems if a file loaded on startup tries to
4844      prompt in the mini-buffer.  */
4845   if (current_kboard == initial_kboard)
4846     current_kboard = terminal->kboard;
4847   terminal->kboard->reference_count++;
4849   dpyinfo->next = x_display_list;
4850   x_display_list = dpyinfo;
4852   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4854   terminal->name = xlispstrdup (display_name);
4856   unblock_input ();
4858   if (!inhibit_x_resources)
4859     {
4860       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4861                  Qt, Qnil, NO, NO);
4862       tmp = Qnil;
4863       /* this is a standard variable */
4864       ns_default ("AppleAntiAliasingThreshold", &tmp,
4865                  make_float (10.0), make_float (6.0), YES, NO);
4866       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4867     }
4869   NSTRACE_MSG ("Colors");
4871   {
4872     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4874     if ( cl == nil )
4875       {
4876         Lisp_Object color_file, color_map, color;
4877         unsigned long c;
4878         char *name;
4880         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4881                          Fsymbol_value (intern ("data-directory")));
4883         color_map = Fx_load_color_file (color_file);
4884         if (NILP (color_map))
4885           fatal ("Could not read %s.\n", SDATA (color_file));
4887         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4888         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4889           {
4890             color = XCAR (color_map);
4891             name = SSDATA (XCAR (color));
4892             c = XINT (XCDR (color));
4893             [cl setColor:
4894                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4895                                       green: GREEN_FROM_ULONG (c) / 255.0
4896                                        blue: BLUE_FROM_ULONG (c) / 255.0
4897                                       alpha: 1.0]
4898                   forKey: [NSString stringWithUTF8String: name]];
4899           }
4900         [cl writeToFile: nil];
4901       }
4902   }
4904   NSTRACE_MSG ("Versions");
4906   {
4907 #ifdef NS_IMPL_GNUSTEP
4908     Vwindow_system_version = build_string (gnustep_base_version);
4909 #else
4910     /*PSnextrelease (128, c); */
4911     char c[DBL_BUFSIZE_BOUND];
4912     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4913     Vwindow_system_version = make_unibyte_string (c, len);
4914 #endif
4915   }
4917   delete_keyboard_wait_descriptor (0);
4919   ns_app_name = [[NSProcessInfo processInfo] processName];
4921   /* Set up OS X app menu */
4923   NSTRACE_MSG ("Menu init");
4925 #ifdef NS_IMPL_COCOA
4926   {
4927     NSMenu *appMenu;
4928     NSMenuItem *item;
4929     /* set up the application menu */
4930     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4931     [svcsMenu setAutoenablesItems: NO];
4932     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4933     [appMenu setAutoenablesItems: NO];
4934     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4935     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4937     [appMenu insertItemWithTitle: @"About Emacs"
4938                           action: @selector (orderFrontStandardAboutPanel:)
4939                    keyEquivalent: @""
4940                          atIndex: 0];
4941     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4942     [appMenu insertItemWithTitle: @"Preferences..."
4943                           action: @selector (showPreferencesWindow:)
4944                    keyEquivalent: @","
4945                          atIndex: 2];
4946     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4947     item = [appMenu insertItemWithTitle: @"Services"
4948                                  action: @selector (menuDown:)
4949                           keyEquivalent: @""
4950                                 atIndex: 4];
4951     [appMenu setSubmenu: svcsMenu forItem: item];
4952     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4953     [appMenu insertItemWithTitle: @"Hide Emacs"
4954                           action: @selector (hide:)
4955                    keyEquivalent: @"h"
4956                          atIndex: 6];
4957     item =  [appMenu insertItemWithTitle: @"Hide Others"
4958                           action: @selector (hideOtherApplications:)
4959                    keyEquivalent: @"h"
4960                          atIndex: 7];
4961     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4962     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4963     [appMenu insertItemWithTitle: @"Quit Emacs"
4964                           action: @selector (terminate:)
4965                    keyEquivalent: @"q"
4966                          atIndex: 9];
4968     item = [mainMenu insertItemWithTitle: ns_app_name
4969                                   action: @selector (menuDown:)
4970                            keyEquivalent: @""
4971                                  atIndex: 0];
4972     [mainMenu setSubmenu: appMenu forItem: item];
4973     [dockMenu insertItemWithTitle: @"New Frame"
4974                            action: @selector (newFrame:)
4975                     keyEquivalent: @""
4976                           atIndex: 0];
4978     [NSApp setMainMenu: mainMenu];
4979     [NSApp setAppleMenu: appMenu];
4980     [NSApp setServicesMenu: svcsMenu];
4981     /* Needed at least on Cocoa, to get dock menu to show windows */
4982     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4984     [[NSNotificationCenter defaultCenter]
4985       addObserver: mainMenu
4986          selector: @selector (trackingNotification:)
4987              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4988     [[NSNotificationCenter defaultCenter]
4989       addObserver: mainMenu
4990          selector: @selector (trackingNotification:)
4991              name: NSMenuDidEndTrackingNotification object: mainMenu];
4992   }
4993 #endif /* MAC OS X menu setup */
4995   /* Register our external input/output types, used for determining
4996      applicable services and also drag/drop eligibility. */
4998   NSTRACE_MSG ("Input/output types");
5000   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5001   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5002                       retain];
5003   ns_drag_types = [[NSArray arrayWithObjects:
5004                             NSStringPboardType,
5005                             NSTabularTextPboardType,
5006                             NSFilenamesPboardType,
5007                             NSURLPboardType, nil] retain];
5009   /* If fullscreen is in init/default-frame-alist, focus isn't set
5010      right for fullscreen windows, so set this.  */
5011   [NSApp activateIgnoringOtherApps:YES];
5013   NSTRACE_MSG ("Call NSApp run");
5015   [NSApp run];
5016   ns_do_open_file = YES;
5018 #ifdef NS_IMPL_GNUSTEP
5019   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5020      We must re-catch it so subprocess works.  */
5021   catch_child_signal ();
5022 #endif
5024   NSTRACE_MSG ("ns_term_init done");
5026   unblock_input ();
5028   return dpyinfo;
5032 void
5033 ns_term_shutdown (int sig)
5035   [[NSUserDefaults standardUserDefaults] synchronize];
5037   /* code not reached in emacs.c after this is called by shut_down_emacs: */
5038   if (STRINGP (Vauto_save_list_file_name))
5039     unlink (SSDATA (Vauto_save_list_file_name));
5041   if (sig == 0 || sig == SIGTERM)
5042     {
5043       [NSApp terminate: NSApp];
5044     }
5045   else // force a stack trace to happen
5046     {
5047       emacs_abort ();
5048     }
5052 /* ==========================================================================
5054     EmacsApp implementation
5056    ========================================================================== */
5059 @implementation EmacsApp
5061 - (id)init
5063   NSTRACE ("[EmacsApp init]");
5065   if ((self = [super init]))
5066     {
5067 #ifdef NS_IMPL_COCOA
5068       self->isFirst = YES;
5069 #endif
5070 #ifdef NS_IMPL_GNUSTEP
5071       self->applicationDidFinishLaunchingCalled = NO;
5072 #endif
5073     }
5075   return self;
5078 #ifdef NS_IMPL_COCOA
5079 - (void)run
5081   NSTRACE ("[EmacsApp run]");
5083 #ifndef NSAppKitVersionNumber10_9
5084 #define NSAppKitVersionNumber10_9 1265
5085 #endif
5087     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5088       {
5089         [super run];
5090         return;
5091       }
5093   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5095   if (isFirst) [self finishLaunching];
5096   isFirst = NO;
5098   shouldKeepRunning = YES;
5099   do
5100     {
5101       [pool release];
5102       pool = [[NSAutoreleasePool alloc] init];
5104       NSEvent *event =
5105         [self nextEventMatchingMask:NSAnyEventMask
5106                           untilDate:[NSDate distantFuture]
5107                              inMode:NSDefaultRunLoopMode
5108                             dequeue:YES];
5110       [self sendEvent:event];
5111       [self updateWindows];
5112     } while (shouldKeepRunning);
5114   [pool release];
5117 - (void)stop: (id)sender
5119   NSTRACE ("[EmacsApp stop:]");
5121     shouldKeepRunning = NO;
5122     // Stop possible dialog also.  Noop if no dialog present.
5123     // The file dialog still leaks 7k - 10k on 10.9 though.
5124     [super stop:sender];
5126 #endif /* NS_IMPL_COCOA */
5128 - (void)logNotification: (NSNotification *)notification
5130   NSTRACE ("[EmacsApp logNotification:]");
5132   const char *name = [[notification name] UTF8String];
5133   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5134       && !strstr (name, "WindowNumber"))
5135     NSLog (@"notification: '%@'", [notification name]);
5139 - (void)sendEvent: (NSEvent *)theEvent
5140 /* --------------------------------------------------------------------------
5141      Called when NSApp is running for each event received.  Used to stop
5142      the loop when we choose, since there's no way to just run one iteration.
5143    -------------------------------------------------------------------------- */
5145   int type = [theEvent type];
5146   NSWindow *window = [theEvent window];
5148   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5149   NSTRACE_MSG ("Type: %d", type);
5151 #ifdef NS_IMPL_GNUSTEP
5152   // Keyboard events aren't propagated to file dialogs for some reason.
5153   if ([NSApp modalWindow] != nil &&
5154       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
5155     {
5156       [[NSApp modalWindow] sendEvent: theEvent];
5157       return;
5158     }
5159 #endif
5161   if (represented_filename != nil && represented_frame)
5162     {
5163       NSString *fstr = represented_filename;
5164       NSView *view = FRAME_NS_VIEW (represented_frame);
5165 #ifdef NS_IMPL_COCOA
5166       /* work around a bug observed on 10.3 and later where
5167          setTitleWithRepresentedFilename does not clear out previous state
5168          if given filename does not exist */
5169       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5170         [[view window] setRepresentedFilename: @""];
5171 #endif
5172       [[view window] setRepresentedFilename: fstr];
5173       [represented_filename release];
5174       represented_filename = nil;
5175       represented_frame = NULL;
5176     }
5178   if (type == NSApplicationDefined)
5179     {
5180       switch ([theEvent data2])
5181         {
5182 #ifdef NS_IMPL_COCOA
5183         case NSAPP_DATA2_RUNASSCRIPT:
5184           ns_run_ascript ();
5185           [self stop: self];
5186           return;
5187 #endif
5188         case NSAPP_DATA2_RUNFILEDIALOG:
5189           ns_run_file_dialog ();
5190           [self stop: self];
5191           return;
5192         }
5193     }
5195   if (type == NSCursorUpdate && window == nil)
5196     {
5197       fprintf (stderr, "Dropping external cursor update event.\n");
5198       return;
5199     }
5201   if (type == NSApplicationDefined)
5202     {
5203       /* Events posted by ns_send_appdefined interrupt the run loop here.
5204          But, if a modal window is up, an appdefined can still come through,
5205          (e.g., from a makeKeyWindow event) but stopping self also stops the
5206          modal loop. Just defer it until later. */
5207       if ([NSApp modalWindow] == nil)
5208         {
5209           last_appdefined_event_data = [theEvent data1];
5210           [self stop: self];
5211         }
5212       else
5213         {
5214           send_appdefined = YES;
5215         }
5216     }
5219 #ifdef NS_IMPL_COCOA
5220   /* If no dialog and none of our frames have focus and it is a move, skip it.
5221      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
5222      such as Wifi, sound, date or similar.
5223      This prevents "spooky" highlighting in the frame under the menu.  */
5224   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
5225     {
5226       struct ns_display_info *di;
5227       BOOL has_focus = NO;
5228       for (di = x_display_list; ! has_focus && di; di = di->next)
5229         has_focus = di->x_focus_frame != 0;
5230       if (! has_focus)
5231         return;
5232     }
5233 #endif
5235   NSTRACE_UNSILENCE();
5237   [super sendEvent: theEvent];
5241 - (void)showPreferencesWindow: (id)sender
5243   struct frame *emacsframe = SELECTED_FRAME ();
5244   NSEvent *theEvent = [NSApp currentEvent];
5246   if (!emacs_event)
5247     return;
5248   emacs_event->kind = NS_NONKEY_EVENT;
5249   emacs_event->code = KEY_NS_SHOW_PREFS;
5250   emacs_event->modifiers = 0;
5251   EV_TRAILER (theEvent);
5255 - (void)newFrame: (id)sender
5257   NSTRACE ("[EmacsApp newFrame:]");
5259   struct frame *emacsframe = SELECTED_FRAME ();
5260   NSEvent *theEvent = [NSApp currentEvent];
5262   if (!emacs_event)
5263     return;
5264   emacs_event->kind = NS_NONKEY_EVENT;
5265   emacs_event->code = KEY_NS_NEW_FRAME;
5266   emacs_event->modifiers = 0;
5267   EV_TRAILER (theEvent);
5271 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5272 - (BOOL) openFile: (NSString *)fileName
5274   NSTRACE ("[EmacsApp openFile:]");
5276   struct frame *emacsframe = SELECTED_FRAME ();
5277   NSEvent *theEvent = [NSApp currentEvent];
5279   if (!emacs_event)
5280     return NO;
5282   emacs_event->kind = NS_NONKEY_EVENT;
5283   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5284   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5285   ns_input_line = Qnil; /* can be start or cons start,end */
5286   emacs_event->modifiers =0;
5287   EV_TRAILER (theEvent);
5289   return YES;
5293 /* **************************************************************************
5295       EmacsApp delegate implementation
5297    ************************************************************************** */
5299 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5300 /* --------------------------------------------------------------------------
5301      When application is loaded, terminate event loop in ns_term_init
5302    -------------------------------------------------------------------------- */
5304   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5306 #ifdef NS_IMPL_GNUSTEP
5307   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5308 #endif
5309   [NSApp setServicesProvider: NSApp];
5311   [self antialiasThresholdDidChange:nil];
5312 #ifdef NS_IMPL_COCOA
5313   [[NSNotificationCenter defaultCenter]
5314     addObserver:self
5315        selector:@selector(antialiasThresholdDidChange:)
5316            name:NSAntialiasThresholdChangedNotification
5317          object:nil];
5318 #endif
5320   ns_send_appdefined (-2);
5323 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5325 #ifdef NS_IMPL_COCOA
5326   macfont_update_antialias_threshold ();
5327 #endif
5331 /* Termination sequences:
5332     C-x C-c:
5333     Cmd-Q:
5334     MenuBar | File | Exit:
5335     Select Quit from App menubar:
5336         -terminate
5337         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5338         ns_term_shutdown()
5340     Select Quit from Dock menu:
5341     Logout attempt:
5342         -appShouldTerminate
5343           Cancel -> Nothing else
5344           Accept ->
5346           -terminate
5347           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5348           ns_term_shutdown()
5352 - (void) terminate: (id)sender
5354   NSTRACE ("[EmacsApp terminate:]");
5356   struct frame *emacsframe = SELECTED_FRAME ();
5358   if (!emacs_event)
5359     return;
5361   emacs_event->kind = NS_NONKEY_EVENT;
5362   emacs_event->code = KEY_NS_POWER_OFF;
5363   emacs_event->arg = Qt; /* mark as non-key event */
5364   EV_TRAILER ((id)nil);
5367 static bool
5368 runAlertPanel(NSString *title,
5369               NSString *msgFormat,
5370               NSString *defaultButton,
5371               NSString *alternateButton)
5373 #if !defined (NS_IMPL_COCOA) || \
5374   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5375   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5376     == NSAlertDefaultReturn;
5377 #else
5378   NSAlert *alert = [[NSAlert alloc] init];
5379   [alert setAlertStyle: NSCriticalAlertStyle];
5380   [alert setMessageText: msgFormat];
5381   [alert addButtonWithTitle: defaultButton];
5382   [alert addButtonWithTitle: alternateButton];
5383   NSInteger ret = [alert runModal];
5384   [alert release];
5385   return ret == NSAlertFirstButtonReturn;
5386 #endif
5390 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5392   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5394   bool ret;
5396   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5397     return NSTerminateNow;
5399     ret = runAlertPanel(ns_app_name,
5400                         @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5401                         @"Save Buffers and Exit", @"Cancel");
5403     if (ret)
5404         return NSTerminateNow;
5405     else
5406         return NSTerminateCancel;
5407     return NSTerminateNow;  /* just in case */
5410 static int
5411 not_in_argv (NSString *arg)
5413   int k;
5414   const char *a = [arg UTF8String];
5415   for (k = 1; k < initial_argc; ++k)
5416     if (strcmp (a, initial_argv[k]) == 0) return 0;
5417   return 1;
5420 /*   Notification from the Workspace to open a file */
5421 - (BOOL)application: sender openFile: (NSString *)file
5423   if (ns_do_open_file || not_in_argv (file))
5424     [ns_pending_files addObject: file];
5425   return YES;
5429 /*   Open a file as a temporary file */
5430 - (BOOL)application: sender openTempFile: (NSString *)file
5432   if (ns_do_open_file || not_in_argv (file))
5433     [ns_pending_files addObject: file];
5434   return YES;
5438 /*   Notification from the Workspace to open a file noninteractively (?) */
5439 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5441   if (ns_do_open_file || not_in_argv (file))
5442     [ns_pending_files addObject: file];
5443   return YES;
5446 /*   Notification from the Workspace to open multiple files */
5447 - (void)application: sender openFiles: (NSArray *)fileList
5449   NSEnumerator *files = [fileList objectEnumerator];
5450   NSString *file;
5451   /* Don't open files from the command line unconditionally,
5452      Cocoa parses the command line wrong, --option value tries to open value
5453      if --option is the last option.  */
5454   while ((file = [files nextObject]) != nil)
5455     if (ns_do_open_file || not_in_argv (file))
5456       [ns_pending_files addObject: file];
5458   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5463 /* Handle dock menu requests.  */
5464 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5466   return dockMenu;
5470 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5471 - (void)applicationWillBecomeActive: (NSNotification *)notification
5473   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5474   //ns_app_active=YES;
5477 - (void)applicationDidBecomeActive: (NSNotification *)notification
5479   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5481 #ifdef NS_IMPL_GNUSTEP
5482   if (! applicationDidFinishLaunchingCalled)
5483     [self applicationDidFinishLaunching:notification];
5484 #endif
5485   //ns_app_active=YES;
5487   ns_update_auto_hide_menu_bar ();
5488   // No constraining takes place when the application is not active.
5489   ns_constrain_all_frames ();
5491 - (void)applicationDidResignActive: (NSNotification *)notification
5493   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5495   //ns_app_active=NO;
5496   ns_send_appdefined (-1);
5501 /* ==========================================================================
5503     EmacsApp aux handlers for managing event loop
5505    ========================================================================== */
5508 - (void)timeout_handler: (NSTimer *)timedEntry
5509 /* --------------------------------------------------------------------------
5510      The timeout specified to ns_select has passed.
5511    -------------------------------------------------------------------------- */
5513   /*NSTRACE ("timeout_handler"); */
5514   ns_send_appdefined (-2);
5517 #ifdef NS_IMPL_GNUSTEP
5518 - (void)sendFromMainThread:(id)unused
5520   ns_send_appdefined (nextappdefined);
5522 #endif
5524 - (void)fd_handler:(id)unused
5525 /* --------------------------------------------------------------------------
5526      Check data waiting on file descriptors and terminate if so
5527    -------------------------------------------------------------------------- */
5529   int result;
5530   int waiting = 1, nfds;
5531   char c;
5533   fd_set readfds, writefds, *wfds;
5534   struct timespec timeout, *tmo;
5535   NSAutoreleasePool *pool = nil;
5537   /* NSTRACE ("fd_handler"); */
5539   for (;;)
5540     {
5541       [pool release];
5542       pool = [[NSAutoreleasePool alloc] init];
5544       if (waiting)
5545         {
5546           fd_set fds;
5547           FD_ZERO (&fds);
5548           FD_SET (selfds[0], &fds);
5549           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5550           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5551             waiting = 0;
5552         }
5553       else
5554         {
5555           pthread_mutex_lock (&select_mutex);
5556           nfds = select_nfds;
5558           if (select_valid & SELECT_HAVE_READ)
5559             readfds = select_readfds;
5560           else
5561             FD_ZERO (&readfds);
5563           if (select_valid & SELECT_HAVE_WRITE)
5564             {
5565               writefds = select_writefds;
5566               wfds = &writefds;
5567             }
5568           else
5569             wfds = NULL;
5570           if (select_valid & SELECT_HAVE_TMO)
5571             {
5572               timeout = select_timeout;
5573               tmo = &timeout;
5574             }
5575           else
5576             tmo = NULL;
5578           pthread_mutex_unlock (&select_mutex);
5580           FD_SET (selfds[0], &readfds);
5581           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5583           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5585           if (result == 0)
5586             ns_send_appdefined (-2);
5587           else if (result > 0)
5588             {
5589               if (FD_ISSET (selfds[0], &readfds))
5590                 {
5591                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5592                     waiting = 1;
5593                 }
5594               else
5595                 {
5596                   pthread_mutex_lock (&select_mutex);
5597                   if (select_valid & SELECT_HAVE_READ)
5598                     select_readfds = readfds;
5599                   if (select_valid & SELECT_HAVE_WRITE)
5600                     select_writefds = writefds;
5601                   if (select_valid & SELECT_HAVE_TMO)
5602                     select_timeout = timeout;
5603                   pthread_mutex_unlock (&select_mutex);
5605                   ns_send_appdefined (result);
5606                 }
5607             }
5608           waiting = 1;
5609         }
5610     }
5615 /* ==========================================================================
5617     Service provision
5619    ========================================================================== */
5621 /* called from system: queue for next pass through event loop */
5622 - (void)requestService: (NSPasteboard *)pboard
5623               userData: (NSString *)userData
5624                  error: (NSString **)error
5626   [ns_pending_service_names addObject: userData];
5627   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5628       SSDATA (ns_string_from_pasteboard (pboard))]];
5632 /* called from ns_read_socket to clear queue */
5633 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5635   struct frame *emacsframe = SELECTED_FRAME ();
5636   NSEvent *theEvent = [NSApp currentEvent];
5638   NSTRACE ("[EmacsApp fulfillService:withArg:]");
5640   if (!emacs_event)
5641     return NO;
5643   emacs_event->kind = NS_NONKEY_EVENT;
5644   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5645   ns_input_spi_name = build_string ([name UTF8String]);
5646   ns_input_spi_arg = build_string ([arg UTF8String]);
5647   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5648   EV_TRAILER (theEvent);
5650   return YES;
5654 @end  /* EmacsApp */
5658 /* ==========================================================================
5660     EmacsView implementation
5662    ========================================================================== */
5665 @implementation EmacsView
5667 /* needed to inform when window closed from LISP */
5668 - (void) setWindowClosing: (BOOL)closing
5670   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5672   windowClosing = closing;
5676 - (void)dealloc
5678   NSTRACE ("[EmacsView dealloc]");
5679   [toolbar release];
5680   if (fs_state == FULLSCREEN_BOTH)
5681     [nonfs_window release];
5682   [super dealloc];
5686 /* called on font panel selection */
5687 - (void)changeFont: (id)sender
5689   NSEvent *e = [[self window] currentEvent];
5690   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5691   struct font *font = face->font;
5692   id newFont;
5693   CGFloat size;
5694   NSFont *nsfont;
5696   NSTRACE ("[EmacsView changeFont:]");
5698   if (!emacs_event)
5699     return;
5701 #ifdef NS_IMPL_GNUSTEP
5702   nsfont = ((struct nsfont_info *)font)->nsfont;
5703 #endif
5704 #ifdef NS_IMPL_COCOA
5705   nsfont = (NSFont *) macfont_get_nsctfont (font);
5706 #endif
5708   if ((newFont = [sender convertFont: nsfont]))
5709     {
5710       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5712       emacs_event->kind = NS_NONKEY_EVENT;
5713       emacs_event->modifiers = 0;
5714       emacs_event->code = KEY_NS_CHANGE_FONT;
5716       size = [newFont pointSize];
5717       ns_input_fontsize = make_number (lrint (size));
5718       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5719       EV_TRAILER (e);
5720     }
5724 - (BOOL)acceptsFirstResponder
5726   NSTRACE ("[EmacsView acceptsFirstResponder]");
5727   return YES;
5731 - (void)resetCursorRects
5733   NSRect visible = [self visibleRect];
5734   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5735   NSTRACE ("[EmacsView resetCursorRects]");
5737   if (currentCursor == nil)
5738     currentCursor = [NSCursor arrowCursor];
5740   if (!NSIsEmptyRect (visible))
5741     [self addCursorRect: visible cursor: currentCursor];
5742   [currentCursor setOnMouseEntered: YES];
5747 /*****************************************************************************/
5748 /* Keyboard handling. */
5749 #define NS_KEYLOG 0
5751 - (void)keyDown: (NSEvent *)theEvent
5753   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5754   int code;
5755   unsigned fnKeysym = 0;
5756   static NSMutableArray *nsEvArray;
5757   int left_is_none;
5758   unsigned int flags = [theEvent modifierFlags];
5760   NSTRACE ("[EmacsView keyDown:]");
5762   /* Rhapsody and OS X give up and down events for the arrow keys */
5763   if (ns_fake_keydown == YES)
5764     ns_fake_keydown = NO;
5765   else if ([theEvent type] != NSKeyDown)
5766     return;
5768   if (!emacs_event)
5769     return;
5771  if (![[self window] isKeyWindow]
5772      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5773      /* we must avoid an infinite loop here. */
5774      && (EmacsView *)[[theEvent window] delegate] != self)
5775    {
5776      /* XXX: There is an occasional condition in which, when Emacs display
5777          updates a different frame from the current one, and temporarily
5778          selects it, then processes some interrupt-driven input
5779          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5780          for some reason that window has its first responder set to the NSView
5781          most recently updated (I guess), which is not the correct one. */
5782      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5783      return;
5784    }
5786   if (nsEvArray == nil)
5787     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5789   [NSCursor setHiddenUntilMouseMoves: YES];
5791   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5792     {
5793       clear_mouse_face (hlinfo);
5794       hlinfo->mouse_face_hidden = 1;
5795     }
5797   if (!processingCompose)
5798     {
5799       /* When using screen sharing, no left or right information is sent,
5800          so use Left key in those cases.  */
5801       int is_left_key, is_right_key;
5803       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5804         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5806       /* (Carbon way: [theEvent keyCode]) */
5808       /* is it a "function key"? */
5809       /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5810          flag set (this is probably a bug in the OS).
5811       */
5812       if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5813         {
5814           fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5815         }
5816       if (fnKeysym == 0)
5817         {
5818           fnKeysym = ns_convert_key (code);
5819         }
5821       if (fnKeysym)
5822         {
5823           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5824              because Emacs treats Delete and KP-Delete same (in simple.el). */
5825           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5826 #ifdef NS_IMPL_GNUSTEP
5827               /*  GNUstep uses incompatible keycodes, even for those that are
5828                   supposed to be hardware independent.  Just check for delete.
5829                   Keypad delete does not have keysym 0xFFFF.
5830                   See http://savannah.gnu.org/bugs/?25395
5831               */
5832               || (fnKeysym == 0xFFFF && code == 127)
5833 #endif
5834             )
5835             code = 0xFF08; /* backspace */
5836           else
5837             code = fnKeysym;
5838         }
5840       /* are there modifiers? */
5841       emacs_event->modifiers = 0;
5843       if (flags & NSHelpKeyMask)
5844           emacs_event->modifiers |= hyper_modifier;
5846       if (flags & NSShiftKeyMask)
5847         emacs_event->modifiers |= shift_modifier;
5849       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5850       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5851         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5853       if (is_right_key)
5854         emacs_event->modifiers |= parse_solitary_modifier
5855           (EQ (ns_right_command_modifier, Qleft)
5856            ? ns_command_modifier
5857            : ns_right_command_modifier);
5859       if (is_left_key)
5860         {
5861           emacs_event->modifiers |= parse_solitary_modifier
5862             (ns_command_modifier);
5864           /* if super (default), take input manager's word so things like
5865              dvorak / qwerty layout work */
5866           if (EQ (ns_command_modifier, Qsuper)
5867               && !fnKeysym
5868               && [[theEvent characters] length] != 0)
5869             {
5870               /* XXX: the code we get will be unshifted, so if we have
5871                  a shift modifier, must convert ourselves */
5872               if (!(flags & NSShiftKeyMask))
5873                 code = [[theEvent characters] characterAtIndex: 0];
5874 #if 0
5875               /* this is ugly and also requires linking w/Carbon framework
5876                  (for LMGetKbdType) so for now leave this rare (?) case
5877                  undealt with.. in future look into CGEvent methods */
5878               else
5879                 {
5880                   long smv = GetScriptManagerVariable (smKeyScript);
5881                   Handle uchrHandle = GetResource
5882                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5883                   UInt32 dummy = 0;
5884                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5885                                  [[theEvent characters] characterAtIndex: 0],
5886                                  kUCKeyActionDisplay,
5887                                  (flags & ~NSCommandKeyMask) >> 8,
5888                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5889                                  &dummy, 1, &dummy, &code);
5890                   code &= 0xFF;
5891                 }
5892 #endif
5893             }
5894         }
5896       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5897       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5898         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5900       if (is_right_key)
5901           emacs_event->modifiers |= parse_solitary_modifier
5902               (EQ (ns_right_control_modifier, Qleft)
5903                ? ns_control_modifier
5904                : ns_right_control_modifier);
5906       if (is_left_key)
5907         emacs_event->modifiers |= parse_solitary_modifier
5908           (ns_control_modifier);
5910       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5911           emacs_event->modifiers |=
5912             parse_solitary_modifier (ns_function_modifier);
5914       left_is_none = NILP (ns_alternate_modifier)
5915         || EQ (ns_alternate_modifier, Qnone);
5917       is_right_key = (flags & NSRightAlternateKeyMask)
5918         == NSRightAlternateKeyMask;
5919       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5920         || (! is_right_key
5921             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5923       if (is_right_key)
5924         {
5925           if ((NILP (ns_right_alternate_modifier)
5926                || EQ (ns_right_alternate_modifier, Qnone)
5927                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5928               && !fnKeysym)
5929             {   /* accept pre-interp alt comb */
5930               if ([[theEvent characters] length] > 0)
5931                 code = [[theEvent characters] characterAtIndex: 0];
5932               /*HACK: clear lone shift modifier to stop next if from firing */
5933               if (emacs_event->modifiers == shift_modifier)
5934                 emacs_event->modifiers = 0;
5935             }
5936           else
5937             emacs_event->modifiers |= parse_solitary_modifier
5938               (EQ (ns_right_alternate_modifier, Qleft)
5939                ? ns_alternate_modifier
5940                : ns_right_alternate_modifier);
5941         }
5943       if (is_left_key) /* default = meta */
5944         {
5945           if (left_is_none && !fnKeysym)
5946             {   /* accept pre-interp alt comb */
5947               if ([[theEvent characters] length] > 0)
5948                 code = [[theEvent characters] characterAtIndex: 0];
5949               /*HACK: clear lone shift modifier to stop next if from firing */
5950               if (emacs_event->modifiers == shift_modifier)
5951                 emacs_event->modifiers = 0;
5952             }
5953           else
5954               emacs_event->modifiers |=
5955                 parse_solitary_modifier (ns_alternate_modifier);
5956         }
5958   if (NS_KEYLOG)
5959     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5960              code, fnKeysym, flags, emacs_event->modifiers);
5962       /* if it was a function key or had modifiers, pass it directly to emacs */
5963       if (fnKeysym || (emacs_event->modifiers
5964                        && (emacs_event->modifiers != shift_modifier)
5965                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5966 /*[[theEvent characters] length] */
5967         {
5968           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5969           if (code < 0x20)
5970             code |= (1<<28)|(3<<16);
5971           else if (code == 0x7f)
5972             code |= (1<<28)|(3<<16);
5973           else if (!fnKeysym)
5974             emacs_event->kind = code > 0xFF
5975               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5977           emacs_event->code = code;
5978           EV_TRAILER (theEvent);
5979           processingCompose = NO;
5980           return;
5981         }
5982     }
5985   if (NS_KEYLOG && !processingCompose)
5986     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5988   processingCompose = YES;
5989   [nsEvArray addObject: theEvent];
5990   [self interpretKeyEvents: nsEvArray];
5991   [nsEvArray removeObject: theEvent];
5995 #ifdef NS_IMPL_COCOA
5996 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5997    decided not to send key-down for.
5998    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5999    This only applies on Tiger and earlier.
6000    If it matches one of these, send it on to keyDown. */
6001 -(void)keyUp: (NSEvent *)theEvent
6003   int flags = [theEvent modifierFlags];
6004   int code = [theEvent keyCode];
6006   NSTRACE ("[EmacsView keyUp:]");
6008   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
6009       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
6010     {
6011       if (NS_KEYLOG)
6012         fprintf (stderr, "keyUp: passed test");
6013       ns_fake_keydown = YES;
6014       [self keyDown: theEvent];
6015     }
6017 #endif
6020 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6023 /* <NSTextInput>: called when done composing;
6024    NOTE: also called when we delete over working text, followed immed.
6025          by doCommandBySelector: deleteBackward: */
6026 - (void)insertText: (id)aString
6028   int code;
6029   int len = [(NSString *)aString length];
6030   int i;
6032   NSTRACE ("[EmacsView insertText:]");
6034   if (NS_KEYLOG)
6035     NSLog (@"insertText '%@'\tlen = %d", aString, len);
6036   processingCompose = NO;
6038   if (!emacs_event)
6039     return;
6041   /* first, clear any working text */
6042   if (workingText != nil)
6043     [self deleteWorkingText];
6045   /* now insert the string as keystrokes */
6046   for (i =0; i<len; i++)
6047     {
6048       code = [aString characterAtIndex: i];
6049       /* TODO: still need this? */
6050       if (code == 0x2DC)
6051         code = '~'; /* 0x7E */
6052       if (code != 32) /* Space */
6053         emacs_event->modifiers = 0;
6054       emacs_event->kind
6055         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6056       emacs_event->code = code;
6057       EV_TRAILER ((id)nil);
6058     }
6062 /* <NSTextInput>: inserts display of composing characters */
6063 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6065   NSString *str = [aString respondsToSelector: @selector (string)] ?
6066     [aString string] : aString;
6068   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6070   if (NS_KEYLOG)
6071     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6072            str, (unsigned long)[str length],
6073            (unsigned long)selRange.length,
6074            (unsigned long)selRange.location);
6076   if (workingText != nil)
6077     [self deleteWorkingText];
6078   if ([str length] == 0)
6079     return;
6081   if (!emacs_event)
6082     return;
6084   processingCompose = YES;
6085   workingText = [str copy];
6086   ns_working_text = build_string ([workingText UTF8String]);
6088   emacs_event->kind = NS_TEXT_EVENT;
6089   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6090   EV_TRAILER ((id)nil);
6094 /* delete display of composing characters [not in <NSTextInput>] */
6095 - (void)deleteWorkingText
6097   NSTRACE ("[EmacsView deleteWorkingText]");
6099   if (workingText == nil)
6100     return;
6101   if (NS_KEYLOG)
6102     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6103   [workingText release];
6104   workingText = nil;
6105   processingCompose = NO;
6107   if (!emacs_event)
6108     return;
6110   emacs_event->kind = NS_TEXT_EVENT;
6111   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6112   EV_TRAILER ((id)nil);
6116 - (BOOL)hasMarkedText
6118   NSTRACE ("[EmacsView hasMarkedText]");
6120   return workingText != nil;
6124 - (NSRange)markedRange
6126   NSTRACE ("[EmacsView markedRange]");
6128   NSRange rng = workingText != nil
6129     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6130   if (NS_KEYLOG)
6131     NSLog (@"markedRange request");
6132   return rng;
6136 - (void)unmarkText
6138   NSTRACE ("[EmacsView unmarkText]");
6140   if (NS_KEYLOG)
6141     NSLog (@"unmark (accept) text");
6142   [self deleteWorkingText];
6143   processingCompose = NO;
6147 /* used to position char selection windows, etc. */
6148 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6150   NSRect rect;
6151   NSPoint pt;
6152   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6154   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6156   if (NS_KEYLOG)
6157     NSLog (@"firstRectForCharRange request");
6159   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6160   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6161   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6162   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6163                                        +FRAME_LINE_HEIGHT (emacsframe));
6165   pt = [self convertPoint: pt toView: nil];
6166   pt = [[self window] convertBaseToScreen: pt];
6167   rect.origin = pt;
6168   return rect;
6172 - (NSInteger)conversationIdentifier
6174   return (NSInteger)self;
6178 - (void)doCommandBySelector: (SEL)aSelector
6180   NSTRACE ("[EmacsView doCommandBySelector:]");
6182   if (NS_KEYLOG)
6183     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6185   processingCompose = NO;
6186   if (aSelector == @selector (deleteBackward:))
6187     {
6188       /* happens when user backspaces over an ongoing composition:
6189          throw a 'delete' into the event queue */
6190       if (!emacs_event)
6191         return;
6192       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6193       emacs_event->code = 0xFF08;
6194       EV_TRAILER ((id)nil);
6195     }
6198 - (NSArray *)validAttributesForMarkedText
6200   static NSArray *arr = nil;
6201   if (arr == nil) arr = [NSArray new];
6202  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6203   return arr;
6206 - (NSRange)selectedRange
6208   if (NS_KEYLOG)
6209     NSLog (@"selectedRange request");
6210   return NSMakeRange (NSNotFound, 0);
6213 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6214     GNUSTEP_GUI_MINOR_VERSION > 22
6215 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6216 #else
6217 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6218 #endif
6220   if (NS_KEYLOG)
6221     NSLog (@"characterIndexForPoint request");
6222   return 0;
6225 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6227   static NSAttributedString *str = nil;
6228   if (str == nil) str = [NSAttributedString new];
6229   if (NS_KEYLOG)
6230     NSLog (@"attributedSubstringFromRange request");
6231   return str;
6234 /* End <NSTextInput> impl. */
6235 /*****************************************************************************/
6238 /* This is what happens when the user presses a mouse button.  */
6239 - (void)mouseDown: (NSEvent *)theEvent
6241   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6242   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6244   NSTRACE ("[EmacsView mouseDown:]");
6246   [self deleteWorkingText];
6248   if (!emacs_event)
6249     return;
6251   dpyinfo->last_mouse_frame = emacsframe;
6252   /* appears to be needed to prevent spurious movement events generated on
6253      button clicks */
6254   emacsframe->mouse_moved = 0;
6256   if ([theEvent type] == NSScrollWheel)
6257     {
6258       CGFloat delta = [theEvent deltaY];
6259       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6260       if (delta == 0)
6261         {
6262           delta = [theEvent deltaX];
6263           if (delta == 0)
6264             {
6265               NSTRACE_MSG ("deltaIsZero");
6266               return;
6267             }
6268           emacs_event->kind = HORIZ_WHEEL_EVENT;
6269         }
6270       else
6271         emacs_event->kind = WHEEL_EVENT;
6273       emacs_event->code = 0;
6274       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6275         ((delta > 0) ? up_modifier : down_modifier);
6276     }
6277   else
6278     {
6279       emacs_event->kind = MOUSE_CLICK_EVENT;
6280       emacs_event->code = EV_BUTTON (theEvent);
6281       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6282                              | EV_UDMODIFIERS (theEvent);
6283     }
6284   XSETINT (emacs_event->x, lrint (p.x));
6285   XSETINT (emacs_event->y, lrint (p.y));
6286   EV_TRAILER (theEvent);
6290 - (void)rightMouseDown: (NSEvent *)theEvent
6292   NSTRACE ("[EmacsView rightMouseDown:]");
6293   [self mouseDown: theEvent];
6297 - (void)otherMouseDown: (NSEvent *)theEvent
6299   NSTRACE ("[EmacsView otherMouseDown:]");
6300   [self mouseDown: theEvent];
6304 - (void)mouseUp: (NSEvent *)theEvent
6306   NSTRACE ("[EmacsView mouseUp:]");
6307   [self mouseDown: theEvent];
6311 - (void)rightMouseUp: (NSEvent *)theEvent
6313   NSTRACE ("[EmacsView rightMouseUp:]");
6314   [self mouseDown: theEvent];
6318 - (void)otherMouseUp: (NSEvent *)theEvent
6320   NSTRACE ("[EmacsView otherMouseUp:]");
6321   [self mouseDown: theEvent];
6325 - (void) scrollWheel: (NSEvent *)theEvent
6327   NSTRACE ("[EmacsView scrollWheel:]");
6328   [self mouseDown: theEvent];
6332 /* Tell emacs the mouse has moved. */
6333 - (void)mouseMoved: (NSEvent *)e
6335   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6336   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6337   Lisp_Object frame;
6338   NSPoint pt;
6340   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6342   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6343   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6344   dpyinfo->last_mouse_motion_x = pt.x;
6345   dpyinfo->last_mouse_motion_y = pt.y;
6347   /* update any mouse face */
6348   if (hlinfo->mouse_face_hidden)
6349     {
6350       hlinfo->mouse_face_hidden = 0;
6351       clear_mouse_face (hlinfo);
6352     }
6354   /* tooltip handling */
6355   previous_help_echo_string = help_echo_string;
6356   help_echo_string = Qnil;
6358   if (!NILP (Vmouse_autoselect_window))
6359     {
6360       NSTRACE_MSG ("mouse_autoselect_window");
6361       static Lisp_Object last_mouse_window;
6362       Lisp_Object window
6363         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6365       if (WINDOWP (window)
6366           && !EQ (window, last_mouse_window)
6367           && !EQ (window, selected_window)
6368           && (focus_follows_mouse
6369               || (EQ (XWINDOW (window)->frame,
6370                       XWINDOW (selected_window)->frame))))
6371         {
6372           NSTRACE_MSG ("in_window");
6373           emacs_event->kind = SELECT_WINDOW_EVENT;
6374           emacs_event->frame_or_window = window;
6375           EV_TRAILER2 (e);
6376         }
6377       /* Remember the last window where we saw the mouse.  */
6378       last_mouse_window = window;
6379     }
6381   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6382     help_echo_string = previous_help_echo_string;
6384   XSETFRAME (frame, emacsframe);
6385   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6386     {
6387       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6388          (note_mouse_highlight), which is called through the
6389          note_mouse_movement () call above */
6390       any_help_event_p = YES;
6391       gen_help_event (help_echo_string, frame, help_echo_window,
6392                       help_echo_object, help_echo_pos);
6393     }
6395   if (emacsframe->mouse_moved && send_appdefined)
6396     ns_send_appdefined (-1);
6400 - (void)mouseDragged: (NSEvent *)e
6402   NSTRACE ("[EmacsView mouseDragged:]");
6403   [self mouseMoved: e];
6407 - (void)rightMouseDragged: (NSEvent *)e
6409   NSTRACE ("[EmacsView rightMouseDragged:]");
6410   [self mouseMoved: e];
6414 - (void)otherMouseDragged: (NSEvent *)e
6416   NSTRACE ("[EmacsView otherMouseDragged:]");
6417   [self mouseMoved: e];
6421 - (BOOL)windowShouldClose: (id)sender
6423   NSEvent *e =[[self window] currentEvent];
6425   NSTRACE ("[EmacsView windowShouldClose:]");
6426   windowClosing = YES;
6427   if (!emacs_event)
6428     return NO;
6429   emacs_event->kind = DELETE_WINDOW_EVENT;
6430   emacs_event->modifiers = 0;
6431   emacs_event->code = 0;
6432   EV_TRAILER (e);
6433   /* Don't close this window, let this be done from lisp code.  */
6434   return NO;
6437 - (void) updateFrameSize: (BOOL) delay;
6439   NSWindow *window = [self window];
6440   NSRect wr = [window frame];
6441   int extra = 0;
6442   int oldc = cols, oldr = rows;
6443   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6444   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6445   int neww, newh;
6447   NSTRACE ("[EmacsView updateFrameSize:]");
6448   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6449   NSTRACE_RECT ("Original frame", wr);
6450   NSTRACE_MSG  ("Original columns: %d", cols);
6451   NSTRACE_MSG  ("Original rows: %d", rows);
6453   if (! [self isFullscreen])
6454     {
6455 #ifdef NS_IMPL_GNUSTEP
6456       // GNUstep does not always update the tool bar height.  Force it.
6457       if (toolbar && [toolbar isVisible])
6458           update_frame_tool_bar (emacsframe);
6459 #endif
6461       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6462         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6463     }
6465   if (wait_for_tool_bar)
6466     {
6467       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6468         {
6469           NSTRACE_MSG ("Waiting for toolbar");
6470           return;
6471         }
6472       wait_for_tool_bar = NO;
6473     }
6475   neww = (int)wr.size.width - emacsframe->border_width;
6476   newh = (int)wr.size.height - extra;
6478   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6479   NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height);
6481   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6482   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6484   if (cols < MINWIDTH)
6485     cols = MINWIDTH;
6487   if (rows < MINHEIGHT)
6488     rows = MINHEIGHT;
6490   NSTRACE_MSG ("New columns: %d", cols);
6491   NSTRACE_MSG ("New rows: %d", rows);
6493   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6494     {
6495       NSView *view = FRAME_NS_VIEW (emacsframe);
6497       change_frame_size (emacsframe,
6498                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6499                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6500                          0, delay, 0, 1);
6501       SET_FRAME_GARBAGED (emacsframe);
6502       cancel_mouse_face (emacsframe);
6504       wr = NSMakeRect (0, 0, neww, newh);
6506       [view setFrame: wr];
6508       // to do: consider using [NSNotificationCenter postNotificationName:].
6509       [self windowDidMove: // Update top/left.
6510               [NSNotification notificationWithName:NSWindowDidMoveNotification
6511                                             object:[view window]]];
6512     }
6513   else
6514     {
6515       NSTRACE_MSG ("No change");
6516     }
6519 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6520 /* normalize frame to gridded text size */
6522   int extra = 0;
6524   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6525            NSTRACE_ARG_SIZE (frameSize));
6526   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6527   NSTRACE_FSTYPE ("fs_state", fs_state);
6529   if (fs_state == FULLSCREEN_MAXIMIZED
6530       && (maximized_width != (int)frameSize.width
6531           || maximized_height != (int)frameSize.height))
6532     [self setFSValue: FULLSCREEN_NONE];
6533   else if (fs_state == FULLSCREEN_WIDTH
6534            && maximized_width != (int)frameSize.width)
6535     [self setFSValue: FULLSCREEN_NONE];
6536   else if (fs_state == FULLSCREEN_HEIGHT
6537            && maximized_height != (int)frameSize.height)
6538     [self setFSValue: FULLSCREEN_NONE];
6540   if (fs_state == FULLSCREEN_NONE)
6541     maximized_width = maximized_height = -1;
6543   if (! [self isFullscreen])
6544     {
6545       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6546         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6547     }
6549   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6550   if (cols < MINWIDTH)
6551     cols = MINWIDTH;
6553   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6554                                            frameSize.height - extra);
6555   if (rows < MINHEIGHT)
6556     rows = MINHEIGHT;
6557 #ifdef NS_IMPL_COCOA
6558   {
6559     /* this sets window title to have size in it; the wm does this under GS */
6560     NSRect r = [[self window] frame];
6561     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6562       {
6563         if (old_title != 0)
6564           {
6565             xfree (old_title);
6566             old_title = 0;
6567           }
6568       }
6569     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6570       {
6571         char *size_title;
6572         NSWindow *window = [self window];
6573         if (old_title == 0)
6574           {
6575             char *t = strdup ([[[self window] title] UTF8String]);
6576             char *pos = strstr (t, "  â€”  ");
6577             if (pos)
6578               *pos = '\0';
6579             old_title = t;
6580           }
6581         size_title = xmalloc (strlen (old_title) + 40);
6582         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6583         [window setTitle: [NSString stringWithUTF8String: size_title]];
6584         [window display];
6585         xfree (size_title);
6586       }
6587   }
6588 #endif /* NS_IMPL_COCOA */
6590   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6592   /* Restrict the new size to the text gird.
6594      Don't restrict the width if the user only adjusted the height, and
6595      vice versa.  (Without this, the frame would shrink, and move
6596      slightly, if the window was resized by dragging one of its
6597      borders.) */
6598   if (!frame_resize_pixelwise)
6599     {
6600       NSRect r = [[self window] frame];
6602       if (r.size.width != frameSize.width)
6603         {
6604           frameSize.width =
6605             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6606         }
6608       if (r.size.height != frameSize.height)
6609         {
6610           frameSize.height =
6611             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6612         }
6613     }
6615   NSTRACE_RETURN_SIZE (frameSize);
6617   return frameSize;
6621 - (void)windowDidResize: (NSNotification *)notification
6623   NSTRACE ("[EmacsView windowDidResize:]");
6624   if (!FRAME_LIVE_P (emacsframe))
6625     {
6626       NSTRACE_MSG ("Ignored (frame dead)");
6627       return;
6628     }
6629   if (emacsframe->output_data.ns->in_animation)
6630     {
6631       NSTRACE_MSG ("Ignored (in animation)");
6632       return;
6633     }
6635   if (! [self fsIsNative])
6636     {
6637       NSWindow *theWindow = [notification object];
6638       /* We can get notification on the non-FS window when in
6639          fullscreen mode.  */
6640       if ([self window] != theWindow) return;
6641     }
6643   NSTRACE_RECT ("frame", [[notification object] frame]);
6645 #ifdef NS_IMPL_GNUSTEP
6646   NSWindow *theWindow = [notification object];
6648    /* In GNUstep, at least currently, it's possible to get a didResize
6649       without getting a willResize.. therefore we need to act as if we got
6650       the willResize now */
6651   NSSize sz = [theWindow frame].size;
6652   sz = [self windowWillResize: theWindow toSize: sz];
6653 #endif /* NS_IMPL_GNUSTEP */
6655   if (cols > 0 && rows > 0)
6656     {
6657       [self updateFrameSize: YES];
6658     }
6660   ns_send_appdefined (-1);
6663 #ifdef NS_IMPL_COCOA
6664 - (void)viewDidEndLiveResize
6666   NSTRACE ("[EmacsView viewDidEndLiveResize]");
6668   [super viewDidEndLiveResize];
6669   if (old_title != 0)
6670     {
6671       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6672       xfree (old_title);
6673       old_title = 0;
6674     }
6675   maximizing_resize = NO;
6677 #endif /* NS_IMPL_COCOA */
6680 - (void)windowDidBecomeKey: (NSNotification *)notification
6681 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6683   [self windowDidBecomeKey];
6687 - (void)windowDidBecomeKey      /* for direct calls */
6689   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6690   struct frame *old_focus = dpyinfo->x_focus_frame;
6692   NSTRACE ("[EmacsView windowDidBecomeKey]");
6694   if (emacsframe != old_focus)
6695     dpyinfo->x_focus_frame = emacsframe;
6697   ns_frame_rehighlight (emacsframe);
6699   if (emacs_event)
6700     {
6701       emacs_event->kind = FOCUS_IN_EVENT;
6702       EV_TRAILER ((id)nil);
6703     }
6707 - (void)windowDidResignKey: (NSNotification *)notification
6708 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6710   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6711   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6712   NSTRACE ("[EmacsView windowDidResignKey:]");
6714   if (is_focus_frame)
6715     dpyinfo->x_focus_frame = 0;
6717   emacsframe->mouse_moved = 0;
6718   ns_frame_rehighlight (emacsframe);
6720   /* FIXME: for some reason needed on second and subsequent clicks away
6721             from sole-frame Emacs to get hollow box to show */
6722   if (!windowClosing && [[self window] isVisible] == YES)
6723     {
6724       x_update_cursor (emacsframe, 1);
6725       x_set_frame_alpha (emacsframe);
6726     }
6728   if (any_help_event_p)
6729     {
6730       Lisp_Object frame;
6731       XSETFRAME (frame, emacsframe);
6732       help_echo_string = Qnil;
6733       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6734     }
6736   if (emacs_event && is_focus_frame)
6737     {
6738       [self deleteWorkingText];
6739       emacs_event->kind = FOCUS_OUT_EVENT;
6740       EV_TRAILER ((id)nil);
6741     }
6745 - (void)windowWillMiniaturize: sender
6747   NSTRACE ("[EmacsView windowWillMiniaturize:]");
6751 - (void)setFrame:(NSRect)frameRect;
6753   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6754            NSTRACE_ARG_RECT (frameRect));
6756   [super setFrame:(NSRect)frameRect];
6760 - (BOOL)isFlipped
6762   return YES;
6766 - (BOOL)isOpaque
6768   return NO;
6772 - initFrameFromEmacs: (struct frame *)f
6774   NSRect r, wr;
6775   Lisp_Object tem;
6776   NSWindow *win;
6777   NSColor *col;
6778   NSString *name;
6780   NSTRACE ("[EmacsView initFrameFromEmacs:]");
6781   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6783   windowClosing = NO;
6784   processingCompose = NO;
6785   scrollbarsNeedingUpdate = 0;
6786   fs_state = FULLSCREEN_NONE;
6787   fs_before_fs = next_maximized = -1;
6788 #ifdef HAVE_NATIVE_FS
6789   fs_is_native = ns_use_native_fullscreen;
6790 #else
6791   fs_is_native = NO;
6792 #endif
6793   maximized_width = maximized_height = -1;
6794   nonfs_window = nil;
6796   ns_userRect = NSMakeRect (0, 0, 0, 0);
6797   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6798                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6799   [self initWithFrame: r];
6800   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6802   FRAME_NS_VIEW (f) = self;
6803   emacsframe = f;
6804 #ifdef NS_IMPL_COCOA
6805   old_title = 0;
6806   maximizing_resize = NO;
6807 #endif
6809   win = [[EmacsWindow alloc]
6810             initWithContentRect: r
6811                       styleMask: (NSResizableWindowMask |
6812 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6813                                   NSTitledWindowMask |
6814 #endif
6815                                   NSMiniaturizableWindowMask |
6816                                   NSClosableWindowMask)
6817                         backing: NSBackingStoreBuffered
6818                           defer: YES];
6820 #ifdef HAVE_NATIVE_FS
6821     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6822 #endif
6824   wr = [win frame];
6825   bwidth = f->border_width = wr.size.width - r.size.width;
6826   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6828   [win setAcceptsMouseMovedEvents: YES];
6829   [win setDelegate: self];
6830 #if !defined (NS_IMPL_COCOA) || \
6831   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6832   [win useOptimizedDrawing: YES];
6833 #endif
6835   [[win contentView] addSubview: self];
6837   if (ns_drag_types)
6838     [self registerForDraggedTypes: ns_drag_types];
6840   tem = f->name;
6841   name = [NSString stringWithUTF8String:
6842                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6843   [win setTitle: name];
6845   /* toolbar support */
6846   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6847                          [NSString stringWithFormat: @"Emacs Frame %d",
6848                                    ns_window_num]];
6849   [win setToolbar: toolbar];
6850   [toolbar setVisible: NO];
6852   /* Don't set frame garbaged until tool bar is up to date?
6853      This avoids an extra clear and redraw (flicker) at frame creation.  */
6854   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6855   else wait_for_tool_bar = NO;
6858 #ifdef NS_IMPL_COCOA
6859   {
6860     NSButton *toggleButton;
6861   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6862   [toggleButton setTarget: self];
6863   [toggleButton setAction: @selector (toggleToolbar: )];
6864   }
6865 #endif
6866   FRAME_TOOLBAR_HEIGHT (f) = 0;
6868   tem = f->icon_name;
6869   if (!NILP (tem))
6870     [win setMiniwindowTitle:
6871            [NSString stringWithUTF8String: SSDATA (tem)]];
6873   {
6874     NSScreen *screen = [win screen];
6876     if (screen != 0)
6877       {
6878         NSPoint pt = NSMakePoint
6879           (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6880            IN_BOUND (-SCREENMAX,
6881                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
6883         [win setFrameTopLeftPoint: pt];
6885         NSTRACE_RECT ("new frame", [win frame]);
6886       }
6887   }
6889   [win makeFirstResponder: self];
6891   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6892                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6893   [win setBackgroundColor: col];
6894   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6895     [win setOpaque: NO];
6897 #if !defined (NS_IMPL_COCOA) || \
6898   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6899   [self allocateGState];
6900 #endif
6901   [NSApp registerServicesMenuSendTypes: ns_send_types
6902                            returnTypes: nil];
6904   ns_window_num++;
6905   return self;
6909 - (void)windowDidMove: sender
6911   NSWindow *win = [self window];
6912   NSRect r = [win frame];
6913   NSArray *screens = [NSScreen screens];
6914   NSScreen *screen = [screens objectAtIndex: 0];
6916   NSTRACE ("[EmacsView windowDidMove:]");
6918   if (!emacsframe->output_data.ns)
6919     return;
6920   if (screen != nil)
6921     {
6922       emacsframe->left_pos = r.origin.x;
6923       emacsframe->top_pos =
6924         [screen frame].size.height - (r.origin.y + r.size.height);
6925     }
6929 /* Called AFTER method below, but before our windowWillResize call there leads
6930    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6931    location so set_window_size moves the frame. */
6932 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6934   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
6935             NSTRACE_FMT_RETURN "YES"),
6936            NSTRACE_ARG_RECT (newFrame));
6938   emacsframe->output_data.ns->zooming = 1;
6939   return YES;
6943 /* Override to do something slightly nonstandard, but nice.  First click on
6944    zoom button will zoom vertically.  Second will zoom completely.  Third
6945    returns to original. */
6946 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6947                         defaultFrame:(NSRect)defaultFrame
6949   // TODO: Rename to "currentFrame" and assign "result" properly in
6950   // all paths.
6951   NSRect result = [sender frame];
6953   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
6954             NSTRACE_FMT_RECT "]"),
6955            NSTRACE_ARG_RECT (defaultFrame));
6956   NSTRACE_FSTYPE ("fs_state", fs_state);
6957   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
6958   NSTRACE_FSTYPE ("next_maximized", next_maximized);
6959   NSTRACE_RECT   ("ns_userRect", ns_userRect);
6960   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6962   if (fs_before_fs != -1) /* Entering fullscreen */
6963     {
6964       NSTRACE_MSG ("Entering fullscreen");
6965       result = defaultFrame;
6966     }
6967   else
6968     {
6969       // Save the window size and position (frame) before the resize.
6970       if (fs_state != FULLSCREEN_MAXIMIZED
6971           && fs_state != FULLSCREEN_WIDTH)
6972         {
6973           ns_userRect.size.width = result.size.width;
6974           ns_userRect.origin.x   = result.origin.x;
6975         }
6977       if (fs_state != FULLSCREEN_MAXIMIZED
6978           && fs_state != FULLSCREEN_HEIGHT)
6979         {
6980           ns_userRect.size.height = result.size.height;
6981           ns_userRect.origin.y    = result.origin.y;
6982         }
6984       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
6986       if (next_maximized == FULLSCREEN_HEIGHT
6987           || (next_maximized == -1
6988               && abs ((int)(defaultFrame.size.height - result.size.height))
6989               > FRAME_LINE_HEIGHT (emacsframe)))
6990         {
6991           /* first click */
6992           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
6993           maximized_height = result.size.height = defaultFrame.size.height;
6994           maximized_width = -1;
6995           result.origin.y = defaultFrame.origin.y;
6996           if (ns_userRect.size.height != 0)
6997             {
6998               result.origin.x = ns_userRect.origin.x;
6999               result.size.width = ns_userRect.size.width;
7000             }
7001           [self setFSValue: FULLSCREEN_HEIGHT];
7002 #ifdef NS_IMPL_COCOA
7003           maximizing_resize = YES;
7004 #endif
7005         }
7006       else if (next_maximized == FULLSCREEN_WIDTH)
7007         {
7008           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7009           maximized_width = result.size.width = defaultFrame.size.width;
7010           maximized_height = -1;
7011           result.origin.x = defaultFrame.origin.x;
7012           if (ns_userRect.size.width != 0)
7013             {
7014               result.origin.y = ns_userRect.origin.y;
7015               result.size.height = ns_userRect.size.height;
7016             }
7017           [self setFSValue: FULLSCREEN_WIDTH];
7018         }
7019       else if (next_maximized == FULLSCREEN_MAXIMIZED
7020                || (next_maximized == -1
7021                    && abs ((int)(defaultFrame.size.width - result.size.width))
7022                    > FRAME_COLUMN_WIDTH (emacsframe)))
7023         {
7024           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7026           result = defaultFrame;  /* second click */
7027           maximized_width = result.size.width;
7028           maximized_height = result.size.height;
7029           [self setFSValue: FULLSCREEN_MAXIMIZED];
7030 #ifdef NS_IMPL_COCOA
7031           maximizing_resize = YES;
7032 #endif
7033         }
7034       else
7035         {
7036           /* restore */
7037           NSTRACE_MSG ("Restore");
7038           result = ns_userRect.size.height ? ns_userRect : result;
7039           NSTRACE_RECT ("restore (2)", result);
7040           ns_userRect = NSMakeRect (0, 0, 0, 0);
7041 #ifdef NS_IMPL_COCOA
7042           maximizing_resize = fs_state != FULLSCREEN_NONE;
7043 #endif
7044           [self setFSValue: FULLSCREEN_NONE];
7045           maximized_width = maximized_height = -1;
7046         }
7047     }
7049   if (fs_before_fs == -1) next_maximized = -1;
7051   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
7052   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
7053   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
7054   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7056   [self windowWillResize: sender toSize: result.size];
7058   NSTRACE_RETURN_RECT (result);
7060   return result;
7064 - (void)windowDidDeminiaturize: sender
7066   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7067   if (!emacsframe->output_data.ns)
7068     return;
7070   SET_FRAME_ICONIFIED (emacsframe, 0);
7071   SET_FRAME_VISIBLE (emacsframe, 1);
7072   windows_or_buffers_changed = 63;
7074   if (emacs_event)
7075     {
7076       emacs_event->kind = DEICONIFY_EVENT;
7077       EV_TRAILER ((id)nil);
7078     }
7082 - (void)windowDidExpose: sender
7084   NSTRACE ("[EmacsView windowDidExpose:]");
7085   if (!emacsframe->output_data.ns)
7086     return;
7088   SET_FRAME_VISIBLE (emacsframe, 1);
7089   SET_FRAME_GARBAGED (emacsframe);
7091   if (send_appdefined)
7092     ns_send_appdefined (-1);
7096 - (void)windowDidMiniaturize: sender
7098   NSTRACE ("[EmacsView windowDidMiniaturize:]");
7099   if (!emacsframe->output_data.ns)
7100     return;
7102   SET_FRAME_ICONIFIED (emacsframe, 1);
7103   SET_FRAME_VISIBLE (emacsframe, 0);
7105   if (emacs_event)
7106     {
7107       emacs_event->kind = ICONIFY_EVENT;
7108       EV_TRAILER ((id)nil);
7109     }
7112 #ifdef HAVE_NATIVE_FS
7113 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7114       willUseFullScreenPresentationOptions:
7115   (NSApplicationPresentationOptions)proposedOptions
7117   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7119 #endif
7121 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7123   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7124   [self windowWillEnterFullScreen];
7126 - (void)windowWillEnterFullScreen /* provided for direct calls */
7128   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7129   fs_before_fs = fs_state;
7132 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7134   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7135   [self windowDidEnterFullScreen];
7138 - (void)windowDidEnterFullScreen /* provided for direct calls */
7140   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7141   [self setFSValue: FULLSCREEN_BOTH];
7142   if (! [self fsIsNative])
7143     {
7144       [self windowDidBecomeKey];
7145       [nonfs_window orderOut:self];
7146     }
7147   else
7148     {
7149       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7150 #ifdef NS_IMPL_COCOA
7151 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7152       unsigned val = (unsigned)[NSApp presentationOptions];
7154       // OSX 10.7 bug fix, the menu won't appear without this.
7155       // val is non-zero on other OSX versions.
7156       if (val == 0)
7157         {
7158           NSApplicationPresentationOptions options
7159             = NSApplicationPresentationAutoHideDock
7160             | NSApplicationPresentationAutoHideMenuBar
7161             | NSApplicationPresentationFullScreen
7162             | NSApplicationPresentationAutoHideToolbar;
7164           [NSApp setPresentationOptions: options];
7165         }
7166 #endif
7167 #endif
7168       [toolbar setVisible:tbar_visible];
7169     }
7172 - (void)windowWillExitFullScreen:(NSNotification *)notification
7174   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7175   [self windowWillExitFullScreen];
7178 - (void)windowWillExitFullScreen /* provided for direct calls */
7180   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7181   if (!FRAME_LIVE_P (emacsframe))
7182     {
7183       NSTRACE_MSG ("Ignored (frame dead)");
7184       return;
7185     }
7186   if (next_maximized != -1)
7187     fs_before_fs = next_maximized;
7190 - (void)windowDidExitFullScreen:(NSNotification *)notification
7192   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7193   [self windowDidExitFullScreen];
7196 - (void)windowDidExitFullScreen /* provided for direct calls */
7198   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7199   if (!FRAME_LIVE_P (emacsframe))
7200     {
7201       NSTRACE_MSG ("Ignored (frame dead)");
7202       return;
7203     }
7204   [self setFSValue: fs_before_fs];
7205   fs_before_fs = -1;
7206 #ifdef HAVE_NATIVE_FS
7207   [self updateCollectionBehavior];
7208 #endif
7209   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7210     {
7211       [toolbar setVisible:YES];
7212       update_frame_tool_bar (emacsframe);
7213       [self updateFrameSize:YES];
7214       [[self window] display];
7215     }
7216   else
7217     [toolbar setVisible:NO];
7219   if (next_maximized != -1)
7220     [[self window] performZoom:self];
7223 - (BOOL)fsIsNative
7225   return fs_is_native;
7228 - (BOOL)isFullscreen
7230   BOOL res;
7232   if (! fs_is_native)
7233     {
7234       res = (nonfs_window != nil);
7235     }
7236   else
7237     {
7238 #ifdef HAVE_NATIVE_FS
7239       res = (([[self window] styleMask] & NSFullScreenWindowMask) != 0);
7240 #else
7241       res = NO;
7242 #endif
7243     }
7245   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7246            (int) res);
7248   return res;
7251 #ifdef HAVE_NATIVE_FS
7252 - (void)updateCollectionBehavior
7254   NSTRACE ("[EmacsView updateCollectionBehavior]");
7256   if (! [self isFullscreen])
7257     {
7258       NSWindow *win = [self window];
7259       NSWindowCollectionBehavior b = [win collectionBehavior];
7260       if (ns_use_native_fullscreen)
7261         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7262       else
7263         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7265       [win setCollectionBehavior: b];
7266       fs_is_native = ns_use_native_fullscreen;
7267     }
7269 #endif
7271 - (void)toggleFullScreen: (id)sender
7273   NSWindow *w, *fw;
7274   BOOL onFirstScreen;
7275   struct frame *f;
7276   NSRect r, wr;
7277   NSColor *col;
7279   NSTRACE ("[EmacsView toggleFullScreen:]");
7281   if (fs_is_native)
7282     {
7283 #ifdef HAVE_NATIVE_FS
7284       [[self window] toggleFullScreen:sender];
7285 #endif
7286       return;
7287     }
7289   w = [self window];
7290   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7291   f = emacsframe;
7292   wr = [w frame];
7293   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7294                                  (FRAME_DEFAULT_FACE (f)),
7295                                  f);
7297   if (fs_state != FULLSCREEN_BOTH)
7298     {
7299       NSScreen *screen = [w screen];
7301 #if defined (NS_IMPL_COCOA) && \
7302   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7303       /* Hide ghost menu bar on secondary monitor? */
7304       if (! onFirstScreen)
7305         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7306 #endif
7307       /* Hide dock and menubar if we are on the primary screen.  */
7308       if (onFirstScreen)
7309         {
7310 #ifdef NS_IMPL_COCOA
7311           NSApplicationPresentationOptions options
7312             = NSApplicationPresentationAutoHideDock
7313             | NSApplicationPresentationAutoHideMenuBar;
7315           [NSApp setPresentationOptions: options];
7316 #else
7317           [NSMenu setMenuBarVisible:NO];
7318 #endif
7319         }
7321       fw = [[EmacsFSWindow alloc]
7322                        initWithContentRect:[w contentRectForFrameRect:wr]
7323                                  styleMask:NSBorderlessWindowMask
7324                                    backing:NSBackingStoreBuffered
7325                                      defer:YES
7326                                     screen:screen];
7328       [fw setContentView:[w contentView]];
7329       [fw setTitle:[w title]];
7330       [fw setDelegate:self];
7331       [fw setAcceptsMouseMovedEvents: YES];
7332 #if !defined (NS_IMPL_COCOA) || \
7333   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7334       [fw useOptimizedDrawing: YES];
7335 #endif
7336       [fw setBackgroundColor: col];
7337       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7338         [fw setOpaque: NO];
7340       f->border_width = 0;
7341       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
7342       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
7343       FRAME_TOOLBAR_HEIGHT (f) = 0;
7345       nonfs_window = w;
7347       [self windowWillEnterFullScreen];
7348       [fw makeKeyAndOrderFront:NSApp];
7349       [fw makeFirstResponder:self];
7350       [w orderOut:self];
7351       r = [fw frameRectForContentRect:[screen frame]];
7352       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7353       [self windowDidEnterFullScreen];
7354       [fw display];
7355     }
7356   else
7357     {
7358       fw = w;
7359       w = nonfs_window;
7360       nonfs_window = nil;
7362       if (onFirstScreen)
7363         {
7364 #ifdef NS_IMPL_COCOA
7365           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7366 #else
7367           [NSMenu setMenuBarVisible:YES];
7368 #endif
7369         }
7371       [w setContentView:[fw contentView]];
7372       [w setBackgroundColor: col];
7373       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7374         [w setOpaque: NO];
7376       f->border_width = bwidth;
7377       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
7378       if (FRAME_EXTERNAL_TOOL_BAR (f))
7379         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
7381       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7383       [self windowWillExitFullScreen];
7384       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7385       [fw close];
7386       [w makeKeyAndOrderFront:NSApp];
7387       [self windowDidExitFullScreen];
7388       [self updateFrameSize:YES];
7389     }
7392 - (void)handleFS
7394   NSTRACE ("[EmacsView handleFS]");
7396   if (fs_state != emacsframe->want_fullscreen)
7397     {
7398       if (fs_state == FULLSCREEN_BOTH)
7399         {
7400           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7401           [self toggleFullScreen:self];
7402         }
7404       switch (emacsframe->want_fullscreen)
7405         {
7406         case FULLSCREEN_BOTH:
7407           NSTRACE_MSG ("FULLSCREEN_BOTH");
7408           [self toggleFullScreen:self];
7409           break;
7410         case FULLSCREEN_WIDTH:
7411           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7412           next_maximized = FULLSCREEN_WIDTH;
7413           if (fs_state != FULLSCREEN_BOTH)
7414             [[self window] performZoom:self];
7415           break;
7416         case FULLSCREEN_HEIGHT:
7417           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7418           next_maximized = FULLSCREEN_HEIGHT;
7419           if (fs_state != FULLSCREEN_BOTH)
7420             [[self window] performZoom:self];
7421           break;
7422         case FULLSCREEN_MAXIMIZED:
7423           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7424           next_maximized = FULLSCREEN_MAXIMIZED;
7425           if (fs_state != FULLSCREEN_BOTH)
7426             [[self window] performZoom:self];
7427           break;
7428         case FULLSCREEN_NONE:
7429           NSTRACE_MSG ("FULLSCREEN_NONE");
7430           if (fs_state != FULLSCREEN_BOTH)
7431             {
7432               next_maximized = FULLSCREEN_NONE;
7433               [[self window] performZoom:self];
7434             }
7435           break;
7436         }
7438       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7439     }
7443 - (void) setFSValue: (int)value
7445   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7446            NSTRACE_ARG_FSTYPE(value));
7448   Lisp_Object lval = Qnil;
7449   switch (value)
7450     {
7451     case FULLSCREEN_BOTH:
7452       lval = Qfullboth;
7453       break;
7454     case FULLSCREEN_WIDTH:
7455       lval = Qfullwidth;
7456       break;
7457     case FULLSCREEN_HEIGHT:
7458       lval = Qfullheight;
7459       break;
7460     case FULLSCREEN_MAXIMIZED:
7461       lval = Qmaximized;
7462       break;
7463     }
7464   store_frame_param (emacsframe, Qfullscreen, lval);
7465   fs_state = value;
7468 - (void)mouseEntered: (NSEvent *)theEvent
7470   NSTRACE ("[EmacsView mouseEntered:]");
7471   if (emacsframe)
7472     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7473       = EV_TIMESTAMP (theEvent);
7477 - (void)mouseExited: (NSEvent *)theEvent
7479   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7481   NSTRACE ("[EmacsView mouseExited:]");
7483   if (!hlinfo)
7484     return;
7486   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7487     = EV_TIMESTAMP (theEvent);
7489   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7490     {
7491       clear_mouse_face (hlinfo);
7492       hlinfo->mouse_face_mouse_frame = 0;
7493     }
7497 - menuDown: sender
7499   NSTRACE ("[EmacsView menuDown:]");
7500   if (context_menu_value == -1)
7501     context_menu_value = [sender tag];
7502   else
7503     {
7504       NSInteger tag = [sender tag];
7505       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7506                                     emacsframe->menu_bar_vector,
7507                                     (void *)tag);
7508     }
7510   ns_send_appdefined (-1);
7511   return self;
7515 - (EmacsToolbar *)toolbar
7517   return toolbar;
7521 /* this gets called on toolbar button click */
7522 - toolbarClicked: (id)item
7524   NSEvent *theEvent;
7525   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7527   NSTRACE ("[EmacsView toolbarClicked:]");
7529   if (!emacs_event)
7530     return self;
7532   /* send first event (for some reason two needed) */
7533   theEvent = [[self window] currentEvent];
7534   emacs_event->kind = TOOL_BAR_EVENT;
7535   XSETFRAME (emacs_event->arg, emacsframe);
7536   EV_TRAILER (theEvent);
7538   emacs_event->kind = TOOL_BAR_EVENT;
7539 /*   XSETINT (emacs_event->code, 0); */
7540   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7541                            idx + TOOL_BAR_ITEM_KEY);
7542   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7543   EV_TRAILER (theEvent);
7544   return self;
7548 - toggleToolbar: (id)sender
7550   NSTRACE ("[EmacsView toggleToolbar:]");
7552   if (!emacs_event)
7553     return self;
7555   emacs_event->kind = NS_NONKEY_EVENT;
7556   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7557   EV_TRAILER ((id)nil);
7558   return self;
7562 - (void)drawRect: (NSRect)rect
7564   int x = NSMinX (rect), y = NSMinY (rect);
7565   int width = NSWidth (rect), height = NSHeight (rect);
7567   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7568            NSTRACE_ARG_RECT(rect));
7570   if (!emacsframe || !emacsframe->output_data.ns)
7571     return;
7573   ns_clear_frame_area (emacsframe, x, y, width, height);
7574   block_input ();
7575   expose_frame (emacsframe, x, y, width, height);
7576   unblock_input ();
7578   /*
7579     drawRect: may be called (at least in OS X 10.5) for invisible
7580     views as well for some reason.  Thus, do not infer visibility
7581     here.
7583     emacsframe->async_visible = 1;
7584     emacsframe->async_iconified = 0;
7585   */
7589 /* NSDraggingDestination protocol methods.  Actually this is not really a
7590    protocol, but a category of Object.  O well...  */
7592 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7594   NSTRACE ("[EmacsView draggingEntered:]");
7595   return NSDragOperationGeneric;
7599 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7601   return YES;
7605 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7607   id pb;
7608   int x, y;
7609   NSString *type;
7610   NSEvent *theEvent = [[self window] currentEvent];
7611   NSPoint position;
7612   NSDragOperation op = [sender draggingSourceOperationMask];
7613   int modifiers = 0;
7615   NSTRACE ("[EmacsView performDragOperation:]");
7617   if (!emacs_event)
7618     return NO;
7620   position = [self convertPoint: [sender draggingLocation] fromView: nil];
7621   x = lrint (position.x);  y = lrint (position.y);
7623   pb = [sender draggingPasteboard];
7624   type = [pb availableTypeFromArray: ns_drag_types];
7626   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7627       // URL drags contain all operations (0xf), don't allow all to be set.
7628       (op & 0xf) != 0xf)
7629     {
7630       if (op & NSDragOperationLink)
7631         modifiers |= NSControlKeyMask;
7632       if (op & NSDragOperationCopy)
7633         modifiers |= NSAlternateKeyMask;
7634       if (op & NSDragOperationGeneric)
7635         modifiers |= NSCommandKeyMask;
7636     }
7638   modifiers = EV_MODIFIERS2 (modifiers);
7639   if (type == 0)
7640     {
7641       return NO;
7642     }
7643   else if ([type isEqualToString: NSFilenamesPboardType])
7644     {
7645       NSArray *files;
7646       NSEnumerator *fenum;
7647       NSString *file;
7649       if (!(files = [pb propertyListForType: type]))
7650         return NO;
7652       fenum = [files objectEnumerator];
7653       while ( (file = [fenum nextObject]) )
7654         {
7655           emacs_event->kind = DRAG_N_DROP_EVENT;
7656           XSETINT (emacs_event->x, x);
7657           XSETINT (emacs_event->y, y);
7658           ns_input_file = append2 (ns_input_file,
7659                                    build_string ([file UTF8String]));
7660           emacs_event->modifiers = modifiers;
7661           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
7662           EV_TRAILER (theEvent);
7663         }
7664       return YES;
7665     }
7666   else if ([type isEqualToString: NSURLPboardType])
7667     {
7668       NSURL *url = [NSURL URLFromPasteboard: pb];
7669       if (url == nil) return NO;
7671       emacs_event->kind = DRAG_N_DROP_EVENT;
7672       XSETINT (emacs_event->x, x);
7673       XSETINT (emacs_event->y, y);
7674       emacs_event->modifiers = modifiers;
7675       emacs_event->arg =  list2 (Qurl,
7676                                  build_string ([[url absoluteString]
7677                                                  UTF8String]));
7678       EV_TRAILER (theEvent);
7680       if ([url isFileURL] != NO)
7681         {
7682           NSString *file = [url path];
7683           ns_input_file = append2 (ns_input_file,
7684                                    build_string ([file UTF8String]));
7685         }
7686       return YES;
7687     }
7688   else if ([type isEqualToString: NSStringPboardType]
7689            || [type isEqualToString: NSTabularTextPboardType])
7690     {
7691       NSString *data;
7693       if (! (data = [pb stringForType: type]))
7694         return NO;
7696       emacs_event->kind = DRAG_N_DROP_EVENT;
7697       XSETINT (emacs_event->x, x);
7698       XSETINT (emacs_event->y, y);
7699       emacs_event->modifiers = modifiers;
7700       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
7701       EV_TRAILER (theEvent);
7702       return YES;
7703     }
7704   else
7705     {
7706       fprintf (stderr, "Invalid data type in dragging pasteboard");
7707       return NO;
7708     }
7712 - (id) validRequestorForSendType: (NSString *)typeSent
7713                       returnType: (NSString *)typeReturned
7715   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7716   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7717       && typeReturned == nil)
7718     {
7719       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7720         return self;
7721     }
7723   return [super validRequestorForSendType: typeSent
7724                                returnType: typeReturned];
7728 /* The next two methods are part of NSServicesRequests informal protocol,
7729    supposedly called when a services menu item is chosen from this app.
7730    But this should not happen because we override the services menu with our
7731    own entries which call ns-perform-service.
7732    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7733    So let's at least stub them out until further investigation can be done. */
7735 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7737   /* we could call ns_string_from_pasteboard(pboard) here but then it should
7738      be written into the buffer in place of the existing selection..
7739      ordinary service calls go through functions defined in ns-win.el */
7740   return NO;
7743 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7745   NSArray *typesDeclared;
7746   Lisp_Object val;
7748   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7750   /* We only support NSStringPboardType */
7751   if ([types containsObject:NSStringPboardType] == NO) {
7752     return NO;
7753   }
7755   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7756   if (CONSP (val) && SYMBOLP (XCAR (val)))
7757     {
7758       val = XCDR (val);
7759       if (CONSP (val) && NILP (XCDR (val)))
7760         val = XCAR (val);
7761     }
7762   if (! STRINGP (val))
7763     return NO;
7765   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7766   [pb declareTypes:typesDeclared owner:nil];
7767   ns_string_to_pasteboard (pb, val);
7768   return YES;
7772 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7773    (gives a miniaturized version of the window); currently we use the latter for
7774    frames whose active buffer doesn't correspond to any file
7775    (e.g., '*scratch*') */
7776 - setMiniwindowImage: (BOOL) setMini
7778   id image = [[self window] miniwindowImage];
7779   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7781   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7782      about "AppleDockIconEnabled" notwithstanding, however the set message
7783      below has its effect nonetheless. */
7784   if (image != emacsframe->output_data.ns->miniimage)
7785     {
7786       if (image && [image isKindOfClass: [EmacsImage class]])
7787         [image release];
7788       [[self window] setMiniwindowImage:
7789                        setMini ? emacsframe->output_data.ns->miniimage : nil];
7790     }
7792   return self;
7796 - (void) setRows: (int) r andColumns: (int) c
7798   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7799   rows = r;
7800   cols = c;
7803 - (int) fullscreenState
7805   return fs_state;
7808 @end  /* EmacsView */
7812 /* ==========================================================================
7814     EmacsWindow implementation
7816    ========================================================================== */
7818 @implementation EmacsWindow
7820 #ifdef NS_IMPL_COCOA
7821 - (id)accessibilityAttributeValue:(NSString *)attribute
7823   Lisp_Object str = Qnil;
7824   struct frame *f = SELECTED_FRAME ();
7825   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7827   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7829   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7830     return NSAccessibilityTextFieldRole;
7832   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7833       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7834     {
7835       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7836     }
7837   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7838     {
7839       if (! NILP (BVAR (curbuf, mark_active)))
7840           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7842       if (NILP (str))
7843         {
7844           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7845           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7846           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7848           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7849             str = make_uninit_multibyte_string (range, byte_range);
7850           else
7851             str = make_uninit_string (range);
7852           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7853              Is this a problem?  */
7854           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7855         }
7856     }
7859   if (! NILP (str))
7860     {
7861       if (CONSP (str) && SYMBOLP (XCAR (str)))
7862         {
7863           str = XCDR (str);
7864           if (CONSP (str) && NILP (XCDR (str)))
7865             str = XCAR (str);
7866         }
7867       if (STRINGP (str))
7868         {
7869           const char *utfStr = SSDATA (str);
7870           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7871           return nsStr;
7872         }
7873     }
7875   return [super accessibilityAttributeValue:attribute];
7877 #endif /* NS_IMPL_COCOA */
7879 /* Constrain size and placement of a frame.
7881    By returning the original "frameRect", the frame is not
7882    constrained. This can lead to unwanted situations where, for
7883    example, the menu bar covers the frame.
7885    The default implementation (accessed using "super") constrains the
7886    frame to the visible area of SCREEN, minus the menu bar (if
7887    present) and the Dock.  Note that default implementation also calls
7888    windowWillResize, with the frame it thinks should have.  (This can
7889    make the frame exit maximized mode.)
7891    Note that this should work in situations where multiple monitors
7892    are present.  Common configurations are side-by-side monitors and a
7893    monitor on top of another (e.g. when a laptop is placed under a
7894    large screen). */
7895 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7897   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
7898              NSTRACE_ARG_RECT (frameRect));
7900 #ifdef NS_IMPL_COCOA
7901 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7902   // If separate spaces is on, it is like each screen is independent.  There is
7903   // no spanning of frames across screens.
7904   if ([NSScreen screensHaveSeparateSpaces])
7905     {
7906       NSTRACE_MSG ("Screens have separate spaces");
7907       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
7908       NSTRACE_RETURN_RECT (frameRect);
7909       return frameRect;
7910     }
7911 #endif
7912 #endif
7914   return constrain_frame_rect(frameRect,
7915                               [(EmacsView *)[self delegate] isFullscreen]);
7919 - (void)performZoom:(id)sender
7921   NSTRACE ("[EmacsWindow performZoom:]");
7923   return [super performZoom:sender];
7926 - (void)zoom:(id)sender
7928   NSTRACE ("[EmacsWindow zoom:]");
7930   ns_update_auto_hide_menu_bar();
7932   // Below are three zoom implementations.  In the final commit, the
7933   // idea is that the last should be included.
7935 #if 0
7936   // Native zoom done using the standard zoom animation.  Size of the
7937   // resulting frame reduced to accommodate the Dock and, if present,
7938   // the menu-bar.
7939   [super zoom:sender];
7941 #elif 0
7942   // Native zoom done using the standard zoom animation, plus an
7943   // explicit resize to cover the full screen, except the menu-bar and
7944   // dock, if present.
7945   [super zoom:sender];
7947   // After the native zoom, resize the resulting frame to fill the
7948   // entire screen, except the menu-bar.
7949   //
7950   // This works for all practical purposes.  (The only minor oddity is
7951   // when transiting from full-height frame to a maximized, the
7952   // animation reduces the height of the frame slightly (to the 4
7953   // pixels needed to accommodate the Doc) before it snaps back into
7954   // full height.  The user would need a very trained eye to spot
7955   // this.)
7956   NSScreen * screen = [self screen];
7957   if (screen != nil)
7958     {
7959       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
7961       NSTRACE_FSTYPE ("fullscreenState", fs_state);
7963       NSRect sr = [screen frame];
7964       struct EmacsMargins margins
7965         = ns_screen_margins_ignoring_hidden_dock(screen);
7967       NSRect wr = [self frame];
7968       NSTRACE_RECT ("Rect after zoom", wr);
7970       NSRect newWr = wr;
7972       if (fs_state == FULLSCREEN_MAXIMIZED
7973           || fs_state == FULLSCREEN_HEIGHT)
7974         {
7975           newWr.origin.y = sr.origin.y + margins.bottom;
7976           newWr.size.height = sr.size.height - margins.top - margins.bottom;
7977         }
7979       if (fs_state == FULLSCREEN_MAXIMIZED
7980           || fs_state == FULLSCREEN_WIDTH)
7981         {
7982           newWr.origin.x = sr.origin.x + margins.left;
7983           newWr.size.width = sr.size.width - margins.right - margins.left;
7984         }
7986       if (newWr.size.width     != wr.size.width
7987           || newWr.size.height != wr.size.height
7988           || newWr.origin.x    != wr.origin.x
7989           || newWr.origin.y    != wr.origin.y)
7990         {
7991           NSTRACE_MSG ("New frame different");
7992           [self setFrame: newWr display: NO];
7993         }
7994     }
7995 #else
7996   // Non-native zoom which is done instantaneously.  The resulting
7997   // frame covers the entire screen, except the menu-bar and dock, if
7998   // present.
7999   NSScreen * screen = [self screen];
8000   if (screen != nil)
8001     {
8002       NSRect sr = [screen frame];
8003       struct EmacsMargins margins
8004         = ns_screen_margins_ignoring_hidden_dock(screen);
8006       sr.size.height -= (margins.top + margins.bottom);
8007       sr.size.width  -= (margins.left + margins.right);
8008       sr.origin.x += margins.left;
8009       sr.origin.y += margins.bottom;
8011       sr = [[self delegate] windowWillUseStandardFrame:self
8012                                           defaultFrame:sr];
8013       [self setFrame: sr display: NO];
8014     }
8015 #endif
8018 - (void)setFrame:(NSRect)windowFrame
8019          display:(BOOL)displayViews
8021   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8022            NSTRACE_ARG_RECT (windowFrame), displayViews);
8024   [super setFrame:windowFrame display:displayViews];
8027 - (void)setFrame:(NSRect)windowFrame
8028          display:(BOOL)displayViews
8029          animate:(BOOL)performAnimation
8031   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8032            " display:%d performAnimation:%d]",
8033            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8035   [super setFrame:windowFrame display:displayViews animate:performAnimation];
8038 - (void)setFrameTopLeftPoint:(NSPoint)point
8040   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8041            NSTRACE_ARG_POINT (point));
8043   [super setFrameTopLeftPoint:point];
8045 @end /* EmacsWindow */
8048 @implementation EmacsFSWindow
8050 - (BOOL)canBecomeKeyWindow
8052   return YES;
8055 - (BOOL)canBecomeMainWindow
8057   return YES;
8060 @end
8062 /* ==========================================================================
8064     EmacsScroller implementation
8066    ========================================================================== */
8069 @implementation EmacsScroller
8071 /* for repeat button push */
8072 #define SCROLL_BAR_FIRST_DELAY 0.5
8073 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8075 + (CGFloat) scrollerWidth
8077   /* TODO: if we want to allow variable widths, this is the place to do it,
8078            however neither GNUstep nor Cocoa support it very well */
8079   CGFloat r;
8080 #if !defined (NS_IMPL_COCOA) || \
8081   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
8082   r = [NSScroller scrollerWidth];
8083 #else
8084   r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
8085                                 scrollerStyle: NSScrollerStyleLegacy];
8086 #endif
8087   return r;
8090 - initFrame: (NSRect )r window: (Lisp_Object)nwin
8092   NSTRACE ("[EmacsScroller initFrame: window:]");
8094   if (r.size.width > r.size.height)
8095       horizontal = YES;
8096   else
8097       horizontal = NO;
8099   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8100   [self setContinuous: YES];
8101   [self setEnabled: YES];
8103   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8104      locked against the top and bottom edges, and right edge on OS X, where
8105      scrollers are on right. */
8106 #ifdef NS_IMPL_GNUSTEP
8107   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8108 #else
8109   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8110 #endif
8112   window = XWINDOW (nwin);
8113   condemned = NO;
8114   if (horizontal)
8115     pixel_length = NSWidth (r);
8116   else
8117     pixel_length = NSHeight (r);
8118   if (pixel_length == 0) pixel_length = 1;
8119   min_portion = 20 / pixel_length;
8121   frame = XFRAME (window->frame);
8122   if (FRAME_LIVE_P (frame))
8123     {
8124       int i;
8125       EmacsView *view = FRAME_NS_VIEW (frame);
8126       NSView *sview = [[view window] contentView];
8127       NSArray *subs = [sview subviews];
8129       /* disable optimization stopping redraw of other scrollbars */
8130       view->scrollbarsNeedingUpdate = 0;
8131       for (i =[subs count]-1; i >= 0; i--)
8132         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8133           view->scrollbarsNeedingUpdate++;
8134       [sview addSubview: self];
8135     }
8137 /*  [self setFrame: r]; */
8139   return self;
8143 - (void)setFrame: (NSRect)newRect
8145   NSTRACE ("[EmacsScroller setFrame:]");
8147 /*  block_input (); */
8148   if (horizontal)
8149     pixel_length = NSWidth (newRect);
8150   else
8151     pixel_length = NSHeight (newRect);
8152   if (pixel_length == 0) pixel_length = 1;
8153   min_portion = 20 / pixel_length;
8154   [super setFrame: newRect];
8155 /*  unblock_input (); */
8159 - (void)dealloc
8161   NSTRACE ("[EmacsScroller dealloc]");
8162   if (window)
8163     {
8164       if (horizontal)
8165         wset_horizontal_scroll_bar (window, Qnil);
8166       else
8167         wset_vertical_scroll_bar (window, Qnil);
8168     }
8169   window = 0;
8170   [super dealloc];
8174 - condemn
8176   NSTRACE ("[EmacsScroller condemn]");
8177   condemned =YES;
8178   return self;
8182 - reprieve
8184   NSTRACE ("[EmacsScroller reprieve]");
8185   condemned =NO;
8186   return self;
8190 -(bool)judge
8192   NSTRACE ("[EmacsScroller judge]");
8193   bool ret = condemned;
8194   if (condemned)
8195     {
8196       EmacsView *view;
8197       block_input ();
8198       /* ensure other scrollbar updates after deletion */
8199       view = (EmacsView *)FRAME_NS_VIEW (frame);
8200       if (view != nil)
8201         view->scrollbarsNeedingUpdate++;
8202       if (window)
8203         {
8204           if (horizontal)
8205             wset_horizontal_scroll_bar (window, Qnil);
8206           else
8207             wset_vertical_scroll_bar (window, Qnil);
8208         }
8209       window = 0;
8210       [self removeFromSuperview];
8211       [self release];
8212       unblock_input ();
8213     }
8214   return ret;
8218 - (void)resetCursorRects
8220   NSRect visible = [self visibleRect];
8221   NSTRACE ("[EmacsScroller resetCursorRects]");
8223   if (!NSIsEmptyRect (visible))
8224     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8225   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8229 - (int) checkSamePosition: (int) position portion: (int) portion
8230                     whole: (int) whole
8232   return em_position ==position && em_portion ==portion && em_whole ==whole
8233     && portion != whole; /* needed for resize empty buf */
8237 - setPosition: (int)position portion: (int)portion whole: (int)whole
8239   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8241   em_position = position;
8242   em_portion = portion;
8243   em_whole = whole;
8245   if (portion >= whole)
8246     {
8247 #ifdef NS_IMPL_COCOA
8248       [self setKnobProportion: 1.0];
8249       [self setDoubleValue: 1.0];
8250 #else
8251       [self setFloatValue: 0.0 knobProportion: 1.0];
8252 #endif
8253     }
8254   else
8255     {
8256       float pos;
8257       CGFloat por;
8258       portion = max ((float)whole*min_portion/pixel_length, portion);
8259       pos = (float)position / (whole - portion);
8260       por = (CGFloat)portion/whole;
8261 #ifdef NS_IMPL_COCOA
8262       [self setKnobProportion: por];
8263       [self setDoubleValue: pos];
8264 #else
8265       [self setFloatValue: pos knobProportion: por];
8266 #endif
8267     }
8269   return self;
8272 /* set up emacs_event */
8273 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8275   Lisp_Object win;
8277   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8279   if (!emacs_event)
8280     return;
8282   emacs_event->part = last_hit_part;
8283   emacs_event->code = 0;
8284   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8285   XSETWINDOW (win, window);
8286   emacs_event->frame_or_window = win;
8287   emacs_event->timestamp = EV_TIMESTAMP (e);
8288   emacs_event->arg = Qnil;
8290   if (horizontal)
8291     {
8292       emacs_event->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT;
8293       XSETINT (emacs_event->x, em_whole * loc / pixel_length);
8294       XSETINT (emacs_event->y, em_whole);
8295     }
8296   else
8297     {
8298       emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8299       XSETINT (emacs_event->x, loc);
8300       XSETINT (emacs_event->y, pixel_length-20);
8301     }
8303   if (q_event_ptr)
8304     {
8305       n_emacs_events_pending++;
8306       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8307     }
8308   else
8309     hold_event (emacs_event);
8310   EVENT_INIT (*emacs_event);
8311   ns_send_appdefined (-1);
8315 /* called manually thru timer to implement repeated button action w/hold-down */
8316 - repeatScroll: (NSTimer *)scrollEntry
8318   NSEvent *e = [[self window] currentEvent];
8319   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8320   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8322   NSTRACE ("[EmacsScroller repeatScroll:]");
8324   /* clear timer if need be */
8325   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8326     {
8327         [scroll_repeat_entry invalidate];
8328         [scroll_repeat_entry release];
8329         scroll_repeat_entry = nil;
8331         if (inKnob)
8332           return self;
8334         scroll_repeat_entry
8335           = [[NSTimer scheduledTimerWithTimeInterval:
8336                         SCROLL_BAR_CONTINUOUS_DELAY
8337                                             target: self
8338                                           selector: @selector (repeatScroll:)
8339                                           userInfo: 0
8340                                            repeats: YES]
8341               retain];
8342     }
8344   [self sendScrollEventAtLoc: 0 fromEvent: e];
8345   return self;
8349 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8350    mouseDragged events without going into a modal loop. */
8351 - (void)mouseDown: (NSEvent *)e
8353   NSRect sr, kr;
8354   /* hitPart is only updated AFTER event is passed on */
8355   NSScrollerPart part = [self testPart: [e locationInWindow]];
8356   CGFloat inc = 0.0, loc, kloc, pos;
8357   int edge = 0;
8359   NSTRACE ("[EmacsScroller mouseDown:]");
8361   switch (part)
8362     {
8363     case NSScrollerDecrementPage:
8364       last_hit_part = horizontal ? scroll_bar_before_handle : scroll_bar_above_handle; break;
8365     case NSScrollerIncrementPage:
8366       last_hit_part = horizontal ? scroll_bar_after_handle : scroll_bar_below_handle; break;
8367     case NSScrollerDecrementLine:
8368       last_hit_part = horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow; break;
8369     case NSScrollerIncrementLine:
8370       last_hit_part = horizontal ? scroll_bar_right_arrow : scroll_bar_down_arrow; break;
8371     case NSScrollerKnob:
8372       last_hit_part = horizontal ? scroll_bar_horizontal_handle : scroll_bar_handle; break;
8373     case NSScrollerKnobSlot:  /* GNUstep-only */
8374       last_hit_part = scroll_bar_move_ratio; break;
8375     default:  /* NSScrollerNoPart? */
8376       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
8377                (long) part);
8378       return;
8379     }
8381   if (part == NSScrollerKnob || part == NSScrollerKnobSlot)
8382     {
8383       /* handle, or on GNUstep possibly slot */
8384       NSEvent *fake_event;
8385       int length;
8387       /* compute float loc in slot and mouse offset on knob */
8388       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8389                       toView: nil];
8390       if (horizontal)
8391         {
8392           length = NSWidth (sr);
8393           loc = ([e locationInWindow].x - NSMinX (sr));
8394         }
8395       else
8396         {
8397           length = NSHeight (sr);
8398           loc = length - ([e locationInWindow].y - NSMinY (sr));
8399         }
8401       if (loc <= 0.0)
8402         {
8403           loc = 0.0;
8404           edge = -1;
8405         }
8406       else if (loc >= length)
8407         {
8408           loc = length;
8409           edge = 1;
8410         }
8412       if (edge)
8413         kloc = 0.5 * edge;
8414       else
8415         {
8416           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8417                           toView: nil];
8418           if (horizontal)
8419             kloc = ([e locationInWindow].x - NSMinX (kr));
8420           else
8421             kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8422         }
8423       last_mouse_offset = kloc;
8425       if (part != NSScrollerKnob)
8426         /* this is a slot click on GNUstep: go straight there */
8427         pos = loc;
8429       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8430       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
8431                                       location: [e locationInWindow]
8432                                  modifierFlags: [e modifierFlags]
8433                                      timestamp: [e timestamp]
8434                                   windowNumber: [e windowNumber]
8435                                        context: [e context]
8436                                    eventNumber: [e eventNumber]
8437                                     clickCount: [e clickCount]
8438                                       pressure: [e pressure]];
8439       [super mouseUp: fake_event];
8440     }
8441   else
8442     {
8443       pos = 0;      /* ignored */
8445       /* set a timer to repeat, as we can't let superclass do this modally */
8446       scroll_repeat_entry
8447         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8448                                             target: self
8449                                           selector: @selector (repeatScroll:)
8450                                           userInfo: 0
8451                                            repeats: YES]
8452             retain];
8453     }
8455   if (part != NSScrollerKnob)
8456     [self sendScrollEventAtLoc: pos fromEvent: e];
8460 /* Called as we manually track scroller drags, rather than superclass. */
8461 - (void)mouseDragged: (NSEvent *)e
8463     NSRect sr;
8464     double loc, pos;
8465     int length;
8467     NSTRACE ("[EmacsScroller mouseDragged:]");
8469       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8470                       toView: nil];
8472       if (horizontal)
8473         {
8474           length = NSWidth (sr);
8475           loc = ([e locationInWindow].x - NSMinX (sr));
8476         }
8477       else
8478         {
8479           length = NSHeight (sr);
8480           loc = length - ([e locationInWindow].y - NSMinY (sr));
8481         }
8483       if (loc <= 0.0)
8484         {
8485           loc = 0.0;
8486         }
8487       else if (loc >= length + last_mouse_offset)
8488         {
8489           loc = length + last_mouse_offset;
8490         }
8492       pos = (loc - last_mouse_offset);
8493       [self sendScrollEventAtLoc: pos fromEvent: e];
8497 - (void)mouseUp: (NSEvent *)e
8499   NSTRACE ("[EmacsScroller mouseUp:]");
8501   if (scroll_repeat_entry)
8502     {
8503       [scroll_repeat_entry invalidate];
8504       [scroll_repeat_entry release];
8505       scroll_repeat_entry = nil;
8506     }
8507   last_hit_part = scroll_bar_above_handle;
8511 /* treat scrollwheel events in the bar as though they were in the main window */
8512 - (void) scrollWheel: (NSEvent *)theEvent
8514   NSTRACE ("[EmacsScroller scrollWheel:]");
8516   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8517   [view mouseDown: theEvent];
8520 @end  /* EmacsScroller */
8523 #ifdef NS_IMPL_GNUSTEP
8524 /* Dummy class to get rid of startup warnings.  */
8525 @implementation EmacsDocument
8527 @end
8528 #endif
8531 /* ==========================================================================
8533    Font-related functions; these used to be in nsfaces.m
8535    ========================================================================== */
8538 Lisp_Object
8539 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8541   struct font *font = XFONT_OBJECT (font_object);
8542   EmacsView *view = FRAME_NS_VIEW (f);
8543   int font_ascent, font_descent;
8545   if (fontset < 0)
8546     fontset = fontset_from_font (font_object);
8547   FRAME_FONTSET (f) = fontset;
8549   if (FRAME_FONT (f) == font)
8550     /* This font is already set in frame F.  There's nothing more to
8551        do.  */
8552     return font_object;
8554   FRAME_FONT (f) = font;
8556   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8557   FRAME_COLUMN_WIDTH (f) = font->average_width;
8558   get_font_ascent_descent (font, &font_ascent, &font_descent);
8559   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8561   /* Compute the scroll bar width in character columns.  */
8562   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8563     {
8564       int wid = FRAME_COLUMN_WIDTH (f);
8565       FRAME_CONFIG_SCROLL_BAR_COLS (f)
8566         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8567     }
8568   else
8569     {
8570       int wid = FRAME_COLUMN_WIDTH (f);
8571       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8572     }
8574   /* Compute the scroll bar height in character lines.  */
8575   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8576     {
8577       int height = FRAME_LINE_HEIGHT (f);
8578       FRAME_CONFIG_SCROLL_BAR_LINES (f)
8579         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8580     }
8581   else
8582     {
8583       int height = FRAME_LINE_HEIGHT (f);
8584       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8585     }
8587   /* Now make the frame display the given font.  */
8588   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8589     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8590                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8591                        false, Qfont);
8593   return font_object;
8597 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8598 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8599          in 1.43. */
8601 const char *
8602 ns_xlfd_to_fontname (const char *xlfd)
8603 /* --------------------------------------------------------------------------
8604     Convert an X font name (XLFD) to an NS font name.
8605     Only family is used.
8606     The string returned is temporarily allocated.
8607    -------------------------------------------------------------------------- */
8609   char *name = xmalloc (180);
8610   int i, len;
8611   const char *ret;
8613   if (!strncmp (xlfd, "--", 2))
8614     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8615   else
8616     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8618   /* stopgap for malformed XLFD input */
8619   if (strlen (name) == 0)
8620     strcpy (name, "Monaco");
8622   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8623      also uppercase after '-' or ' ' */
8624   name[0] = c_toupper (name[0]);
8625   for (len =strlen (name), i =0; i<len; i++)
8626     {
8627       if (name[i] == '$')
8628         {
8629           name[i] = '-';
8630           if (i+1<len)
8631             name[i+1] = c_toupper (name[i+1]);
8632         }
8633       else if (name[i] == '_')
8634         {
8635           name[i] = ' ';
8636           if (i+1<len)
8637             name[i+1] = c_toupper (name[i+1]);
8638         }
8639     }
8640 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
8641   ret = [[NSString stringWithUTF8String: name] UTF8String];
8642   xfree (name);
8643   return ret;
8647 void
8648 syms_of_nsterm (void)
8650   NSTRACE ("syms_of_nsterm");
8652   ns_antialias_threshold = 10.0;
8654   /* from 23+ we need to tell emacs what modifiers there are.. */
8655   DEFSYM (Qmodifier_value, "modifier-value");
8656   DEFSYM (Qalt, "alt");
8657   DEFSYM (Qhyper, "hyper");
8658   DEFSYM (Qmeta, "meta");
8659   DEFSYM (Qsuper, "super");
8660   DEFSYM (Qcontrol, "control");
8661   DEFSYM (QUTF8_STRING, "UTF8_STRING");
8663   DEFSYM (Qfile, "file");
8664   DEFSYM (Qurl, "url");
8666   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8667   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8668   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8669   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8670   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8672   DEFVAR_LISP ("ns-input-file", ns_input_file,
8673               "The file specified in the last NS event.");
8674   ns_input_file =Qnil;
8676   DEFVAR_LISP ("ns-working-text", ns_working_text,
8677               "String for visualizing working composition sequence.");
8678   ns_working_text =Qnil;
8680   DEFVAR_LISP ("ns-input-font", ns_input_font,
8681               "The font specified in the last NS event.");
8682   ns_input_font =Qnil;
8684   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8685               "The fontsize specified in the last NS event.");
8686   ns_input_fontsize =Qnil;
8688   DEFVAR_LISP ("ns-input-line", ns_input_line,
8689                "The line specified in the last NS event.");
8690   ns_input_line =Qnil;
8692   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8693                "The service name specified in the last NS event.");
8694   ns_input_spi_name =Qnil;
8696   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8697                "The service argument specified in the last NS event.");
8698   ns_input_spi_arg =Qnil;
8700   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8701                "This variable describes the behavior of the alternate or option key.\n\
8702 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8703 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8704 at all, allowing it to be used at a lower level for accented character entry.");
8705   ns_alternate_modifier = Qmeta;
8707   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8708                "This variable describes the behavior of the right alternate or option key.\n\
8709 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8710 Set to left means be the same key as `ns-alternate-modifier'.\n\
8711 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8712 at all, allowing it to be used at a lower level for accented character entry.");
8713   ns_right_alternate_modifier = Qleft;
8715   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8716                "This variable describes the behavior of the command key.\n\
8717 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8718   ns_command_modifier = Qsuper;
8720   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8721                "This variable describes the behavior of the right command key.\n\
8722 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8723 Set to left means be the same key as `ns-command-modifier'.\n\
8724 Set to none means that the command / option key is not interpreted by Emacs\n\
8725 at all, allowing it to be used at a lower level for accented character entry.");
8726   ns_right_command_modifier = Qleft;
8728   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8729                "This variable describes the behavior of the control key.\n\
8730 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8731   ns_control_modifier = Qcontrol;
8733   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8734                "This variable describes the behavior of the right control key.\n\
8735 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8736 Set to left means be the same key as `ns-control-modifier'.\n\
8737 Set to none means that the control / option key is not interpreted by Emacs\n\
8738 at all, allowing it to be used at a lower level for accented character entry.");
8739   ns_right_control_modifier = Qleft;
8741   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8742                "This variable describes the behavior of the function key (on laptops).\n\
8743 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8744 Set to none means that the function key is not interpreted by Emacs at all,\n\
8745 allowing it to be used at a lower level for accented character entry.");
8746   ns_function_modifier = Qnone;
8748   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8749                "Non-nil (the default) means to render text antialiased.");
8750   ns_antialias_text = Qt;
8752   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8753                "Whether to confirm application quit using dialog.");
8754   ns_confirm_quit = Qnil;
8756   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8757                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8758 Only works on OSX 10.6 or later.  */);
8759   ns_auto_hide_menu_bar = Qnil;
8761   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8762      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
8763 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
8764 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
8765 Default is t for OSX >= 10.7, nil otherwise.  */);
8766 #ifdef HAVE_NATIVE_FS
8767   ns_use_native_fullscreen = YES;
8768 #else
8769   ns_use_native_fullscreen = NO;
8770 #endif
8771   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8773   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8774      doc: /*Non-nil means use animation on non-native fullscreen.
8775 For native fullscreen, this does nothing.
8776 Default is nil.  */);
8777   ns_use_fullscreen_animation = NO;
8779   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8780      doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
8781 Note that this does not apply to images.
8782 This variable is ignored on OSX < 10.7 and GNUstep.  */);
8783   ns_use_srgb_colorspace = YES;
8785   /* TODO: move to common code */
8786   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8787                doc: /* Which toolkit scroll bars Emacs uses, if any.
8788 A value of nil means Emacs doesn't use toolkit scroll bars.
8789 With the X Window system, the value is a symbol describing the
8790 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
8791 With MS Windows or Nextstep, the value is t.  */);
8792   Vx_toolkit_scroll_bars = Qt;
8794   DEFVAR_BOOL ("x-use-underline-position-properties",
8795                x_use_underline_position_properties,
8796      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8797 A value of nil means ignore them.  If you encounter fonts with bogus
8798 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8799 to 4.1, set this to nil. */);
8800   x_use_underline_position_properties = 0;
8802   DEFVAR_BOOL ("x-underline-at-descent-line",
8803                x_underline_at_descent_line,
8804      doc: /* Non-nil means to draw the underline at the same place as the descent line.
8805 A value of nil means to draw the underline according to the value of the
8806 variable `x-use-underline-position-properties', which is usually at the
8807 baseline level.  The default value is nil.  */);
8808   x_underline_at_descent_line = 0;
8810   /* Tell Emacs about this window system.  */
8811   Fprovide (Qns, Qnil);
8813   DEFSYM (Qcocoa, "cocoa");
8814   DEFSYM (Qgnustep, "gnustep");
8816 #ifdef NS_IMPL_COCOA
8817   Fprovide (Qcocoa, Qnil);
8818   syms_of_macfont ();
8819 #else
8820   Fprovide (Qgnustep, Qnil);
8821   syms_of_nsfont ();
8822 #endif