* lisp/erc/erc-backend.el: Use lexical-binding. Silence byte-compiler
[emacs.git] / src / nsterm.m
blob4048ac465468e345e4fb55bb4e29b8371de16de2
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       /* Set LANG to locale, but not if LANG is already set. */
600       setenv("LANG", [[locale localeIdentifier] UTF8String], 0);
601     }
602   @catch (NSException *e)
603     {
604       NSLog (@"Locale detection failed: %@: %@", [e name], [e reason]);
605     }
609 void
610 ns_release_object (void *obj)
611 /* --------------------------------------------------------------------------
612     Release an object (callable from C)
613    -------------------------------------------------------------------------- */
615     [(id)obj release];
619 void
620 ns_retain_object (void *obj)
621 /* --------------------------------------------------------------------------
622     Retain an object (callable from C)
623    -------------------------------------------------------------------------- */
625     [(id)obj retain];
629 void *
630 ns_alloc_autorelease_pool (void)
631 /* --------------------------------------------------------------------------
632      Allocate a pool for temporary objects (callable from C)
633    -------------------------------------------------------------------------- */
635   return [[NSAutoreleasePool alloc] init];
639 void
640 ns_release_autorelease_pool (void *pool)
641 /* --------------------------------------------------------------------------
642      Free a pool and temporary objects it refers to (callable from C)
643    -------------------------------------------------------------------------- */
645   ns_release_object (pool);
649 static BOOL
650 ns_menu_bar_should_be_hidden (void)
651 /* True, if the menu bar should be hidden.  */
653   return !NILP (ns_auto_hide_menu_bar)
654     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
658 struct EmacsMargins
660   CGFloat top;
661   CGFloat bottom;
662   CGFloat left;
663   CGFloat right;
667 static struct EmacsMargins
668 ns_screen_margins (NSScreen *screen)
669 /* The parts of SCREEN used by the operating system.  */
671   NSTRACE ("ns_screen_margins");
673   struct EmacsMargins margins;
675   NSRect screenFrame = [screen frame];
676   NSRect screenVisibleFrame = [screen visibleFrame];
678   /* Sometimes, visibleFrame isn't up-to-date with respect to a hidden
679      menu bar, check this explicitly.  */
680   if (ns_menu_bar_should_be_hidden())
681     {
682       margins.top = 0;
683     }
684   else
685     {
686       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
687       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
688                                  + screenVisibleFrame.size.height);
690       margins.top = frameTop - visibleFrameTop;
691     }
693   {
694     CGFloat frameRight = screenFrame.origin.x + screenFrame.size.width;
695     CGFloat visibleFrameRight = (screenVisibleFrame.origin.x
696                                  + screenVisibleFrame.size.width);
697     margins.right = frameRight - visibleFrameRight;
698   }
700   margins.bottom = screenVisibleFrame.origin.y - screenFrame.origin.y;
701   margins.left   = screenVisibleFrame.origin.x - screenFrame.origin.x;
703   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
704                margins.left,
705                margins.right,
706                margins.top,
707                margins.bottom);
709   return margins;
713 /* A screen margin between 1 and DOCK_IGNORE_LIMIT (inclusive) is
714    assumed to contain a hidden dock.  OS X currently use 4 pixels for
715    this, however, to be future compatible, a larger value is used.  */
716 #define DOCK_IGNORE_LIMIT 6
718 static struct EmacsMargins
719 ns_screen_margins_ignoring_hidden_dock (NSScreen *screen)
720 /* The parts of SCREEN used by the operating system, excluding the parts
721 reserved for an hidden dock.  */
723   NSTRACE ("ns_screen_margins_ignoring_hidden_dock");
725   struct EmacsMargins margins = ns_screen_margins(screen);
727   /* OS X (currently) reserved 4 pixels along the edge where a hidden
728      dock is located.  Unfortunately, it's not possible to find the
729      location and information about if the dock is hidden.  Instead,
730      it is assumed that if the margin of an edge is less than
731      DOCK_IGNORE_LIMIT, it contains a hidden dock.  */
732   if (margins.left <= DOCK_IGNORE_LIMIT)
733     {
734       margins.left = 0;
735     }
736   if (margins.right <= DOCK_IGNORE_LIMIT)
737     {
738       margins.right = 0;
739     }
740   if (margins.top <= DOCK_IGNORE_LIMIT)
741     {
742       margins.top = 0;
743     }
744   /* Note: This doesn't occur in current versions of OS X, but
745      included for completeness and future compatibility.  */
746   if (margins.bottom <= DOCK_IGNORE_LIMIT)
747     {
748       margins.bottom = 0;
749     }
751   NSTRACE_MSG ("left:%g right:%g top:%g bottom:%g",
752                margins.left,
753                margins.right,
754                margins.top,
755                margins.bottom);
757   return margins;
761 static CGFloat
762 ns_menu_bar_height (NSScreen *screen)
763 /* The height of the menu bar, if visible.
765    Note: Don't use this when fullscreen is enabled -- the screen
766    sometimes includes, sometimes excludes the menu bar area.  */
768   struct EmacsMargins margins = ns_screen_margins(screen);
770   CGFloat res = margins.top;
772   NSTRACE ("ns_menu_bar_height " NSTRACE_FMT_RETURN " %.0f", res);
774   return res;
778 /* ==========================================================================
780     Focus (clipping) and screen update
782    ========================================================================== */
785 // Window constraining
786 // -------------------
788 // To ensure that the windows are not placed under the menu bar, they
789 // are typically moved by the call-back constrainFrameRect. However,
790 // by overriding it, it's possible to inhibit this, leaving the window
791 // in it's original position.
793 // It's possible to hide the menu bar. However, technically, it's only
794 // possible to hide it when the application is active. To ensure that
795 // this work properly, the menu bar and window constraining are
796 // deferred until the application becomes active.
798 // Even though it's not possible to manually move a window above the
799 // top of the screen, it is allowed if it's done programmatically,
800 // when the menu is hidden. This allows the editable area to cover the
801 // full screen height.
803 // Test cases
804 // ----------
806 // Use the following extra files:
808 //    init.el:
809 //       ;; Hide menu and place frame slightly above the top of the screen.
810 //       (setq ns-auto-hide-menu-bar t)
811 //       (set-frame-position (selected-frame) 0 -20)
813 // Test 1:
815 //    emacs -Q -l init.el
817 //    Result: No menu bar, and the title bar should be above the screen.
819 // Test 2:
821 //    emacs -Q
823 //    Result: Menu bar visible, frame placed immediately below the menu.
826 static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
828   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
829              NSTRACE_ARG_RECT (frameRect));
831   // --------------------
832   // Collect information about the screen the frame is covering.
833   //
835   NSArray *screens = [NSScreen screens];
836   NSUInteger nr_screens = [screens count];
838   int i;
840   // The height of the menu bar, if present in any screen the frame is
841   // displayed in.
842   int menu_bar_height = 0;
844   // A rectangle covering all the screen the frame is displayed in.
845   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
846   for (i = 0; i < nr_screens; ++i )
847     {
848       NSScreen *s = [screens objectAtIndex: i];
849       NSRect scrRect = [s frame];
851       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
852                    i, NSTRACE_ARG_RECT (scrRect));
854       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
855         {
856           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
858           if (!isFullscreen)
859             {
860               CGFloat screen_menu_bar_height = ns_menu_bar_height (s);
861               menu_bar_height = max(menu_bar_height, screen_menu_bar_height);
862             }
863         }
864     }
866   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
868   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
870   if (multiscreenRect.size.width == 0
871       || multiscreenRect.size.height == 0)
872     {
873       // Failed to find any monitor, give up.
874       NSTRACE_MSG ("multiscreenRect empty");
875       NSTRACE_RETURN_RECT (frameRect);
876       return frameRect;
877     }
880   // --------------------
881   // Find a suitable placement.
882   //
884   if (ns_menu_bar_should_be_hidden())
885     {
886       // When the menu bar is hidden, the user may place part of the
887       // frame above the top of the screen, for example to hide the
888       // title bar.
889       //
890       // Hence, keep the original position.
891     }
892   else
893     {
894       // Ensure that the frame is below the menu bar, or below the top
895       // of the screen.
896       //
897       // This assume that the menu bar is placed at the top in the
898       // rectangle that covers the monitors.  (It doesn't have to be,
899       // but if it's not it's hard to do anything useful.)
900       CGFloat topOfWorkArea = (multiscreenRect.origin.y
901                                + multiscreenRect.size.height
902                                - menu_bar_height);
904       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
905       if (topOfFrame > topOfWorkArea)
906         {
907           frameRect.origin.y -= topOfFrame - topOfWorkArea;
908           NSTRACE_RECT ("After placement adjust", frameRect);
909         }
910     }
912   // Include the following section to restrict frame to the screens.
913   // (If so, update it to allow the frame to stretch down below the
914   // screen.)
915 #if 0
916   // --------------------
917   // Ensure frame doesn't stretch below the screens.
918   //
920   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
922   if (diff > 0)
923     {
924       frameRect.origin.y = multiscreenRect.origin.y;
925       frameRect.size.height -= diff;
926     }
927 #endif
929   NSTRACE_RETURN_RECT (frameRect);
930   return frameRect;
934 static void
935 ns_constrain_all_frames (void)
936 /* --------------------------------------------------------------------------
937      Ensure that the menu bar doesn't cover any frames.
938    -------------------------------------------------------------------------- */
940   Lisp_Object tail, frame;
942   NSTRACE ("ns_constrain_all_frames");
944   block_input ();
946   FOR_EACH_FRAME (tail, frame)
947     {
948       struct frame *f = XFRAME (frame);
949       if (FRAME_NS_P (f))
950         {
951           EmacsView *view = FRAME_NS_VIEW (f);
953           if (![view isFullscreen])
954             {
955               [[view window]
956                 setFrame:constrain_frame_rect([[view window] frame], false)
957                  display:NO];
958             }
959         }
960     }
962   unblock_input ();
966 static void
967 ns_update_auto_hide_menu_bar (void)
968 /* --------------------------------------------------------------------------
969      Show or hide the menu bar, based on user setting.
970    -------------------------------------------------------------------------- */
972 #ifdef NS_IMPL_COCOA
973   NSTRACE ("ns_update_auto_hide_menu_bar");
975   block_input ();
977   if (NSApp != nil && [NSApp isActive])
978     {
979       // Note, "setPresentationOptions" triggers an error unless the
980       // application is active.
981       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
983       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
984         {
985           NSApplicationPresentationOptions options
986             = NSApplicationPresentationDefault;
988           if (menu_bar_should_be_hidden)
989             options |= NSApplicationPresentationAutoHideMenuBar
990               | NSApplicationPresentationAutoHideDock;
992           [NSApp setPresentationOptions: options];
994           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
996           if (!ns_menu_bar_is_hidden)
997             {
998               ns_constrain_all_frames ();
999             }
1000         }
1001     }
1003   unblock_input ();
1004 #endif
1008 static void
1009 ns_update_begin (struct frame *f)
1010 /* --------------------------------------------------------------------------
1011    Prepare for a grouped sequence of drawing calls
1012    external (RIF) call; whole frame, called before update_window_begin
1013    -------------------------------------------------------------------------- */
1015   EmacsView *view = FRAME_NS_VIEW (f);
1016   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
1018   ns_update_auto_hide_menu_bar ();
1020 #ifdef NS_IMPL_COCOA
1021   if ([view isFullscreen] && [view fsIsNative])
1022   {
1023     // Fix reappearing tool bar in fullscreen for OSX 10.7
1024     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
1025     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
1026     if (! tbar_visible != ! [toolbar isVisible])
1027       [toolbar setVisible: tbar_visible];
1028   }
1029 #endif
1031   ns_updating_frame = f;
1032   [view lockFocus];
1034   /* drawRect may have been called for say the minibuffer, and then clip path
1035      is for the minibuffer.  But the display engine may draw more because
1036      we have set the frame as garbaged.  So reset clip path to the whole
1037      view.  */
1038 #ifdef NS_IMPL_COCOA
1039   {
1040     NSBezierPath *bp;
1041     NSRect r = [view frame];
1042     NSRect cr = [[view window] frame];
1043     /* If a large frame size is set, r may be larger than the window frame
1044        before constrained.  In that case don't change the clip path, as we
1045        will clear in to the tool bar and title bar.  */
1046     if (r.size.height
1047         + FRAME_NS_TITLEBAR_HEIGHT (f)
1048         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
1049       {
1050         bp = [[NSBezierPath bezierPathWithRect: r] retain];
1051         [bp setClip];
1052         [bp release];
1053       }
1054   }
1055 #endif
1057 #ifdef NS_IMPL_GNUSTEP
1058   uRect = NSMakeRect (0, 0, 0, 0);
1059 #endif
1063 static void
1064 ns_update_window_begin (struct window *w)
1065 /* --------------------------------------------------------------------------
1066    Prepare for a grouped sequence of drawing calls
1067    external (RIF) call; for one window, called after update_begin
1068    -------------------------------------------------------------------------- */
1070   struct frame *f = XFRAME (WINDOW_FRAME (w));
1071   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1073   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
1074   w->output_cursor = w->cursor;
1076   block_input ();
1078   if (f == hlinfo->mouse_face_mouse_frame)
1079     {
1080       /* Don't do highlighting for mouse motion during the update.  */
1081       hlinfo->mouse_face_defer = 1;
1083         /* If the frame needs to be redrawn,
1084            simply forget about any prior mouse highlighting.  */
1085       if (FRAME_GARBAGED_P (f))
1086         hlinfo->mouse_face_window = Qnil;
1088       /* (further code for mouse faces ifdef'd out in other terms elided) */
1089     }
1091   unblock_input ();
1095 static void
1096 ns_update_window_end (struct window *w, bool cursor_on_p,
1097                       bool mouse_face_overwritten_p)
1098 /* --------------------------------------------------------------------------
1099    Finished a grouped sequence of drawing calls
1100    external (RIF) call; for one window called before update_end
1101    -------------------------------------------------------------------------- */
1103   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
1105   /* note: this fn is nearly identical in all terms */
1106   if (!w->pseudo_window_p)
1107     {
1108       block_input ();
1110       if (cursor_on_p)
1111         display_and_set_cursor (w, 1,
1112                                 w->output_cursor.hpos, w->output_cursor.vpos,
1113                                 w->output_cursor.x, w->output_cursor.y);
1115       if (draw_window_fringes (w, 1))
1116         {
1117           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1118             x_draw_right_divider (w);
1119           else
1120             x_draw_vertical_border (w);
1121         }
1123       unblock_input ();
1124     }
1126   /* If a row with mouse-face was overwritten, arrange for
1127      frame_up_to_date to redisplay the mouse highlight.  */
1128   if (mouse_face_overwritten_p)
1129     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1133 static void
1134 ns_update_end (struct frame *f)
1135 /* --------------------------------------------------------------------------
1136    Finished a grouped sequence of drawing calls
1137    external (RIF) call; for whole frame, called after update_window_end
1138    -------------------------------------------------------------------------- */
1140   EmacsView *view = FRAME_NS_VIEW (f);
1142   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1144 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1145   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1147   block_input ();
1149   [view unlockFocus];
1150   [[view window] flushWindow];
1152   unblock_input ();
1153   ns_updating_frame = NULL;
1156 static void
1157 ns_focus (struct frame *f, NSRect *r, int n)
1158 /* --------------------------------------------------------------------------
1159    Internal: Focus on given frame.  During small local updates this is used to
1160      draw, however during large updates, ns_update_begin and ns_update_end are
1161      called to wrap the whole thing, in which case these calls are stubbed out.
1162      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1163      the back end won't do this automatically, and will just end up flushing
1164      the entire window.
1165    -------------------------------------------------------------------------- */
1167   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1168   if (r != NULL)
1169     {
1170       NSTRACE_RECT ("r", *r);
1171     }
1173   if (f != ns_updating_frame)
1174     {
1175       NSView *view = FRAME_NS_VIEW (f);
1176       if (view != focus_view)
1177         {
1178           if (focus_view != NULL)
1179             {
1180               [focus_view unlockFocus];
1181               [[focus_view window] flushWindow];
1182 /*debug_lock--; */
1183             }
1185           if (view)
1186             [view lockFocus];
1187           focus_view = view;
1188 /*if (view) debug_lock++; */
1189         }
1190     }
1192   /* clipping */
1193   if (r)
1194     {
1195       [[NSGraphicsContext currentContext] saveGraphicsState];
1196       if (n == 2)
1197         NSRectClipList (r, 2);
1198       else
1199         NSRectClip (*r);
1200       gsaved = YES;
1201     }
1205 static void
1206 ns_unfocus (struct frame *f)
1207 /* --------------------------------------------------------------------------
1208      Internal: Remove focus on given frame
1209    -------------------------------------------------------------------------- */
1211   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1213   if (gsaved)
1214     {
1215       [[NSGraphicsContext currentContext] restoreGraphicsState];
1216       gsaved = NO;
1217     }
1219   if (f != ns_updating_frame)
1220     {
1221       if (focus_view != NULL)
1222         {
1223           [focus_view unlockFocus];
1224           [[focus_view window] flushWindow];
1225           focus_view = NULL;
1226 /*debug_lock--; */
1227         }
1228     }
1232 static void
1233 ns_clip_to_row (struct window *w, struct glyph_row *row,
1234                 enum glyph_row_area area, BOOL gc)
1235 /* --------------------------------------------------------------------------
1236      Internal (but parallels other terms): Focus drawing on given row
1237    -------------------------------------------------------------------------- */
1239   struct frame *f = XFRAME (WINDOW_FRAME (w));
1240   NSRect clip_rect;
1241   int window_x, window_y, window_width;
1243   window_box (w, area, &window_x, &window_y, &window_width, 0);
1245   clip_rect.origin.x = window_x;
1246   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1247   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1248   clip_rect.size.width = window_width;
1249   clip_rect.size.height = row->visible_height;
1251   ns_focus (f, &clip_rect, 1);
1255 /* ==========================================================================
1257     Visible bell and beep.
1259    ========================================================================== */
1262 // This bell implementation shows the visual bell image asynchronously
1263 // from the rest of Emacs. This is done by adding a NSView to the
1264 // superview of the Emacs window and removing it using a timer.
1266 // Unfortunately, some Emacs operations, like scrolling, is done using
1267 // low-level primitives that copy the content of the window, including
1268 // the bell image. To some extent, this is handled by removing the
1269 // image prior to scrolling and marking that the window is in need for
1270 // redisplay.
1272 // To test this code, make sure that there is no artifacts of the bell
1273 // image in the following situations. Use a non-empty buffer (like the
1274 // tutorial) to ensure that a scroll is performed:
1276 // * Single-window: C-g C-v
1278 // * Side-by-windows: C-x 3 C-g C-v
1280 // * Windows above each other: C-x 2 C-g C-v
1282 @interface EmacsBell : NSImageView
1284   // Number of currently active bell:s.
1285   unsigned int nestCount;
1286   NSView * mView;
1287   bool isAttached;
1289 - (void)show:(NSView *)view;
1290 - (void)hide;
1291 - (void)remove;
1292 @end
1294 @implementation EmacsBell
1296 - (id)init;
1298   NSTRACE ("[EmacsBell init]");
1299   if ((self = [super init]))
1300     {
1301       nestCount = 0;
1302       isAttached = false;
1303 #ifdef NS_IMPL_GNUSTEP
1304       // GNUstep doesn't provide named images.  This was reported in
1305       // 2011, see https://savannah.gnu.org/bugs/?33396
1306       //
1307       // As a drop in replacement, a semitransparent gray square is used.
1308       self.image = [[NSImage alloc] initWithSize:NSMakeSize(32 * 5, 32 * 5)];
1309       [self.image lockFocus];
1310       [[NSColor colorForEmacsRed:0.5 green:0.5 blue:0.5 alpha:0.5] set];
1311       NSRectFill(NSMakeRect(0, 0, 32, 32));
1312       [self.image unlockFocus];
1313 #else
1314       self.image = [NSImage imageNamed:NSImageNameCaution];
1315       [self.image setSize:NSMakeSize(self.image.size.width * 5,
1316                                      self.image.size.height * 5)];
1317 #endif
1318     }
1319   return self;
1322 - (void)show:(NSView *)view
1324   NSTRACE ("[EmacsBell show:]");
1325   NSTRACE_MSG ("nestCount: %u", nestCount);
1327   // Show the image, unless it's already shown.
1328   if (nestCount == 0)
1329     {
1330       NSRect rect = [view bounds];
1331       NSPoint pos;
1332       pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
1333       pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1335       [self setFrameOrigin:pos];
1336       [self setFrameSize:self.image.size];
1338       isAttached = true;
1339       mView = view;
1340       [[[view window] contentView] addSubview:self
1341                                    positioned:NSWindowAbove
1342                                    relativeTo:nil];
1343     }
1345   ++nestCount;
1347   [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1351 - (void)hide
1353   // Note: Trace output from this method isn't shown, reason unknown.
1354   // NSTRACE ("[EmacsBell hide]");
1356   if (nestCount > 0)
1357     --nestCount;
1359   // Remove the image once the last bell became inactive.
1360   if (nestCount == 0)
1361     {
1362       [self remove];
1363     }
1367 -(void)remove
1369   NSTRACE ("[EmacsBell remove]");
1370   if (isAttached)
1371     {
1372       NSTRACE_MSG ("removeFromSuperview");
1373       [self removeFromSuperview];
1374       mView.needsDisplay = YES;
1375       isAttached = false;
1376     }
1379 @end
1382 static EmacsBell * bell_view = nil;
1384 static void
1385 ns_ring_bell (struct frame *f)
1386 /* --------------------------------------------------------------------------
1387      "Beep" routine
1388    -------------------------------------------------------------------------- */
1390   NSTRACE ("ns_ring_bell");
1391   if (visible_bell)
1392     {
1393       struct frame *frame = SELECTED_FRAME ();
1394       NSView *view;
1396       if (bell_view == nil)
1397         {
1398           bell_view = [[EmacsBell alloc] init];
1399           [bell_view retain];
1400         }
1402       block_input ();
1404       view = FRAME_NS_VIEW (frame);
1405       if (view != nil)
1406         {
1407           [bell_view show:view];
1408         }
1410       unblock_input ();
1411     }
1412   else
1413     {
1414       NSBeep ();
1415     }
1419 static void hide_bell ()
1420 /* --------------------------------------------------------------------------
1421      Ensure the bell is hidden.
1422    -------------------------------------------------------------------------- */
1424   NSTRACE ("hide_bell");
1426   if (bell_view != nil)
1427     {
1428       [bell_view remove];
1429     }
1433 /* ==========================================================================
1435     Frame / window manager related functions
1437    ========================================================================== */
1440 static void
1441 ns_raise_frame (struct frame *f)
1442 /* --------------------------------------------------------------------------
1443      Bring window to foreground and make it active
1444    -------------------------------------------------------------------------- */
1446   NSView *view;
1448   check_window_system (f);
1449   view = FRAME_NS_VIEW (f);
1450   block_input ();
1451   if (FRAME_VISIBLE_P (f))
1452     [[view window] makeKeyAndOrderFront: NSApp];
1453   unblock_input ();
1457 static void
1458 ns_lower_frame (struct frame *f)
1459 /* --------------------------------------------------------------------------
1460      Send window to back
1461    -------------------------------------------------------------------------- */
1463   NSView *view;
1465   check_window_system (f);
1466   view = FRAME_NS_VIEW (f);
1467   block_input ();
1468   [[view window] orderBack: NSApp];
1469   unblock_input ();
1473 static void
1474 ns_frame_raise_lower (struct frame *f, bool raise)
1475 /* --------------------------------------------------------------------------
1476      External (hook)
1477    -------------------------------------------------------------------------- */
1479   NSTRACE ("ns_frame_raise_lower");
1481   if (raise)
1482     ns_raise_frame (f);
1483   else
1484     ns_lower_frame (f);
1488 static void
1489 ns_frame_rehighlight (struct frame *frame)
1490 /* --------------------------------------------------------------------------
1491      External (hook): called on things like window switching within frame
1492    -------------------------------------------------------------------------- */
1494   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1495   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1497   NSTRACE ("ns_frame_rehighlight");
1498   if (dpyinfo->x_focus_frame)
1499     {
1500       dpyinfo->x_highlight_frame
1501         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1502            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1503            : dpyinfo->x_focus_frame);
1504       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1505         {
1506           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1507           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1508         }
1509     }
1510   else
1511       dpyinfo->x_highlight_frame = 0;
1513   if (dpyinfo->x_highlight_frame &&
1514          dpyinfo->x_highlight_frame != old_highlight)
1515     {
1516       if (old_highlight)
1517         {
1518           x_update_cursor (old_highlight, 1);
1519           x_set_frame_alpha (old_highlight);
1520         }
1521       if (dpyinfo->x_highlight_frame)
1522         {
1523           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1524           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1525         }
1526     }
1530 void
1531 x_make_frame_visible (struct frame *f)
1532 /* --------------------------------------------------------------------------
1533      External: Show the window (X11 semantics)
1534    -------------------------------------------------------------------------- */
1536   NSTRACE ("x_make_frame_visible");
1537   /* XXX: at some points in past this was not needed, as the only place that
1538      called this (frame.c:Fraise_frame ()) also called raise_lower;
1539      if this ends up the case again, comment this out again. */
1540   if (!FRAME_VISIBLE_P (f))
1541     {
1542       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1544       SET_FRAME_VISIBLE (f, 1);
1545       ns_raise_frame (f);
1547       /* Making a new frame from a fullscreen frame will make the new frame
1548          fullscreen also.  So skip handleFS as this will print an error.  */
1549       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1550           && [view isFullscreen])
1551         return;
1553       if (f->want_fullscreen != FULLSCREEN_NONE)
1554         {
1555           block_input ();
1556           [view handleFS];
1557           unblock_input ();
1558         }
1559     }
1563 void
1564 x_make_frame_invisible (struct frame *f)
1565 /* --------------------------------------------------------------------------
1566      External: Hide the window (X11 semantics)
1567    -------------------------------------------------------------------------- */
1569   NSView *view;
1570   NSTRACE ("x_make_frame_invisible");
1571   check_window_system (f);
1572   view = FRAME_NS_VIEW (f);
1573   [[view window] orderOut: NSApp];
1574   SET_FRAME_VISIBLE (f, 0);
1575   SET_FRAME_ICONIFIED (f, 0);
1579 void
1580 x_iconify_frame (struct frame *f)
1581 /* --------------------------------------------------------------------------
1582      External: Iconify window
1583    -------------------------------------------------------------------------- */
1585   NSView *view;
1586   struct ns_display_info *dpyinfo;
1588   NSTRACE ("x_iconify_frame");
1589   check_window_system (f);
1590   view = FRAME_NS_VIEW (f);
1591   dpyinfo = FRAME_DISPLAY_INFO (f);
1593   if (dpyinfo->x_highlight_frame == f)
1594     dpyinfo->x_highlight_frame = 0;
1596   if ([[view window] windowNumber] <= 0)
1597     {
1598       /* the window is still deferred.  Make it very small, bring it
1599          on screen and order it out. */
1600       NSRect s = { { 100, 100}, {0, 0} };
1601       NSRect t;
1602       t = [[view window] frame];
1603       [[view window] setFrame: s display: NO];
1604       [[view window] orderBack: NSApp];
1605       [[view window] orderOut: NSApp];
1606       [[view window] setFrame: t display: NO];
1607     }
1608   [[view window] miniaturize: NSApp];
1611 /* Free X resources of frame F.  */
1613 void
1614 x_free_frame_resources (struct frame *f)
1616   NSView *view;
1617   struct ns_display_info *dpyinfo;
1618   Mouse_HLInfo *hlinfo;
1620   NSTRACE ("x_free_frame_resources");
1621   check_window_system (f);
1622   view = FRAME_NS_VIEW (f);
1623   dpyinfo = FRAME_DISPLAY_INFO (f);
1624   hlinfo = MOUSE_HL_INFO (f);
1626   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1628   block_input ();
1630   free_frame_menubar (f);
1631   free_frame_faces (f);
1633   if (f == dpyinfo->x_focus_frame)
1634     dpyinfo->x_focus_frame = 0;
1635   if (f == dpyinfo->x_highlight_frame)
1636     dpyinfo->x_highlight_frame = 0;
1637   if (f == hlinfo->mouse_face_mouse_frame)
1638     reset_mouse_highlight (hlinfo);
1640   if (f->output_data.ns->miniimage != nil)
1641     [f->output_data.ns->miniimage release];
1643   [[view window] close];
1644   [view release];
1646   xfree (f->output_data.ns);
1648   unblock_input ();
1651 void
1652 x_destroy_window (struct frame *f)
1653 /* --------------------------------------------------------------------------
1654      External: Delete the window
1655    -------------------------------------------------------------------------- */
1657   NSTRACE ("x_destroy_window");
1658   check_window_system (f);
1659   x_free_frame_resources (f);
1660   ns_window_num--;
1664 void
1665 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1666 /* --------------------------------------------------------------------------
1667      External: Position the window
1668    -------------------------------------------------------------------------- */
1670   NSView *view = FRAME_NS_VIEW (f);
1671   NSArray *screens = [NSScreen screens];
1672   NSScreen *fscreen = [screens objectAtIndex: 0];
1673   NSScreen *screen = [[view window] screen];
1675   NSTRACE ("x_set_offset");
1677   block_input ();
1679   f->left_pos = xoff;
1680   f->top_pos = yoff;
1682   if (view != nil && screen && fscreen)
1683     {
1684       f->left_pos = f->size_hint_flags & XNegative
1685         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1686         : f->left_pos;
1687       /* We use visibleFrame here to take menu bar into account.
1688          Ideally we should also adjust left/top with visibleFrame.origin.  */
1690       f->top_pos = f->size_hint_flags & YNegative
1691         ? ([screen visibleFrame].size.height + f->top_pos
1692            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1693            - FRAME_TOOLBAR_HEIGHT (f))
1694         : f->top_pos;
1695 #ifdef NS_IMPL_GNUSTEP
1696       if (f->left_pos < 100)
1697         f->left_pos = 100;  /* don't overlap menu */
1698 #endif
1699       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1700          menu bar.  */
1701       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
1702                                 SCREENMAXBOUND ([fscreen frame].size.height
1703                                                 - NS_TOP_POS (f)));
1704       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1705       [[view window] setFrameTopLeftPoint: pt];
1706       f->size_hint_flags &= ~(XNegative|YNegative);
1707     }
1709   unblock_input ();
1713 void
1714 x_set_window_size (struct frame *f,
1715                    bool change_gravity,
1716                    int width,
1717                    int height,
1718                    bool pixelwise)
1719 /* --------------------------------------------------------------------------
1720      Adjust window pixel size based on given character grid size
1721      Impl is a bit more complex than other terms, need to do some
1722      internal clipping.
1723    -------------------------------------------------------------------------- */
1725   EmacsView *view = FRAME_NS_VIEW (f);
1726   NSWindow *window = [view window];
1727   NSRect wr = [window frame];
1728   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1729   int pixelwidth, pixelheight;
1730   int orig_height = wr.size.height;
1732   NSTRACE ("x_set_window_size");
1734   if (view == nil)
1735     return;
1737   NSTRACE_RECT ("current", wr);
1738   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1739   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1741   block_input ();
1743   if (pixelwise)
1744     {
1745       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1746       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1747     }
1748   else
1749     {
1750       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1751       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1752     }
1754   /* If we have a toolbar, take its height into account. */
1755   if (tb && ! [view isFullscreen])
1756     {
1757     /* NOTE: previously this would generate wrong result if toolbar not
1758              yet displayed and fixing toolbar_height=32 helped, but
1759              now (200903) seems no longer needed */
1760     FRAME_TOOLBAR_HEIGHT (f) =
1761       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1762         - FRAME_NS_TITLEBAR_HEIGHT (f);
1763 #if 0
1764       /* Only breaks things here, removed by martin 2015-09-30.  */
1765 #ifdef NS_IMPL_GNUSTEP
1766       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1767 #endif
1768 #endif
1769     }
1770   else
1771     FRAME_TOOLBAR_HEIGHT (f) = 0;
1773   wr.size.width = pixelwidth + f->border_width;
1774   wr.size.height = pixelheight;
1775   if (! [view isFullscreen])
1776     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1777       + FRAME_TOOLBAR_HEIGHT (f);
1779   /* Do not try to constrain to this screen.  We may have multiple
1780      screens, and want Emacs to span those.  Constraining to screen
1781      prevents that, and that is not nice to the user.  */
1782  if (f->output_data.ns->zooming)
1783    f->output_data.ns->zooming = 0;
1784  else
1785    wr.origin.y += orig_height - wr.size.height;
1787  frame_size_history_add
1788    (f, Qx_set_window_size_1, width, height,
1789     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1790            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1791            make_number (f->border_width),
1792            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1793            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1795   [window setFrame: wr display: YES];
1797   /* This is a trick to compensate for Emacs' managing the scrollbar area
1798      as a fixed number of standard character columns.  Instead of leaving
1799      blank space for the extra, we chopped it off above.  Now for
1800      left-hand scrollbars, we shift all rendering to the left by the
1801      difference between the real width and Emacs' imagined one.  For
1802      right-hand bars, don't worry about it since the extra is never used.
1803      (Obviously doesn't work for vertically split windows tho..) */
1804   {
1805     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1806       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1807                      - NS_SCROLL_BAR_WIDTH (f), 0)
1808       : NSMakePoint (0, 0);
1810     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1811     [view setBoundsOrigin: origin];
1812   }
1814   [view updateFrameSize: NO];
1815   unblock_input ();
1819 static void
1820 ns_fullscreen_hook (struct frame *f)
1822   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1824   NSTRACE ("ns_fullscreen_hook");
1826   if (!FRAME_VISIBLE_P (f))
1827     return;
1829    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1830     {
1831       /* Old style fs don't initiate correctly if created from
1832          init/default-frame alist, so use a timer (not nice...).
1833       */
1834       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1835                                      selector: @selector (handleFS)
1836                                      userInfo: nil repeats: NO];
1837       return;
1838     }
1840   block_input ();
1841   [view handleFS];
1842   unblock_input ();
1845 /* ==========================================================================
1847     Color management
1849    ========================================================================== */
1852 NSColor *
1853 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1855   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1856   if (idx < 1 || idx >= color_table->avail)
1857     return nil;
1858   return color_table->colors[idx];
1862 unsigned long
1863 ns_index_color (NSColor *color, struct frame *f)
1865   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1866   ptrdiff_t idx;
1867   ptrdiff_t i;
1869   if (!color_table->colors)
1870     {
1871       color_table->size = NS_COLOR_CAPACITY;
1872       color_table->avail = 1; /* skip idx=0 as marker */
1873       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1874       color_table->colors[0] = nil;
1875       color_table->empty_indices = [[NSMutableSet alloc] init];
1876     }
1878   /* Do we already have this color?  */
1879   for (i = 1; i < color_table->avail; i++)
1880     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1881       return i;
1883   if ([color_table->empty_indices count] > 0)
1884     {
1885       NSNumber *index = [color_table->empty_indices anyObject];
1886       [color_table->empty_indices removeObject: index];
1887       idx = [index unsignedLongValue];
1888     }
1889   else
1890     {
1891       if (color_table->avail == color_table->size)
1892         color_table->colors =
1893           xpalloc (color_table->colors, &color_table->size, 1,
1894                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1895       idx = color_table->avail++;
1896     }
1898   color_table->colors[idx] = color;
1899   [color retain];
1900 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1901   return idx;
1905 void
1906 ns_free_indexed_color (unsigned long idx, struct frame *f)
1908   struct ns_color_table *color_table;
1909   NSColor *color;
1910   NSNumber *index;
1912   if (!f)
1913     return;
1915   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1917   if (idx <= 0 || idx >= color_table->size) {
1918     message1 ("ns_free_indexed_color: Color index out of range.\n");
1919     return;
1920   }
1922   index = [NSNumber numberWithUnsignedInt: idx];
1923   if ([color_table->empty_indices containsObject: index]) {
1924     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1925     return;
1926   }
1928   color = color_table->colors[idx];
1929   [color release];
1930   color_table->colors[idx] = nil;
1931   [color_table->empty_indices addObject: index];
1932 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1936 static int
1937 ns_get_color (const char *name, NSColor **col)
1938 /* --------------------------------------------------------------------------
1939      Parse a color name
1940    -------------------------------------------------------------------------- */
1941 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1942    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1943    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1945   NSColor *new = nil;
1946   static char hex[20];
1947   int scaling = 0;
1948   float r = -1.0, g, b;
1949   NSString *nsname = [NSString stringWithUTF8String: name];
1951   NSTRACE ("ns_get_color(%s, **)", name);
1953   block_input ();
1955   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1956     {
1957 #ifdef NS_IMPL_COCOA
1958       NSString *defname = [[NSUserDefaults standardUserDefaults]
1959                             stringForKey: @"AppleHighlightColor"];
1960       if (defname != nil)
1961         nsname = defname;
1962       else
1963 #endif
1964       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1965         {
1966           *col = [new colorUsingDefaultColorSpace];
1967           unblock_input ();
1968           return 0;
1969         }
1970       else
1971         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1973       name = [nsname UTF8String];
1974     }
1975   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1976     {
1977       /* NOTE: OSX applications normally don't set foreground selection, but
1978          text may be unreadable if we don't.
1979       */
1980       if ((new = [NSColor selectedTextColor]) != nil)
1981         {
1982           *col = [new colorUsingDefaultColorSpace];
1983           unblock_input ();
1984           return 0;
1985         }
1987       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1988       name = [nsname UTF8String];
1989     }
1991   /* First, check for some sort of numeric specification. */
1992   hex[0] = '\0';
1994   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1995     {
1996       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1997       [scanner scanFloat: &r];
1998       [scanner scanFloat: &g];
1999       [scanner scanFloat: &b];
2000     }
2001   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
2002     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
2003   else if (name[0] == '#')        /* An old X11 format; convert to newer */
2004     {
2005       int len = (strlen(name) - 1);
2006       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
2007       int i;
2008       scaling = strlen(name+start) / 3;
2009       for (i = 0; i < 3; i++)
2010         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
2011                  name + start + i * scaling);
2012       hex[3 * (scaling + 1) - 1] = '\0';
2013     }
2015   if (hex[0])
2016     {
2017       int rr, gg, bb;
2018       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
2019       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
2020         {
2021           r = rr / fscale;
2022           g = gg / fscale;
2023           b = bb / fscale;
2024         }
2025     }
2027   if (r >= 0.0F)
2028     {
2029       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
2030       unblock_input ();
2031       return 0;
2032     }
2034   /* Otherwise, color is expected to be from a list */
2035   {
2036     NSEnumerator *lenum, *cenum;
2037     NSString *name;
2038     NSColorList *clist;
2040 #ifdef NS_IMPL_GNUSTEP
2041     /* XXX: who is wrong, the requestor or the implementation? */
2042     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
2043         == NSOrderedSame)
2044       nsname = @"highlightColor";
2045 #endif
2047     lenum = [[NSColorList availableColorLists] objectEnumerator];
2048     while ( (clist = [lenum nextObject]) && new == nil)
2049       {
2050         cenum = [[clist allKeys] objectEnumerator];
2051         while ( (name = [cenum nextObject]) && new == nil )
2052           {
2053             if ([name compare: nsname
2054                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
2055               new = [clist colorWithKey: name];
2056           }
2057       }
2058   }
2060   if (new)
2061     *col = [new colorUsingDefaultColorSpace];
2062   unblock_input ();
2063   return new ? 0 : 1;
2068 ns_lisp_to_color (Lisp_Object color, NSColor **col)
2069 /* --------------------------------------------------------------------------
2070      Convert a Lisp string object to a NS color
2071    -------------------------------------------------------------------------- */
2073   NSTRACE ("ns_lisp_to_color");
2074   if (STRINGP (color))
2075     return ns_get_color (SSDATA (color), col);
2076   else if (SYMBOLP (color))
2077     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
2078   return 1;
2082 Lisp_Object
2083 ns_color_to_lisp (NSColor *col)
2084 /* --------------------------------------------------------------------------
2085      Convert a color to a lisp string with the RGB equivalent
2086    -------------------------------------------------------------------------- */
2088   EmacsCGFloat red, green, blue, alpha, gray;
2089   char buf[1024];
2090   const char *str;
2091   NSTRACE ("ns_color_to_lisp");
2093   block_input ();
2094   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
2096       if ((str =[[col colorNameComponent] UTF8String]))
2097         {
2098           unblock_input ();
2099           return build_string ((char *)str);
2100         }
2102     [[col colorUsingDefaultColorSpace]
2103         getRed: &red green: &green blue: &blue alpha: &alpha];
2104   if (red == green && red == blue)
2105     {
2106       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
2107             getWhite: &gray alpha: &alpha];
2108       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
2109                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
2110       unblock_input ();
2111       return build_string (buf);
2112     }
2114   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
2115             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
2117   unblock_input ();
2118   return build_string (buf);
2122 void
2123 ns_query_color(void *col, XColor *color_def, int setPixel)
2124 /* --------------------------------------------------------------------------
2125          Get ARGB values out of NSColor col and put them into color_def.
2126          If setPixel, set the pixel to a concatenated version.
2127          and set color_def pixel to the resulting index.
2128    -------------------------------------------------------------------------- */
2130   EmacsCGFloat r, g, b, a;
2132   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
2133   color_def->red   = r * 65535;
2134   color_def->green = g * 65535;
2135   color_def->blue  = b * 65535;
2137   if (setPixel == YES)
2138     color_def->pixel
2139       = ARGB_TO_ULONG((int)(a*255),
2140                       (int)(r*255), (int)(g*255), (int)(b*255));
2144 bool
2145 ns_defined_color (struct frame *f,
2146                   const char *name,
2147                   XColor *color_def,
2148                   bool alloc,
2149                   bool makeIndex)
2150 /* --------------------------------------------------------------------------
2151          Return true if named color found, and set color_def rgb accordingly.
2152          If makeIndex and alloc are nonzero put the color in the color_table,
2153          and set color_def pixel to the resulting index.
2154          If makeIndex is zero, set color_def pixel to ARGB.
2155          Return false if not found
2156    -------------------------------------------------------------------------- */
2158   NSColor *col;
2159   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
2161   block_input ();
2162   if (ns_get_color (name, &col) != 0) /* Color not found  */
2163     {
2164       unblock_input ();
2165       return 0;
2166     }
2167   if (makeIndex && alloc)
2168     color_def->pixel = ns_index_color (col, f);
2169   ns_query_color (col, color_def, !makeIndex);
2170   unblock_input ();
2171   return 1;
2175 void
2176 x_set_frame_alpha (struct frame *f)
2177 /* --------------------------------------------------------------------------
2178      change the entire-frame transparency
2179    -------------------------------------------------------------------------- */
2181   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2182   double alpha = 1.0;
2183   double alpha_min = 1.0;
2185   NSTRACE ("x_set_frame_alpha");
2187   if (dpyinfo->x_highlight_frame == f)
2188     alpha = f->alpha[0];
2189   else
2190     alpha = f->alpha[1];
2192   if (FLOATP (Vframe_alpha_lower_limit))
2193     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2194   else if (INTEGERP (Vframe_alpha_lower_limit))
2195     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2197   if (alpha < 0.0)
2198     return;
2199   else if (1.0 < alpha)
2200     alpha = 1.0;
2201   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2202     alpha = alpha_min;
2204 #ifdef NS_IMPL_COCOA
2205   {
2206     EmacsView *view = FRAME_NS_VIEW (f);
2207   [[view window] setAlphaValue: alpha];
2208   }
2209 #endif
2213 /* ==========================================================================
2215     Mouse handling
2217    ========================================================================== */
2220 void
2221 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2222 /* --------------------------------------------------------------------------
2223      Programmatically reposition mouse pointer in pixel coordinates
2224    -------------------------------------------------------------------------- */
2226   NSTRACE ("frame_set_mouse_pixel_position");
2227   ns_raise_frame (f);
2228 #if 0
2229   /* FIXME: this does not work, and what about GNUstep? */
2230 #ifdef NS_IMPL_COCOA
2231   [FRAME_NS_VIEW (f) lockFocus];
2232   PSsetmouse ((float)pix_x, (float)pix_y);
2233   [FRAME_NS_VIEW (f) unlockFocus];
2234 #endif
2235 #endif
2238 static int
2239 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2240 /*   ------------------------------------------------------------------------
2241      Called by EmacsView on mouseMovement events.  Passes on
2242      to emacs mainstream code if we moved off of a rect of interest
2243      known as last_mouse_glyph.
2244      ------------------------------------------------------------------------ */
2246   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2247   NSRect *r;
2249 //  NSTRACE ("note_mouse_movement");
2251   dpyinfo->last_mouse_motion_frame = frame;
2252   r = &dpyinfo->last_mouse_glyph;
2254   /* Note, this doesn't get called for enter/leave, since we don't have a
2255      position.  Those are taken care of in the corresponding NSView methods. */
2257   /* has movement gone beyond last rect we were tracking? */
2258   if (x < r->origin.x || x >= r->origin.x + r->size.width
2259       || y < r->origin.y || y >= r->origin.y + r->size.height)
2260     {
2261       ns_update_begin (frame);
2262       frame->mouse_moved = 1;
2263       note_mouse_highlight (frame, x, y);
2264       remember_mouse_glyph (frame, x, y, r);
2265       ns_update_end (frame);
2266       return 1;
2267     }
2269   return 0;
2273 static void
2274 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2275                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2276                    Time *time)
2277 /* --------------------------------------------------------------------------
2278     External (hook): inform emacs about mouse position and hit parts.
2279     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2280     x & y should be position in the scrollbar (the whole bar, not the handle)
2281     and length of scrollbar respectively
2282    -------------------------------------------------------------------------- */
2284   id view;
2285   NSPoint position;
2286   Lisp_Object frame, tail;
2287   struct frame *f;
2288   struct ns_display_info *dpyinfo;
2290   NSTRACE ("ns_mouse_position");
2292   if (*fp == NULL)
2293     {
2294       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2295       return;
2296     }
2298   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2300   block_input ();
2302   /* Clear the mouse-moved flag for every frame on this display.  */
2303   FOR_EACH_FRAME (tail, frame)
2304     if (FRAME_NS_P (XFRAME (frame))
2305         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2306       XFRAME (frame)->mouse_moved = 0;
2308   dpyinfo->last_mouse_scroll_bar = nil;
2309   if (dpyinfo->last_mouse_frame
2310       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2311     f = dpyinfo->last_mouse_frame;
2312   else
2313     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2315   if (f && FRAME_NS_P (f))
2316     {
2317       view = FRAME_NS_VIEW (*fp);
2319       position = [[view window] mouseLocationOutsideOfEventStream];
2320       position = [view convertPoint: position fromView: nil];
2321       remember_mouse_glyph (f, position.x, position.y,
2322                             &dpyinfo->last_mouse_glyph);
2323       NSTRACE_POINT ("position", position);
2325       if (bar_window) *bar_window = Qnil;
2326       if (part) *part = scroll_bar_above_handle;
2328       if (x) XSETINT (*x, lrint (position.x));
2329       if (y) XSETINT (*y, lrint (position.y));
2330       if (time)
2331         *time = dpyinfo->last_mouse_movement_time;
2332       *fp = f;
2333     }
2335   unblock_input ();
2339 static void
2340 ns_frame_up_to_date (struct frame *f)
2341 /* --------------------------------------------------------------------------
2342     External (hook): Fix up mouse highlighting right after a full update.
2343     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2344    -------------------------------------------------------------------------- */
2346   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2348   if (FRAME_NS_P (f))
2349     {
2350       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2351       if (f == hlinfo->mouse_face_mouse_frame)
2352         {
2353           block_input ();
2354           ns_update_begin(f);
2355           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2356                                 hlinfo->mouse_face_mouse_x,
2357                                 hlinfo->mouse_face_mouse_y);
2358           ns_update_end(f);
2359           unblock_input ();
2360         }
2361     }
2365 static void
2366 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2367 /* --------------------------------------------------------------------------
2368     External (RIF): set frame mouse pointer type.
2369    -------------------------------------------------------------------------- */
2371   NSTRACE ("ns_define_frame_cursor");
2372   if (FRAME_POINTER_TYPE (f) != cursor)
2373     {
2374       EmacsView *view = FRAME_NS_VIEW (f);
2375       FRAME_POINTER_TYPE (f) = cursor;
2376       [[view window] invalidateCursorRectsForView: view];
2377       /* Redisplay assumes this function also draws the changed frame
2378          cursor, but this function doesn't, so do it explicitly.  */
2379       x_update_cursor (f, 1);
2380     }
2385 /* ==========================================================================
2387     Keyboard handling
2389    ========================================================================== */
2392 static unsigned
2393 ns_convert_key (unsigned code)
2394 /* --------------------------------------------------------------------------
2395     Internal call used by NSView-keyDown.
2396    -------------------------------------------------------------------------- */
2398   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2399   unsigned keysym;
2400   /* An array would be faster, but less easy to read. */
2401   for (keysym = 0; keysym < last_keysym; keysym += 2)
2402     if (code == convert_ns_to_X_keysym[keysym])
2403       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2404   return 0;
2405 /* if decide to use keyCode and Carbon table, use this line:
2406      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2410 char *
2411 x_get_keysym_name (int keysym)
2412 /* --------------------------------------------------------------------------
2413     Called by keyboard.c.  Not sure if the return val is important, except
2414     that it be unique.
2415    -------------------------------------------------------------------------- */
2417   static char value[16];
2418   NSTRACE ("x_get_keysym_name");
2419   sprintf (value, "%d", keysym);
2420   return value;
2425 /* ==========================================================================
2427     Block drawing operations
2429    ========================================================================== */
2432 static void
2433 ns_redraw_scroll_bars (struct frame *f)
2435   int i;
2436   id view;
2437   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2438   NSTRACE ("ns_redraw_scroll_bars");
2439   for (i =[subviews count]-1; i >= 0; i--)
2440     {
2441       view = [subviews objectAtIndex: i];
2442       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2443       [view display];
2444     }
2448 void
2449 ns_clear_frame (struct frame *f)
2450 /* --------------------------------------------------------------------------
2451       External (hook): Erase the entire frame
2452    -------------------------------------------------------------------------- */
2454   NSView *view = FRAME_NS_VIEW (f);
2455   NSRect r;
2457   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2459  /* comes on initial frame because we have
2460     after-make-frame-functions = select-frame */
2461  if (!FRAME_DEFAULT_FACE (f))
2462    return;
2464   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2466   r = [view bounds];
2468   block_input ();
2469   ns_focus (f, &r, 1);
2470   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2471   NSRectFill (r);
2472   ns_unfocus (f);
2474   /* as of 2006/11 or so this is now needed */
2475   ns_redraw_scroll_bars (f);
2476   unblock_input ();
2480 static void
2481 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2482 /* --------------------------------------------------------------------------
2483     External (RIF):  Clear section of frame
2484    -------------------------------------------------------------------------- */
2486   NSRect r = NSMakeRect (x, y, width, height);
2487   NSView *view = FRAME_NS_VIEW (f);
2488   struct face *face = FRAME_DEFAULT_FACE (f);
2490   if (!view || !face)
2491     return;
2493   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2495   r = NSIntersectionRect (r, [view frame]);
2496   ns_focus (f, &r, 1);
2497   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2499   NSRectFill (r);
2501   ns_unfocus (f);
2502   return;
2505 static void
2506 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2508   NSTRACE ("ns_copy_bits");
2510   if (FRAME_NS_VIEW (f))
2511     {
2512       hide_bell();              // Ensure the bell image isn't scrolled.
2514       ns_focus (f, &dest, 1);
2515       [FRAME_NS_VIEW (f) scrollRect: src
2516                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2517                                                  dest.origin.y - src.origin.y)];
2518       ns_unfocus (f);
2519     }
2522 static void
2523 ns_scroll_run (struct window *w, struct run *run)
2524 /* --------------------------------------------------------------------------
2525     External (RIF):  Insert or delete n lines at line vpos
2526    -------------------------------------------------------------------------- */
2528   struct frame *f = XFRAME (w->frame);
2529   int x, y, width, height, from_y, to_y, bottom_y;
2531   NSTRACE ("ns_scroll_run");
2533   /* begin copy from other terms */
2534   /* Get frame-relative bounding box of the text display area of W,
2535      without mode lines.  Include in this box the left and right
2536      fringe of W.  */
2537   window_box (w, ANY_AREA, &x, &y, &width, &height);
2539   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2540   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2541   bottom_y = y + height;
2543   if (to_y < from_y)
2544     {
2545       /* Scrolling up.  Make sure we don't copy part of the mode
2546          line at the bottom.  */
2547       if (from_y + run->height > bottom_y)
2548         height = bottom_y - from_y;
2549       else
2550         height = run->height;
2551     }
2552   else
2553     {
2554       /* Scrolling down.  Make sure we don't copy over the mode line.
2555          at the bottom.  */
2556       if (to_y + run->height > bottom_y)
2557         height = bottom_y - to_y;
2558       else
2559         height = run->height;
2560     }
2561   /* end copy from other terms */
2563   if (height == 0)
2564       return;
2566   block_input ();
2568   x_clear_cursor (w);
2570   {
2571     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2572     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2574     ns_copy_bits (f, srcRect , dstRect);
2575   }
2577   unblock_input ();
2581 static void
2582 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2583 /* --------------------------------------------------------------------------
2584     External (RIF): preparatory to fringe update after text was updated
2585    -------------------------------------------------------------------------- */
2587   struct frame *f;
2588   int width, height;
2590   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2592   /* begin copy from other terms */
2593   eassert (w);
2595   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2596     desired_row->redraw_fringe_bitmaps_p = 1;
2598   /* When a window has disappeared, make sure that no rest of
2599      full-width rows stays visible in the internal border.  */
2600   if (windows_or_buffers_changed
2601       && desired_row->full_width_p
2602       && (f = XFRAME (w->frame),
2603           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2604           width != 0)
2605       && (height = desired_row->visible_height,
2606           height > 0))
2607     {
2608       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2610       block_input ();
2611       ns_clear_frame_area (f, 0, y, width, height);
2612       ns_clear_frame_area (f,
2613                            FRAME_PIXEL_WIDTH (f) - width,
2614                            y, width, height);
2615       unblock_input ();
2616     }
2620 static void
2621 ns_shift_glyphs_for_insert (struct frame *f,
2622                            int x, int y, int width, int height,
2623                            int shift_by)
2624 /* --------------------------------------------------------------------------
2625     External (RIF): copy an area horizontally, don't worry about clearing src
2626    -------------------------------------------------------------------------- */
2628   NSRect srcRect = NSMakeRect (x, y, width, height);
2629   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2631   NSTRACE ("ns_shift_glyphs_for_insert");
2633   ns_copy_bits (f, srcRect, dstRect);
2638 /* ==========================================================================
2640     Character encoding and metrics
2642    ========================================================================== */
2645 static void
2646 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2647 /* --------------------------------------------------------------------------
2648      External (RIF); compute left/right overhang of whole string and set in s
2649    -------------------------------------------------------------------------- */
2651   struct font *font = s->font;
2653   if (s->char2b)
2654     {
2655       struct font_metrics metrics;
2656       unsigned int codes[2];
2657       codes[0] = *(s->char2b);
2658       codes[1] = *(s->char2b + s->nchars - 1);
2660       font->driver->text_extents (font, codes, 2, &metrics);
2661       s->left_overhang = -metrics.lbearing;
2662       s->right_overhang
2663         = metrics.rbearing > metrics.width
2664         ? metrics.rbearing - metrics.width : 0;
2665     }
2666   else
2667     {
2668       s->left_overhang = 0;
2669       if (EQ (font->driver->type, Qns))
2670         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2671           FONT_HEIGHT (font) * 0.2 : 0;
2672       else
2673         s->right_overhang = 0;
2674     }
2679 /* ==========================================================================
2681     Fringe and cursor drawing
2683    ========================================================================== */
2686 extern int max_used_fringe_bitmap;
2687 static void
2688 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2689                       struct draw_fringe_bitmap_params *p)
2690 /* --------------------------------------------------------------------------
2691     External (RIF); fringe-related
2692    -------------------------------------------------------------------------- */
2694   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2695      periodic bitmap is used to create a continuous pattern.  Since a
2696      bitmap is rendered one text line at a time, the start offset (dh)
2697      of the bitmap varies.  Concretely, this is used for the empty
2698      line indicator.
2700      For a bitmap, "h + dh" is the full height and is always
2701      invariant.  For a normal bitmap "dh" is zero.
2703      For example, when the period is three and the full height is 72
2704      the following combinations exists:
2706        h=72 dh=0
2707        h=71 dh=1
2708        h=70 dh=2 */
2710   struct frame *f = XFRAME (WINDOW_FRAME (w));
2711   struct face *face = p->face;
2712   static EmacsImage **bimgs = NULL;
2713   static int nBimgs = 0;
2715   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2716   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2717                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2719   /* grow bimgs if needed */
2720   if (nBimgs < max_used_fringe_bitmap)
2721     {
2722       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2723       memset (bimgs + nBimgs, 0,
2724               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2725       nBimgs = max_used_fringe_bitmap;
2726     }
2728   /* Must clip because of partially visible lines.  */
2729   ns_clip_to_row (w, row, ANY_AREA, YES);
2731   if (!p->overlay_p)
2732     {
2733       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2735       if (bx >= 0 && nx > 0)
2736         {
2737           NSRect r = NSMakeRect (bx, by, nx, ny);
2738           NSRectClip (r);
2739           [ns_lookup_indexed_color (face->background, f) set];
2740           NSRectFill (r);
2741         }
2742     }
2744   if (p->which)
2745     {
2746       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2747       EmacsImage *img = bimgs[p->which - 1];
2749       if (!img)
2750         {
2751           // Note: For "periodic" images, allocate one EmacsImage for
2752           // the base image, and use it for all dh:s.
2753           unsigned short *bits = p->bits;
2754           int full_height = p->h + p->dh;
2755           int i;
2756           unsigned char *cbits = xmalloc (full_height);
2758           for (i = 0; i < full_height; i++)
2759             cbits[i] = bits[i];
2760           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2761                                          height: full_height
2762                                              fg: 0 bg: 0];
2763           bimgs[p->which - 1] = img;
2764           xfree (cbits);
2765         }
2767       NSTRACE_RECT ("r", r);
2769       NSRectClip (r);
2770       /* Since we composite the bitmap instead of just blitting it, we need
2771          to erase the whole background. */
2772       [ns_lookup_indexed_color(face->background, f) set];
2773       NSRectFill (r);
2775       {
2776         NSColor *bm_color;
2777         if (!p->cursor_p)
2778           bm_color = ns_lookup_indexed_color(face->foreground, f);
2779         else if (p->overlay_p)
2780           bm_color = ns_lookup_indexed_color(face->background, f);
2781         else
2782           bm_color = f->output_data.ns->cursor_color;
2783         [img setXBMColor: bm_color];
2784       }
2786 #ifdef NS_IMPL_COCOA
2787       // Note: For periodic images, the full image height is "h + hd".
2788       // By using the height h, a suitable part of the image is used.
2789       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2791       NSTRACE_RECT ("fromRect", fromRect);
2793       [img drawInRect: r
2794               fromRect: fromRect
2795              operation: NSCompositeSourceOver
2796               fraction: 1.0
2797            respectFlipped: YES
2798                 hints: nil];
2799 #else
2800       {
2801         NSPoint pt = r.origin;
2802         pt.y += p->h;
2803         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2804       }
2805 #endif
2806     }
2807   ns_unfocus (f);
2811 static void
2812 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2813                        int x, int y, enum text_cursor_kinds cursor_type,
2814                        int cursor_width, bool on_p, bool active_p)
2815 /* --------------------------------------------------------------------------
2816      External call (RIF): draw cursor.
2817      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2818    -------------------------------------------------------------------------- */
2820   NSRect r, s;
2821   int fx, fy, h, cursor_height;
2822   struct frame *f = WINDOW_XFRAME (w);
2823   struct glyph *phys_cursor_glyph;
2824   struct glyph *cursor_glyph;
2825   struct face *face;
2826   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2828   /* If cursor is out of bounds, don't draw garbage.  This can happen
2829      in mini-buffer windows when switching between echo area glyphs
2830      and mini-buffer.  */
2832   NSTRACE ("ns_draw_window_cursor");
2834   if (!on_p)
2835     return;
2837   w->phys_cursor_type = cursor_type;
2838   w->phys_cursor_on_p = on_p;
2840   if (cursor_type == NO_CURSOR)
2841     {
2842       w->phys_cursor_width = 0;
2843       return;
2844     }
2846   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2847     {
2848       if (glyph_row->exact_window_width_line_p
2849           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2850         {
2851           glyph_row->cursor_in_fringe_p = 1;
2852           draw_fringe_bitmap (w, glyph_row, 0);
2853         }
2854       return;
2855     }
2857   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2858      (other terminals do it the other way round).  We must set
2859      w->phys_cursor_width to the cursor width.  For bar cursors, that
2860      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2861   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2863   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2864      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2865   if (cursor_type == BAR_CURSOR)
2866     {
2867       if (cursor_width < 1)
2868         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2869       w->phys_cursor_width = cursor_width;
2870     }
2871   /* If we have an HBAR, "cursor_width" MAY specify height. */
2872   else if (cursor_type == HBAR_CURSOR)
2873     {
2874       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2875       if (cursor_height > glyph_row->height)
2876         cursor_height = glyph_row->height;
2877       if (h > cursor_height) // Cursor smaller than line height, move down
2878         fy += h - cursor_height;
2879       h = cursor_height;
2880     }
2882   r.origin.x = fx, r.origin.y = fy;
2883   r.size.height = h;
2884   r.size.width = w->phys_cursor_width;
2886   /* TODO: only needed in rare cases with last-resort font in HELLO..
2887      should we do this more efficiently? */
2888   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2891   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2892   if (face && NS_FACE_BACKGROUND (face)
2893       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2894     {
2895       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2896       hollow_color = FRAME_CURSOR_COLOR (f);
2897     }
2898   else
2899     [FRAME_CURSOR_COLOR (f) set];
2901 #ifdef NS_IMPL_COCOA
2902   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2903            atomic.  Cleaner ways of doing this should be investigated.
2904            One way would be to set a global variable DRAWING_CURSOR
2905            when making the call to draw_phys..(), don't focus in that
2906            case, then move the ns_unfocus() here after that call. */
2907   NSDisableScreenUpdates ();
2908 #endif
2910   switch (cursor_type)
2911     {
2912     case DEFAULT_CURSOR:
2913     case NO_CURSOR:
2914       break;
2915     case FILLED_BOX_CURSOR:
2916       NSRectFill (r);
2917       break;
2918     case HOLLOW_BOX_CURSOR:
2919       NSRectFill (r);
2920       [hollow_color set];
2921       NSRectFill (NSInsetRect (r, 1, 1));
2922       [FRAME_CURSOR_COLOR (f) set];
2923       break;
2924     case HBAR_CURSOR:
2925       NSRectFill (r);
2926       break;
2927     case BAR_CURSOR:
2928       s = r;
2929       /* If the character under cursor is R2L, draw the bar cursor
2930          on the right of its glyph, rather than on the left.  */
2931       cursor_glyph = get_phys_cursor_glyph (w);
2932       if ((cursor_glyph->resolved_level & 1) != 0)
2933         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2935       NSRectFill (s);
2936       break;
2937     }
2938   ns_unfocus (f);
2940   /* draw the character under the cursor */
2941   if (cursor_type != NO_CURSOR)
2942     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2944 #ifdef NS_IMPL_COCOA
2945   NSEnableScreenUpdates ();
2946 #endif
2951 static void
2952 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2953 /* --------------------------------------------------------------------------
2954      External (RIF): Draw a vertical line.
2955    -------------------------------------------------------------------------- */
2957   struct frame *f = XFRAME (WINDOW_FRAME (w));
2958   struct face *face;
2959   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2961   NSTRACE ("ns_draw_vertical_window_border");
2963   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2964   if (face)
2965       [ns_lookup_indexed_color(face->foreground, f) set];
2967   ns_focus (f, &r, 1);
2968   NSRectFill(r);
2969   ns_unfocus (f);
2973 static void
2974 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2975 /* --------------------------------------------------------------------------
2976      External (RIF): Draw a window divider.
2977    -------------------------------------------------------------------------- */
2979   struct frame *f = XFRAME (WINDOW_FRAME (w));
2980   struct face *face;
2981   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2983   NSTRACE ("ns_draw_window_divider");
2985   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2986   if (face)
2987       [ns_lookup_indexed_color(face->foreground, f) set];
2989   ns_focus (f, &r, 1);
2990   NSRectFill(r);
2991   ns_unfocus (f);
2994 static void
2995 ns_show_hourglass (struct frame *f)
2997   /* TODO: add NSProgressIndicator to all frames.  */
3000 static void
3001 ns_hide_hourglass (struct frame *f)
3003   /* TODO: remove NSProgressIndicator from all frames.  */
3006 /* ==========================================================================
3008     Glyph drawing operations
3010    ========================================================================== */
3012 static int
3013 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
3014 /* --------------------------------------------------------------------------
3015     Wrapper utility to account for internal border width on full-width lines,
3016     and allow top full-width rows to hit the frame top.  nr should be pointer
3017     to two successive NSRects.  Number of rects actually used is returned.
3018    -------------------------------------------------------------------------- */
3020   int n = get_glyph_string_clip_rects (s, nr, 2);
3021   return n;
3024 /* --------------------------------------------------------------------
3025    Draw a wavy line under glyph string s. The wave fills wave_height
3026    pixels from y.
3028                     x          wave_length = 2
3029                                  --
3030                 y    *   *   *   *   *
3031                      |* * * * * * * * *
3032     wave_height = 3  | *   *   *   *
3033   --------------------------------------------------------------------- */
3035 static void
3036 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
3038   int wave_height = 3, wave_length = 2;
3039   int y, dx, dy, odd, xmax;
3040   NSPoint a, b;
3041   NSRect waveClip;
3043   dx = wave_length;
3044   dy = wave_height - 1;
3045   y =  s->ybase - wave_height + 3;
3046   xmax = x + width;
3048   /* Find and set clipping rectangle */
3049   waveClip = NSMakeRect (x, y, width, wave_height);
3050   [[NSGraphicsContext currentContext] saveGraphicsState];
3051   NSRectClip (waveClip);
3053   /* Draw the waves */
3054   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
3055   b.x = a.x + dx;
3056   odd = (int)(a.x/dx) % 2;
3057   a.y = b.y = y + 0.5;
3059   if (odd)
3060     a.y += dy;
3061   else
3062     b.y += dy;
3064   while (a.x <= xmax)
3065     {
3066       [NSBezierPath strokeLineFromPoint:a toPoint:b];
3067       a.x = b.x, a.y = b.y;
3068       b.x += dx, b.y = y + 0.5 + odd*dy;
3069       odd = !odd;
3070     }
3072   /* Restore previous clipping rectangle(s) */
3073   [[NSGraphicsContext currentContext] restoreGraphicsState];
3078 void
3079 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
3080                          NSColor *defaultCol, CGFloat width, CGFloat x)
3081 /* --------------------------------------------------------------------------
3082    Draw underline, overline, and strike-through on glyph string s.
3083    -------------------------------------------------------------------------- */
3085   if (s->for_overlaps)
3086     return;
3088   /* Do underline. */
3089   if (face->underline_p)
3090     {
3091       if (s->face->underline_type == FACE_UNDER_WAVE)
3092         {
3093           if (face->underline_defaulted_p)
3094             [defaultCol set];
3095           else
3096             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3098           ns_draw_underwave (s, width, x);
3099         }
3100       else if (s->face->underline_type == FACE_UNDER_LINE)
3101         {
3103           NSRect r;
3104           unsigned long thickness, position;
3106           /* If the prev was underlined, match its appearance. */
3107           if (s->prev && s->prev->face->underline_p
3108               && s->prev->face->underline_type == FACE_UNDER_LINE
3109               && s->prev->underline_thickness > 0)
3110             {
3111               thickness = s->prev->underline_thickness;
3112               position = s->prev->underline_position;
3113             }
3114           else
3115             {
3116               struct font *font;
3117               unsigned long descent;
3119               font=s->font;
3120               descent = s->y + s->height - s->ybase;
3122               /* Use underline thickness of font, defaulting to 1. */
3123               thickness = (font && font->underline_thickness > 0)
3124                 ? font->underline_thickness : 1;
3126               /* Determine the offset of underlining from the baseline. */
3127               if (x_underline_at_descent_line)
3128                 position = descent - thickness;
3129               else if (x_use_underline_position_properties
3130                        && font && font->underline_position >= 0)
3131                 position = font->underline_position;
3132               else if (font)
3133                 position = lround (font->descent / 2);
3134               else
3135                 position = underline_minimum_offset;
3137               position = max (position, underline_minimum_offset);
3139               /* Ensure underlining is not cropped. */
3140               if (descent <= position)
3141                 {
3142                   position = descent - 1;
3143                   thickness = 1;
3144                 }
3145               else if (descent < position + thickness)
3146                 thickness = 1;
3147             }
3149           s->underline_thickness = thickness;
3150           s->underline_position = position;
3152           r = NSMakeRect (x, s->ybase + position, width, thickness);
3154           if (face->underline_defaulted_p)
3155             [defaultCol set];
3156           else
3157             [ns_lookup_indexed_color (face->underline_color, s->f) set];
3158           NSRectFill (r);
3159         }
3160     }
3161   /* Do overline. We follow other terms in using a thickness of 1
3162      and ignoring overline_margin. */
3163   if (face->overline_p)
3164     {
3165       NSRect r;
3166       r = NSMakeRect (x, s->y, width, 1);
3168       if (face->overline_color_defaulted_p)
3169         [defaultCol set];
3170       else
3171         [ns_lookup_indexed_color (face->overline_color, s->f) set];
3172       NSRectFill (r);
3173     }
3175   /* Do strike-through.  We follow other terms for thickness and
3176      vertical position.*/
3177   if (face->strike_through_p)
3178     {
3179       NSRect r;
3180       unsigned long dy;
3182       dy = lrint ((s->height - 1) / 2);
3183       r = NSMakeRect (x, s->y + dy, width, 1);
3185       if (face->strike_through_color_defaulted_p)
3186         [defaultCol set];
3187       else
3188         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3189       NSRectFill (r);
3190     }
3193 static void
3194 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3195              char left_p, char right_p)
3196 /* --------------------------------------------------------------------------
3197     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3198     Note we can't just use an NSDrawRect command, because of the possibility
3199     of some sides not being drawn, and because the rect will be filled.
3200    -------------------------------------------------------------------------- */
3202   NSRect s = r;
3203   [col set];
3205   /* top, bottom */
3206   s.size.height = thickness;
3207   NSRectFill (s);
3208   s.origin.y += r.size.height - thickness;
3209   NSRectFill (s);
3211   s.size.height = r.size.height;
3212   s.origin.y = r.origin.y;
3214   /* left, right (optional) */
3215   s.size.width = thickness;
3216   if (left_p)
3217     NSRectFill (s);
3218   if (right_p)
3219     {
3220       s.origin.x += r.size.width - thickness;
3221       NSRectFill (s);
3222     }
3226 static void
3227 ns_draw_relief (NSRect r, int thickness, char raised_p,
3228                char top_p, char bottom_p, char left_p, char right_p,
3229                struct glyph_string *s)
3230 /* --------------------------------------------------------------------------
3231     Draw a relief rect inside r, optionally leaving some sides open.
3232     Note we can't just use an NSDrawBezel command, because of the possibility
3233     of some sides not being drawn, and because the rect will be filled.
3234    -------------------------------------------------------------------------- */
3236   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3237   NSColor *newBaseCol = nil;
3238   NSRect sr = r;
3240   NSTRACE ("ns_draw_relief");
3242   /* set up colors */
3244   if (s->face->use_box_color_for_shadows_p)
3245     {
3246       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3247     }
3248 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3249            && s->img->pixmap
3250            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3251        {
3252          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3253        } */
3254   else
3255     {
3256       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3257     }
3259   if (newBaseCol == nil)
3260     newBaseCol = [NSColor grayColor];
3262   if (newBaseCol != baseCol)  /* TODO: better check */
3263     {
3264       [baseCol release];
3265       baseCol = [newBaseCol retain];
3266       [lightCol release];
3267       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3268       [darkCol release];
3269       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3270     }
3272   [(raised_p ? lightCol : darkCol) set];
3274   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3276   /* top */
3277   sr.size.height = thickness;
3278   if (top_p) NSRectFill (sr);
3280   /* left */
3281   sr.size.height = r.size.height;
3282   sr.size.width = thickness;
3283   if (left_p) NSRectFill (sr);
3285   [(raised_p ? darkCol : lightCol) set];
3287   /* bottom */
3288   sr.size.width = r.size.width;
3289   sr.size.height = thickness;
3290   sr.origin.y += r.size.height - thickness;
3291   if (bottom_p) NSRectFill (sr);
3293   /* right */
3294   sr.size.height = r.size.height;
3295   sr.origin.y = r.origin.y;
3296   sr.size.width = thickness;
3297   sr.origin.x += r.size.width - thickness;
3298   if (right_p) NSRectFill (sr);
3302 static void
3303 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3304 /* --------------------------------------------------------------------------
3305       Function modeled after x_draw_glyph_string_box ().
3306       Sets up parameters for drawing.
3307    -------------------------------------------------------------------------- */
3309   int right_x, last_x;
3310   char left_p, right_p;
3311   struct glyph *last_glyph;
3312   NSRect r;
3313   int thickness;
3314   struct face *face;
3316   if (s->hl == DRAW_MOUSE_FACE)
3317     {
3318       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3319       if (!face)
3320         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3321     }
3322   else
3323     face = s->face;
3325   thickness = face->box_line_width;
3327   NSTRACE ("ns_dumpglyphs_box_or_relief");
3329   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3330             ? WINDOW_RIGHT_EDGE_X (s->w)
3331             : window_box_right (s->w, s->area));
3332   last_glyph = (s->cmp || s->img
3333                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3335   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3336               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3338   left_p = (s->first_glyph->left_box_line_p
3339             || (s->hl == DRAW_MOUSE_FACE
3340                 && (s->prev == NULL || s->prev->hl != s->hl)));
3341   right_p = (last_glyph->right_box_line_p
3342              || (s->hl == DRAW_MOUSE_FACE
3343                  && (s->next == NULL || s->next->hl != s->hl)));
3345   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3347   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3348   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3349     {
3350       ns_draw_box (r, abs (thickness),
3351                    ns_lookup_indexed_color (face->box_color, s->f),
3352                   left_p, right_p);
3353     }
3354   else
3355     {
3356       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3357                      1, 1, left_p, right_p, s);
3358     }
3362 static void
3363 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3364 /* --------------------------------------------------------------------------
3365       Modeled after x_draw_glyph_string_background, which draws BG in
3366       certain cases.  Others are left to the text rendering routine.
3367    -------------------------------------------------------------------------- */
3369   NSTRACE ("ns_maybe_dumpglyphs_background");
3371   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3372     {
3373       int box_line_width = max (s->face->box_line_width, 0);
3374       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3375           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3376              dimensions, since the actual glyphs might be much
3377              smaller.  So in that case we always clear the rectangle
3378              with background color.  */
3379           || FONT_TOO_HIGH (s->font)
3380           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3381         {
3382           struct face *face;
3383           if (s->hl == DRAW_MOUSE_FACE)
3384             {
3385               face = FACE_FROM_ID (s->f,
3386                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3387               if (!face)
3388                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3389             }
3390           else
3391             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3392           if (!face->stipple)
3393             [(NS_FACE_BACKGROUND (face) != 0
3394               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3395               : FRAME_BACKGROUND_COLOR (s->f)) set];
3396           else
3397             {
3398               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3399               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3400             }
3402           if (s->hl != DRAW_CURSOR)
3403             {
3404               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3405                                     s->background_width,
3406                                     s->height-2*box_line_width);
3407               NSRectFill (r);
3408             }
3410           s->background_filled_p = 1;
3411         }
3412     }
3416 static void
3417 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3418 /* --------------------------------------------------------------------------
3419       Renders an image and associated borders.
3420    -------------------------------------------------------------------------- */
3422   EmacsImage *img = s->img->pixmap;
3423   int box_line_vwidth = max (s->face->box_line_width, 0);
3424   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3425   int bg_x, bg_y, bg_height;
3426   int th;
3427   char raised_p;
3428   NSRect br;
3429   struct face *face;
3430   NSColor *tdCol;
3432   NSTRACE ("ns_dumpglyphs_image");
3434   if (s->face->box != FACE_NO_BOX
3435       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3436     x += abs (s->face->box_line_width);
3438   bg_x = x;
3439   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3440   bg_height = s->height;
3441   /* other terms have this, but was causing problems w/tabbar mode */
3442   /* - 2 * box_line_vwidth; */
3444   if (s->slice.x == 0) x += s->img->hmargin;
3445   if (s->slice.y == 0) y += s->img->vmargin;
3447   /* Draw BG: if we need larger area than image itself cleared, do that,
3448      otherwise, since we composite the image under NS (instead of mucking
3449      with its background color), we must clear just the image area. */
3450   if (s->hl == DRAW_MOUSE_FACE)
3451     {
3452       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3453       if (!face)
3454        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3455     }
3456   else
3457     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3459   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3461   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3462       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3463     {
3464       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3465       s->background_filled_p = 1;
3466     }
3467   else
3468     {
3469       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3470     }
3472   NSRectFill (br);
3474   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3475   if (img != nil)
3476     {
3477 #ifdef NS_IMPL_COCOA
3478       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3479       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3480                               s->slice.width, s->slice.height);
3481       [img drawInRect: dr
3482              fromRect: ir
3483              operation: NSCompositeSourceOver
3484               fraction: 1.0
3485            respectFlipped: YES
3486                 hints: nil];
3487 #else
3488       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3489                   operation: NSCompositeSourceOver];
3490 #endif
3491     }
3493   if (s->hl == DRAW_CURSOR)
3494     {
3495     [FRAME_CURSOR_COLOR (s->f) set];
3496     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3497       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3498     else
3499       /* Currently on NS img->mask is always 0. Since
3500          get_window_cursor_type specifies a hollow box cursor when on
3501          a non-masked image we never reach this clause. But we put it
3502          in in anticipation of better support for image masks on
3503          NS. */
3504       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3505     }
3506   else
3507     {
3508       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3509     }
3511   /* Draw underline, overline, strike-through. */
3512   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3514   /* Draw relief, if requested */
3515   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3516     {
3517       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3518         {
3519           th = tool_bar_button_relief >= 0 ?
3520             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3521           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3522         }
3523       else
3524         {
3525           th = abs (s->img->relief);
3526           raised_p = (s->img->relief > 0);
3527         }
3529       r.origin.x = x - th;
3530       r.origin.y = y - th;
3531       r.size.width = s->slice.width + 2*th-1;
3532       r.size.height = s->slice.height + 2*th-1;
3533       ns_draw_relief (r, th, raised_p,
3534                       s->slice.y == 0,
3535                       s->slice.y + s->slice.height == s->img->height,
3536                       s->slice.x == 0,
3537                       s->slice.x + s->slice.width == s->img->width, s);
3538     }
3540   /* If there is no mask, the background won't be seen,
3541      so draw a rectangle on the image for the cursor.
3542      Do this for all images, getting transparency right is not reliable.  */
3543   if (s->hl == DRAW_CURSOR)
3544     {
3545       int thickness = abs (s->img->relief);
3546       if (thickness == 0) thickness = 1;
3547       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3548     }
3552 static void
3553 ns_dumpglyphs_stretch (struct glyph_string *s)
3555   NSRect r[2];
3556   int n, i;
3557   struct face *face;
3558   NSColor *fgCol, *bgCol;
3560   if (!s->background_filled_p)
3561     {
3562       n = ns_get_glyph_string_clip_rect (s, r);
3563       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3565       ns_focus (s->f, r, n);
3567       if (s->hl == DRAW_MOUSE_FACE)
3568        {
3569          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3570          if (!face)
3571            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3572        }
3573       else
3574        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3576       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3577       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3579       for (i = 0; i < n; ++i)
3580         {
3581           if (!s->row->full_width_p)
3582             {
3583               int overrun, leftoverrun;
3585               /* truncate to avoid overwriting fringe and/or scrollbar */
3586               overrun = max (0, (s->x + s->background_width)
3587                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3588                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3589               r[i].size.width -= overrun;
3591               /* truncate to avoid overwriting to left of the window box */
3592               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3593                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3595               if (leftoverrun > 0)
3596                 {
3597                   r[i].origin.x += leftoverrun;
3598                   r[i].size.width -= leftoverrun;
3599                 }
3601               /* XXX: Try to work between problem where a stretch glyph on
3602                  a partially-visible bottom row will clear part of the
3603                  modeline, and another where list-buffers headers and similar
3604                  rows erroneously have visible_height set to 0.  Not sure
3605                  where this is coming from as other terms seem not to show. */
3606               r[i].size.height = min (s->height, s->row->visible_height);
3607             }
3609           [bgCol set];
3611           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3612              overwriting cursor (usually when cursor on a tab) */
3613           if (s->hl == DRAW_CURSOR)
3614             {
3615               CGFloat x, width;
3617               x = r[i].origin.x;
3618               width = s->w->phys_cursor_width;
3619               r[i].size.width -= width;
3620               r[i].origin.x += width;
3622               NSRectFill (r[i]);
3624               /* Draw overlining, etc. on the cursor. */
3625               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3626                 ns_draw_text_decoration (s, face, bgCol, width, x);
3627               else
3628                 ns_draw_text_decoration (s, face, fgCol, width, x);
3629             }
3630           else
3631             {
3632               NSRectFill (r[i]);
3633             }
3635           /* Draw overlining, etc. on the stretch glyph (or the part
3636              of the stretch glyph after the cursor). */
3637           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3638                                    r[i].origin.x);
3639         }
3640       ns_unfocus (s->f);
3641       s->background_filled_p = 1;
3642     }
3646 static void
3647 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3649   int i, j, x;
3650   struct font *font = s->font;
3652   /* If first glyph of S has a left box line, start drawing the text
3653      of S to the right of that box line.  */
3654   if (s->face && s->face->box != FACE_NO_BOX
3655       && s->first_glyph->left_box_line_p)
3656     x = s->x + eabs (s->face->box_line_width);
3657   else
3658     x = s->x;
3660   /* S is a glyph string for a composition.  S->cmp_from is the index
3661      of the first character drawn for glyphs of this composition.
3662      S->cmp_from == 0 means we are drawing the very first character of
3663      this composition.  */
3665   /* Draw a rectangle for the composition if the font for the very
3666      first character of the composition could not be loaded.  */
3667   if (s->font_not_found_p)
3668     {
3669       if (s->cmp_from == 0)
3670         {
3671           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3672           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3673         }
3674     }
3675   else if (! s->first_glyph->u.cmp.automatic)
3676     {
3677       int y = s->ybase;
3679       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3680         /* TAB in a composition means display glyphs with padding
3681            space on the left or right.  */
3682         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3683           {
3684             int xx = x + s->cmp->offsets[j * 2];
3685             int yy = y - s->cmp->offsets[j * 2 + 1];
3687             font->driver->draw (s, j, j + 1, xx, yy, false);
3688             if (s->face->overstrike)
3689               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3690           }
3691     }
3692   else
3693     {
3694       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3695       Lisp_Object glyph;
3696       int y = s->ybase;
3697       int width = 0;
3699       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3700         {
3701           glyph = LGSTRING_GLYPH (gstring, i);
3702           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3703             width += LGLYPH_WIDTH (glyph);
3704           else
3705             {
3706               int xoff, yoff, wadjust;
3708               if (j < i)
3709                 {
3710                   font->driver->draw (s, j, i, x, y, false);
3711                   if (s->face->overstrike)
3712                     font->driver->draw (s, j, i, x + 1, y, false);
3713                   x += width;
3714                 }
3715               xoff = LGLYPH_XOFF (glyph);
3716               yoff = LGLYPH_YOFF (glyph);
3717               wadjust = LGLYPH_WADJUST (glyph);
3718               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3719               if (s->face->overstrike)
3720                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3721                                     false);
3722               x += wadjust;
3723               j = i + 1;
3724               width = 0;
3725             }
3726         }
3727       if (j < i)
3728         {
3729           font->driver->draw (s, j, i, x, y, false);
3730           if (s->face->overstrike)
3731             font->driver->draw (s, j, i, x + 1, y, false);
3732         }
3733     }
3736 static void
3737 ns_draw_glyph_string (struct glyph_string *s)
3738 /* --------------------------------------------------------------------------
3739       External (RIF): Main draw-text call.
3740    -------------------------------------------------------------------------- */
3742   /* TODO (optimize): focus for box and contents draw */
3743   NSRect r[2];
3744   int n, flags;
3745   char box_drawn_p = 0;
3746   struct font *font = s->face->font;
3747   if (! font) font = FRAME_FONT (s->f);
3749   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3751   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3752     {
3753       int width;
3754       struct glyph_string *next;
3756       for (width = 0, next = s->next;
3757            next && width < s->right_overhang;
3758            width += next->width, next = next->next)
3759         if (next->first_glyph->type != IMAGE_GLYPH)
3760           {
3761             if (next->first_glyph->type != STRETCH_GLYPH)
3762               {
3763                 n = ns_get_glyph_string_clip_rect (s->next, r);
3764                 ns_focus (s->f, r, n);
3765                 ns_maybe_dumpglyphs_background (s->next, 1);
3766                 ns_unfocus (s->f);
3767               }
3768             else
3769               {
3770                 ns_dumpglyphs_stretch (s->next);
3771               }
3772             next->num_clips = 0;
3773           }
3774     }
3776   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3777         && (s->first_glyph->type == CHAR_GLYPH
3778             || s->first_glyph->type == COMPOSITE_GLYPH))
3779     {
3780       n = ns_get_glyph_string_clip_rect (s, r);
3781       ns_focus (s->f, r, n);
3782       ns_maybe_dumpglyphs_background (s, 1);
3783       ns_dumpglyphs_box_or_relief (s);
3784       ns_unfocus (s->f);
3785       box_drawn_p = 1;
3786     }
3788   switch (s->first_glyph->type)
3789     {
3791     case IMAGE_GLYPH:
3792       n = ns_get_glyph_string_clip_rect (s, r);
3793       ns_focus (s->f, r, n);
3794       ns_dumpglyphs_image (s, r[0]);
3795       ns_unfocus (s->f);
3796       break;
3798     case STRETCH_GLYPH:
3799       ns_dumpglyphs_stretch (s);
3800       break;
3802     case CHAR_GLYPH:
3803     case COMPOSITE_GLYPH:
3804       n = ns_get_glyph_string_clip_rect (s, r);
3805       ns_focus (s->f, r, n);
3807       if (s->for_overlaps || (s->cmp_from > 0
3808                               && ! s->first_glyph->u.cmp.automatic))
3809         s->background_filled_p = 1;
3810       else
3811         ns_maybe_dumpglyphs_background
3812           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3814       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3815         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3816          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3817           NS_DUMPGLYPH_NORMAL));
3819       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3820         {
3821           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3822           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3823           NS_FACE_FOREGROUND (s->face) = tmp;
3824         }
3826       {
3827         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3829         if (isComposite)
3830           ns_draw_composite_glyph_string_foreground (s);
3831         else
3832           font->driver->draw
3833             (s, s->cmp_from, s->nchars, s->x, s->ybase,
3834              (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3835              || flags == NS_DUMPGLYPH_MOUSEFACE);
3836       }
3838       {
3839         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3840                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3841                                                    s->f)
3842                         : FRAME_FOREGROUND_COLOR (s->f));
3843         [col set];
3845         /* Draw underline, overline, strike-through. */
3846         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3847       }
3849       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3850         {
3851           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3852           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3853           NS_FACE_FOREGROUND (s->face) = tmp;
3854         }
3856       ns_unfocus (s->f);
3857       break;
3859     case GLYPHLESS_GLYPH:
3860       n = ns_get_glyph_string_clip_rect (s, r);
3861       ns_focus (s->f, r, n);
3863       if (s->for_overlaps || (s->cmp_from > 0
3864                               && ! s->first_glyph->u.cmp.automatic))
3865         s->background_filled_p = 1;
3866       else
3867         ns_maybe_dumpglyphs_background
3868           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3869       /* ... */
3870       /* Not yet implemented.  */
3871       /* ... */
3872       ns_unfocus (s->f);
3873       break;
3875     default:
3876       emacs_abort ();
3877     }
3879   /* Draw box if not done already. */
3880   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3881     {
3882       n = ns_get_glyph_string_clip_rect (s, r);
3883       ns_focus (s->f, r, n);
3884       ns_dumpglyphs_box_or_relief (s);
3885       ns_unfocus (s->f);
3886     }
3888   s->num_clips = 0;
3893 /* ==========================================================================
3895     Event loop
3897    ========================================================================== */
3900 static void
3901 ns_send_appdefined (int value)
3902 /* --------------------------------------------------------------------------
3903     Internal: post an appdefined event which EmacsApp-sendEvent will
3904               recognize and take as a command to halt the event loop.
3905    -------------------------------------------------------------------------- */
3907   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
3909 #ifdef NS_IMPL_GNUSTEP
3910   // GNUstep needs postEvent to happen on the main thread.
3911   if (! [[NSThread currentThread] isMainThread])
3912     {
3913       EmacsApp *app = (EmacsApp *)NSApp;
3914       app->nextappdefined = value;
3915       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3916                             withObject:nil
3917                          waitUntilDone:YES];
3918       return;
3919     }
3920 #endif
3922   /* Only post this event if we haven't already posted one.  This will end
3923        the [NXApp run] main loop after having processed all events queued at
3924        this moment.  */
3926 #ifdef NS_IMPL_COCOA
3927   if (! send_appdefined)
3928     {
3929       /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3930          in certain situations (rapid incoming events).
3931          So check if we have one, if not add one.  */
3932       NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3933                                           untilDate:[NSDate distantPast]
3934                                              inMode:NSDefaultRunLoopMode
3935                                             dequeue:NO];
3936       if (! appev) send_appdefined = YES;
3937     }
3938 #endif
3940   if (send_appdefined)
3941     {
3942       NSEvent *nxev;
3944       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3945       send_appdefined = NO;
3947       /* Don't need wakeup timer any more */
3948       if (timed_entry)
3949         {
3950           [timed_entry invalidate];
3951           [timed_entry release];
3952           timed_entry = nil;
3953         }
3955       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3956                                 location: NSMakePoint (0, 0)
3957                            modifierFlags: 0
3958                                timestamp: 0
3959                             windowNumber: [[NSApp mainWindow] windowNumber]
3960                                  context: [NSApp context]
3961                                  subtype: 0
3962                                    data1: value
3963                                    data2: 0];
3965       /* Post an application defined event on the event queue.  When this is
3966          received the [NXApp run] will return, thus having processed all
3967          events which are currently queued.  */
3968       [NSApp postEvent: nxev atStart: NO];
3969     }
3972 #ifdef HAVE_NATIVE_FS
3973 static void
3974 check_native_fs ()
3976   Lisp_Object frame, tail;
3978   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3979     return;
3981   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3983   FOR_EACH_FRAME (tail, frame)
3984     {
3985       struct frame *f = XFRAME (frame);
3986       if (FRAME_NS_P (f))
3987         {
3988           EmacsView *view = FRAME_NS_VIEW (f);
3989           [view updateCollectionBehavior];
3990         }
3991     }
3993 #endif
3995 /* GNUstep does not have cancelTracking.  */
3996 #ifdef NS_IMPL_COCOA
3997 /* Check if menu open should be canceled or continued as normal.  */
3998 void
3999 ns_check_menu_open (NSMenu *menu)
4001   /* Click in menu bar? */
4002   NSArray *a = [[NSApp mainMenu] itemArray];
4003   int i;
4004   BOOL found = NO;
4006   if (menu == nil) // Menu tracking ended.
4007     {
4008       if (menu_will_open_state == MENU_OPENING)
4009         menu_will_open_state = MENU_NONE;
4010       return;
4011     }
4013   for (i = 0; ! found && i < [a count]; i++)
4014     found = menu == [[a objectAtIndex:i] submenu];
4015   if (found)
4016     {
4017       if (menu_will_open_state == MENU_NONE && emacs_event)
4018         {
4019           NSEvent *theEvent = [NSApp currentEvent];
4020           struct frame *emacsframe = SELECTED_FRAME ();
4022           [menu cancelTracking];
4023           menu_will_open_state = MENU_PENDING;
4024           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
4025           EV_TRAILER (theEvent);
4027           CGEventRef ourEvent = CGEventCreate (NULL);
4028           menu_mouse_point = CGEventGetLocation (ourEvent);
4029           CFRelease (ourEvent);
4030         }
4031       else if (menu_will_open_state == MENU_OPENING)
4032         {
4033           menu_will_open_state = MENU_NONE;
4034         }
4035     }
4038 /* Redo saved menu click if state is MENU_PENDING.  */
4039 void
4040 ns_check_pending_open_menu ()
4042   if (menu_will_open_state == MENU_PENDING)
4043     {
4044       CGEventSourceRef source
4045         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
4047       CGEventRef event = CGEventCreateMouseEvent (source,
4048                                                   kCGEventLeftMouseDown,
4049                                                   menu_mouse_point,
4050                                                   kCGMouseButtonLeft);
4051       CGEventSetType (event, kCGEventLeftMouseDown);
4052       CGEventPost (kCGHIDEventTap, event);
4053       CFRelease (event);
4054       CFRelease (source);
4056       menu_will_open_state = MENU_OPENING;
4057     }
4059 #endif /* NS_IMPL_COCOA */
4061 static void
4062 unwind_apploopnr (Lisp_Object not_used)
4064   --apploopnr;
4065   n_emacs_events_pending = 0;
4066   ns_finish_events ();
4067   q_event_ptr = NULL;
4070 static int
4071 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
4072 /* --------------------------------------------------------------------------
4073      External (hook): Post an event to ourself and keep reading events until
4074      we read it back again.  In effect process all events which were waiting.
4075      From 21+ we have to manage the event buffer ourselves.
4076    -------------------------------------------------------------------------- */
4078   struct input_event ev;
4079   int nevents;
4081   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
4083 #ifdef HAVE_NATIVE_FS
4084   check_native_fs ();
4085 #endif
4087   if ([NSApp modalWindow] != nil)
4088     return -1;
4090   if (hold_event_q.nr > 0)
4091     {
4092       int i;
4093       for (i = 0; i < hold_event_q.nr; ++i)
4094         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
4095       hold_event_q.nr = 0;
4096       return i;
4097     }
4099   block_input ();
4100   n_emacs_events_pending = 0;
4101   ns_init_events (&ev);
4102   q_event_ptr = hold_quit;
4104   /* we manage autorelease pools by allocate/reallocate each time around
4105      the loop; strict nesting is occasionally violated but seems not to
4106      matter.. earlier methods using full nesting caused major memory leaks */
4107   [outerpool release];
4108   outerpool = [[NSAutoreleasePool alloc] init];
4110   /* If have pending open-file requests, attend to the next one of those. */
4111   if (ns_pending_files && [ns_pending_files count] != 0
4112       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
4113     {
4114       [ns_pending_files removeObjectAtIndex: 0];
4115     }
4116   /* Deal with pending service requests. */
4117   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
4118     && [(EmacsApp *)
4119          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
4120                       withArg: [ns_pending_service_args objectAtIndex: 0]])
4121     {
4122       [ns_pending_service_names removeObjectAtIndex: 0];
4123       [ns_pending_service_args removeObjectAtIndex: 0];
4124     }
4125   else
4126     {
4127       ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4128       /* Run and wait for events.  We must always send one NX_APPDEFINED event
4129          to ourself, otherwise [NXApp run] will never exit.  */
4130       send_appdefined = YES;
4131       ns_send_appdefined (-1);
4133       if (++apploopnr != 1)
4134         {
4135           emacs_abort ();
4136         }
4137       record_unwind_protect (unwind_apploopnr, Qt);
4138       [NSApp run];
4139       unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
4140     }
4142   nevents = n_emacs_events_pending;
4143   n_emacs_events_pending = 0;
4144   ns_finish_events ();
4145   q_event_ptr = NULL;
4146   unblock_input ();
4148   return nevents;
4153 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
4154            fd_set *exceptfds, struct timespec const *timeout,
4155            sigset_t const *sigmask)
4156 /* --------------------------------------------------------------------------
4157      Replacement for select, checking for events
4158    -------------------------------------------------------------------------- */
4160   int result;
4161   int t, k, nr = 0;
4162   struct input_event event;
4163   char c;
4165   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
4167 #ifdef HAVE_NATIVE_FS
4168   check_native_fs ();
4169 #endif
4171   if (hold_event_q.nr > 0)
4172     {
4173       /* We already have events pending. */
4174       raise (SIGIO);
4175       errno = EINTR;
4176       return -1;
4177     }
4179   for (k = 0; k < nfds+1; k++)
4180     {
4181       if (readfds && FD_ISSET(k, readfds)) ++nr;
4182       if (writefds && FD_ISSET(k, writefds)) ++nr;
4183     }
4185   if (NSApp == nil
4186       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4187     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
4189   [outerpool release];
4190   outerpool = [[NSAutoreleasePool alloc] init];
4193   send_appdefined = YES;
4194   if (nr > 0)
4195     {
4196       pthread_mutex_lock (&select_mutex);
4197       select_nfds = nfds;
4198       select_valid = 0;
4199       if (readfds)
4200         {
4201           select_readfds = *readfds;
4202           select_valid += SELECT_HAVE_READ;
4203         }
4204       if (writefds)
4205         {
4206           select_writefds = *writefds;
4207           select_valid += SELECT_HAVE_WRITE;
4208         }
4210       if (timeout)
4211         {
4212           select_timeout = *timeout;
4213           select_valid += SELECT_HAVE_TMO;
4214         }
4216       pthread_mutex_unlock (&select_mutex);
4218       /* Inform fd_handler that select should be called */
4219       c = 'g';
4220       emacs_write_sig (selfds[1], &c, 1);
4221     }
4222   else if (nr == 0 && timeout)
4223     {
4224       /* No file descriptor, just a timeout, no need to wake fd_handler  */
4225       double time = timespectod (*timeout);
4226       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4227                                                       target: NSApp
4228                                                     selector:
4229                                   @selector (timeout_handler:)
4230                                                     userInfo: 0
4231                                                      repeats: NO]
4232                       retain];
4233     }
4234   else /* No timeout and no file descriptors, can this happen?  */
4235     {
4236       /* Send appdefined so we exit from the loop */
4237       ns_send_appdefined (-1);
4238     }
4240   block_input ();
4241   ns_init_events (&event);
4242   if (++apploopnr != 1)
4243     {
4244       emacs_abort ();
4245     }
4247   {
4248     ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4249     record_unwind_protect (unwind_apploopnr, Qt);
4250     [NSApp run];
4251     unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
4252   }
4254   ns_finish_events ();
4255   if (nr > 0 && readfds)
4256     {
4257       c = 's';
4258       emacs_write_sig (selfds[1], &c, 1);
4259     }
4260   unblock_input ();
4262   t = last_appdefined_event_data;
4264   if (t != NO_APPDEFINED_DATA)
4265     {
4266       last_appdefined_event_data = NO_APPDEFINED_DATA;
4268       if (t == -2)
4269         {
4270           /* The NX_APPDEFINED event we received was a timeout. */
4271           result = 0;
4272         }
4273       else if (t == -1)
4274         {
4275           /* The NX_APPDEFINED event we received was the result of
4276              at least one real input event arriving.  */
4277           errno = EINTR;
4278           result = -1;
4279         }
4280       else
4281         {
4282           /* Received back from select () in fd_handler; copy the results */
4283           pthread_mutex_lock (&select_mutex);
4284           if (readfds) *readfds = select_readfds;
4285           if (writefds) *writefds = select_writefds;
4286           pthread_mutex_unlock (&select_mutex);
4287           result = t;
4288         }
4289     }
4290   else
4291     {
4292       errno = EINTR;
4293       result = -1;
4294     }
4296   return result;
4301 /* ==========================================================================
4303     Scrollbar handling
4305    ========================================================================== */
4308 static void
4309 ns_set_vertical_scroll_bar (struct window *window,
4310                            int portion, int whole, int position)
4311 /* --------------------------------------------------------------------------
4312       External (hook): Update or add scrollbar
4313    -------------------------------------------------------------------------- */
4315   Lisp_Object win;
4316   NSRect r, v;
4317   struct frame *f = XFRAME (WINDOW_FRAME (window));
4318   EmacsView *view = FRAME_NS_VIEW (f);
4319   EmacsScroller *bar;
4320   int window_y, window_height;
4321   int top, left, height, width;
4322   BOOL update_p = YES;
4324   /* optimization; display engine sends WAY too many of these.. */
4325   if (!NILP (window->vertical_scroll_bar))
4326     {
4327       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4328       if ([bar checkSamePosition: position portion: portion whole: whole])
4329         {
4330           if (view->scrollbarsNeedingUpdate == 0)
4331             {
4332               if (!windows_or_buffers_changed)
4333                   return;
4334             }
4335           else
4336             view->scrollbarsNeedingUpdate--;
4337           update_p = NO;
4338         }
4339     }
4341   NSTRACE ("ns_set_vertical_scroll_bar");
4343   /* Get dimensions.  */
4344   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4345   top = window_y;
4346   height = window_height;
4347   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
4348   left = WINDOW_SCROLL_BAR_AREA_X (window);
4350   r = NSMakeRect (left, top, width, height);
4351   /* the parent view is flipped, so we need to flip y value */
4352   v = [view frame];
4353   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4355   XSETWINDOW (win, window);
4356   block_input ();
4358   /* we want at least 5 lines to display a scrollbar */
4359   if (WINDOW_TOTAL_LINES (window) < 5)
4360     {
4361       if (!NILP (window->vertical_scroll_bar))
4362         {
4363           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4364           [bar removeFromSuperview];
4365           wset_vertical_scroll_bar (window, Qnil);
4366           [bar release];
4367         }
4368       ns_clear_frame_area (f, left, top, width, height);
4369       unblock_input ();
4370       return;
4371     }
4373   if (NILP (window->vertical_scroll_bar))
4374     {
4375       if (width > 0 && height > 0)
4376         ns_clear_frame_area (f, left, top, width, height);
4378       bar = [[EmacsScroller alloc] initFrame: r window: win];
4379       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4380       update_p = YES;
4381     }
4382   else
4383     {
4384       NSRect oldRect;
4385       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4386       oldRect = [bar frame];
4387       r.size.width = oldRect.size.width;
4388       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4389         {
4390           if (oldRect.origin.x != r.origin.x)
4391               ns_clear_frame_area (f, left, top, width, height);
4392           [bar setFrame: r];
4393         }
4394     }
4396   if (update_p)
4397     [bar setPosition: position portion: portion whole: whole];
4398   unblock_input ();
4402 static void
4403 ns_set_horizontal_scroll_bar (struct window *window,
4404                               int portion, int whole, int position)
4405 /* --------------------------------------------------------------------------
4406       External (hook): Update or add scrollbar
4407    -------------------------------------------------------------------------- */
4409   Lisp_Object win;
4410   NSRect r, v;
4411   struct frame *f = XFRAME (WINDOW_FRAME (window));
4412   EmacsView *view = FRAME_NS_VIEW (f);
4413   EmacsScroller *bar;
4414   int top, height, left, width;
4415   int window_x, window_width;
4416   BOOL update_p = YES;
4418   /* optimization; display engine sends WAY too many of these.. */
4419   if (!NILP (window->horizontal_scroll_bar))
4420     {
4421       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4422       if ([bar checkSamePosition: position portion: portion whole: whole])
4423         {
4424           if (view->scrollbarsNeedingUpdate == 0)
4425             {
4426               if (!windows_or_buffers_changed)
4427                   return;
4428             }
4429           else
4430             view->scrollbarsNeedingUpdate--;
4431           update_p = NO;
4432         }
4433     }
4435   NSTRACE ("ns_set_horizontal_scroll_bar");
4437   /* Get dimensions.  */
4438   window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
4439   left = window_x;
4440   width = window_width;
4441   height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
4442   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4444   r = NSMakeRect (left, top, width, height);
4445   /* the parent view is flipped, so we need to flip y value */
4446   v = [view frame];
4447   /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
4448   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4450   XSETWINDOW (win, window);
4451   block_input ();
4453   if (WINDOW_TOTAL_COLS (window) < 5)
4454     {
4455       if (!NILP (window->horizontal_scroll_bar))
4456         {
4457           bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4458           [bar removeFromSuperview];
4459           wset_horizontal_scroll_bar (window, Qnil);
4460         }
4461       ns_clear_frame_area (f, left, top, width, height);
4462       unblock_input ();
4463       return;
4464     }
4466   if (NILP (window->horizontal_scroll_bar))
4467     {
4468       if (width > 0 && height > 0)
4469         ns_clear_frame_area (f, left, top, width, height);
4471       bar = [[EmacsScroller alloc] initFrame: r window: win];
4472       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4473       update_p = YES;
4474     }
4475   else
4476     {
4477       NSRect oldRect;
4478       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4479       oldRect = [bar frame];
4480       r.size.width = oldRect.size.width;
4481       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4482         {
4483           if (oldRect.origin.x != r.origin.x)
4484               ns_clear_frame_area (f, left, top, width, height);
4485           [bar setFrame: r];
4486           update_p = YES;
4487         }
4488     }
4490   if (update_p)
4491     [bar setPosition: position portion: portion whole: whole];
4492   unblock_input ();
4496 static void
4497 ns_condemn_scroll_bars (struct frame *f)
4498 /* --------------------------------------------------------------------------
4499      External (hook): arrange for all frame's scrollbars to be removed
4500      at next call to judge_scroll_bars, except for those redeemed.
4501    -------------------------------------------------------------------------- */
4503   int i;
4504   id view;
4505   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4507   NSTRACE ("ns_condemn_scroll_bars");
4509   for (i =[subviews count]-1; i >= 0; i--)
4510     {
4511       view = [subviews objectAtIndex: i];
4512       if ([view isKindOfClass: [EmacsScroller class]])
4513         [view condemn];
4514     }
4518 static void
4519 ns_redeem_scroll_bar (struct window *window)
4520 /* --------------------------------------------------------------------------
4521      External (hook): arrange to spare this window's scrollbar
4522      at next call to judge_scroll_bars.
4523    -------------------------------------------------------------------------- */
4525   id bar;
4526   NSTRACE ("ns_redeem_scroll_bar");
4527   if (!NILP (window->vertical_scroll_bar))
4528     {
4529       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4530       [bar reprieve];
4531     }
4533   if (!NILP (window->horizontal_scroll_bar))
4534     {
4535       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4536       [bar reprieve];
4537     }
4541 static void
4542 ns_judge_scroll_bars (struct frame *f)
4543 /* --------------------------------------------------------------------------
4544      External (hook): destroy all scrollbars on frame that weren't
4545      redeemed after call to condemn_scroll_bars.
4546    -------------------------------------------------------------------------- */
4548   int i;
4549   id view;
4550   EmacsView *eview = FRAME_NS_VIEW (f);
4551   NSArray *subviews = [[eview superview] subviews];
4552   BOOL removed = NO;
4554   NSTRACE ("ns_judge_scroll_bars");
4555   for (i = [subviews count]-1; i >= 0; --i)
4556     {
4557       view = [subviews objectAtIndex: i];
4558       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4559       if ([view judge])
4560         removed = YES;
4561     }
4563   if (removed)
4564     [eview updateFrameSize: NO];
4567 /* ==========================================================================
4569     Initialization
4571    ========================================================================== */
4574 x_display_pixel_height (struct ns_display_info *dpyinfo)
4576   NSArray *screens = [NSScreen screens];
4577   NSEnumerator *enumerator = [screens objectEnumerator];
4578   NSScreen *screen;
4579   NSRect frame;
4581   frame = NSZeroRect;
4582   while ((screen = [enumerator nextObject]) != nil)
4583     frame = NSUnionRect (frame, [screen frame]);
4585   return NSHeight (frame);
4589 x_display_pixel_width (struct ns_display_info *dpyinfo)
4591   NSArray *screens = [NSScreen screens];
4592   NSEnumerator *enumerator = [screens objectEnumerator];
4593   NSScreen *screen;
4594   NSRect frame;
4596   frame = NSZeroRect;
4597   while ((screen = [enumerator nextObject]) != nil)
4598     frame = NSUnionRect (frame, [screen frame]);
4600   return NSWidth (frame);
4604 static Lisp_Object ns_string_to_lispmod (const char *s)
4605 /* --------------------------------------------------------------------------
4606      Convert modifier name to lisp symbol
4607    -------------------------------------------------------------------------- */
4609   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4610     return Qmeta;
4611   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4612     return Qsuper;
4613   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4614     return Qcontrol;
4615   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4616     return Qalt;
4617   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4618     return Qhyper;
4619   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4620     return Qnone;
4621   else
4622     return Qnil;
4626 static void
4627 ns_default (const char *parameter, Lisp_Object *result,
4628            Lisp_Object yesval, Lisp_Object noval,
4629            BOOL is_float, BOOL is_modstring)
4630 /* --------------------------------------------------------------------------
4631       Check a parameter value in user's preferences
4632    -------------------------------------------------------------------------- */
4634   const char *value = ns_get_defaults_value (parameter);
4636   if (value)
4637     {
4638       double f;
4639       char *pos;
4640       if (c_strcasecmp (value, "YES") == 0)
4641         *result = yesval;
4642       else if (c_strcasecmp (value, "NO") == 0)
4643         *result = noval;
4644       else if (is_float && (f = strtod (value, &pos), pos != value))
4645         *result = make_float (f);
4646       else if (is_modstring && value)
4647         *result = ns_string_to_lispmod (value);
4648       else fprintf (stderr,
4649                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4650     }
4654 static void
4655 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4656 /* --------------------------------------------------------------------------
4657       Initialize global info and storage for display.
4658    -------------------------------------------------------------------------- */
4660     NSScreen *screen = [NSScreen mainScreen];
4661     NSWindowDepth depth = [screen depth];
4663     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4664     dpyinfo->resy = 72.27;
4665     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4666                                                   NSColorSpaceFromDepth (depth)]
4667                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4668                                                  NSColorSpaceFromDepth (depth)];
4669     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4670     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4671     dpyinfo->color_table->colors = NULL;
4672     dpyinfo->root_window = 42; /* a placeholder.. */
4673     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4674     dpyinfo->n_fonts = 0;
4675     dpyinfo->smallest_font_height = 1;
4676     dpyinfo->smallest_char_width = 1;
4678     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4682 /* This and next define (many of the) public functions in this file. */
4683 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4684          with using despite presence in the "system dependent" redisplay
4685          interface.  In addition, many of the ns_ methods have code that is
4686          shared with all terms, indicating need for further refactoring. */
4687 extern frame_parm_handler ns_frame_parm_handlers[];
4688 static struct redisplay_interface ns_redisplay_interface =
4690   ns_frame_parm_handlers,
4691   x_produce_glyphs,
4692   x_write_glyphs,
4693   x_insert_glyphs,
4694   x_clear_end_of_line,
4695   ns_scroll_run,
4696   ns_after_update_window_line,
4697   ns_update_window_begin,
4698   ns_update_window_end,
4699   0, /* flush_display */
4700   x_clear_window_mouse_face,
4701   x_get_glyph_overhangs,
4702   x_fix_overlapping_area,
4703   ns_draw_fringe_bitmap,
4704   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4705   0, /* destroy_fringe_bitmap */
4706   ns_compute_glyph_string_overhangs,
4707   ns_draw_glyph_string,
4708   ns_define_frame_cursor,
4709   ns_clear_frame_area,
4710   ns_draw_window_cursor,
4711   ns_draw_vertical_window_border,
4712   ns_draw_window_divider,
4713   ns_shift_glyphs_for_insert,
4714   ns_show_hourglass,
4715   ns_hide_hourglass
4719 static void
4720 ns_delete_display (struct ns_display_info *dpyinfo)
4722   /* TODO... */
4726 /* This function is called when the last frame on a display is deleted. */
4727 static void
4728 ns_delete_terminal (struct terminal *terminal)
4730   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4732   NSTRACE ("ns_delete_terminal");
4734   /* Protect against recursive calls.  delete_frame in
4735      delete_terminal calls us back when it deletes our last frame.  */
4736   if (!terminal->name)
4737     return;
4739   block_input ();
4741   x_destroy_all_bitmaps (dpyinfo);
4742   ns_delete_display (dpyinfo);
4743   unblock_input ();
4747 static struct terminal *
4748 ns_create_terminal (struct ns_display_info *dpyinfo)
4749 /* --------------------------------------------------------------------------
4750       Set up use of NS before we make the first connection.
4751    -------------------------------------------------------------------------- */
4753   struct terminal *terminal;
4755   NSTRACE ("ns_create_terminal");
4757   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4759   terminal->display_info.ns = dpyinfo;
4760   dpyinfo->terminal = terminal;
4762   terminal->clear_frame_hook = ns_clear_frame;
4763   terminal->ring_bell_hook = ns_ring_bell;
4764   terminal->update_begin_hook = ns_update_begin;
4765   terminal->update_end_hook = ns_update_end;
4766   terminal->read_socket_hook = ns_read_socket;
4767   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4768   terminal->mouse_position_hook = ns_mouse_position;
4769   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4770   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4771   terminal->fullscreen_hook = ns_fullscreen_hook;
4772   terminal->menu_show_hook = ns_menu_show;
4773   terminal->popup_dialog_hook = ns_popup_dialog;
4774   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4775   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4776   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4777   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4778   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4779   terminal->delete_frame_hook = x_destroy_window;
4780   terminal->delete_terminal_hook = ns_delete_terminal;
4781   /* Other hooks are NULL by default.  */
4783   return terminal;
4787 struct ns_display_info *
4788 ns_term_init (Lisp_Object display_name)
4789 /* --------------------------------------------------------------------------
4790      Start the Application and get things rolling.
4791    -------------------------------------------------------------------------- */
4793   struct terminal *terminal;
4794   struct ns_display_info *dpyinfo;
4795   static int ns_initialized = 0;
4796   Lisp_Object tmp;
4798   if (ns_initialized) return x_display_list;
4799   ns_initialized = 1;
4801   block_input ();
4803   NSTRACE ("ns_term_init");
4805   [outerpool release];
4806   outerpool = [[NSAutoreleasePool alloc] init];
4808   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4809   /*GSDebugAllocationActive (YES); */
4810   block_input ();
4812   baud_rate = 38400;
4813   Fset_input_interrupt_mode (Qnil);
4815   if (selfds[0] == -1)
4816     {
4817       if (emacs_pipe (selfds) != 0)
4818         {
4819           fprintf (stderr, "Failed to create pipe: %s\n",
4820                    emacs_strerror (errno));
4821           emacs_abort ();
4822         }
4824       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4825       FD_ZERO (&select_readfds);
4826       FD_ZERO (&select_writefds);
4827       pthread_mutex_init (&select_mutex, NULL);
4828     }
4830   ns_pending_files = [[NSMutableArray alloc] init];
4831   ns_pending_service_names = [[NSMutableArray alloc] init];
4832   ns_pending_service_args = [[NSMutableArray alloc] init];
4834 /* Start app and create the main menu, window, view.
4835      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4836      The view will then ask the NSApp to stop and return to Emacs. */
4837   [EmacsApp sharedApplication];
4838   if (NSApp == nil)
4839     return NULL;
4840   [NSApp setDelegate: NSApp];
4842   /* Start the select thread.  */
4843   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4844                            toTarget:NSApp
4845                          withObject:nil];
4847   /* debugging: log all notifications */
4848   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4849                                          selector: @selector (logNotification:)
4850                                              name: nil object: nil]; */
4852   dpyinfo = xzalloc (sizeof *dpyinfo);
4854   ns_initialize_display_info (dpyinfo);
4855   terminal = ns_create_terminal (dpyinfo);
4857   terminal->kboard = allocate_kboard (Qns);
4858   /* Don't let the initial kboard remain current longer than necessary.
4859      That would cause problems if a file loaded on startup tries to
4860      prompt in the mini-buffer.  */
4861   if (current_kboard == initial_kboard)
4862     current_kboard = terminal->kboard;
4863   terminal->kboard->reference_count++;
4865   dpyinfo->next = x_display_list;
4866   x_display_list = dpyinfo;
4868   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4870   terminal->name = xlispstrdup (display_name);
4872   unblock_input ();
4874   if (!inhibit_x_resources)
4875     {
4876       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4877                  Qt, Qnil, NO, NO);
4878       tmp = Qnil;
4879       /* this is a standard variable */
4880       ns_default ("AppleAntiAliasingThreshold", &tmp,
4881                  make_float (10.0), make_float (6.0), YES, NO);
4882       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4883     }
4885   NSTRACE_MSG ("Colors");
4887   {
4888     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4890     if ( cl == nil )
4891       {
4892         Lisp_Object color_file, color_map, color;
4893         unsigned long c;
4894         char *name;
4896         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4897                          Fsymbol_value (intern ("data-directory")));
4899         color_map = Fx_load_color_file (color_file);
4900         if (NILP (color_map))
4901           fatal ("Could not read %s.\n", SDATA (color_file));
4903         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4904         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4905           {
4906             color = XCAR (color_map);
4907             name = SSDATA (XCAR (color));
4908             c = XINT (XCDR (color));
4909             [cl setColor:
4910                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4911                                       green: GREEN_FROM_ULONG (c) / 255.0
4912                                        blue: BLUE_FROM_ULONG (c) / 255.0
4913                                       alpha: 1.0]
4914                   forKey: [NSString stringWithUTF8String: name]];
4915           }
4916         [cl writeToFile: nil];
4917       }
4918   }
4920   NSTRACE_MSG ("Versions");
4922   {
4923 #ifdef NS_IMPL_GNUSTEP
4924     Vwindow_system_version = build_string (gnustep_base_version);
4925 #else
4926     /*PSnextrelease (128, c); */
4927     char c[DBL_BUFSIZE_BOUND];
4928     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4929     Vwindow_system_version = make_unibyte_string (c, len);
4930 #endif
4931   }
4933   delete_keyboard_wait_descriptor (0);
4935   ns_app_name = [[NSProcessInfo processInfo] processName];
4937   /* Set up OS X app menu */
4939   NSTRACE_MSG ("Menu init");
4941 #ifdef NS_IMPL_COCOA
4942   {
4943     NSMenu *appMenu;
4944     NSMenuItem *item;
4945     /* set up the application menu */
4946     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4947     [svcsMenu setAutoenablesItems: NO];
4948     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4949     [appMenu setAutoenablesItems: NO];
4950     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4951     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4953     [appMenu insertItemWithTitle: @"About Emacs"
4954                           action: @selector (orderFrontStandardAboutPanel:)
4955                    keyEquivalent: @""
4956                          atIndex: 0];
4957     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4958     [appMenu insertItemWithTitle: @"Preferences..."
4959                           action: @selector (showPreferencesWindow:)
4960                    keyEquivalent: @","
4961                          atIndex: 2];
4962     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4963     item = [appMenu insertItemWithTitle: @"Services"
4964                                  action: @selector (menuDown:)
4965                           keyEquivalent: @""
4966                                 atIndex: 4];
4967     [appMenu setSubmenu: svcsMenu forItem: item];
4968     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4969     [appMenu insertItemWithTitle: @"Hide Emacs"
4970                           action: @selector (hide:)
4971                    keyEquivalent: @"h"
4972                          atIndex: 6];
4973     item =  [appMenu insertItemWithTitle: @"Hide Others"
4974                           action: @selector (hideOtherApplications:)
4975                    keyEquivalent: @"h"
4976                          atIndex: 7];
4977     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4978     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4979     [appMenu insertItemWithTitle: @"Quit Emacs"
4980                           action: @selector (terminate:)
4981                    keyEquivalent: @"q"
4982                          atIndex: 9];
4984     item = [mainMenu insertItemWithTitle: ns_app_name
4985                                   action: @selector (menuDown:)
4986                            keyEquivalent: @""
4987                                  atIndex: 0];
4988     [mainMenu setSubmenu: appMenu forItem: item];
4989     [dockMenu insertItemWithTitle: @"New Frame"
4990                            action: @selector (newFrame:)
4991                     keyEquivalent: @""
4992                           atIndex: 0];
4994     [NSApp setMainMenu: mainMenu];
4995     [NSApp setAppleMenu: appMenu];
4996     [NSApp setServicesMenu: svcsMenu];
4997     /* Needed at least on Cocoa, to get dock menu to show windows */
4998     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
5000     [[NSNotificationCenter defaultCenter]
5001       addObserver: mainMenu
5002          selector: @selector (trackingNotification:)
5003              name: NSMenuDidBeginTrackingNotification object: mainMenu];
5004     [[NSNotificationCenter defaultCenter]
5005       addObserver: mainMenu
5006          selector: @selector (trackingNotification:)
5007              name: NSMenuDidEndTrackingNotification object: mainMenu];
5008   }
5009 #endif /* MAC OS X menu setup */
5011   /* Register our external input/output types, used for determining
5012      applicable services and also drag/drop eligibility. */
5014   NSTRACE_MSG ("Input/output types");
5016   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
5017   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
5018                       retain];
5019   ns_drag_types = [[NSArray arrayWithObjects:
5020                             NSStringPboardType,
5021                             NSTabularTextPboardType,
5022                             NSFilenamesPboardType,
5023                             NSURLPboardType, nil] retain];
5025   /* If fullscreen is in init/default-frame-alist, focus isn't set
5026      right for fullscreen windows, so set this.  */
5027   [NSApp activateIgnoringOtherApps:YES];
5029   NSTRACE_MSG ("Call NSApp run");
5031   [NSApp run];
5032   ns_do_open_file = YES;
5034 #ifdef NS_IMPL_GNUSTEP
5035   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
5036      We must re-catch it so subprocess works.  */
5037   catch_child_signal ();
5038 #endif
5040   NSTRACE_MSG ("ns_term_init done");
5042   unblock_input ();
5044   return dpyinfo;
5048 void
5049 ns_term_shutdown (int sig)
5051   [[NSUserDefaults standardUserDefaults] synchronize];
5053   /* code not reached in emacs.c after this is called by shut_down_emacs: */
5054   if (STRINGP (Vauto_save_list_file_name))
5055     unlink (SSDATA (Vauto_save_list_file_name));
5057   if (sig == 0 || sig == SIGTERM)
5058     {
5059       [NSApp terminate: NSApp];
5060     }
5061   else // force a stack trace to happen
5062     {
5063       emacs_abort ();
5064     }
5068 /* ==========================================================================
5070     EmacsApp implementation
5072    ========================================================================== */
5075 @implementation EmacsApp
5077 - (id)init
5079   NSTRACE ("[EmacsApp init]");
5081   if ((self = [super init]))
5082     {
5083 #ifdef NS_IMPL_COCOA
5084       self->isFirst = YES;
5085 #endif
5086 #ifdef NS_IMPL_GNUSTEP
5087       self->applicationDidFinishLaunchingCalled = NO;
5088 #endif
5089     }
5091   return self;
5094 #ifdef NS_IMPL_COCOA
5095 - (void)run
5097   NSTRACE ("[EmacsApp run]");
5099 #ifndef NSAppKitVersionNumber10_9
5100 #define NSAppKitVersionNumber10_9 1265
5101 #endif
5103     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
5104       {
5105         [super run];
5106         return;
5107       }
5109   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
5111   if (isFirst) [self finishLaunching];
5112   isFirst = NO;
5114   shouldKeepRunning = YES;
5115   do
5116     {
5117       [pool release];
5118       pool = [[NSAutoreleasePool alloc] init];
5120       NSEvent *event =
5121         [self nextEventMatchingMask:NSAnyEventMask
5122                           untilDate:[NSDate distantFuture]
5123                              inMode:NSDefaultRunLoopMode
5124                             dequeue:YES];
5126       [self sendEvent:event];
5127       [self updateWindows];
5128     } while (shouldKeepRunning);
5130   [pool release];
5133 - (void)stop: (id)sender
5135   NSTRACE ("[EmacsApp stop:]");
5137     shouldKeepRunning = NO;
5138     // Stop possible dialog also.  Noop if no dialog present.
5139     // The file dialog still leaks 7k - 10k on 10.9 though.
5140     [super stop:sender];
5142 #endif /* NS_IMPL_COCOA */
5144 - (void)logNotification: (NSNotification *)notification
5146   NSTRACE ("[EmacsApp logNotification:]");
5148   const char *name = [[notification name] UTF8String];
5149   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
5150       && !strstr (name, "WindowNumber"))
5151     NSLog (@"notification: '%@'", [notification name]);
5155 - (void)sendEvent: (NSEvent *)theEvent
5156 /* --------------------------------------------------------------------------
5157      Called when NSApp is running for each event received.  Used to stop
5158      the loop when we choose, since there's no way to just run one iteration.
5159    -------------------------------------------------------------------------- */
5161   int type = [theEvent type];
5162   NSWindow *window = [theEvent window];
5164   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
5165   NSTRACE_MSG ("Type: %d", type);
5167 #ifdef NS_IMPL_GNUSTEP
5168   // Keyboard events aren't propagated to file dialogs for some reason.
5169   if ([NSApp modalWindow] != nil &&
5170       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
5171     {
5172       [[NSApp modalWindow] sendEvent: theEvent];
5173       return;
5174     }
5175 #endif
5177   if (represented_filename != nil && represented_frame)
5178     {
5179       NSString *fstr = represented_filename;
5180       NSView *view = FRAME_NS_VIEW (represented_frame);
5181 #ifdef NS_IMPL_COCOA
5182       /* work around a bug observed on 10.3 and later where
5183          setTitleWithRepresentedFilename does not clear out previous state
5184          if given filename does not exist */
5185       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5186         [[view window] setRepresentedFilename: @""];
5187 #endif
5188       [[view window] setRepresentedFilename: fstr];
5189       [represented_filename release];
5190       represented_filename = nil;
5191       represented_frame = NULL;
5192     }
5194   if (type == NSApplicationDefined)
5195     {
5196       switch ([theEvent data2])
5197         {
5198 #ifdef NS_IMPL_COCOA
5199         case NSAPP_DATA2_RUNASSCRIPT:
5200           ns_run_ascript ();
5201           [self stop: self];
5202           return;
5203 #endif
5204         case NSAPP_DATA2_RUNFILEDIALOG:
5205           ns_run_file_dialog ();
5206           [self stop: self];
5207           return;
5208         }
5209     }
5211   if (type == NSCursorUpdate && window == nil)
5212     {
5213       fprintf (stderr, "Dropping external cursor update event.\n");
5214       return;
5215     }
5217   if (type == NSApplicationDefined)
5218     {
5219       /* Events posted by ns_send_appdefined interrupt the run loop here.
5220          But, if a modal window is up, an appdefined can still come through,
5221          (e.g., from a makeKeyWindow event) but stopping self also stops the
5222          modal loop. Just defer it until later. */
5223       if ([NSApp modalWindow] == nil)
5224         {
5225           last_appdefined_event_data = [theEvent data1];
5226           [self stop: self];
5227         }
5228       else
5229         {
5230           send_appdefined = YES;
5231         }
5232     }
5235 #ifdef NS_IMPL_COCOA
5236   /* If no dialog and none of our frames have focus and it is a move, skip it.
5237      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
5238      such as Wifi, sound, date or similar.
5239      This prevents "spooky" highlighting in the frame under the menu.  */
5240   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
5241     {
5242       struct ns_display_info *di;
5243       BOOL has_focus = NO;
5244       for (di = x_display_list; ! has_focus && di; di = di->next)
5245         has_focus = di->x_focus_frame != 0;
5246       if (! has_focus)
5247         return;
5248     }
5249 #endif
5251   NSTRACE_UNSILENCE();
5253   [super sendEvent: theEvent];
5257 - (void)showPreferencesWindow: (id)sender
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_SHOW_PREFS;
5266   emacs_event->modifiers = 0;
5267   EV_TRAILER (theEvent);
5271 - (void)newFrame: (id)sender
5273   NSTRACE ("[EmacsApp newFrame:]");
5275   struct frame *emacsframe = SELECTED_FRAME ();
5276   NSEvent *theEvent = [NSApp currentEvent];
5278   if (!emacs_event)
5279     return;
5280   emacs_event->kind = NS_NONKEY_EVENT;
5281   emacs_event->code = KEY_NS_NEW_FRAME;
5282   emacs_event->modifiers = 0;
5283   EV_TRAILER (theEvent);
5287 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5288 - (BOOL) openFile: (NSString *)fileName
5290   NSTRACE ("[EmacsApp openFile:]");
5292   struct frame *emacsframe = SELECTED_FRAME ();
5293   NSEvent *theEvent = [NSApp currentEvent];
5295   if (!emacs_event)
5296     return NO;
5298   emacs_event->kind = NS_NONKEY_EVENT;
5299   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5300   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5301   ns_input_line = Qnil; /* can be start or cons start,end */
5302   emacs_event->modifiers =0;
5303   EV_TRAILER (theEvent);
5305   return YES;
5309 /* **************************************************************************
5311       EmacsApp delegate implementation
5313    ************************************************************************** */
5315 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5316 /* --------------------------------------------------------------------------
5317      When application is loaded, terminate event loop in ns_term_init
5318    -------------------------------------------------------------------------- */
5320   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5322 #ifdef NS_IMPL_GNUSTEP
5323   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5324 #endif
5325   [NSApp setServicesProvider: NSApp];
5327   [self antialiasThresholdDidChange:nil];
5328 #ifdef NS_IMPL_COCOA
5329   [[NSNotificationCenter defaultCenter]
5330     addObserver:self
5331        selector:@selector(antialiasThresholdDidChange:)
5332            name:NSAntialiasThresholdChangedNotification
5333          object:nil];
5334 #endif
5336   ns_send_appdefined (-2);
5339 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5341 #ifdef NS_IMPL_COCOA
5342   macfont_update_antialias_threshold ();
5343 #endif
5347 /* Termination sequences:
5348     C-x C-c:
5349     Cmd-Q:
5350     MenuBar | File | Exit:
5351     Select Quit from App menubar:
5352         -terminate
5353         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5354         ns_term_shutdown()
5356     Select Quit from Dock menu:
5357     Logout attempt:
5358         -appShouldTerminate
5359           Cancel -> Nothing else
5360           Accept ->
5362           -terminate
5363           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5364           ns_term_shutdown()
5368 - (void) terminate: (id)sender
5370   NSTRACE ("[EmacsApp terminate:]");
5372   struct frame *emacsframe = SELECTED_FRAME ();
5374   if (!emacs_event)
5375     return;
5377   emacs_event->kind = NS_NONKEY_EVENT;
5378   emacs_event->code = KEY_NS_POWER_OFF;
5379   emacs_event->arg = Qt; /* mark as non-key event */
5380   EV_TRAILER ((id)nil);
5383 static bool
5384 runAlertPanel(NSString *title,
5385               NSString *msgFormat,
5386               NSString *defaultButton,
5387               NSString *alternateButton)
5389 #if !defined (NS_IMPL_COCOA) || \
5390   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5391   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5392     == NSAlertDefaultReturn;
5393 #else
5394   NSAlert *alert = [[NSAlert alloc] init];
5395   [alert setAlertStyle: NSCriticalAlertStyle];
5396   [alert setMessageText: msgFormat];
5397   [alert addButtonWithTitle: defaultButton];
5398   [alert addButtonWithTitle: alternateButton];
5399   NSInteger ret = [alert runModal];
5400   [alert release];
5401   return ret == NSAlertFirstButtonReturn;
5402 #endif
5406 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5408   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5410   bool ret;
5412   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5413     return NSTerminateNow;
5415     ret = runAlertPanel(ns_app_name,
5416                         @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5417                         @"Save Buffers and Exit", @"Cancel");
5419     if (ret)
5420         return NSTerminateNow;
5421     else
5422         return NSTerminateCancel;
5423     return NSTerminateNow;  /* just in case */
5426 static int
5427 not_in_argv (NSString *arg)
5429   int k;
5430   const char *a = [arg UTF8String];
5431   for (k = 1; k < initial_argc; ++k)
5432     if (strcmp (a, initial_argv[k]) == 0) return 0;
5433   return 1;
5436 /*   Notification from the Workspace to open a file */
5437 - (BOOL)application: sender openFile: (NSString *)file
5439   if (ns_do_open_file || not_in_argv (file))
5440     [ns_pending_files addObject: file];
5441   return YES;
5445 /*   Open a file as a temporary file */
5446 - (BOOL)application: sender openTempFile: (NSString *)file
5448   if (ns_do_open_file || not_in_argv (file))
5449     [ns_pending_files addObject: file];
5450   return YES;
5454 /*   Notification from the Workspace to open a file noninteractively (?) */
5455 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5457   if (ns_do_open_file || not_in_argv (file))
5458     [ns_pending_files addObject: file];
5459   return YES;
5462 /*   Notification from the Workspace to open multiple files */
5463 - (void)application: sender openFiles: (NSArray *)fileList
5465   NSEnumerator *files = [fileList objectEnumerator];
5466   NSString *file;
5467   /* Don't open files from the command line unconditionally,
5468      Cocoa parses the command line wrong, --option value tries to open value
5469      if --option is the last option.  */
5470   while ((file = [files nextObject]) != nil)
5471     if (ns_do_open_file || not_in_argv (file))
5472       [ns_pending_files addObject: file];
5474   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5479 /* Handle dock menu requests.  */
5480 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5482   return dockMenu;
5486 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5487 - (void)applicationWillBecomeActive: (NSNotification *)notification
5489   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5490   //ns_app_active=YES;
5493 - (void)applicationDidBecomeActive: (NSNotification *)notification
5495   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5497 #ifdef NS_IMPL_GNUSTEP
5498   if (! applicationDidFinishLaunchingCalled)
5499     [self applicationDidFinishLaunching:notification];
5500 #endif
5501   //ns_app_active=YES;
5503   ns_update_auto_hide_menu_bar ();
5504   // No constraining takes place when the application is not active.
5505   ns_constrain_all_frames ();
5507 - (void)applicationDidResignActive: (NSNotification *)notification
5509   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5511   //ns_app_active=NO;
5512   ns_send_appdefined (-1);
5517 /* ==========================================================================
5519     EmacsApp aux handlers for managing event loop
5521    ========================================================================== */
5524 - (void)timeout_handler: (NSTimer *)timedEntry
5525 /* --------------------------------------------------------------------------
5526      The timeout specified to ns_select has passed.
5527    -------------------------------------------------------------------------- */
5529   /*NSTRACE ("timeout_handler"); */
5530   ns_send_appdefined (-2);
5533 #ifdef NS_IMPL_GNUSTEP
5534 - (void)sendFromMainThread:(id)unused
5536   ns_send_appdefined (nextappdefined);
5538 #endif
5540 - (void)fd_handler:(id)unused
5541 /* --------------------------------------------------------------------------
5542      Check data waiting on file descriptors and terminate if so
5543    -------------------------------------------------------------------------- */
5545   int result;
5546   int waiting = 1, nfds;
5547   char c;
5549   fd_set readfds, writefds, *wfds;
5550   struct timespec timeout, *tmo;
5551   NSAutoreleasePool *pool = nil;
5553   /* NSTRACE ("fd_handler"); */
5555   for (;;)
5556     {
5557       [pool release];
5558       pool = [[NSAutoreleasePool alloc] init];
5560       if (waiting)
5561         {
5562           fd_set fds;
5563           FD_ZERO (&fds);
5564           FD_SET (selfds[0], &fds);
5565           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5566           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5567             waiting = 0;
5568         }
5569       else
5570         {
5571           pthread_mutex_lock (&select_mutex);
5572           nfds = select_nfds;
5574           if (select_valid & SELECT_HAVE_READ)
5575             readfds = select_readfds;
5576           else
5577             FD_ZERO (&readfds);
5579           if (select_valid & SELECT_HAVE_WRITE)
5580             {
5581               writefds = select_writefds;
5582               wfds = &writefds;
5583             }
5584           else
5585             wfds = NULL;
5586           if (select_valid & SELECT_HAVE_TMO)
5587             {
5588               timeout = select_timeout;
5589               tmo = &timeout;
5590             }
5591           else
5592             tmo = NULL;
5594           pthread_mutex_unlock (&select_mutex);
5596           FD_SET (selfds[0], &readfds);
5597           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5599           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5601           if (result == 0)
5602             ns_send_appdefined (-2);
5603           else if (result > 0)
5604             {
5605               if (FD_ISSET (selfds[0], &readfds))
5606                 {
5607                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5608                     waiting = 1;
5609                 }
5610               else
5611                 {
5612                   pthread_mutex_lock (&select_mutex);
5613                   if (select_valid & SELECT_HAVE_READ)
5614                     select_readfds = readfds;
5615                   if (select_valid & SELECT_HAVE_WRITE)
5616                     select_writefds = writefds;
5617                   if (select_valid & SELECT_HAVE_TMO)
5618                     select_timeout = timeout;
5619                   pthread_mutex_unlock (&select_mutex);
5621                   ns_send_appdefined (result);
5622                 }
5623             }
5624           waiting = 1;
5625         }
5626     }
5631 /* ==========================================================================
5633     Service provision
5635    ========================================================================== */
5637 /* called from system: queue for next pass through event loop */
5638 - (void)requestService: (NSPasteboard *)pboard
5639               userData: (NSString *)userData
5640                  error: (NSString **)error
5642   [ns_pending_service_names addObject: userData];
5643   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5644       SSDATA (ns_string_from_pasteboard (pboard))]];
5648 /* called from ns_read_socket to clear queue */
5649 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5651   struct frame *emacsframe = SELECTED_FRAME ();
5652   NSEvent *theEvent = [NSApp currentEvent];
5654   NSTRACE ("[EmacsApp fulfillService:withArg:]");
5656   if (!emacs_event)
5657     return NO;
5659   emacs_event->kind = NS_NONKEY_EVENT;
5660   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5661   ns_input_spi_name = build_string ([name UTF8String]);
5662   ns_input_spi_arg = build_string ([arg UTF8String]);
5663   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5664   EV_TRAILER (theEvent);
5666   return YES;
5670 @end  /* EmacsApp */
5674 /* ==========================================================================
5676     EmacsView implementation
5678    ========================================================================== */
5681 @implementation EmacsView
5683 /* needed to inform when window closed from LISP */
5684 - (void) setWindowClosing: (BOOL)closing
5686   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5688   windowClosing = closing;
5692 - (void)dealloc
5694   NSTRACE ("[EmacsView dealloc]");
5695   [toolbar release];
5696   if (fs_state == FULLSCREEN_BOTH)
5697     [nonfs_window release];
5698   [super dealloc];
5702 /* called on font panel selection */
5703 - (void)changeFont: (id)sender
5705   NSEvent *e = [[self window] currentEvent];
5706   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5707   struct font *font = face->font;
5708   id newFont;
5709   CGFloat size;
5710   NSFont *nsfont;
5712   NSTRACE ("[EmacsView changeFont:]");
5714   if (!emacs_event)
5715     return;
5717 #ifdef NS_IMPL_GNUSTEP
5718   nsfont = ((struct nsfont_info *)font)->nsfont;
5719 #endif
5720 #ifdef NS_IMPL_COCOA
5721   nsfont = (NSFont *) macfont_get_nsctfont (font);
5722 #endif
5724   if ((newFont = [sender convertFont: nsfont]))
5725     {
5726       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5728       emacs_event->kind = NS_NONKEY_EVENT;
5729       emacs_event->modifiers = 0;
5730       emacs_event->code = KEY_NS_CHANGE_FONT;
5732       size = [newFont pointSize];
5733       ns_input_fontsize = make_number (lrint (size));
5734       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5735       EV_TRAILER (e);
5736     }
5740 - (BOOL)acceptsFirstResponder
5742   NSTRACE ("[EmacsView acceptsFirstResponder]");
5743   return YES;
5747 - (void)resetCursorRects
5749   NSRect visible = [self visibleRect];
5750   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5751   NSTRACE ("[EmacsView resetCursorRects]");
5753   if (currentCursor == nil)
5754     currentCursor = [NSCursor arrowCursor];
5756   if (!NSIsEmptyRect (visible))
5757     [self addCursorRect: visible cursor: currentCursor];
5758   [currentCursor setOnMouseEntered: YES];
5763 /*****************************************************************************/
5764 /* Keyboard handling. */
5765 #define NS_KEYLOG 0
5767 - (void)keyDown: (NSEvent *)theEvent
5769   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5770   int code;
5771   unsigned fnKeysym = 0;
5772   static NSMutableArray *nsEvArray;
5773   int left_is_none;
5774   unsigned int flags = [theEvent modifierFlags];
5776   NSTRACE ("[EmacsView keyDown:]");
5778   /* Rhapsody and OS X give up and down events for the arrow keys */
5779   if (ns_fake_keydown == YES)
5780     ns_fake_keydown = NO;
5781   else if ([theEvent type] != NSKeyDown)
5782     return;
5784   if (!emacs_event)
5785     return;
5787  if (![[self window] isKeyWindow]
5788      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5789      /* we must avoid an infinite loop here. */
5790      && (EmacsView *)[[theEvent window] delegate] != self)
5791    {
5792      /* XXX: There is an occasional condition in which, when Emacs display
5793          updates a different frame from the current one, and temporarily
5794          selects it, then processes some interrupt-driven input
5795          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5796          for some reason that window has its first responder set to the NSView
5797          most recently updated (I guess), which is not the correct one. */
5798      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5799      return;
5800    }
5802   if (nsEvArray == nil)
5803     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5805   [NSCursor setHiddenUntilMouseMoves: YES];
5807   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5808     {
5809       clear_mouse_face (hlinfo);
5810       hlinfo->mouse_face_hidden = 1;
5811     }
5813   if (!processingCompose)
5814     {
5815       /* When using screen sharing, no left or right information is sent,
5816          so use Left key in those cases.  */
5817       int is_left_key, is_right_key;
5819       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5820         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5822       /* (Carbon way: [theEvent keyCode]) */
5824       /* is it a "function key"? */
5825       /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5826          flag set (this is probably a bug in the OS).
5827       */
5828       if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5829         {
5830           fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5831         }
5832       if (fnKeysym == 0)
5833         {
5834           fnKeysym = ns_convert_key (code);
5835         }
5837       if (fnKeysym)
5838         {
5839           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5840              because Emacs treats Delete and KP-Delete same (in simple.el). */
5841           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5842 #ifdef NS_IMPL_GNUSTEP
5843               /*  GNUstep uses incompatible keycodes, even for those that are
5844                   supposed to be hardware independent.  Just check for delete.
5845                   Keypad delete does not have keysym 0xFFFF.
5846                   See http://savannah.gnu.org/bugs/?25395
5847               */
5848               || (fnKeysym == 0xFFFF && code == 127)
5849 #endif
5850             )
5851             code = 0xFF08; /* backspace */
5852           else
5853             code = fnKeysym;
5854         }
5856       /* are there modifiers? */
5857       emacs_event->modifiers = 0;
5859       if (flags & NSHelpKeyMask)
5860           emacs_event->modifiers |= hyper_modifier;
5862       if (flags & NSShiftKeyMask)
5863         emacs_event->modifiers |= shift_modifier;
5865       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5866       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5867         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5869       if (is_right_key)
5870         emacs_event->modifiers |= parse_solitary_modifier
5871           (EQ (ns_right_command_modifier, Qleft)
5872            ? ns_command_modifier
5873            : ns_right_command_modifier);
5875       if (is_left_key)
5876         {
5877           emacs_event->modifiers |= parse_solitary_modifier
5878             (ns_command_modifier);
5880           /* if super (default), take input manager's word so things like
5881              dvorak / qwerty layout work */
5882           if (EQ (ns_command_modifier, Qsuper)
5883               && !fnKeysym
5884               && [[theEvent characters] length] != 0)
5885             {
5886               /* XXX: the code we get will be unshifted, so if we have
5887                  a shift modifier, must convert ourselves */
5888               if (!(flags & NSShiftKeyMask))
5889                 code = [[theEvent characters] characterAtIndex: 0];
5890 #if 0
5891               /* this is ugly and also requires linking w/Carbon framework
5892                  (for LMGetKbdType) so for now leave this rare (?) case
5893                  undealt with.. in future look into CGEvent methods */
5894               else
5895                 {
5896                   long smv = GetScriptManagerVariable (smKeyScript);
5897                   Handle uchrHandle = GetResource
5898                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5899                   UInt32 dummy = 0;
5900                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5901                                  [[theEvent characters] characterAtIndex: 0],
5902                                  kUCKeyActionDisplay,
5903                                  (flags & ~NSCommandKeyMask) >> 8,
5904                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5905                                  &dummy, 1, &dummy, &code);
5906                   code &= 0xFF;
5907                 }
5908 #endif
5909             }
5910         }
5912       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5913       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5914         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5916       if (is_right_key)
5917           emacs_event->modifiers |= parse_solitary_modifier
5918               (EQ (ns_right_control_modifier, Qleft)
5919                ? ns_control_modifier
5920                : ns_right_control_modifier);
5922       if (is_left_key)
5923         emacs_event->modifiers |= parse_solitary_modifier
5924           (ns_control_modifier);
5926       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5927           emacs_event->modifiers |=
5928             parse_solitary_modifier (ns_function_modifier);
5930       left_is_none = NILP (ns_alternate_modifier)
5931         || EQ (ns_alternate_modifier, Qnone);
5933       is_right_key = (flags & NSRightAlternateKeyMask)
5934         == NSRightAlternateKeyMask;
5935       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5936         || (! is_right_key
5937             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5939       if (is_right_key)
5940         {
5941           if ((NILP (ns_right_alternate_modifier)
5942                || EQ (ns_right_alternate_modifier, Qnone)
5943                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5944               && !fnKeysym)
5945             {   /* accept pre-interp alt comb */
5946               if ([[theEvent characters] length] > 0)
5947                 code = [[theEvent characters] characterAtIndex: 0];
5948               /*HACK: clear lone shift modifier to stop next if from firing */
5949               if (emacs_event->modifiers == shift_modifier)
5950                 emacs_event->modifiers = 0;
5951             }
5952           else
5953             emacs_event->modifiers |= parse_solitary_modifier
5954               (EQ (ns_right_alternate_modifier, Qleft)
5955                ? ns_alternate_modifier
5956                : ns_right_alternate_modifier);
5957         }
5959       if (is_left_key) /* default = meta */
5960         {
5961           if (left_is_none && !fnKeysym)
5962             {   /* accept pre-interp alt comb */
5963               if ([[theEvent characters] length] > 0)
5964                 code = [[theEvent characters] characterAtIndex: 0];
5965               /*HACK: clear lone shift modifier to stop next if from firing */
5966               if (emacs_event->modifiers == shift_modifier)
5967                 emacs_event->modifiers = 0;
5968             }
5969           else
5970               emacs_event->modifiers |=
5971                 parse_solitary_modifier (ns_alternate_modifier);
5972         }
5974   if (NS_KEYLOG)
5975     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5976              code, fnKeysym, flags, emacs_event->modifiers);
5978       /* if it was a function key or had modifiers, pass it directly to emacs */
5979       if (fnKeysym || (emacs_event->modifiers
5980                        && (emacs_event->modifiers != shift_modifier)
5981                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5982 /*[[theEvent characters] length] */
5983         {
5984           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5985           if (code < 0x20)
5986             code |= (1<<28)|(3<<16);
5987           else if (code == 0x7f)
5988             code |= (1<<28)|(3<<16);
5989           else if (!fnKeysym)
5990             emacs_event->kind = code > 0xFF
5991               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5993           emacs_event->code = code;
5994           EV_TRAILER (theEvent);
5995           processingCompose = NO;
5996           return;
5997         }
5998     }
6001   if (NS_KEYLOG && !processingCompose)
6002     fprintf (stderr, "keyDown: Begin compose sequence.\n");
6004   processingCompose = YES;
6005   [nsEvArray addObject: theEvent];
6006   [self interpretKeyEvents: nsEvArray];
6007   [nsEvArray removeObject: theEvent];
6011 #ifdef NS_IMPL_COCOA
6012 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
6013    decided not to send key-down for.
6014    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
6015    This only applies on Tiger and earlier.
6016    If it matches one of these, send it on to keyDown. */
6017 -(void)keyUp: (NSEvent *)theEvent
6019   int flags = [theEvent modifierFlags];
6020   int code = [theEvent keyCode];
6022   NSTRACE ("[EmacsView keyUp:]");
6024   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
6025       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
6026     {
6027       if (NS_KEYLOG)
6028         fprintf (stderr, "keyUp: passed test");
6029       ns_fake_keydown = YES;
6030       [self keyDown: theEvent];
6031     }
6033 #endif
6036 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
6039 /* <NSTextInput>: called when done composing;
6040    NOTE: also called when we delete over working text, followed immed.
6041          by doCommandBySelector: deleteBackward: */
6042 - (void)insertText: (id)aString
6044   int code;
6045   int len = [(NSString *)aString length];
6046   int i;
6048   NSTRACE ("[EmacsView insertText:]");
6050   if (NS_KEYLOG)
6051     NSLog (@"insertText '%@'\tlen = %d", aString, len);
6052   processingCompose = NO;
6054   if (!emacs_event)
6055     return;
6057   /* first, clear any working text */
6058   if (workingText != nil)
6059     [self deleteWorkingText];
6061   /* now insert the string as keystrokes */
6062   for (i =0; i<len; i++)
6063     {
6064       code = [aString characterAtIndex: i];
6065       /* TODO: still need this? */
6066       if (code == 0x2DC)
6067         code = '~'; /* 0x7E */
6068       if (code != 32) /* Space */
6069         emacs_event->modifiers = 0;
6070       emacs_event->kind
6071         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
6072       emacs_event->code = code;
6073       EV_TRAILER ((id)nil);
6074     }
6078 /* <NSTextInput>: inserts display of composing characters */
6079 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
6081   NSString *str = [aString respondsToSelector: @selector (string)] ?
6082     [aString string] : aString;
6084   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
6086   if (NS_KEYLOG)
6087     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
6088            str, (unsigned long)[str length],
6089            (unsigned long)selRange.length,
6090            (unsigned long)selRange.location);
6092   if (workingText != nil)
6093     [self deleteWorkingText];
6094   if ([str length] == 0)
6095     return;
6097   if (!emacs_event)
6098     return;
6100   processingCompose = YES;
6101   workingText = [str copy];
6102   ns_working_text = build_string ([workingText UTF8String]);
6104   emacs_event->kind = NS_TEXT_EVENT;
6105   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
6106   EV_TRAILER ((id)nil);
6110 /* delete display of composing characters [not in <NSTextInput>] */
6111 - (void)deleteWorkingText
6113   NSTRACE ("[EmacsView deleteWorkingText]");
6115   if (workingText == nil)
6116     return;
6117   if (NS_KEYLOG)
6118     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
6119   [workingText release];
6120   workingText = nil;
6121   processingCompose = NO;
6123   if (!emacs_event)
6124     return;
6126   emacs_event->kind = NS_TEXT_EVENT;
6127   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
6128   EV_TRAILER ((id)nil);
6132 - (BOOL)hasMarkedText
6134   NSTRACE ("[EmacsView hasMarkedText]");
6136   return workingText != nil;
6140 - (NSRange)markedRange
6142   NSTRACE ("[EmacsView markedRange]");
6144   NSRange rng = workingText != nil
6145     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
6146   if (NS_KEYLOG)
6147     NSLog (@"markedRange request");
6148   return rng;
6152 - (void)unmarkText
6154   NSTRACE ("[EmacsView unmarkText]");
6156   if (NS_KEYLOG)
6157     NSLog (@"unmark (accept) text");
6158   [self deleteWorkingText];
6159   processingCompose = NO;
6163 /* used to position char selection windows, etc. */
6164 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
6166   NSRect rect;
6167   NSPoint pt;
6168   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
6170   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
6172   if (NS_KEYLOG)
6173     NSLog (@"firstRectForCharRange request");
6175   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
6176   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
6177   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
6178   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
6179                                        +FRAME_LINE_HEIGHT (emacsframe));
6181   pt = [self convertPoint: pt toView: nil];
6182   pt = [[self window] convertBaseToScreen: pt];
6183   rect.origin = pt;
6184   return rect;
6188 - (NSInteger)conversationIdentifier
6190   return (NSInteger)self;
6194 - (void)doCommandBySelector: (SEL)aSelector
6196   NSTRACE ("[EmacsView doCommandBySelector:]");
6198   if (NS_KEYLOG)
6199     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6201   processingCompose = NO;
6202   if (aSelector == @selector (deleteBackward:))
6203     {
6204       /* happens when user backspaces over an ongoing composition:
6205          throw a 'delete' into the event queue */
6206       if (!emacs_event)
6207         return;
6208       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6209       emacs_event->code = 0xFF08;
6210       EV_TRAILER ((id)nil);
6211     }
6214 - (NSArray *)validAttributesForMarkedText
6216   static NSArray *arr = nil;
6217   if (arr == nil) arr = [NSArray new];
6218  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6219   return arr;
6222 - (NSRange)selectedRange
6224   if (NS_KEYLOG)
6225     NSLog (@"selectedRange request");
6226   return NSMakeRange (NSNotFound, 0);
6229 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6230     GNUSTEP_GUI_MINOR_VERSION > 22
6231 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6232 #else
6233 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6234 #endif
6236   if (NS_KEYLOG)
6237     NSLog (@"characterIndexForPoint request");
6238   return 0;
6241 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6243   static NSAttributedString *str = nil;
6244   if (str == nil) str = [NSAttributedString new];
6245   if (NS_KEYLOG)
6246     NSLog (@"attributedSubstringFromRange request");
6247   return str;
6250 /* End <NSTextInput> impl. */
6251 /*****************************************************************************/
6254 /* This is what happens when the user presses a mouse button.  */
6255 - (void)mouseDown: (NSEvent *)theEvent
6257   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6258   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6260   NSTRACE ("[EmacsView mouseDown:]");
6262   [self deleteWorkingText];
6264   if (!emacs_event)
6265     return;
6267   dpyinfo->last_mouse_frame = emacsframe;
6268   /* appears to be needed to prevent spurious movement events generated on
6269      button clicks */
6270   emacsframe->mouse_moved = 0;
6272   if ([theEvent type] == NSScrollWheel)
6273     {
6274       CGFloat delta = [theEvent deltaY];
6275       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6276       if (delta == 0)
6277         {
6278           delta = [theEvent deltaX];
6279           if (delta == 0)
6280             {
6281               NSTRACE_MSG ("deltaIsZero");
6282               return;
6283             }
6284           emacs_event->kind = HORIZ_WHEEL_EVENT;
6285         }
6286       else
6287         emacs_event->kind = WHEEL_EVENT;
6289       emacs_event->code = 0;
6290       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6291         ((delta > 0) ? up_modifier : down_modifier);
6292     }
6293   else
6294     {
6295       emacs_event->kind = MOUSE_CLICK_EVENT;
6296       emacs_event->code = EV_BUTTON (theEvent);
6297       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6298                              | EV_UDMODIFIERS (theEvent);
6299     }
6300   XSETINT (emacs_event->x, lrint (p.x));
6301   XSETINT (emacs_event->y, lrint (p.y));
6302   EV_TRAILER (theEvent);
6306 - (void)rightMouseDown: (NSEvent *)theEvent
6308   NSTRACE ("[EmacsView rightMouseDown:]");
6309   [self mouseDown: theEvent];
6313 - (void)otherMouseDown: (NSEvent *)theEvent
6315   NSTRACE ("[EmacsView otherMouseDown:]");
6316   [self mouseDown: theEvent];
6320 - (void)mouseUp: (NSEvent *)theEvent
6322   NSTRACE ("[EmacsView mouseUp:]");
6323   [self mouseDown: theEvent];
6327 - (void)rightMouseUp: (NSEvent *)theEvent
6329   NSTRACE ("[EmacsView rightMouseUp:]");
6330   [self mouseDown: theEvent];
6334 - (void)otherMouseUp: (NSEvent *)theEvent
6336   NSTRACE ("[EmacsView otherMouseUp:]");
6337   [self mouseDown: theEvent];
6341 - (void) scrollWheel: (NSEvent *)theEvent
6343   NSTRACE ("[EmacsView scrollWheel:]");
6344   [self mouseDown: theEvent];
6348 /* Tell emacs the mouse has moved. */
6349 - (void)mouseMoved: (NSEvent *)e
6351   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6352   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6353   Lisp_Object frame;
6354   NSPoint pt;
6356   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6358   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6359   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6360   dpyinfo->last_mouse_motion_x = pt.x;
6361   dpyinfo->last_mouse_motion_y = pt.y;
6363   /* update any mouse face */
6364   if (hlinfo->mouse_face_hidden)
6365     {
6366       hlinfo->mouse_face_hidden = 0;
6367       clear_mouse_face (hlinfo);
6368     }
6370   /* tooltip handling */
6371   previous_help_echo_string = help_echo_string;
6372   help_echo_string = Qnil;
6374   if (!NILP (Vmouse_autoselect_window))
6375     {
6376       NSTRACE_MSG ("mouse_autoselect_window");
6377       static Lisp_Object last_mouse_window;
6378       Lisp_Object window
6379         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6381       if (WINDOWP (window)
6382           && !EQ (window, last_mouse_window)
6383           && !EQ (window, selected_window)
6384           && (focus_follows_mouse
6385               || (EQ (XWINDOW (window)->frame,
6386                       XWINDOW (selected_window)->frame))))
6387         {
6388           NSTRACE_MSG ("in_window");
6389           emacs_event->kind = SELECT_WINDOW_EVENT;
6390           emacs_event->frame_or_window = window;
6391           EV_TRAILER2 (e);
6392         }
6393       /* Remember the last window where we saw the mouse.  */
6394       last_mouse_window = window;
6395     }
6397   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6398     help_echo_string = previous_help_echo_string;
6400   XSETFRAME (frame, emacsframe);
6401   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6402     {
6403       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6404          (note_mouse_highlight), which is called through the
6405          note_mouse_movement () call above */
6406       any_help_event_p = YES;
6407       gen_help_event (help_echo_string, frame, help_echo_window,
6408                       help_echo_object, help_echo_pos);
6409     }
6411   if (emacsframe->mouse_moved && send_appdefined)
6412     ns_send_appdefined (-1);
6416 - (void)mouseDragged: (NSEvent *)e
6418   NSTRACE ("[EmacsView mouseDragged:]");
6419   [self mouseMoved: e];
6423 - (void)rightMouseDragged: (NSEvent *)e
6425   NSTRACE ("[EmacsView rightMouseDragged:]");
6426   [self mouseMoved: e];
6430 - (void)otherMouseDragged: (NSEvent *)e
6432   NSTRACE ("[EmacsView otherMouseDragged:]");
6433   [self mouseMoved: e];
6437 - (BOOL)windowShouldClose: (id)sender
6439   NSEvent *e =[[self window] currentEvent];
6441   NSTRACE ("[EmacsView windowShouldClose:]");
6442   windowClosing = YES;
6443   if (!emacs_event)
6444     return NO;
6445   emacs_event->kind = DELETE_WINDOW_EVENT;
6446   emacs_event->modifiers = 0;
6447   emacs_event->code = 0;
6448   EV_TRAILER (e);
6449   /* Don't close this window, let this be done from lisp code.  */
6450   return NO;
6453 - (void) updateFrameSize: (BOOL) delay;
6455   NSWindow *window = [self window];
6456   NSRect wr = [window frame];
6457   int extra = 0;
6458   int oldc = cols, oldr = rows;
6459   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6460   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6461   int neww, newh;
6463   NSTRACE ("[EmacsView updateFrameSize:]");
6464   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6465   NSTRACE_RECT ("Original frame", wr);
6466   NSTRACE_MSG  ("Original columns: %d", cols);
6467   NSTRACE_MSG  ("Original rows: %d", rows);
6469   if (! [self isFullscreen])
6470     {
6471 #ifdef NS_IMPL_GNUSTEP
6472       // GNUstep does not always update the tool bar height.  Force it.
6473       if (toolbar && [toolbar isVisible])
6474           update_frame_tool_bar (emacsframe);
6475 #endif
6477       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6478         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6479     }
6481   if (wait_for_tool_bar)
6482     {
6483       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6484         {
6485           NSTRACE_MSG ("Waiting for toolbar");
6486           return;
6487         }
6488       wait_for_tool_bar = NO;
6489     }
6491   neww = (int)wr.size.width - emacsframe->border_width;
6492   newh = (int)wr.size.height - extra;
6494   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6495   NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height);
6497   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6498   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6500   if (cols < MINWIDTH)
6501     cols = MINWIDTH;
6503   if (rows < MINHEIGHT)
6504     rows = MINHEIGHT;
6506   NSTRACE_MSG ("New columns: %d", cols);
6507   NSTRACE_MSG ("New rows: %d", rows);
6509   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6510     {
6511       NSView *view = FRAME_NS_VIEW (emacsframe);
6513       change_frame_size (emacsframe,
6514                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6515                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6516                          0, delay, 0, 1);
6517       SET_FRAME_GARBAGED (emacsframe);
6518       cancel_mouse_face (emacsframe);
6520       wr = NSMakeRect (0, 0, neww, newh);
6522       [view setFrame: wr];
6524       // to do: consider using [NSNotificationCenter postNotificationName:].
6525       [self windowDidMove: // Update top/left.
6526               [NSNotification notificationWithName:NSWindowDidMoveNotification
6527                                             object:[view window]]];
6528     }
6529   else
6530     {
6531       NSTRACE_MSG ("No change");
6532     }
6535 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6536 /* normalize frame to gridded text size */
6538   int extra = 0;
6540   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6541            NSTRACE_ARG_SIZE (frameSize));
6542   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6543   NSTRACE_FSTYPE ("fs_state", fs_state);
6545   if (fs_state == FULLSCREEN_MAXIMIZED
6546       && (maximized_width != (int)frameSize.width
6547           || maximized_height != (int)frameSize.height))
6548     [self setFSValue: FULLSCREEN_NONE];
6549   else if (fs_state == FULLSCREEN_WIDTH
6550            && maximized_width != (int)frameSize.width)
6551     [self setFSValue: FULLSCREEN_NONE];
6552   else if (fs_state == FULLSCREEN_HEIGHT
6553            && maximized_height != (int)frameSize.height)
6554     [self setFSValue: FULLSCREEN_NONE];
6556   if (fs_state == FULLSCREEN_NONE)
6557     maximized_width = maximized_height = -1;
6559   if (! [self isFullscreen])
6560     {
6561       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6562         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6563     }
6565   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6566   if (cols < MINWIDTH)
6567     cols = MINWIDTH;
6569   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6570                                            frameSize.height - extra);
6571   if (rows < MINHEIGHT)
6572     rows = MINHEIGHT;
6573 #ifdef NS_IMPL_COCOA
6574   {
6575     /* this sets window title to have size in it; the wm does this under GS */
6576     NSRect r = [[self window] frame];
6577     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6578       {
6579         if (old_title != 0)
6580           {
6581             xfree (old_title);
6582             old_title = 0;
6583           }
6584       }
6585     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6586       {
6587         char *size_title;
6588         NSWindow *window = [self window];
6589         if (old_title == 0)
6590           {
6591             char *t = strdup ([[[self window] title] UTF8String]);
6592             char *pos = strstr (t, "  â€”  ");
6593             if (pos)
6594               *pos = '\0';
6595             old_title = t;
6596           }
6597         size_title = xmalloc (strlen (old_title) + 40);
6598         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6599         [window setTitle: [NSString stringWithUTF8String: size_title]];
6600         [window display];
6601         xfree (size_title);
6602       }
6603   }
6604 #endif /* NS_IMPL_COCOA */
6606   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6608   /* Restrict the new size to the text gird.
6610      Don't restrict the width if the user only adjusted the height, and
6611      vice versa.  (Without this, the frame would shrink, and move
6612      slightly, if the window was resized by dragging one of its
6613      borders.) */
6614   if (!frame_resize_pixelwise)
6615     {
6616       NSRect r = [[self window] frame];
6618       if (r.size.width != frameSize.width)
6619         {
6620           frameSize.width =
6621             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6622         }
6624       if (r.size.height != frameSize.height)
6625         {
6626           frameSize.height =
6627             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6628         }
6629     }
6631   NSTRACE_RETURN_SIZE (frameSize);
6633   return frameSize;
6637 - (void)windowDidResize: (NSNotification *)notification
6639   NSTRACE ("[EmacsView windowDidResize:]");
6640   if (!FRAME_LIVE_P (emacsframe))
6641     {
6642       NSTRACE_MSG ("Ignored (frame dead)");
6643       return;
6644     }
6645   if (emacsframe->output_data.ns->in_animation)
6646     {
6647       NSTRACE_MSG ("Ignored (in animation)");
6648       return;
6649     }
6651   if (! [self fsIsNative])
6652     {
6653       NSWindow *theWindow = [notification object];
6654       /* We can get notification on the non-FS window when in
6655          fullscreen mode.  */
6656       if ([self window] != theWindow) return;
6657     }
6659   NSTRACE_RECT ("frame", [[notification object] frame]);
6661 #ifdef NS_IMPL_GNUSTEP
6662   NSWindow *theWindow = [notification object];
6664    /* In GNUstep, at least currently, it's possible to get a didResize
6665       without getting a willResize.. therefore we need to act as if we got
6666       the willResize now */
6667   NSSize sz = [theWindow frame].size;
6668   sz = [self windowWillResize: theWindow toSize: sz];
6669 #endif /* NS_IMPL_GNUSTEP */
6671   if (cols > 0 && rows > 0)
6672     {
6673       [self updateFrameSize: YES];
6674     }
6676   ns_send_appdefined (-1);
6679 #ifdef NS_IMPL_COCOA
6680 - (void)viewDidEndLiveResize
6682   NSTRACE ("[EmacsView viewDidEndLiveResize]");
6684   [super viewDidEndLiveResize];
6685   if (old_title != 0)
6686     {
6687       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6688       xfree (old_title);
6689       old_title = 0;
6690     }
6691   maximizing_resize = NO;
6693 #endif /* NS_IMPL_COCOA */
6696 - (void)windowDidBecomeKey: (NSNotification *)notification
6697 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6699   [self windowDidBecomeKey];
6703 - (void)windowDidBecomeKey      /* for direct calls */
6705   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6706   struct frame *old_focus = dpyinfo->x_focus_frame;
6708   NSTRACE ("[EmacsView windowDidBecomeKey]");
6710   if (emacsframe != old_focus)
6711     dpyinfo->x_focus_frame = emacsframe;
6713   ns_frame_rehighlight (emacsframe);
6715   if (emacs_event)
6716     {
6717       emacs_event->kind = FOCUS_IN_EVENT;
6718       EV_TRAILER ((id)nil);
6719     }
6723 - (void)windowDidResignKey: (NSNotification *)notification
6724 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6726   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6727   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6728   NSTRACE ("[EmacsView windowDidResignKey:]");
6730   if (is_focus_frame)
6731     dpyinfo->x_focus_frame = 0;
6733   emacsframe->mouse_moved = 0;
6734   ns_frame_rehighlight (emacsframe);
6736   /* FIXME: for some reason needed on second and subsequent clicks away
6737             from sole-frame Emacs to get hollow box to show */
6738   if (!windowClosing && [[self window] isVisible] == YES)
6739     {
6740       x_update_cursor (emacsframe, 1);
6741       x_set_frame_alpha (emacsframe);
6742     }
6744   if (any_help_event_p)
6745     {
6746       Lisp_Object frame;
6747       XSETFRAME (frame, emacsframe);
6748       help_echo_string = Qnil;
6749       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6750     }
6752   if (emacs_event && is_focus_frame)
6753     {
6754       [self deleteWorkingText];
6755       emacs_event->kind = FOCUS_OUT_EVENT;
6756       EV_TRAILER ((id)nil);
6757     }
6761 - (void)windowWillMiniaturize: sender
6763   NSTRACE ("[EmacsView windowWillMiniaturize:]");
6767 - (void)setFrame:(NSRect)frameRect;
6769   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6770            NSTRACE_ARG_RECT (frameRect));
6772   [super setFrame:(NSRect)frameRect];
6776 - (BOOL)isFlipped
6778   return YES;
6782 - (BOOL)isOpaque
6784   return NO;
6788 - initFrameFromEmacs: (struct frame *)f
6790   NSRect r, wr;
6791   Lisp_Object tem;
6792   NSWindow *win;
6793   NSColor *col;
6794   NSString *name;
6796   NSTRACE ("[EmacsView initFrameFromEmacs:]");
6797   NSTRACE_MSG ("cols:%d lines:%d", f->text_cols, f->text_lines);
6799   windowClosing = NO;
6800   processingCompose = NO;
6801   scrollbarsNeedingUpdate = 0;
6802   fs_state = FULLSCREEN_NONE;
6803   fs_before_fs = next_maximized = -1;
6804 #ifdef HAVE_NATIVE_FS
6805   fs_is_native = ns_use_native_fullscreen;
6806 #else
6807   fs_is_native = NO;
6808 #endif
6809   maximized_width = maximized_height = -1;
6810   nonfs_window = nil;
6812   ns_userRect = NSMakeRect (0, 0, 0, 0);
6813   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6814                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6815   [self initWithFrame: r];
6816   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6818   FRAME_NS_VIEW (f) = self;
6819   emacsframe = f;
6820 #ifdef NS_IMPL_COCOA
6821   old_title = 0;
6822   maximizing_resize = NO;
6823 #endif
6825   win = [[EmacsWindow alloc]
6826             initWithContentRect: r
6827                       styleMask: (NSResizableWindowMask |
6828 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6829                                   NSTitledWindowMask |
6830 #endif
6831                                   NSMiniaturizableWindowMask |
6832                                   NSClosableWindowMask)
6833                         backing: NSBackingStoreBuffered
6834                           defer: YES];
6836 #ifdef HAVE_NATIVE_FS
6837     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6838 #endif
6840   wr = [win frame];
6841   bwidth = f->border_width = wr.size.width - r.size.width;
6842   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6844   [win setAcceptsMouseMovedEvents: YES];
6845   [win setDelegate: self];
6846 #if !defined (NS_IMPL_COCOA) || \
6847   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6848   [win useOptimizedDrawing: YES];
6849 #endif
6851   [[win contentView] addSubview: self];
6853   if (ns_drag_types)
6854     [self registerForDraggedTypes: ns_drag_types];
6856   tem = f->name;
6857   name = [NSString stringWithUTF8String:
6858                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6859   [win setTitle: name];
6861   /* toolbar support */
6862   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6863                          [NSString stringWithFormat: @"Emacs Frame %d",
6864                                    ns_window_num]];
6865   [win setToolbar: toolbar];
6866   [toolbar setVisible: NO];
6868   /* Don't set frame garbaged until tool bar is up to date?
6869      This avoids an extra clear and redraw (flicker) at frame creation.  */
6870   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6871   else wait_for_tool_bar = NO;
6874 #ifdef NS_IMPL_COCOA
6875   {
6876     NSButton *toggleButton;
6877   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6878   [toggleButton setTarget: self];
6879   [toggleButton setAction: @selector (toggleToolbar: )];
6880   }
6881 #endif
6882   FRAME_TOOLBAR_HEIGHT (f) = 0;
6884   tem = f->icon_name;
6885   if (!NILP (tem))
6886     [win setMiniwindowTitle:
6887            [NSString stringWithUTF8String: SSDATA (tem)]];
6889   {
6890     NSScreen *screen = [win screen];
6892     if (screen != 0)
6893       {
6894         NSPoint pt = NSMakePoint
6895           (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6896            IN_BOUND (-SCREENMAX,
6897                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
6899         [win setFrameTopLeftPoint: pt];
6901         NSTRACE_RECT ("new frame", [win frame]);
6902       }
6903   }
6905   [win makeFirstResponder: self];
6907   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6908                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6909   [win setBackgroundColor: col];
6910   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6911     [win setOpaque: NO];
6913 #if !defined (NS_IMPL_COCOA) || \
6914   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6915   [self allocateGState];
6916 #endif
6917   [NSApp registerServicesMenuSendTypes: ns_send_types
6918                            returnTypes: nil];
6920   ns_window_num++;
6921   return self;
6925 - (void)windowDidMove: sender
6927   NSWindow *win = [self window];
6928   NSRect r = [win frame];
6929   NSArray *screens = [NSScreen screens];
6930   NSScreen *screen = [screens objectAtIndex: 0];
6932   NSTRACE ("[EmacsView windowDidMove:]");
6934   if (!emacsframe->output_data.ns)
6935     return;
6936   if (screen != nil)
6937     {
6938       emacsframe->left_pos = r.origin.x;
6939       emacsframe->top_pos =
6940         [screen frame].size.height - (r.origin.y + r.size.height);
6941     }
6945 /* Called AFTER method below, but before our windowWillResize call there leads
6946    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6947    location so set_window_size moves the frame. */
6948 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6950   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
6951             NSTRACE_FMT_RETURN "YES"),
6952            NSTRACE_ARG_RECT (newFrame));
6954   emacsframe->output_data.ns->zooming = 1;
6955   return YES;
6959 /* Override to do something slightly nonstandard, but nice.  First click on
6960    zoom button will zoom vertically.  Second will zoom completely.  Third
6961    returns to original. */
6962 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6963                         defaultFrame:(NSRect)defaultFrame
6965   // TODO: Rename to "currentFrame" and assign "result" properly in
6966   // all paths.
6967   NSRect result = [sender frame];
6969   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
6970             NSTRACE_FMT_RECT "]"),
6971            NSTRACE_ARG_RECT (defaultFrame));
6972   NSTRACE_FSTYPE ("fs_state", fs_state);
6973   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
6974   NSTRACE_FSTYPE ("next_maximized", next_maximized);
6975   NSTRACE_RECT   ("ns_userRect", ns_userRect);
6976   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6978   if (fs_before_fs != -1) /* Entering fullscreen */
6979     {
6980       NSTRACE_MSG ("Entering fullscreen");
6981       result = defaultFrame;
6982     }
6983   else
6984     {
6985       // Save the window size and position (frame) before the resize.
6986       if (fs_state != FULLSCREEN_MAXIMIZED
6987           && fs_state != FULLSCREEN_WIDTH)
6988         {
6989           ns_userRect.size.width = result.size.width;
6990           ns_userRect.origin.x   = result.origin.x;
6991         }
6993       if (fs_state != FULLSCREEN_MAXIMIZED
6994           && fs_state != FULLSCREEN_HEIGHT)
6995         {
6996           ns_userRect.size.height = result.size.height;
6997           ns_userRect.origin.y    = result.origin.y;
6998         }
7000       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
7002       if (next_maximized == FULLSCREEN_HEIGHT
7003           || (next_maximized == -1
7004               && abs ((int)(defaultFrame.size.height - result.size.height))
7005               > FRAME_LINE_HEIGHT (emacsframe)))
7006         {
7007           /* first click */
7008           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7009           maximized_height = result.size.height = defaultFrame.size.height;
7010           maximized_width = -1;
7011           result.origin.y = defaultFrame.origin.y;
7012           if (ns_userRect.size.height != 0)
7013             {
7014               result.origin.x = ns_userRect.origin.x;
7015               result.size.width = ns_userRect.size.width;
7016             }
7017           [self setFSValue: FULLSCREEN_HEIGHT];
7018 #ifdef NS_IMPL_COCOA
7019           maximizing_resize = YES;
7020 #endif
7021         }
7022       else if (next_maximized == FULLSCREEN_WIDTH)
7023         {
7024           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7025           maximized_width = result.size.width = defaultFrame.size.width;
7026           maximized_height = -1;
7027           result.origin.x = defaultFrame.origin.x;
7028           if (ns_userRect.size.width != 0)
7029             {
7030               result.origin.y = ns_userRect.origin.y;
7031               result.size.height = ns_userRect.size.height;
7032             }
7033           [self setFSValue: FULLSCREEN_WIDTH];
7034         }
7035       else if (next_maximized == FULLSCREEN_MAXIMIZED
7036                || (next_maximized == -1
7037                    && abs ((int)(defaultFrame.size.width - result.size.width))
7038                    > FRAME_COLUMN_WIDTH (emacsframe)))
7039         {
7040           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7042           result = defaultFrame;  /* second click */
7043           maximized_width = result.size.width;
7044           maximized_height = result.size.height;
7045           [self setFSValue: FULLSCREEN_MAXIMIZED];
7046 #ifdef NS_IMPL_COCOA
7047           maximizing_resize = YES;
7048 #endif
7049         }
7050       else
7051         {
7052           /* restore */
7053           NSTRACE_MSG ("Restore");
7054           result = ns_userRect.size.height ? ns_userRect : result;
7055           NSTRACE_RECT ("restore (2)", result);
7056           ns_userRect = NSMakeRect (0, 0, 0, 0);
7057 #ifdef NS_IMPL_COCOA
7058           maximizing_resize = fs_state != FULLSCREEN_NONE;
7059 #endif
7060           [self setFSValue: FULLSCREEN_NONE];
7061           maximized_width = maximized_height = -1;
7062         }
7063     }
7065   if (fs_before_fs == -1) next_maximized = -1;
7067   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
7068   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
7069   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
7070   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
7072   [self windowWillResize: sender toSize: result.size];
7074   NSTRACE_RETURN_RECT (result);
7076   return result;
7080 - (void)windowDidDeminiaturize: sender
7082   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
7083   if (!emacsframe->output_data.ns)
7084     return;
7086   SET_FRAME_ICONIFIED (emacsframe, 0);
7087   SET_FRAME_VISIBLE (emacsframe, 1);
7088   windows_or_buffers_changed = 63;
7090   if (emacs_event)
7091     {
7092       emacs_event->kind = DEICONIFY_EVENT;
7093       EV_TRAILER ((id)nil);
7094     }
7098 - (void)windowDidExpose: sender
7100   NSTRACE ("[EmacsView windowDidExpose:]");
7101   if (!emacsframe->output_data.ns)
7102     return;
7104   SET_FRAME_VISIBLE (emacsframe, 1);
7105   SET_FRAME_GARBAGED (emacsframe);
7107   if (send_appdefined)
7108     ns_send_appdefined (-1);
7112 - (void)windowDidMiniaturize: sender
7114   NSTRACE ("[EmacsView windowDidMiniaturize:]");
7115   if (!emacsframe->output_data.ns)
7116     return;
7118   SET_FRAME_ICONIFIED (emacsframe, 1);
7119   SET_FRAME_VISIBLE (emacsframe, 0);
7121   if (emacs_event)
7122     {
7123       emacs_event->kind = ICONIFY_EVENT;
7124       EV_TRAILER ((id)nil);
7125     }
7128 #ifdef HAVE_NATIVE_FS
7129 - (NSApplicationPresentationOptions)window:(NSWindow *)window
7130       willUseFullScreenPresentationOptions:
7131   (NSApplicationPresentationOptions)proposedOptions
7133   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
7135 #endif
7137 - (void)windowWillEnterFullScreen:(NSNotification *)notification
7139   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
7140   [self windowWillEnterFullScreen];
7142 - (void)windowWillEnterFullScreen /* provided for direct calls */
7144   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
7145   fs_before_fs = fs_state;
7148 - (void)windowDidEnterFullScreen:(NSNotification *)notification
7150   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
7151   [self windowDidEnterFullScreen];
7154 - (void)windowDidEnterFullScreen /* provided for direct calls */
7156   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
7157   [self setFSValue: FULLSCREEN_BOTH];
7158   if (! [self fsIsNative])
7159     {
7160       [self windowDidBecomeKey];
7161       [nonfs_window orderOut:self];
7162     }
7163   else
7164     {
7165       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
7166 #ifdef NS_IMPL_COCOA
7167 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
7168       unsigned val = (unsigned)[NSApp presentationOptions];
7170       // OSX 10.7 bug fix, the menu won't appear without this.
7171       // val is non-zero on other OSX versions.
7172       if (val == 0)
7173         {
7174           NSApplicationPresentationOptions options
7175             = NSApplicationPresentationAutoHideDock
7176             | NSApplicationPresentationAutoHideMenuBar
7177             | NSApplicationPresentationFullScreen
7178             | NSApplicationPresentationAutoHideToolbar;
7180           [NSApp setPresentationOptions: options];
7181         }
7182 #endif
7183 #endif
7184       [toolbar setVisible:tbar_visible];
7185     }
7188 - (void)windowWillExitFullScreen:(NSNotification *)notification
7190   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7191   [self windowWillExitFullScreen];
7194 - (void)windowWillExitFullScreen /* provided for direct calls */
7196   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7197   if (!FRAME_LIVE_P (emacsframe))
7198     {
7199       NSTRACE_MSG ("Ignored (frame dead)");
7200       return;
7201     }
7202   if (next_maximized != -1)
7203     fs_before_fs = next_maximized;
7206 - (void)windowDidExitFullScreen:(NSNotification *)notification
7208   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7209   [self windowDidExitFullScreen];
7212 - (void)windowDidExitFullScreen /* provided for direct calls */
7214   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7215   if (!FRAME_LIVE_P (emacsframe))
7216     {
7217       NSTRACE_MSG ("Ignored (frame dead)");
7218       return;
7219     }
7220   [self setFSValue: fs_before_fs];
7221   fs_before_fs = -1;
7222 #ifdef HAVE_NATIVE_FS
7223   [self updateCollectionBehavior];
7224 #endif
7225   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7226     {
7227       [toolbar setVisible:YES];
7228       update_frame_tool_bar (emacsframe);
7229       [self updateFrameSize:YES];
7230       [[self window] display];
7231     }
7232   else
7233     [toolbar setVisible:NO];
7235   if (next_maximized != -1)
7236     [[self window] performZoom:self];
7239 - (BOOL)fsIsNative
7241   return fs_is_native;
7244 - (BOOL)isFullscreen
7246   BOOL res;
7248   if (! fs_is_native)
7249     {
7250       res = (nonfs_window != nil);
7251     }
7252   else
7253     {
7254 #ifdef HAVE_NATIVE_FS
7255       res = (([[self window] styleMask] & NSFullScreenWindowMask) != 0);
7256 #else
7257       res = NO;
7258 #endif
7259     }
7261   NSTRACE ("[EmacsView isFullscreen] " NSTRACE_FMT_RETURN " %d",
7262            (int) res);
7264   return res;
7267 #ifdef HAVE_NATIVE_FS
7268 - (void)updateCollectionBehavior
7270   NSTRACE ("[EmacsView updateCollectionBehavior]");
7272   if (! [self isFullscreen])
7273     {
7274       NSWindow *win = [self window];
7275       NSWindowCollectionBehavior b = [win collectionBehavior];
7276       if (ns_use_native_fullscreen)
7277         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7278       else
7279         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7281       [win setCollectionBehavior: b];
7282       fs_is_native = ns_use_native_fullscreen;
7283     }
7285 #endif
7287 - (void)toggleFullScreen: (id)sender
7289   NSWindow *w, *fw;
7290   BOOL onFirstScreen;
7291   struct frame *f;
7292   NSRect r, wr;
7293   NSColor *col;
7295   NSTRACE ("[EmacsView toggleFullScreen:]");
7297   if (fs_is_native)
7298     {
7299 #ifdef HAVE_NATIVE_FS
7300       [[self window] toggleFullScreen:sender];
7301 #endif
7302       return;
7303     }
7305   w = [self window];
7306   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7307   f = emacsframe;
7308   wr = [w frame];
7309   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7310                                  (FRAME_DEFAULT_FACE (f)),
7311                                  f);
7313   if (fs_state != FULLSCREEN_BOTH)
7314     {
7315       NSScreen *screen = [w screen];
7317 #if defined (NS_IMPL_COCOA) && \
7318   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7319       /* Hide ghost menu bar on secondary monitor? */
7320       if (! onFirstScreen)
7321         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7322 #endif
7323       /* Hide dock and menubar if we are on the primary screen.  */
7324       if (onFirstScreen)
7325         {
7326 #ifdef NS_IMPL_COCOA
7327           NSApplicationPresentationOptions options
7328             = NSApplicationPresentationAutoHideDock
7329             | NSApplicationPresentationAutoHideMenuBar;
7331           [NSApp setPresentationOptions: options];
7332 #else
7333           [NSMenu setMenuBarVisible:NO];
7334 #endif
7335         }
7337       fw = [[EmacsFSWindow alloc]
7338                        initWithContentRect:[w contentRectForFrameRect:wr]
7339                                  styleMask:NSBorderlessWindowMask
7340                                    backing:NSBackingStoreBuffered
7341                                      defer:YES
7342                                     screen:screen];
7344       [fw setContentView:[w contentView]];
7345       [fw setTitle:[w title]];
7346       [fw setDelegate:self];
7347       [fw setAcceptsMouseMovedEvents: YES];
7348 #if !defined (NS_IMPL_COCOA) || \
7349   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7350       [fw useOptimizedDrawing: YES];
7351 #endif
7352       [fw setBackgroundColor: col];
7353       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7354         [fw setOpaque: NO];
7356       f->border_width = 0;
7357       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
7358       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
7359       FRAME_TOOLBAR_HEIGHT (f) = 0;
7361       nonfs_window = w;
7363       [self windowWillEnterFullScreen];
7364       [fw makeKeyAndOrderFront:NSApp];
7365       [fw makeFirstResponder:self];
7366       [w orderOut:self];
7367       r = [fw frameRectForContentRect:[screen frame]];
7368       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7369       [self windowDidEnterFullScreen];
7370       [fw display];
7371     }
7372   else
7373     {
7374       fw = w;
7375       w = nonfs_window;
7376       nonfs_window = nil;
7378       if (onFirstScreen)
7379         {
7380 #ifdef NS_IMPL_COCOA
7381           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7382 #else
7383           [NSMenu setMenuBarVisible:YES];
7384 #endif
7385         }
7387       [w setContentView:[fw contentView]];
7388       [w setBackgroundColor: col];
7389       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7390         [w setOpaque: NO];
7392       f->border_width = bwidth;
7393       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
7394       if (FRAME_EXTERNAL_TOOL_BAR (f))
7395         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
7397       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7399       [self windowWillExitFullScreen];
7400       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7401       [fw close];
7402       [w makeKeyAndOrderFront:NSApp];
7403       [self windowDidExitFullScreen];
7404       [self updateFrameSize:YES];
7405     }
7408 - (void)handleFS
7410   NSTRACE ("[EmacsView handleFS]");
7412   if (fs_state != emacsframe->want_fullscreen)
7413     {
7414       if (fs_state == FULLSCREEN_BOTH)
7415         {
7416           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7417           [self toggleFullScreen:self];
7418         }
7420       switch (emacsframe->want_fullscreen)
7421         {
7422         case FULLSCREEN_BOTH:
7423           NSTRACE_MSG ("FULLSCREEN_BOTH");
7424           [self toggleFullScreen:self];
7425           break;
7426         case FULLSCREEN_WIDTH:
7427           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7428           next_maximized = FULLSCREEN_WIDTH;
7429           if (fs_state != FULLSCREEN_BOTH)
7430             [[self window] performZoom:self];
7431           break;
7432         case FULLSCREEN_HEIGHT:
7433           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7434           next_maximized = FULLSCREEN_HEIGHT;
7435           if (fs_state != FULLSCREEN_BOTH)
7436             [[self window] performZoom:self];
7437           break;
7438         case FULLSCREEN_MAXIMIZED:
7439           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7440           next_maximized = FULLSCREEN_MAXIMIZED;
7441           if (fs_state != FULLSCREEN_BOTH)
7442             [[self window] performZoom:self];
7443           break;
7444         case FULLSCREEN_NONE:
7445           NSTRACE_MSG ("FULLSCREEN_NONE");
7446           if (fs_state != FULLSCREEN_BOTH)
7447             {
7448               next_maximized = FULLSCREEN_NONE;
7449               [[self window] performZoom:self];
7450             }
7451           break;
7452         }
7454       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7455     }
7459 - (void) setFSValue: (int)value
7461   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7462            NSTRACE_ARG_FSTYPE(value));
7464   Lisp_Object lval = Qnil;
7465   switch (value)
7466     {
7467     case FULLSCREEN_BOTH:
7468       lval = Qfullboth;
7469       break;
7470     case FULLSCREEN_WIDTH:
7471       lval = Qfullwidth;
7472       break;
7473     case FULLSCREEN_HEIGHT:
7474       lval = Qfullheight;
7475       break;
7476     case FULLSCREEN_MAXIMIZED:
7477       lval = Qmaximized;
7478       break;
7479     }
7480   store_frame_param (emacsframe, Qfullscreen, lval);
7481   fs_state = value;
7484 - (void)mouseEntered: (NSEvent *)theEvent
7486   NSTRACE ("[EmacsView mouseEntered:]");
7487   if (emacsframe)
7488     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7489       = EV_TIMESTAMP (theEvent);
7493 - (void)mouseExited: (NSEvent *)theEvent
7495   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7497   NSTRACE ("[EmacsView mouseExited:]");
7499   if (!hlinfo)
7500     return;
7502   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7503     = EV_TIMESTAMP (theEvent);
7505   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7506     {
7507       clear_mouse_face (hlinfo);
7508       hlinfo->mouse_face_mouse_frame = 0;
7509     }
7513 - menuDown: sender
7515   NSTRACE ("[EmacsView menuDown:]");
7516   if (context_menu_value == -1)
7517     context_menu_value = [sender tag];
7518   else
7519     {
7520       NSInteger tag = [sender tag];
7521       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7522                                     emacsframe->menu_bar_vector,
7523                                     (void *)tag);
7524     }
7526   ns_send_appdefined (-1);
7527   return self;
7531 - (EmacsToolbar *)toolbar
7533   return toolbar;
7537 /* this gets called on toolbar button click */
7538 - toolbarClicked: (id)item
7540   NSEvent *theEvent;
7541   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7543   NSTRACE ("[EmacsView toolbarClicked:]");
7545   if (!emacs_event)
7546     return self;
7548   /* send first event (for some reason two needed) */
7549   theEvent = [[self window] currentEvent];
7550   emacs_event->kind = TOOL_BAR_EVENT;
7551   XSETFRAME (emacs_event->arg, emacsframe);
7552   EV_TRAILER (theEvent);
7554   emacs_event->kind = TOOL_BAR_EVENT;
7555 /*   XSETINT (emacs_event->code, 0); */
7556   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7557                            idx + TOOL_BAR_ITEM_KEY);
7558   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7559   EV_TRAILER (theEvent);
7560   return self;
7564 - toggleToolbar: (id)sender
7566   NSTRACE ("[EmacsView toggleToolbar:]");
7568   if (!emacs_event)
7569     return self;
7571   emacs_event->kind = NS_NONKEY_EVENT;
7572   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7573   EV_TRAILER ((id)nil);
7574   return self;
7578 - (void)drawRect: (NSRect)rect
7580   int x = NSMinX (rect), y = NSMinY (rect);
7581   int width = NSWidth (rect), height = NSHeight (rect);
7583   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7584            NSTRACE_ARG_RECT(rect));
7586   if (!emacsframe || !emacsframe->output_data.ns)
7587     return;
7589   ns_clear_frame_area (emacsframe, x, y, width, height);
7590   block_input ();
7591   expose_frame (emacsframe, x, y, width, height);
7592   unblock_input ();
7594   /*
7595     drawRect: may be called (at least in OS X 10.5) for invisible
7596     views as well for some reason.  Thus, do not infer visibility
7597     here.
7599     emacsframe->async_visible = 1;
7600     emacsframe->async_iconified = 0;
7601   */
7605 /* NSDraggingDestination protocol methods.  Actually this is not really a
7606    protocol, but a category of Object.  O well...  */
7608 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7610   NSTRACE ("[EmacsView draggingEntered:]");
7611   return NSDragOperationGeneric;
7615 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7617   return YES;
7621 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7623   id pb;
7624   int x, y;
7625   NSString *type;
7626   NSEvent *theEvent = [[self window] currentEvent];
7627   NSPoint position;
7628   NSDragOperation op = [sender draggingSourceOperationMask];
7629   int modifiers = 0;
7631   NSTRACE ("[EmacsView performDragOperation:]");
7633   if (!emacs_event)
7634     return NO;
7636   position = [self convertPoint: [sender draggingLocation] fromView: nil];
7637   x = lrint (position.x);  y = lrint (position.y);
7639   pb = [sender draggingPasteboard];
7640   type = [pb availableTypeFromArray: ns_drag_types];
7642   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7643       // URL drags contain all operations (0xf), don't allow all to be set.
7644       (op & 0xf) != 0xf)
7645     {
7646       if (op & NSDragOperationLink)
7647         modifiers |= NSControlKeyMask;
7648       if (op & NSDragOperationCopy)
7649         modifiers |= NSAlternateKeyMask;
7650       if (op & NSDragOperationGeneric)
7651         modifiers |= NSCommandKeyMask;
7652     }
7654   modifiers = EV_MODIFIERS2 (modifiers);
7655   if (type == 0)
7656     {
7657       return NO;
7658     }
7659   else if ([type isEqualToString: NSFilenamesPboardType])
7660     {
7661       NSArray *files;
7662       NSEnumerator *fenum;
7663       NSString *file;
7665       if (!(files = [pb propertyListForType: type]))
7666         return NO;
7668       fenum = [files objectEnumerator];
7669       while ( (file = [fenum nextObject]) )
7670         {
7671           emacs_event->kind = DRAG_N_DROP_EVENT;
7672           XSETINT (emacs_event->x, x);
7673           XSETINT (emacs_event->y, y);
7674           ns_input_file = append2 (ns_input_file,
7675                                    build_string ([file UTF8String]));
7676           emacs_event->modifiers = modifiers;
7677           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
7678           EV_TRAILER (theEvent);
7679         }
7680       return YES;
7681     }
7682   else if ([type isEqualToString: NSURLPboardType])
7683     {
7684       NSURL *url = [NSURL URLFromPasteboard: pb];
7685       if (url == nil) return NO;
7687       emacs_event->kind = DRAG_N_DROP_EVENT;
7688       XSETINT (emacs_event->x, x);
7689       XSETINT (emacs_event->y, y);
7690       emacs_event->modifiers = modifiers;
7691       emacs_event->arg =  list2 (Qurl,
7692                                  build_string ([[url absoluteString]
7693                                                  UTF8String]));
7694       EV_TRAILER (theEvent);
7696       if ([url isFileURL] != NO)
7697         {
7698           NSString *file = [url path];
7699           ns_input_file = append2 (ns_input_file,
7700                                    build_string ([file UTF8String]));
7701         }
7702       return YES;
7703     }
7704   else if ([type isEqualToString: NSStringPboardType]
7705            || [type isEqualToString: NSTabularTextPboardType])
7706     {
7707       NSString *data;
7709       if (! (data = [pb stringForType: type]))
7710         return NO;
7712       emacs_event->kind = DRAG_N_DROP_EVENT;
7713       XSETINT (emacs_event->x, x);
7714       XSETINT (emacs_event->y, y);
7715       emacs_event->modifiers = modifiers;
7716       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
7717       EV_TRAILER (theEvent);
7718       return YES;
7719     }
7720   else
7721     {
7722       fprintf (stderr, "Invalid data type in dragging pasteboard");
7723       return NO;
7724     }
7728 - (id) validRequestorForSendType: (NSString *)typeSent
7729                       returnType: (NSString *)typeReturned
7731   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7732   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7733       && typeReturned == nil)
7734     {
7735       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7736         return self;
7737     }
7739   return [super validRequestorForSendType: typeSent
7740                                returnType: typeReturned];
7744 /* The next two methods are part of NSServicesRequests informal protocol,
7745    supposedly called when a services menu item is chosen from this app.
7746    But this should not happen because we override the services menu with our
7747    own entries which call ns-perform-service.
7748    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7749    So let's at least stub them out until further investigation can be done. */
7751 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7753   /* we could call ns_string_from_pasteboard(pboard) here but then it should
7754      be written into the buffer in place of the existing selection..
7755      ordinary service calls go through functions defined in ns-win.el */
7756   return NO;
7759 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7761   NSArray *typesDeclared;
7762   Lisp_Object val;
7764   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7766   /* We only support NSStringPboardType */
7767   if ([types containsObject:NSStringPboardType] == NO) {
7768     return NO;
7769   }
7771   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7772   if (CONSP (val) && SYMBOLP (XCAR (val)))
7773     {
7774       val = XCDR (val);
7775       if (CONSP (val) && NILP (XCDR (val)))
7776         val = XCAR (val);
7777     }
7778   if (! STRINGP (val))
7779     return NO;
7781   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7782   [pb declareTypes:typesDeclared owner:nil];
7783   ns_string_to_pasteboard (pb, val);
7784   return YES;
7788 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7789    (gives a miniaturized version of the window); currently we use the latter for
7790    frames whose active buffer doesn't correspond to any file
7791    (e.g., '*scratch*') */
7792 - setMiniwindowImage: (BOOL) setMini
7794   id image = [[self window] miniwindowImage];
7795   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7797   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7798      about "AppleDockIconEnabled" notwithstanding, however the set message
7799      below has its effect nonetheless. */
7800   if (image != emacsframe->output_data.ns->miniimage)
7801     {
7802       if (image && [image isKindOfClass: [EmacsImage class]])
7803         [image release];
7804       [[self window] setMiniwindowImage:
7805                        setMini ? emacsframe->output_data.ns->miniimage : nil];
7806     }
7808   return self;
7812 - (void) setRows: (int) r andColumns: (int) c
7814   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7815   rows = r;
7816   cols = c;
7819 - (int) fullscreenState
7821   return fs_state;
7824 @end  /* EmacsView */
7828 /* ==========================================================================
7830     EmacsWindow implementation
7832    ========================================================================== */
7834 @implementation EmacsWindow
7836 #ifdef NS_IMPL_COCOA
7837 - (id)accessibilityAttributeValue:(NSString *)attribute
7839   Lisp_Object str = Qnil;
7840   struct frame *f = SELECTED_FRAME ();
7841   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7843   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7845   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7846     return NSAccessibilityTextFieldRole;
7848   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7849       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7850     {
7851       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7852     }
7853   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7854     {
7855       if (! NILP (BVAR (curbuf, mark_active)))
7856           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7858       if (NILP (str))
7859         {
7860           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7861           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7862           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7864           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7865             str = make_uninit_multibyte_string (range, byte_range);
7866           else
7867             str = make_uninit_string (range);
7868           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7869              Is this a problem?  */
7870           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7871         }
7872     }
7875   if (! NILP (str))
7876     {
7877       if (CONSP (str) && SYMBOLP (XCAR (str)))
7878         {
7879           str = XCDR (str);
7880           if (CONSP (str) && NILP (XCDR (str)))
7881             str = XCAR (str);
7882         }
7883       if (STRINGP (str))
7884         {
7885           const char *utfStr = SSDATA (str);
7886           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7887           return nsStr;
7888         }
7889     }
7891   return [super accessibilityAttributeValue:attribute];
7893 #endif /* NS_IMPL_COCOA */
7895 /* Constrain size and placement of a frame.
7897    By returning the original "frameRect", the frame is not
7898    constrained. This can lead to unwanted situations where, for
7899    example, the menu bar covers the frame.
7901    The default implementation (accessed using "super") constrains the
7902    frame to the visible area of SCREEN, minus the menu bar (if
7903    present) and the Dock.  Note that default implementation also calls
7904    windowWillResize, with the frame it thinks should have.  (This can
7905    make the frame exit maximized mode.)
7907    Note that this should work in situations where multiple monitors
7908    are present.  Common configurations are side-by-side monitors and a
7909    monitor on top of another (e.g. when a laptop is placed under a
7910    large screen). */
7911 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7913   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
7914              NSTRACE_ARG_RECT (frameRect));
7916 #ifdef NS_IMPL_COCOA
7917 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7918   // If separate spaces is on, it is like each screen is independent.  There is
7919   // no spanning of frames across screens.
7920   if ([NSScreen screensHaveSeparateSpaces])
7921     {
7922       NSTRACE_MSG ("Screens have separate spaces");
7923       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
7924       NSTRACE_RETURN_RECT (frameRect);
7925       return frameRect;
7926     }
7927 #endif
7928 #endif
7930   return constrain_frame_rect(frameRect,
7931                               [(EmacsView *)[self delegate] isFullscreen]);
7935 - (void)performZoom:(id)sender
7937   NSTRACE ("[EmacsWindow performZoom:]");
7939   return [super performZoom:sender];
7942 - (void)zoom:(id)sender
7944   NSTRACE ("[EmacsWindow zoom:]");
7946   ns_update_auto_hide_menu_bar();
7948   // Below are three zoom implementations.  In the final commit, the
7949   // idea is that the last should be included.
7951 #if 0
7952   // Native zoom done using the standard zoom animation.  Size of the
7953   // resulting frame reduced to accommodate the Dock and, if present,
7954   // the menu-bar.
7955   [super zoom:sender];
7957 #elif 0
7958   // Native zoom done using the standard zoom animation, plus an
7959   // explicit resize to cover the full screen, except the menu-bar and
7960   // dock, if present.
7961   [super zoom:sender];
7963   // After the native zoom, resize the resulting frame to fill the
7964   // entire screen, except the menu-bar.
7965   //
7966   // This works for all practical purposes.  (The only minor oddity is
7967   // when transiting from full-height frame to a maximized, the
7968   // animation reduces the height of the frame slightly (to the 4
7969   // pixels needed to accommodate the Doc) before it snaps back into
7970   // full height.  The user would need a very trained eye to spot
7971   // this.)
7972   NSScreen * screen = [self screen];
7973   if (screen != nil)
7974     {
7975       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
7977       NSTRACE_FSTYPE ("fullscreenState", fs_state);
7979       NSRect sr = [screen frame];
7980       struct EmacsMargins margins
7981         = ns_screen_margins_ignoring_hidden_dock(screen);
7983       NSRect wr = [self frame];
7984       NSTRACE_RECT ("Rect after zoom", wr);
7986       NSRect newWr = wr;
7988       if (fs_state == FULLSCREEN_MAXIMIZED
7989           || fs_state == FULLSCREEN_HEIGHT)
7990         {
7991           newWr.origin.y = sr.origin.y + margins.bottom;
7992           newWr.size.height = sr.size.height - margins.top - margins.bottom;
7993         }
7995       if (fs_state == FULLSCREEN_MAXIMIZED
7996           || fs_state == FULLSCREEN_WIDTH)
7997         {
7998           newWr.origin.x = sr.origin.x + margins.left;
7999           newWr.size.width = sr.size.width - margins.right - margins.left;
8000         }
8002       if (newWr.size.width     != wr.size.width
8003           || newWr.size.height != wr.size.height
8004           || newWr.origin.x    != wr.origin.x
8005           || newWr.origin.y    != wr.origin.y)
8006         {
8007           NSTRACE_MSG ("New frame different");
8008           [self setFrame: newWr display: NO];
8009         }
8010     }
8011 #else
8012   // Non-native zoom which is done instantaneously.  The resulting
8013   // frame covers the entire screen, except the menu-bar and dock, if
8014   // present.
8015   NSScreen * screen = [self screen];
8016   if (screen != nil)
8017     {
8018       NSRect sr = [screen frame];
8019       struct EmacsMargins margins
8020         = ns_screen_margins_ignoring_hidden_dock(screen);
8022       sr.size.height -= (margins.top + margins.bottom);
8023       sr.size.width  -= (margins.left + margins.right);
8024       sr.origin.x += margins.left;
8025       sr.origin.y += margins.bottom;
8027       sr = [[self delegate] windowWillUseStandardFrame:self
8028                                           defaultFrame:sr];
8029       [self setFrame: sr display: NO];
8030     }
8031 #endif
8034 - (void)setFrame:(NSRect)windowFrame
8035          display:(BOOL)displayViews
8037   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
8038            NSTRACE_ARG_RECT (windowFrame), displayViews);
8040   [super setFrame:windowFrame display:displayViews];
8043 - (void)setFrame:(NSRect)windowFrame
8044          display:(BOOL)displayViews
8045          animate:(BOOL)performAnimation
8047   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
8048            " display:%d performAnimation:%d]",
8049            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
8051   [super setFrame:windowFrame display:displayViews animate:performAnimation];
8054 - (void)setFrameTopLeftPoint:(NSPoint)point
8056   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
8057            NSTRACE_ARG_POINT (point));
8059   [super setFrameTopLeftPoint:point];
8061 @end /* EmacsWindow */
8064 @implementation EmacsFSWindow
8066 - (BOOL)canBecomeKeyWindow
8068   return YES;
8071 - (BOOL)canBecomeMainWindow
8073   return YES;
8076 @end
8078 /* ==========================================================================
8080     EmacsScroller implementation
8082    ========================================================================== */
8085 @implementation EmacsScroller
8087 /* for repeat button push */
8088 #define SCROLL_BAR_FIRST_DELAY 0.5
8089 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
8091 + (CGFloat) scrollerWidth
8093   /* TODO: if we want to allow variable widths, this is the place to do it,
8094            however neither GNUstep nor Cocoa support it very well */
8095   CGFloat r;
8096 #if !defined (NS_IMPL_COCOA) || \
8097   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
8098   r = [NSScroller scrollerWidth];
8099 #else
8100   r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
8101                                 scrollerStyle: NSScrollerStyleLegacy];
8102 #endif
8103   return r;
8107 - initFrame: (NSRect )r window: (Lisp_Object)nwin
8109   NSTRACE ("[EmacsScroller initFrame: window:]");
8111   r.size.width = [EmacsScroller scrollerWidth];
8112   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
8113   [self setContinuous: YES];
8114   [self setEnabled: YES];
8116   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
8117      locked against the top and bottom edges, and right edge on OS X, where
8118      scrollers are on right. */
8119 #ifdef NS_IMPL_GNUSTEP
8120   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
8121 #else
8122   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
8123 #endif
8125   window = XWINDOW (nwin);
8126   condemned = NO;
8127   pixel_height = NSHeight (r);
8128   if (pixel_height == 0) pixel_height = 1;
8129   min_portion = 20 / pixel_height;
8131   frame = XFRAME (window->frame);
8132   if (FRAME_LIVE_P (frame))
8133     {
8134       int i;
8135       EmacsView *view = FRAME_NS_VIEW (frame);
8136       NSView *sview = [[view window] contentView];
8137       NSArray *subs = [sview subviews];
8139       /* disable optimization stopping redraw of other scrollbars */
8140       view->scrollbarsNeedingUpdate = 0;
8141       for (i =[subs count]-1; i >= 0; i--)
8142         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
8143           view->scrollbarsNeedingUpdate++;
8144       [sview addSubview: self];
8145     }
8147 /*  [self setFrame: r]; */
8149   return self;
8153 - (void)setFrame: (NSRect)newRect
8155   NSTRACE ("[EmacsScroller setFrame:]");
8157 /*  block_input (); */
8158   pixel_height = NSHeight (newRect);
8159   if (pixel_height == 0) pixel_height = 1;
8160   min_portion = 20 / pixel_height;
8161   [super setFrame: newRect];
8162 /*  unblock_input (); */
8166 - (void)dealloc
8168   NSTRACE ("[EmacsScroller dealloc]");
8169   if (window)
8170     wset_vertical_scroll_bar (window, Qnil);
8171   window = 0;
8172   [super dealloc];
8176 - condemn
8178   NSTRACE ("[EmacsScroller condemn]");
8179   condemned =YES;
8180   return self;
8184 - reprieve
8186   NSTRACE ("[EmacsScroller reprieve]");
8187   condemned =NO;
8188   return self;
8192 -(bool)judge
8194   NSTRACE ("[EmacsScroller judge]");
8195   bool ret = condemned;
8196   if (condemned)
8197     {
8198       EmacsView *view;
8199       block_input ();
8200       /* ensure other scrollbar updates after deletion */
8201       view = (EmacsView *)FRAME_NS_VIEW (frame);
8202       if (view != nil)
8203         view->scrollbarsNeedingUpdate++;
8204       if (window)
8205         wset_vertical_scroll_bar (window, Qnil);
8206       window = 0;
8207       [self removeFromSuperview];
8208       [self release];
8209       unblock_input ();
8210     }
8211   return ret;
8215 - (void)resetCursorRects
8217   NSRect visible = [self visibleRect];
8218   NSTRACE ("[EmacsScroller resetCursorRects]");
8220   if (!NSIsEmptyRect (visible))
8221     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8222   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8226 - (int) checkSamePosition: (int) position portion: (int) portion
8227                     whole: (int) whole
8229   return em_position ==position && em_portion ==portion && em_whole ==whole
8230     && portion != whole; /* needed for resize empty buf */
8234 - setPosition: (int)position portion: (int)portion whole: (int)whole
8236   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8238   em_position = position;
8239   em_portion = portion;
8240   em_whole = whole;
8242   if (portion >= whole)
8243     {
8244 #ifdef NS_IMPL_COCOA
8245       [self setKnobProportion: 1.0];
8246       [self setDoubleValue: 1.0];
8247 #else
8248       [self setFloatValue: 0.0 knobProportion: 1.0];
8249 #endif
8250     }
8251   else
8252     {
8253       float pos;
8254       CGFloat por;
8255       portion = max ((float)whole*min_portion/pixel_height, portion);
8256       pos = (float)position / (whole - portion);
8257       por = (CGFloat)portion/whole;
8258 #ifdef NS_IMPL_COCOA
8259       [self setKnobProportion: por];
8260       [self setDoubleValue: pos];
8261 #else
8262       [self setFloatValue: pos knobProportion: por];
8263 #endif
8264     }
8266   return self;
8269 /* set up emacs_event */
8270 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8272   Lisp_Object win;
8274   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8276   if (!emacs_event)
8277     return;
8279   emacs_event->part = last_hit_part;
8280   emacs_event->code = 0;
8281   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8282   XSETWINDOW (win, window);
8283   emacs_event->frame_or_window = win;
8284   emacs_event->timestamp = EV_TIMESTAMP (e);
8285   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8286   emacs_event->arg = Qnil;
8287   XSETINT (emacs_event->x, loc * pixel_height);
8288   XSETINT (emacs_event->y, pixel_height-20);
8290   if (q_event_ptr)
8291     {
8292       n_emacs_events_pending++;
8293       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8294     }
8295   else
8296     hold_event (emacs_event);
8297   EVENT_INIT (*emacs_event);
8298   ns_send_appdefined (-1);
8302 /* called manually thru timer to implement repeated button action w/hold-down */
8303 - repeatScroll: (NSTimer *)scrollEntry
8305   NSEvent *e = [[self window] currentEvent];
8306   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8307   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8309   NSTRACE ("[EmacsScroller repeatScroll:]");
8311   /* clear timer if need be */
8312   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8313     {
8314         [scroll_repeat_entry invalidate];
8315         [scroll_repeat_entry release];
8316         scroll_repeat_entry = nil;
8318         if (inKnob)
8319           return self;
8321         scroll_repeat_entry
8322           = [[NSTimer scheduledTimerWithTimeInterval:
8323                         SCROLL_BAR_CONTINUOUS_DELAY
8324                                             target: self
8325                                           selector: @selector (repeatScroll:)
8326                                           userInfo: 0
8327                                            repeats: YES]
8328               retain];
8329     }
8331   [self sendScrollEventAtLoc: 0 fromEvent: e];
8332   return self;
8336 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8337    mouseDragged events without going into a modal loop. */
8338 - (void)mouseDown: (NSEvent *)e
8340   NSRect sr, kr;
8341   /* hitPart is only updated AFTER event is passed on */
8342   NSScrollerPart part = [self testPart: [e locationInWindow]];
8343   CGFloat inc = 0.0, loc, kloc, pos;
8344   int edge = 0;
8346   NSTRACE ("[EmacsScroller mouseDown:]");
8348   switch (part)
8349     {
8350     case NSScrollerDecrementPage:
8351         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
8352     case NSScrollerIncrementPage:
8353         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
8354     case NSScrollerDecrementLine:
8355       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
8356     case NSScrollerIncrementLine:
8357       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
8358     case NSScrollerKnob:
8359       last_hit_part = scroll_bar_handle; break;
8360     case NSScrollerKnobSlot:  /* GNUstep-only */
8361       last_hit_part = scroll_bar_move_ratio; break;
8362     default:  /* NSScrollerNoPart? */
8363       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
8364                (long) part);
8365       return;
8366     }
8368   if (inc != 0.0)
8369     {
8370       pos = 0;      /* ignored */
8372       /* set a timer to repeat, as we can't let superclass do this modally */
8373       scroll_repeat_entry
8374         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8375                                             target: self
8376                                           selector: @selector (repeatScroll:)
8377                                           userInfo: 0
8378                                            repeats: YES]
8379             retain];
8380     }
8381   else
8382     {
8383       /* handle, or on GNUstep possibly slot */
8384       NSEvent *fake_event;
8386       /* compute float loc in slot and mouse offset on knob */
8387       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8388                       toView: nil];
8389       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8390       if (loc <= 0.0)
8391         {
8392           loc = 0.0;
8393           edge = -1;
8394         }
8395       else if (loc >= NSHeight (sr))
8396         {
8397           loc = NSHeight (sr);
8398           edge = 1;
8399         }
8401       if (edge)
8402         kloc = 0.5 * edge;
8403       else
8404         {
8405           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8406                           toView: nil];
8407           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8408         }
8409       last_mouse_offset = kloc;
8411       /* if knob, tell emacs a location offset by knob pos
8412          (to indicate top of handle) */
8413       if (part == NSScrollerKnob)
8414           pos = (loc - last_mouse_offset) / NSHeight (sr);
8415       else
8416         /* else this is a slot click on GNUstep: go straight there */
8417         pos = loc / NSHeight (sr);
8419       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8420       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
8421                                       location: [e locationInWindow]
8422                                  modifierFlags: [e modifierFlags]
8423                                      timestamp: [e timestamp]
8424                                   windowNumber: [e windowNumber]
8425                                        context: [e context]
8426                                    eventNumber: [e eventNumber]
8427                                     clickCount: [e clickCount]
8428                                       pressure: [e pressure]];
8429       [super mouseUp: fake_event];
8430     }
8432   if (part != NSScrollerKnob)
8433     [self sendScrollEventAtLoc: pos fromEvent: e];
8437 /* Called as we manually track scroller drags, rather than superclass. */
8438 - (void)mouseDragged: (NSEvent *)e
8440     NSRect sr;
8441     double loc, pos;
8443     NSTRACE ("[EmacsScroller mouseDragged:]");
8445       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8446                       toView: nil];
8447       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8449       if (loc <= 0.0)
8450         {
8451           loc = 0.0;
8452         }
8453       else if (loc >= NSHeight (sr) + last_mouse_offset)
8454         {
8455           loc = NSHeight (sr) + last_mouse_offset;
8456         }
8458       pos = (loc - last_mouse_offset) / NSHeight (sr);
8459       [self sendScrollEventAtLoc: pos fromEvent: e];
8463 - (void)mouseUp: (NSEvent *)e
8465   NSTRACE ("[EmacsScroller mouseUp:]");
8467   if (scroll_repeat_entry)
8468     {
8469       [scroll_repeat_entry invalidate];
8470       [scroll_repeat_entry release];
8471       scroll_repeat_entry = nil;
8472     }
8473   last_hit_part = scroll_bar_above_handle;
8477 /* treat scrollwheel events in the bar as though they were in the main window */
8478 - (void) scrollWheel: (NSEvent *)theEvent
8480   NSTRACE ("[EmacsScroller scrollWheel:]");
8482   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8483   [view mouseDown: theEvent];
8486 @end  /* EmacsScroller */
8489 #ifdef NS_IMPL_GNUSTEP
8490 /* Dummy class to get rid of startup warnings.  */
8491 @implementation EmacsDocument
8493 @end
8494 #endif
8497 /* ==========================================================================
8499    Font-related functions; these used to be in nsfaces.m
8501    ========================================================================== */
8504 Lisp_Object
8505 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8507   struct font *font = XFONT_OBJECT (font_object);
8508   EmacsView *view = FRAME_NS_VIEW (f);
8509   int font_ascent, font_descent;
8511   if (fontset < 0)
8512     fontset = fontset_from_font (font_object);
8513   FRAME_FONTSET (f) = fontset;
8515   if (FRAME_FONT (f) == font)
8516     /* This font is already set in frame F.  There's nothing more to
8517        do.  */
8518     return font_object;
8520   FRAME_FONT (f) = font;
8522   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8523   FRAME_COLUMN_WIDTH (f) = font->average_width;
8524   get_font_ascent_descent (font, &font_ascent, &font_descent);
8525   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8527   /* Compute the scroll bar width in character columns.  */
8528   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8529     {
8530       int wid = FRAME_COLUMN_WIDTH (f);
8531       FRAME_CONFIG_SCROLL_BAR_COLS (f)
8532         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8533     }
8534   else
8535     {
8536       int wid = FRAME_COLUMN_WIDTH (f);
8537       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8538     }
8540   /* Compute the scroll bar height in character lines.  */
8541   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8542     {
8543       int height = FRAME_LINE_HEIGHT (f);
8544       FRAME_CONFIG_SCROLL_BAR_LINES (f)
8545         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8546     }
8547   else
8548     {
8549       int height = FRAME_LINE_HEIGHT (f);
8550       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8551     }
8553   /* Now make the frame display the given font.  */
8554   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8555     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8556                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8557                        false, Qfont);
8559   return font_object;
8563 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8564 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8565          in 1.43. */
8567 const char *
8568 ns_xlfd_to_fontname (const char *xlfd)
8569 /* --------------------------------------------------------------------------
8570     Convert an X font name (XLFD) to an NS font name.
8571     Only family is used.
8572     The string returned is temporarily allocated.
8573    -------------------------------------------------------------------------- */
8575   char *name = xmalloc (180);
8576   int i, len;
8577   const char *ret;
8579   if (!strncmp (xlfd, "--", 2))
8580     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8581   else
8582     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8584   /* stopgap for malformed XLFD input */
8585   if (strlen (name) == 0)
8586     strcpy (name, "Monaco");
8588   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8589      also uppercase after '-' or ' ' */
8590   name[0] = c_toupper (name[0]);
8591   for (len =strlen (name), i =0; i<len; i++)
8592     {
8593       if (name[i] == '$')
8594         {
8595           name[i] = '-';
8596           if (i+1<len)
8597             name[i+1] = c_toupper (name[i+1]);
8598         }
8599       else if (name[i] == '_')
8600         {
8601           name[i] = ' ';
8602           if (i+1<len)
8603             name[i+1] = c_toupper (name[i+1]);
8604         }
8605     }
8606 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
8607   ret = [[NSString stringWithUTF8String: name] UTF8String];
8608   xfree (name);
8609   return ret;
8613 void
8614 syms_of_nsterm (void)
8616   NSTRACE ("syms_of_nsterm");
8618   ns_antialias_threshold = 10.0;
8620   /* from 23+ we need to tell emacs what modifiers there are.. */
8621   DEFSYM (Qmodifier_value, "modifier-value");
8622   DEFSYM (Qalt, "alt");
8623   DEFSYM (Qhyper, "hyper");
8624   DEFSYM (Qmeta, "meta");
8625   DEFSYM (Qsuper, "super");
8626   DEFSYM (Qcontrol, "control");
8627   DEFSYM (QUTF8_STRING, "UTF8_STRING");
8629   DEFSYM (Qfile, "file");
8630   DEFSYM (Qurl, "url");
8632   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8633   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8634   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8635   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8636   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8638   DEFVAR_LISP ("ns-input-file", ns_input_file,
8639               "The file specified in the last NS event.");
8640   ns_input_file =Qnil;
8642   DEFVAR_LISP ("ns-working-text", ns_working_text,
8643               "String for visualizing working composition sequence.");
8644   ns_working_text =Qnil;
8646   DEFVAR_LISP ("ns-input-font", ns_input_font,
8647               "The font specified in the last NS event.");
8648   ns_input_font =Qnil;
8650   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8651               "The fontsize specified in the last NS event.");
8652   ns_input_fontsize =Qnil;
8654   DEFVAR_LISP ("ns-input-line", ns_input_line,
8655                "The line specified in the last NS event.");
8656   ns_input_line =Qnil;
8658   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8659                "The service name specified in the last NS event.");
8660   ns_input_spi_name =Qnil;
8662   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8663                "The service argument specified in the last NS event.");
8664   ns_input_spi_arg =Qnil;
8666   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8667                "This variable describes the behavior of the alternate or option key.\n\
8668 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8669 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8670 at all, allowing it to be used at a lower level for accented character entry.");
8671   ns_alternate_modifier = Qmeta;
8673   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8674                "This variable describes the behavior of the right alternate or option key.\n\
8675 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8676 Set to left means be the same key as `ns-alternate-modifier'.\n\
8677 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8678 at all, allowing it to be used at a lower level for accented character entry.");
8679   ns_right_alternate_modifier = Qleft;
8681   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8682                "This variable describes the behavior of the command key.\n\
8683 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8684   ns_command_modifier = Qsuper;
8686   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8687                "This variable describes the behavior of the right command key.\n\
8688 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8689 Set to left means be the same key as `ns-command-modifier'.\n\
8690 Set to none means that the command / option key is not interpreted by Emacs\n\
8691 at all, allowing it to be used at a lower level for accented character entry.");
8692   ns_right_command_modifier = Qleft;
8694   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8695                "This variable describes the behavior of the control key.\n\
8696 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8697   ns_control_modifier = Qcontrol;
8699   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8700                "This variable describes the behavior of the right control key.\n\
8701 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8702 Set to left means be the same key as `ns-control-modifier'.\n\
8703 Set to none means that the control / 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_right_control_modifier = Qleft;
8707   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8708                "This variable describes the behavior of the function key (on laptops).\n\
8709 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8710 Set to none means that the function key is not interpreted by Emacs at all,\n\
8711 allowing it to be used at a lower level for accented character entry.");
8712   ns_function_modifier = Qnone;
8714   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8715                "Non-nil (the default) means to render text antialiased.");
8716   ns_antialias_text = Qt;
8718   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8719                "Whether to confirm application quit using dialog.");
8720   ns_confirm_quit = Qnil;
8722   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8723                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8724 Only works on OSX 10.6 or later.  */);
8725   ns_auto_hide_menu_bar = Qnil;
8727   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8728      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
8729 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
8730 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
8731 Default is t for OSX >= 10.7, nil otherwise.  */);
8732 #ifdef HAVE_NATIVE_FS
8733   ns_use_native_fullscreen = YES;
8734 #else
8735   ns_use_native_fullscreen = NO;
8736 #endif
8737   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8739   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8740      doc: /*Non-nil means use animation on non-native fullscreen.
8741 For native fullscreen, this does nothing.
8742 Default is nil.  */);
8743   ns_use_fullscreen_animation = NO;
8745   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8746      doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
8747 Note that this does not apply to images.
8748 This variable is ignored on OSX < 10.7 and GNUstep.  */);
8749   ns_use_srgb_colorspace = YES;
8751   /* TODO: move to common code */
8752   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8753                doc: /* Which toolkit scroll bars Emacs uses, if any.
8754 A value of nil means Emacs doesn't use toolkit scroll bars.
8755 With the X Window system, the value is a symbol describing the
8756 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
8757 With MS Windows or Nextstep, the value is t.  */);
8758   Vx_toolkit_scroll_bars = Qt;
8760   DEFVAR_BOOL ("x-use-underline-position-properties",
8761                x_use_underline_position_properties,
8762      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8763 A value of nil means ignore them.  If you encounter fonts with bogus
8764 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8765 to 4.1, set this to nil. */);
8766   x_use_underline_position_properties = 0;
8768   DEFVAR_BOOL ("x-underline-at-descent-line",
8769                x_underline_at_descent_line,
8770      doc: /* Non-nil means to draw the underline at the same place as the descent line.
8771 A value of nil means to draw the underline according to the value of the
8772 variable `x-use-underline-position-properties', which is usually at the
8773 baseline level.  The default value is nil.  */);
8774   x_underline_at_descent_line = 0;
8776   /* Tell Emacs about this window system.  */
8777   Fprovide (Qns, Qnil);
8779   DEFSYM (Qcocoa, "cocoa");
8780   DEFSYM (Qgnustep, "gnustep");
8782 #ifdef NS_IMPL_COCOA
8783   Fprovide (Qcocoa, Qnil);
8784   syms_of_macfont ();
8785 #else
8786   Fprovide (Qgnustep, Qnil);
8787   syms_of_nsfont ();
8788 #endif