Fix point positioning after transposing with negative arg
[emacs.git] / src / nsterm.m
blob5c39d5c0e4d1bf1d156705309edfd740ce82415d
1 /* NeXT/Open/GNUstep / MacOSX communication module.      -*- coding: utf-8 -*-
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2015 Free Software
4 Foundation, Inc.
6 This file is part of GNU Emacs.
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
22 Originally by Carl Edman
23 Updated by Christian Limpach (chris@nice.ch)
24 OpenStep/Rhapsody port by Scott Bender (sbender@harmony-ds.com)
25 MacOSX/Aqua port by Christophe de Dinechin (descubes@earthlink.net)
26 GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu)
29 /* This should be the first include, as it may set up #defines affecting
30    interpretation of even the system includes. */
31 #include <config.h>
33 #include <fcntl.h>
34 #include <math.h>
35 #include <pthread.h>
36 #include <sys/types.h>
37 #include <time.h>
38 #include <signal.h>
39 #include <unistd.h>
41 #include <c-ctype.h>
42 #include <c-strcase.h>
43 #include <ftoastr.h>
45 #include "lisp.h"
46 #include "blockinput.h"
47 #include "sysselect.h"
48 #include "nsterm.h"
49 #include "systime.h"
50 #include "character.h"
51 #include "fontset.h"
52 #include "composite.h"
53 #include "ccl.h"
55 #include "termhooks.h"
56 #include "termchar.h"
57 #include "menu.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "buffer.h"
61 #include "font.h"
63 #ifdef NS_IMPL_GNUSTEP
64 #include "process.h"
65 #endif
67 #ifdef NS_IMPL_COCOA
68 #include "macfont.h"
69 #endif
72 extern NSString *NSMenuDidBeginTrackingNotification;
75 #if NSTRACE_ENABLED
76 int nstrace_num = 0;
77 int nstrace_depth = 0;
79 /* Called when nstrace_enabled goes out of scope. */
80 void nstrace_leave(int * pointer_to_nstrace_enabled)
82   if (*pointer_to_nstrace_enabled)
83     {
84       --nstrace_depth;
85     }
89 void ns_print_fullscreen_type_name (char const * s, int fs_type)
91   // This is a support function for the NSTRACE system, don't add a
92   // NSTRACE () here.  However, a local `nstrace_enabled' variable is
93   // needed by the NSTRACE_MSG macros.
94   int nstrace_enabled = 1;
96   switch (fs_type)
97     {
98     case FULLSCREEN_NONE:
99       NSTRACE_MSG ("%s: FULLSCREEN_NONE", s);
100       break;
102     case FULLSCREEN_WIDTH:
103       NSTRACE_MSG ("%s: FULLSCREEN_WIDTH", s);
104       break;
106     case FULLSCREEN_HEIGHT:
107       NSTRACE_MSG ("%s: FULLSCREEN_HEIGHT", s);
108       break;
110     case FULLSCREEN_BOTH:
111       NSTRACE_MSG ("%s: FULLSCREEN_BOTH", s);
112       break;
114     case FULLSCREEN_MAXIMIZED:
115       NSTRACE_MSG ("%s: FULLSCREEN_MAXIMIZED", s);
116       break;
118     default:
119       NSTRACE_MSG ("%s: %d", s, fs_type);
120       break;
121     }
123 #endif
126 /* ==========================================================================
128    NSColor, EmacsColor category.
130    ========================================================================== */
131 @implementation NSColor (EmacsColor)
132 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
133                          blue:(CGFloat)blue alpha:(CGFloat)alpha
135 #ifdef NS_IMPL_COCOA
136 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
137   if (ns_use_srgb_colorspace)
138       return [NSColor colorWithSRGBRed: red
139                                  green: green
140                                   blue: blue
141                                  alpha: alpha];
142 #endif
143 #endif
144   return [NSColor colorWithCalibratedRed: red
145                                    green: green
146                                     blue: blue
147                                    alpha: alpha];
150 - (NSColor *)colorUsingDefaultColorSpace
152 #ifdef NS_IMPL_COCOA
153 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
154   if (ns_use_srgb_colorspace)
155     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
156 #endif
157 #endif
158   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
161 @end
163 /* ==========================================================================
165     Local declarations
167    ========================================================================== */
169 /* Convert a symbol indexed with an NSxxx value to a value as defined
170    in keyboard.c (lispy_function_key). I hope this is a correct way
171    of doing things... */
172 static unsigned convert_ns_to_X_keysym[] =
174   NSHomeFunctionKey,            0x50,
175   NSLeftArrowFunctionKey,       0x51,
176   NSUpArrowFunctionKey,         0x52,
177   NSRightArrowFunctionKey,      0x53,
178   NSDownArrowFunctionKey,       0x54,
179   NSPageUpFunctionKey,          0x55,
180   NSPageDownFunctionKey,        0x56,
181   NSEndFunctionKey,             0x57,
182   NSBeginFunctionKey,           0x58,
183   NSSelectFunctionKey,          0x60,
184   NSPrintFunctionKey,           0x61,
185   NSClearLineFunctionKey,       0x0B,
186   NSExecuteFunctionKey,         0x62,
187   NSInsertFunctionKey,          0x63,
188   NSUndoFunctionKey,            0x65,
189   NSRedoFunctionKey,            0x66,
190   NSMenuFunctionKey,            0x67,
191   NSFindFunctionKey,            0x68,
192   NSHelpFunctionKey,            0x6A,
193   NSBreakFunctionKey,           0x6B,
195   NSF1FunctionKey,              0xBE,
196   NSF2FunctionKey,              0xBF,
197   NSF3FunctionKey,              0xC0,
198   NSF4FunctionKey,              0xC1,
199   NSF5FunctionKey,              0xC2,
200   NSF6FunctionKey,              0xC3,
201   NSF7FunctionKey,              0xC4,
202   NSF8FunctionKey,              0xC5,
203   NSF9FunctionKey,              0xC6,
204   NSF10FunctionKey,             0xC7,
205   NSF11FunctionKey,             0xC8,
206   NSF12FunctionKey,             0xC9,
207   NSF13FunctionKey,             0xCA,
208   NSF14FunctionKey,             0xCB,
209   NSF15FunctionKey,             0xCC,
210   NSF16FunctionKey,             0xCD,
211   NSF17FunctionKey,             0xCE,
212   NSF18FunctionKey,             0xCF,
213   NSF19FunctionKey,             0xD0,
214   NSF20FunctionKey,             0xD1,
215   NSF21FunctionKey,             0xD2,
216   NSF22FunctionKey,             0xD3,
217   NSF23FunctionKey,             0xD4,
218   NSF24FunctionKey,             0xD5,
220   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
221   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
222   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
224   NSTabCharacter,               0x09,
225   0x19,                         0x09,  /* left tab->regular since pass shift */
226   NSCarriageReturnCharacter,    0x0D,
227   NSNewlineCharacter,           0x0D,
228   NSEnterCharacter,             0x8D,
230   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
231   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
232   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
233   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
234   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
235   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
236   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
237   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
238   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
239   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
240   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
241   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
242   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
243   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
244   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
245   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
247   0x1B,                         0x1B   /* escape */
250 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
251    the maximum font size to NOT antialias.  On GNUstep there is currently
252    no way to control this behavior. */
253 float ns_antialias_threshold;
255 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
256 NSString *ns_app_name = @"Emacs";  /* default changed later */
258 /* Display variables */
259 struct ns_display_info *x_display_list; /* Chain of existing displays */
260 long context_menu_value = 0;
262 /* display update */
263 static struct frame *ns_updating_frame;
264 static NSView *focus_view = NULL;
265 static int ns_window_num = 0;
266 #ifdef NS_IMPL_GNUSTEP
267 static NSRect uRect;            // TODO: This is dead, remove it?
268 #endif
269 static BOOL gsaved = NO;
270 static BOOL ns_fake_keydown = NO;
271 #ifdef NS_IMPL_COCOA
272 static BOOL ns_menu_bar_is_hidden = NO;
273 #endif
274 /*static int debug_lock = 0; */
276 /* event loop */
277 static BOOL send_appdefined = YES;
278 #define NO_APPDEFINED_DATA (-8)
279 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
280 static NSTimer *timed_entry = 0;
281 static NSTimer *scroll_repeat_entry = nil;
282 static fd_set select_readfds, select_writefds;
283 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
284 static int select_nfds = 0, select_valid = 0;
285 static struct timespec select_timeout = { 0, 0 };
286 static int selfds[2] = { -1, -1 };
287 static pthread_mutex_t select_mutex;
288 static int apploopnr = 0;
289 static NSAutoreleasePool *outerpool;
290 static struct input_event *emacs_event = NULL;
291 static struct input_event *q_event_ptr = NULL;
292 static int n_emacs_events_pending = 0;
293 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
294   *ns_pending_service_args;
295 static BOOL ns_do_open_file = NO;
296 static BOOL ns_last_use_native_fullscreen;
298 /* Non-zero means that a HELP_EVENT has been generated since Emacs
299    start.  */
301 static BOOL any_help_event_p = NO;
303 static struct {
304   struct input_event *q;
305   int nr, cap;
306 } hold_event_q = {
307   NULL, 0, 0
310 static NSString *represented_filename = nil;
311 static struct frame *represented_frame = 0;
313 #ifdef NS_IMPL_COCOA
315  * State for pending menu activation:
316  * MENU_NONE     Normal state
317  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
318  *               run lisp to update the menu.
319  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
320  *               will open.
321  */
322 #define MENU_NONE 0
323 #define MENU_PENDING 1
324 #define MENU_OPENING 2
325 static int menu_will_open_state = MENU_NONE;
327 /* Saved position for menu click.  */
328 static CGPoint menu_mouse_point;
329 #endif
331 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
332 #define NS_FUNCTION_KEY_MASK 0x800000
333 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
334 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
335 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
336 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
337 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
338 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
339 #define EV_MODIFIERS2(flags)                          \
340     (((flags & NSHelpKeyMask) ?           \
341            hyper_modifier : 0)                        \
342      | (!EQ (ns_right_alternate_modifier, Qleft) && \
343         ((flags & NSRightAlternateKeyMask) \
344          == NSRightAlternateKeyMask) ? \
345            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
346      | ((flags & NSAlternateKeyMask) ?                 \
347            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
348      | ((flags & NSShiftKeyMask) ?     \
349            shift_modifier : 0)                        \
350      | (!EQ (ns_right_control_modifier, Qleft) && \
351         ((flags & NSRightControlKeyMask) \
352          == NSRightControlKeyMask) ? \
353            parse_solitary_modifier (ns_right_control_modifier) : 0) \
354      | ((flags & NSControlKeyMask) ?      \
355            parse_solitary_modifier (ns_control_modifier) : 0)     \
356      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
357            parse_solitary_modifier (ns_function_modifier) : 0)    \
358      | (!EQ (ns_right_command_modifier, Qleft) && \
359         ((flags & NSRightCommandKeyMask) \
360          == NSRightCommandKeyMask) ? \
361            parse_solitary_modifier (ns_right_command_modifier) : 0) \
362      | ((flags & NSCommandKeyMask) ?      \
363            parse_solitary_modifier (ns_command_modifier):0))
364 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
366 #define EV_UDMODIFIERS(e)                                      \
367     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
368      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
369      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
370      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
371      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
372      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
373      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
374      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
375      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
377 #define EV_BUTTON(e)                                                         \
378     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
379       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
380      [e buttonNumber] - 1)
382 /* Convert the time field to a timestamp in milliseconds. */
383 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
385 /* This is a piece of code which is common to all the event handling
386    methods.  Maybe it should even be a function.  */
387 #define EV_TRAILER(e)                                                   \
388   {                                                                     \
389     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
390     EV_TRAILER2 (e);                                                    \
391   }
393 #define EV_TRAILER2(e)                                                  \
394   {                                                                     \
395       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
396       if (q_event_ptr)                                                  \
397         {                                                               \
398           Lisp_Object tem = Vinhibit_quit;                              \
399           Vinhibit_quit = Qt;                                           \
400           n_emacs_events_pending++;                                     \
401           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
402           Vinhibit_quit = tem;                                          \
403         }                                                               \
404       else                                                              \
405         hold_event (emacs_event);                                       \
406       EVENT_INIT (*emacs_event);                                        \
407       ns_send_appdefined (-1);                                          \
408     }
410 /* TODO: get rid of need for these forward declarations */
411 static void ns_condemn_scroll_bars (struct frame *f);
412 static void ns_judge_scroll_bars (struct frame *f);
413 void x_set_frame_alpha (struct frame *f);
416 /* ==========================================================================
418     Utilities
420    ========================================================================== */
422 void
423 ns_set_represented_filename (NSString* fstr, struct frame *f)
425   represented_filename = [fstr retain];
426   represented_frame = f;
429 void
430 ns_init_events (struct input_event* ev)
432   EVENT_INIT (*ev);
433   emacs_event = ev;
436 void
437 ns_finish_events ()
439   emacs_event = NULL;
442 static void
443 hold_event (struct input_event *event)
445   if (hold_event_q.nr == hold_event_q.cap)
446     {
447       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
448       else hold_event_q.cap *= 2;
449       hold_event_q.q =
450         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
451     }
453   hold_event_q.q[hold_event_q.nr++] = *event;
454   /* Make sure ns_read_socket is called, i.e. we have input.  */
455   raise (SIGIO);
456   send_appdefined = YES;
459 static Lisp_Object
460 append2 (Lisp_Object list, Lisp_Object item)
461 /* --------------------------------------------------------------------------
462    Utility to append to a list
463    -------------------------------------------------------------------------- */
465   return CALLN (Fnconc, list, list1 (item));
469 const char *
470 ns_etc_directory (void)
471 /* If running as a self-contained app bundle, return as a string the
472    filename of the etc directory, if present; else nil.  */
474   NSBundle *bundle = [NSBundle mainBundle];
475   NSString *resourceDir = [bundle resourcePath];
476   NSString *resourcePath;
477   NSFileManager *fileManager = [NSFileManager defaultManager];
478   BOOL isDir;
480   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
481   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
482     {
483       if (isDir) return [resourcePath UTF8String];
484     }
485   return NULL;
489 const char *
490 ns_exec_path (void)
491 /* If running as a self-contained app bundle, return as a path string
492    the filenames of the libexec and bin directories, ie libexec:bin.
493    Otherwise, return nil.
494    Normally, Emacs does not add its own bin/ directory to the PATH.
495    However, a self-contained NS build has a different layout, with
496    bin/ and libexec/ subdirectories in the directory that contains
497    Emacs.app itself.
498    We put libexec first, because init_callproc_1 uses the first
499    element to initialize exec-directory.  An alternative would be
500    for init_callproc to check for invocation-directory/libexec.
503   NSBundle *bundle = [NSBundle mainBundle];
504   NSString *resourceDir = [bundle resourcePath];
505   NSString *binDir = [bundle bundlePath];
506   NSString *resourcePath, *resourcePaths;
507   NSRange range;
508   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
509   NSFileManager *fileManager = [NSFileManager defaultManager];
510   NSArray *paths;
511   NSEnumerator *pathEnum;
512   BOOL isDir;
514   range = [resourceDir rangeOfString: @"Contents"];
515   if (range.location != NSNotFound)
516     {
517       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
518 #ifdef NS_IMPL_COCOA
519       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
520 #endif
521     }
523   paths = [binDir stringsByAppendingPaths:
524                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
525   pathEnum = [paths objectEnumerator];
526   resourcePaths = @"";
528   while ((resourcePath = [pathEnum nextObject]))
529     {
530       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
531         if (isDir)
532           {
533             if ([resourcePaths length] > 0)
534               resourcePaths
535                 = [resourcePaths stringByAppendingString: pathSeparator];
536             resourcePaths
537               = [resourcePaths stringByAppendingString: resourcePath];
538           }
539     }
540   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
542   return NULL;
546 const char *
547 ns_load_path (void)
548 /* If running as a self-contained app bundle, return as a path string
549    the filenames of the site-lisp and lisp directories.
550    Ie, site-lisp:lisp.  Otherwise, return nil.  */
552   NSBundle *bundle = [NSBundle mainBundle];
553   NSString *resourceDir = [bundle resourcePath];
554   NSString *resourcePath, *resourcePaths;
555   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
556   NSFileManager *fileManager = [NSFileManager defaultManager];
557   BOOL isDir;
558   NSArray *paths = [resourceDir stringsByAppendingPaths:
559                               [NSArray arrayWithObjects:
560                                          @"site-lisp", @"lisp", nil]];
561   NSEnumerator *pathEnum = [paths objectEnumerator];
562   resourcePaths = @"";
564   /* Hack to skip site-lisp.  */
565   if (no_site_lisp) resourcePath = [pathEnum nextObject];
567   while ((resourcePath = [pathEnum nextObject]))
568     {
569       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
570         if (isDir)
571           {
572             if ([resourcePaths length] > 0)
573               resourcePaths
574                 = [resourcePaths stringByAppendingString: pathSeparator];
575             resourcePaths
576               = [resourcePaths stringByAppendingString: resourcePath];
577           }
578     }
579   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
581   return NULL;
584 static void
585 ns_timeout (int usecs)
586 /* --------------------------------------------------------------------------
587      Blocking timer utility used by ns_ring_bell
588    -------------------------------------------------------------------------- */
590   struct timespec wakeup = timespec_add (current_timespec (),
591                                          make_timespec (0, usecs * 1000));
593   /* Keep waiting until past the time wakeup.  */
594   while (1)
595     {
596       struct timespec timeout, now = current_timespec ();
597       if (timespec_cmp (wakeup, now) <= 0)
598         break;
599       timeout = timespec_sub (wakeup, now);
601       /* Try to wait that long--but we might wake up sooner.  */
602       pselect (0, NULL, NULL, NULL, &timeout, NULL);
603     }
607 void
608 ns_release_object (void *obj)
609 /* --------------------------------------------------------------------------
610     Release an object (callable from C)
611    -------------------------------------------------------------------------- */
613     [(id)obj release];
617 void
618 ns_retain_object (void *obj)
619 /* --------------------------------------------------------------------------
620     Retain an object (callable from C)
621    -------------------------------------------------------------------------- */
623     [(id)obj retain];
627 void *
628 ns_alloc_autorelease_pool (void)
629 /* --------------------------------------------------------------------------
630      Allocate a pool for temporary objects (callable from C)
631    -------------------------------------------------------------------------- */
633   return [[NSAutoreleasePool alloc] init];
637 void
638 ns_release_autorelease_pool (void *pool)
639 /* --------------------------------------------------------------------------
640      Free a pool and temporary objects it refers to (callable from C)
641    -------------------------------------------------------------------------- */
643   ns_release_object (pool);
647 /* True, if the menu bar should be hidden.  */
649 static BOOL
650 ns_menu_bar_should_be_hidden (void)
652   return !NILP (ns_auto_hide_menu_bar)
653     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
657 static CGFloat
658 ns_menu_bar_height (NSScreen *screen)
659 /* The height of the menu bar, if visible. */
661   //  NSTRACE ("ns_menu_bar_height");
663   CGFloat res;
665   if (ns_menu_bar_should_be_hidden())
666     {
667       res = 0;
668     }
669   else
670     {
671       NSRect screenFrame = [screen frame];
672       NSRect screenVisibleFrame = [screen visibleFrame];
674       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
675       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
676                                  + screenVisibleFrame.size.height);
678       res = frameTop - visibleFrameTop;
680     }
682   // NSTRACE_MSG (NSTRACE_FMT_RETURN "%.0f", res);
684   return res;
688 /* ==========================================================================
690     Focus (clipping) and screen update
692    ========================================================================== */
695 // Window constraining
696 // -------------------
698 // To ensure that the windows are not placed under the menu bar, they
699 // are typically moved by the call-back constrainFrameRect. However,
700 // by overriding it, it's possible to inhibit this, leaving the window
701 // in it's original position.
703 // It's possible to hide the menu bar. However, technically, it's only
704 // possible to hide it when the application is active. To ensure that
705 // this work properly, the menu bar and window constraining are
706 // deferred until the application becomes active.
708 // Even though it's not possible to manually move a window above the
709 // top of the screen, it is allowed if it's done programmatically,
710 // when the menu is hidden. This allows the editable area to cover the
711 // full screen height.
713 // Test cases
714 // ----------
716 // Use the following extra files:
718 //    init.el:
719 //       ;; Hide menu and place frame slightly above the top of the screen.
720 //       (setq ns-auto-hide-menu-bar t)
721 //       (set-frame-position (selected-frame) 0 -20)
723 // Test 1:
725 //    emacs -Q -l init.el
727 //    Result: No menu bar, and the title bar should be above the screen.
729 // Test 2:
731 //    emacs -Q
733 //    Result: Menu bar visible, frame placed immediately below the menu.
736 static NSRect constrain_frame_rect(NSRect frameRect)
738   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
739              NSTRACE_ARG_RECT (frameRect));
741   // --------------------
742   // Collect information about the screen the frame is covering.
743   //
745   NSArray *screens = [NSScreen screens];
746   NSUInteger nr_screens = [screens count];
748   int i;
750   // The height of the menu bar, if present in any screen the frame is
751   // displayed in.
752   int menu_bar_height = 0;
754   // A rectangle covering all the screen the frame is displayed in.
755   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
756   for (i = 0; i < nr_screens; ++i )
757     {
758       NSScreen *s = [screens objectAtIndex: i];
759       NSRect scrRect = [s frame];
761       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
762                    i, NSTRACE_ARG_RECT (scrRect));
764       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
765         {
766           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
768           menu_bar_height = max(menu_bar_height, ns_menu_bar_height (s));
769         }
770     }
772   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
774   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
776   if (multiscreenRect.size.width == 0
777       || multiscreenRect.size.height == 0)
778     {
779       // Failed to find any monitor, give up.
780       NSTRACE_MSG ("multiscreenRect empty");
781       NSTRACE_RETURN_RECT (frameRect);
782       return frameRect;
783     }
786   // --------------------
787   // Find a suitable placement.
788   //
790   if (ns_menu_bar_should_be_hidden())
791     {
792       // When the menu bar is hidden, the user may place part of the
793       // frame above the top of the screen, for example to hide the
794       // title bar.
795       //
796       // Hence, keep the original position.
797     }
798   else
799     {
800       // Ensure that the frame is below the menu bar, or below the top
801       // of the screen.
802       //
803       // This assume that the menu bar is placed at the top in the
804       // rectangle that covers the monitors.  (It doesn't have to be,
805       // but if it's not it's hard to do anything useful.)
806       CGFloat topOfWorkArea = (multiscreenRect.origin.y
807                                + multiscreenRect.size.height
808                                - menu_bar_height);
810       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
811       if (topOfFrame > topOfWorkArea)
812         {
813           frameRect.origin.y -= topOfFrame - topOfWorkArea;
814           NSTRACE_RECT ("After placement adjust", frameRect);
815         }
816     }
818   // Include the following section to restrict frame to the screens.
819   // (If so, update it to allow the frame to stretch down below the
820   // screen.)
821 #if 0
822   // --------------------
823   // Ensure frame doesn't stretch below the screens.
824   //
826   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
828   if (diff > 0)
829     {
830       frameRect.origin.y = multiscreenRect.origin.y;
831       frameRect.size.height -= diff;
832     }
833 #endif
835   NSTRACE_RETURN_RECT (frameRect);
836   return frameRect;
840 static void
841 ns_constrain_all_frames (void)
842 /* --------------------------------------------------------------------------
843      Ensure that the menu bar doesn't cover any frames.
844    -------------------------------------------------------------------------- */
846   Lisp_Object tail, frame;
848   NSTRACE ("ns_constrain_all_frames");
850   block_input ();
852   FOR_EACH_FRAME (tail, frame)
853     {
854       struct frame *f = XFRAME (frame);
855       if (FRAME_NS_P (f))
856         {
857           EmacsView *view = FRAME_NS_VIEW (f);
859           if (![view isFullscreen])
860             {
861               [[view window]
862                 setFrame:constrain_frame_rect([[view window] frame])
863                  display:NO];
864             }
865         }
866     }
868   unblock_input ();
872 static void
873 ns_update_auto_hide_menu_bar (void)
874 /* --------------------------------------------------------------------------
875      Show or hide the menu bar, based on user setting.
876    -------------------------------------------------------------------------- */
878 #ifdef NS_IMPL_COCOA
879   NSTRACE ("ns_update_auto_hide_menu_bar");
881   block_input ();
883   if (NSApp != nil && [NSApp isActive])
884     {
885       // Note, "setPresentationOptions" triggers an error unless the
886       // application is active.
887       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
889       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
890         {
891           NSApplicationPresentationOptions options
892             = NSApplicationPresentationDefault;
894           if (menu_bar_should_be_hidden)
895             options |= NSApplicationPresentationAutoHideMenuBar
896               | NSApplicationPresentationAutoHideDock;
898           [NSApp setPresentationOptions: options];
900           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
902           if (!ns_menu_bar_is_hidden)
903             {
904               ns_constrain_all_frames ();
905             }
906         }
907     }
909   unblock_input ();
910 #endif
914 static void
915 ns_update_begin (struct frame *f)
916 /* --------------------------------------------------------------------------
917    Prepare for a grouped sequence of drawing calls
918    external (RIF) call; whole frame, called before update_window_begin
919    -------------------------------------------------------------------------- */
921   EmacsView *view = FRAME_NS_VIEW (f);
922   NSTRACE ("ns_update_begin");
924   ns_update_auto_hide_menu_bar ();
926 #ifdef NS_IMPL_COCOA
927   if ([view isFullscreen] && [view fsIsNative])
928   {
929     // Fix reappearing tool bar in fullscreen for OSX 10.7
930     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
931     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
932     if (! tbar_visible != ! [toolbar isVisible])
933       [toolbar setVisible: tbar_visible];
934   }
935 #endif
937   ns_updating_frame = f;
938   [view lockFocus];
940   /* drawRect may have been called for say the minibuffer, and then clip path
941      is for the minibuffer.  But the display engine may draw more because
942      we have set the frame as garbaged.  So reset clip path to the whole
943      view.  */
944 #ifdef NS_IMPL_COCOA
945   {
946     NSBezierPath *bp;
947     NSRect r = [view frame];
948     NSRect cr = [[view window] frame];
949     /* If a large frame size is set, r may be larger than the window frame
950        before constrained.  In that case don't change the clip path, as we
951        will clear in to the tool bar and title bar.  */
952     if (r.size.height
953         + FRAME_NS_TITLEBAR_HEIGHT (f)
954         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
955       {
956         bp = [[NSBezierPath bezierPathWithRect: r] retain];
957         [bp setClip];
958         [bp release];
959       }
960   }
961 #endif
963 #ifdef NS_IMPL_GNUSTEP
964   uRect = NSMakeRect (0, 0, 0, 0);
965 #endif
969 static void
970 ns_update_window_begin (struct window *w)
971 /* --------------------------------------------------------------------------
972    Prepare for a grouped sequence of drawing calls
973    external (RIF) call; for one window, called after update_begin
974    -------------------------------------------------------------------------- */
976   struct frame *f = XFRAME (WINDOW_FRAME (w));
977   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
979   NSTRACE ("ns_update_window_begin");
980   w->output_cursor = w->cursor;
982   block_input ();
984   if (f == hlinfo->mouse_face_mouse_frame)
985     {
986       /* Don't do highlighting for mouse motion during the update.  */
987       hlinfo->mouse_face_defer = 1;
989         /* If the frame needs to be redrawn,
990            simply forget about any prior mouse highlighting.  */
991       if (FRAME_GARBAGED_P (f))
992         hlinfo->mouse_face_window = Qnil;
994       /* (further code for mouse faces ifdef'd out in other terms elided) */
995     }
997   unblock_input ();
1001 static void
1002 ns_update_window_end (struct window *w, bool cursor_on_p,
1003                       bool mouse_face_overwritten_p)
1004 /* --------------------------------------------------------------------------
1005    Finished a grouped sequence of drawing calls
1006    external (RIF) call; for one window called before update_end
1007    -------------------------------------------------------------------------- */
1009   NSTRACE ("update_window_end");
1011   /* note: this fn is nearly identical in all terms */
1012   if (!w->pseudo_window_p)
1013     {
1014       block_input ();
1016       if (cursor_on_p)
1017         display_and_set_cursor (w, 1,
1018                                 w->output_cursor.hpos, w->output_cursor.vpos,
1019                                 w->output_cursor.x, w->output_cursor.y);
1021       if (draw_window_fringes (w, 1))
1022         {
1023           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1024             x_draw_right_divider (w);
1025           else
1026             x_draw_vertical_border (w);
1027         }
1029       unblock_input ();
1030     }
1032   /* If a row with mouse-face was overwritten, arrange for
1033      frame_up_to_date to redisplay the mouse highlight.  */
1034   if (mouse_face_overwritten_p)
1035     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1039 static void
1040 ns_update_end (struct frame *f)
1041 /* --------------------------------------------------------------------------
1042    Finished a grouped sequence of drawing calls
1043    external (RIF) call; for whole frame, called after update_window_end
1044    -------------------------------------------------------------------------- */
1046   EmacsView *view = FRAME_NS_VIEW (f);
1048   NSTRACE ("ns_update_end");
1050 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1051   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1053   block_input ();
1055   [view unlockFocus];
1056   [[view window] flushWindow];
1058   unblock_input ();
1059   ns_updating_frame = NULL;
1062 static void
1063 ns_focus (struct frame *f, NSRect *r, int n)
1064 /* --------------------------------------------------------------------------
1065    Internal: Focus on given frame.  During small local updates this is used to
1066      draw, however during large updates, ns_update_begin and ns_update_end are
1067      called to wrap the whole thing, in which case these calls are stubbed out.
1068      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1069      the back end won't do this automatically, and will just end up flushing
1070      the entire window.
1071    -------------------------------------------------------------------------- */
1073 //  NSTRACE ("ns_focus");
1074 /* static int c =0;
1075    fprintf (stderr, "focus: %d", c++);
1076    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
1077    fprintf (stderr, "\n"); */
1079   if (f != ns_updating_frame)
1080     {
1081       NSView *view = FRAME_NS_VIEW (f);
1082       if (view != focus_view)
1083         {
1084           if (focus_view != NULL)
1085             {
1086               [focus_view unlockFocus];
1087               [[focus_view window] flushWindow];
1088 /*debug_lock--; */
1089             }
1091           if (view)
1092             [view lockFocus];
1093           focus_view = view;
1094 /*if (view) debug_lock++; */
1095         }
1096     }
1098   /* clipping */
1099   if (r)
1100     {
1101       [[NSGraphicsContext currentContext] saveGraphicsState];
1102       if (n == 2)
1103         NSRectClipList (r, 2);
1104       else
1105         NSRectClip (*r);
1106       gsaved = YES;
1107     }
1111 static void
1112 ns_unfocus (struct frame *f)
1113 /* --------------------------------------------------------------------------
1114      Internal: Remove focus on given frame
1115    -------------------------------------------------------------------------- */
1117 //  NSTRACE ("ns_unfocus");
1119   if (gsaved)
1120     {
1121       [[NSGraphicsContext currentContext] restoreGraphicsState];
1122       gsaved = NO;
1123     }
1125   if (f != ns_updating_frame)
1126     {
1127       if (focus_view != NULL)
1128         {
1129           [focus_view unlockFocus];
1130           [[focus_view window] flushWindow];
1131           focus_view = NULL;
1132 /*debug_lock--; */
1133         }
1134     }
1138 static void
1139 ns_clip_to_row (struct window *w, struct glyph_row *row,
1140                 enum glyph_row_area area, BOOL gc)
1141 /* --------------------------------------------------------------------------
1142      Internal (but parallels other terms): Focus drawing on given row
1143    -------------------------------------------------------------------------- */
1145   struct frame *f = XFRAME (WINDOW_FRAME (w));
1146   NSRect clip_rect;
1147   int window_x, window_y, window_width;
1149   window_box (w, area, &window_x, &window_y, &window_width, 0);
1151   clip_rect.origin.x = window_x;
1152   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1153   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1154   clip_rect.size.width = window_width;
1155   clip_rect.size.height = row->visible_height;
1157   ns_focus (f, &clip_rect, 1);
1161 static void
1162 ns_ring_bell (struct frame *f)
1163 /* --------------------------------------------------------------------------
1164      "Beep" routine
1165    -------------------------------------------------------------------------- */
1167   NSTRACE ("ns_ring_bell");
1168   if (visible_bell)
1169     {
1170       NSAutoreleasePool *pool;
1171       struct frame *frame = SELECTED_FRAME ();
1172       NSView *view;
1174       block_input ();
1175       pool = [[NSAutoreleasePool alloc] init];
1177       view = FRAME_NS_VIEW (frame);
1178       if (view != nil)
1179         {
1180           NSRect r, surr;
1181           NSPoint dim = NSMakePoint (128, 128);
1183           r = [view bounds];
1184           r.origin.x += (r.size.width - dim.x) / 2;
1185           r.origin.y += (r.size.height - dim.y) / 2;
1186           r.size.width = dim.x;
1187           r.size.height = dim.y;
1188           surr = NSInsetRect (r, -2, -2);
1189           ns_focus (frame, &surr, 1);
1190           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
1191           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
1192                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
1193           NSRectFill (r);
1194           [[view window] flushWindow];
1195           ns_timeout (150000);
1196           [[view window] restoreCachedImage];
1197           [[view window] flushWindow];
1198           ns_unfocus (frame);
1199         }
1200       [pool release];
1201       unblock_input ();
1202     }
1203   else
1204     {
1205       NSBeep ();
1206     }
1209 /* ==========================================================================
1211     Frame / window manager related functions
1213    ========================================================================== */
1216 static void
1217 ns_raise_frame (struct frame *f)
1218 /* --------------------------------------------------------------------------
1219      Bring window to foreground and make it active
1220    -------------------------------------------------------------------------- */
1222   NSView *view;
1223   check_window_system (f);
1224   view = FRAME_NS_VIEW (f);
1225   block_input ();
1226   if (FRAME_VISIBLE_P (f))
1227     [[view window] makeKeyAndOrderFront: NSApp];
1228   unblock_input ();
1232 static void
1233 ns_lower_frame (struct frame *f)
1234 /* --------------------------------------------------------------------------
1235      Send window to back
1236    -------------------------------------------------------------------------- */
1238   NSView *view;
1239   check_window_system (f);
1240   view = FRAME_NS_VIEW (f);
1241   block_input ();
1242   [[view window] orderBack: NSApp];
1243   unblock_input ();
1247 static void
1248 ns_frame_raise_lower (struct frame *f, bool raise)
1249 /* --------------------------------------------------------------------------
1250      External (hook)
1251    -------------------------------------------------------------------------- */
1253   NSTRACE ("ns_frame_raise_lower");
1255   if (raise)
1256     ns_raise_frame (f);
1257   else
1258     ns_lower_frame (f);
1262 static void
1263 ns_frame_rehighlight (struct frame *frame)
1264 /* --------------------------------------------------------------------------
1265      External (hook): called on things like window switching within frame
1266    -------------------------------------------------------------------------- */
1268   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1269   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1271   NSTRACE ("ns_frame_rehighlight");
1272   if (dpyinfo->x_focus_frame)
1273     {
1274       dpyinfo->x_highlight_frame
1275         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1276            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1277            : dpyinfo->x_focus_frame);
1278       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1279         {
1280           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1281           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1282         }
1283     }
1284   else
1285       dpyinfo->x_highlight_frame = 0;
1287   if (dpyinfo->x_highlight_frame &&
1288          dpyinfo->x_highlight_frame != old_highlight)
1289     {
1290       if (old_highlight)
1291         {
1292           x_update_cursor (old_highlight, 1);
1293           x_set_frame_alpha (old_highlight);
1294         }
1295       if (dpyinfo->x_highlight_frame)
1296         {
1297           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1298           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1299         }
1300     }
1304 void
1305 x_make_frame_visible (struct frame *f)
1306 /* --------------------------------------------------------------------------
1307      External: Show the window (X11 semantics)
1308    -------------------------------------------------------------------------- */
1310   NSTRACE ("x_make_frame_visible");
1311   /* XXX: at some points in past this was not needed, as the only place that
1312      called this (frame.c:Fraise_frame ()) also called raise_lower;
1313      if this ends up the case again, comment this out again. */
1314   if (!FRAME_VISIBLE_P (f))
1315     {
1316       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1318       SET_FRAME_VISIBLE (f, 1);
1319       ns_raise_frame (f);
1321       /* Making a new frame from a fullscreen frame will make the new frame
1322          fullscreen also.  So skip handleFS as this will print an error.  */
1323       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1324           && [view isFullscreen])
1325         return;
1327       if (f->want_fullscreen != FULLSCREEN_NONE)
1328         {
1329           block_input ();
1330           [view handleFS];
1331           unblock_input ();
1332         }
1333     }
1337 void
1338 x_make_frame_invisible (struct frame *f)
1339 /* --------------------------------------------------------------------------
1340      External: Hide the window (X11 semantics)
1341    -------------------------------------------------------------------------- */
1343   NSView *view;
1344   NSTRACE ("x_make_frame_invisible");
1345   check_window_system (f);
1346   view = FRAME_NS_VIEW (f);
1347   [[view window] orderOut: NSApp];
1348   SET_FRAME_VISIBLE (f, 0);
1349   SET_FRAME_ICONIFIED (f, 0);
1353 void
1354 x_iconify_frame (struct frame *f)
1355 /* --------------------------------------------------------------------------
1356      External: Iconify window
1357    -------------------------------------------------------------------------- */
1359   NSView *view;
1360   struct ns_display_info *dpyinfo;
1362   NSTRACE ("x_iconify_frame");
1363   check_window_system (f);
1364   view = FRAME_NS_VIEW (f);
1365   dpyinfo = FRAME_DISPLAY_INFO (f);
1367   if (dpyinfo->x_highlight_frame == f)
1368     dpyinfo->x_highlight_frame = 0;
1370   if ([[view window] windowNumber] <= 0)
1371     {
1372       /* the window is still deferred.  Make it very small, bring it
1373          on screen and order it out. */
1374       NSRect s = { { 100, 100}, {0, 0} };
1375       NSRect t;
1376       t = [[view window] frame];
1377       [[view window] setFrame: s display: NO];
1378       [[view window] orderBack: NSApp];
1379       [[view window] orderOut: NSApp];
1380       [[view window] setFrame: t display: NO];
1381     }
1382   [[view window] miniaturize: NSApp];
1385 /* Free X resources of frame F.  */
1387 void
1388 x_free_frame_resources (struct frame *f)
1390   NSView *view;
1391   struct ns_display_info *dpyinfo;
1392   Mouse_HLInfo *hlinfo;
1394   NSTRACE ("x_free_frame_resources");
1395   check_window_system (f);
1396   view = FRAME_NS_VIEW (f);
1397   dpyinfo = FRAME_DISPLAY_INFO (f);
1398   hlinfo = MOUSE_HL_INFO (f);
1400   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1402   block_input ();
1404   free_frame_menubar (f);
1405   free_frame_faces (f);
1407   if (f == dpyinfo->x_focus_frame)
1408     dpyinfo->x_focus_frame = 0;
1409   if (f == dpyinfo->x_highlight_frame)
1410     dpyinfo->x_highlight_frame = 0;
1411   if (f == hlinfo->mouse_face_mouse_frame)
1412     reset_mouse_highlight (hlinfo);
1414   if (f->output_data.ns->miniimage != nil)
1415     [f->output_data.ns->miniimage release];
1417   [[view window] close];
1418   [view release];
1420   xfree (f->output_data.ns);
1422   unblock_input ();
1425 void
1426 x_destroy_window (struct frame *f)
1427 /* --------------------------------------------------------------------------
1428      External: Delete the window
1429    -------------------------------------------------------------------------- */
1431   NSTRACE ("x_destroy_window");
1432   check_window_system (f);
1433   x_free_frame_resources (f);
1434   ns_window_num--;
1438 void
1439 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1440 /* --------------------------------------------------------------------------
1441      External: Position the window
1442    -------------------------------------------------------------------------- */
1444   NSView *view = FRAME_NS_VIEW (f);
1445   NSArray *screens = [NSScreen screens];
1446   NSScreen *fscreen = [screens objectAtIndex: 0];
1447   NSScreen *screen = [[view window] screen];
1449   NSTRACE ("x_set_offset");
1451   block_input ();
1453   f->left_pos = xoff;
1454   f->top_pos = yoff;
1456   if (view != nil && screen && fscreen)
1457     {
1458       f->left_pos = f->size_hint_flags & XNegative
1459         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1460         : f->left_pos;
1461       /* We use visibleFrame here to take menu bar into account.
1462          Ideally we should also adjust left/top with visibleFrame.origin.  */
1464       f->top_pos = f->size_hint_flags & YNegative
1465         ? ([screen visibleFrame].size.height + f->top_pos
1466            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1467            - FRAME_TOOLBAR_HEIGHT (f))
1468         : f->top_pos;
1469 #ifdef NS_IMPL_GNUSTEP
1470       if (f->left_pos < 100)
1471         f->left_pos = 100;  /* don't overlap menu */
1472 #endif
1473       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1474          menu bar.  */
1475       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
1476                                 SCREENMAXBOUND ([fscreen frame].size.height
1477                                                 - NS_TOP_POS (f)));
1478       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1479       [[view window] setFrameTopLeftPoint: pt];
1480       f->size_hint_flags &= ~(XNegative|YNegative);
1481     }
1483   unblock_input ();
1487 void
1488 x_set_window_size (struct frame *f,
1489                    bool change_gravity,
1490                    int width,
1491                    int height,
1492                    bool pixelwise)
1493 /* --------------------------------------------------------------------------
1494      Adjust window pixel size based on given character grid size
1495      Impl is a bit more complex than other terms, need to do some
1496      internal clipping.
1497    -------------------------------------------------------------------------- */
1499   EmacsView *view = FRAME_NS_VIEW (f);
1500   NSWindow *window = [view window];
1501   NSRect wr = [window frame];
1502   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1503   int pixelwidth, pixelheight;
1504   int rows, cols;
1505   int orig_height = wr.size.height;
1507   NSTRACE ("x_set_window_size");
1509   if (view == nil)
1510     return;
1512   NSTRACE_RECT ("current", wr);
1514 /*fprintf (stderr, "\tsetWindowSize: %d x %d, pixelwise %d, font size %d x %d\n", width, height, pixelwise, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));*/
1516   block_input ();
1518   if (pixelwise)
1519     {
1520       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1521       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1522       cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1523       rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1524     }
1525   else
1526     {
1527       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1528       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1529       cols = width;
1530       rows = height;
1531     }
1533   /* If we have a toolbar, take its height into account. */
1534   if (tb && ! [view isFullscreen])
1535     {
1536     /* NOTE: previously this would generate wrong result if toolbar not
1537              yet displayed and fixing toolbar_height=32 helped, but
1538              now (200903) seems no longer needed */
1539     FRAME_TOOLBAR_HEIGHT (f) =
1540       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1541         - FRAME_NS_TITLEBAR_HEIGHT (f);
1542 #if 0
1543       /* Only breaks things here, removed by martin 2015-09-30.  */
1544 #ifdef NS_IMPL_GNUSTEP
1545       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1546 #endif
1547 #endif
1548     }
1549   else
1550     FRAME_TOOLBAR_HEIGHT (f) = 0;
1552   wr.size.width = pixelwidth + f->border_width;
1553   wr.size.height = pixelheight;
1554   if (! [view isFullscreen])
1555     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1556       + FRAME_TOOLBAR_HEIGHT (f);
1558   /* Do not try to constrain to this screen.  We may have multiple
1559      screens, and want Emacs to span those.  Constraining to screen
1560      prevents that, and that is not nice to the user.  */
1561  if (f->output_data.ns->zooming)
1562    f->output_data.ns->zooming = 0;
1563  else
1564    wr.origin.y += orig_height - wr.size.height;
1566  frame_size_history_add
1567    (f, Qx_set_window_size_1, width, height,
1568     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1569            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1570            make_number (f->border_width),
1571            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1572            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1574   NSTRACE_RECT ("setFrame", wr);
1575   [window setFrame: wr display: YES];
1577   /* This is a trick to compensate for Emacs' managing the scrollbar area
1578      as a fixed number of standard character columns.  Instead of leaving
1579      blank space for the extra, we chopped it off above.  Now for
1580      left-hand scrollbars, we shift all rendering to the left by the
1581      difference between the real width and Emacs' imagined one.  For
1582      right-hand bars, don't worry about it since the extra is never used.
1583      (Obviously doesn't work for vertically split windows tho..) */
1584   {
1585     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1586       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1587                      - NS_SCROLL_BAR_WIDTH (f), 0)
1588       : NSMakePoint (0, 0);
1589     NSTRACE_RECT ("setFrame", wr);
1590     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1591     [view setBoundsOrigin: origin];
1592   }
1594   [view updateFrameSize: NO];
1595   unblock_input ();
1599 static void
1600 ns_fullscreen_hook (struct frame *f)
1602   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1604   NSTRACE ("ns_fullscreen_hook");
1606   if (!FRAME_VISIBLE_P (f))
1607     return;
1609    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1610     {
1611       /* Old style fs don't initiate correctly if created from
1612          init/default-frame alist, so use a timer (not nice...).
1613       */
1614       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1615                                      selector: @selector (handleFS)
1616                                      userInfo: nil repeats: NO];
1617       return;
1618     }
1620   block_input ();
1621   [view handleFS];
1622   unblock_input ();
1625 /* ==========================================================================
1627     Color management
1629    ========================================================================== */
1632 NSColor *
1633 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1635   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1636   if (idx < 1 || idx >= color_table->avail)
1637     return nil;
1638   return color_table->colors[idx];
1642 unsigned long
1643 ns_index_color (NSColor *color, struct frame *f)
1645   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1646   ptrdiff_t idx;
1647   ptrdiff_t i;
1649   if (!color_table->colors)
1650     {
1651       color_table->size = NS_COLOR_CAPACITY;
1652       color_table->avail = 1; /* skip idx=0 as marker */
1653       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1654       color_table->colors[0] = nil;
1655       color_table->empty_indices = [[NSMutableSet alloc] init];
1656     }
1658   /* Do we already have this color?  */
1659   for (i = 1; i < color_table->avail; i++)
1660     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1661       return i;
1663   if ([color_table->empty_indices count] > 0)
1664     {
1665       NSNumber *index = [color_table->empty_indices anyObject];
1666       [color_table->empty_indices removeObject: index];
1667       idx = [index unsignedLongValue];
1668     }
1669   else
1670     {
1671       if (color_table->avail == color_table->size)
1672         color_table->colors =
1673           xpalloc (color_table->colors, &color_table->size, 1,
1674                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1675       idx = color_table->avail++;
1676     }
1678   color_table->colors[idx] = color;
1679   [color retain];
1680 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1681   return idx;
1685 void
1686 ns_free_indexed_color (unsigned long idx, struct frame *f)
1688   struct ns_color_table *color_table;
1689   NSColor *color;
1690   NSNumber *index;
1692   if (!f)
1693     return;
1695   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1697   if (idx <= 0 || idx >= color_table->size) {
1698     message1 ("ns_free_indexed_color: Color index out of range.\n");
1699     return;
1700   }
1702   index = [NSNumber numberWithUnsignedInt: idx];
1703   if ([color_table->empty_indices containsObject: index]) {
1704     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1705     return;
1706   }
1708   color = color_table->colors[idx];
1709   [color release];
1710   color_table->colors[idx] = nil;
1711   [color_table->empty_indices addObject: index];
1712 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1716 static int
1717 ns_get_color (const char *name, NSColor **col)
1718 /* --------------------------------------------------------------------------
1719      Parse a color name
1720    -------------------------------------------------------------------------- */
1721 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1722    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1723    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1725   NSColor *new = nil;
1726   static char hex[20];
1727   int scaling = 0;
1728   float r = -1.0, g, b;
1729   NSString *nsname = [NSString stringWithUTF8String: name];
1731 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1732   block_input ();
1734   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1735     {
1736 #ifdef NS_IMPL_COCOA
1737       NSString *defname = [[NSUserDefaults standardUserDefaults]
1738                             stringForKey: @"AppleHighlightColor"];
1739       if (defname != nil)
1740         nsname = defname;
1741       else
1742 #endif
1743       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1744         {
1745           *col = [new colorUsingDefaultColorSpace];
1746           unblock_input ();
1747           return 0;
1748         }
1749       else
1750         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1752       name = [nsname UTF8String];
1753     }
1754   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1755     {
1756       /* NOTE: OSX applications normally don't set foreground selection, but
1757          text may be unreadable if we don't.
1758       */
1759       if ((new = [NSColor selectedTextColor]) != nil)
1760         {
1761           *col = [new colorUsingDefaultColorSpace];
1762           unblock_input ();
1763           return 0;
1764         }
1766       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1767       name = [nsname UTF8String];
1768     }
1770   /* First, check for some sort of numeric specification. */
1771   hex[0] = '\0';
1773   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1774     {
1775       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1776       [scanner scanFloat: &r];
1777       [scanner scanFloat: &g];
1778       [scanner scanFloat: &b];
1779     }
1780   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1781     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1782   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1783     {
1784       int len = (strlen(name) - 1);
1785       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1786       int i;
1787       scaling = strlen(name+start) / 3;
1788       for (i = 0; i < 3; i++)
1789         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1790                  name + start + i * scaling);
1791       hex[3 * (scaling + 1) - 1] = '\0';
1792     }
1794   if (hex[0])
1795     {
1796       int rr, gg, bb;
1797       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1798       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1799         {
1800           r = rr / fscale;
1801           g = gg / fscale;
1802           b = bb / fscale;
1803         }
1804     }
1806   if (r >= 0.0F)
1807     {
1808       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1809       unblock_input ();
1810       return 0;
1811     }
1813   /* Otherwise, color is expected to be from a list */
1814   {
1815     NSEnumerator *lenum, *cenum;
1816     NSString *name;
1817     NSColorList *clist;
1819 #ifdef NS_IMPL_GNUSTEP
1820     /* XXX: who is wrong, the requestor or the implementation? */
1821     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1822         == NSOrderedSame)
1823       nsname = @"highlightColor";
1824 #endif
1826     lenum = [[NSColorList availableColorLists] objectEnumerator];
1827     while ( (clist = [lenum nextObject]) && new == nil)
1828       {
1829         cenum = [[clist allKeys] objectEnumerator];
1830         while ( (name = [cenum nextObject]) && new == nil )
1831           {
1832             if ([name compare: nsname
1833                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1834               new = [clist colorWithKey: name];
1835           }
1836       }
1837   }
1839   if (new)
1840     *col = [new colorUsingDefaultColorSpace];
1841   unblock_input ();
1842   return new ? 0 : 1;
1847 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1848 /* --------------------------------------------------------------------------
1849      Convert a Lisp string object to a NS color
1850    -------------------------------------------------------------------------- */
1852   NSTRACE ("ns_lisp_to_color");
1853   if (STRINGP (color))
1854     return ns_get_color (SSDATA (color), col);
1855   else if (SYMBOLP (color))
1856     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1857   return 1;
1861 Lisp_Object
1862 ns_color_to_lisp (NSColor *col)
1863 /* --------------------------------------------------------------------------
1864      Convert a color to a lisp string with the RGB equivalent
1865    -------------------------------------------------------------------------- */
1867   EmacsCGFloat red, green, blue, alpha, gray;
1868   char buf[1024];
1869   const char *str;
1870   NSTRACE ("ns_color_to_lisp");
1872   block_input ();
1873   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1875       if ((str =[[col colorNameComponent] UTF8String]))
1876         {
1877           unblock_input ();
1878           return build_string ((char *)str);
1879         }
1881     [[col colorUsingDefaultColorSpace]
1882         getRed: &red green: &green blue: &blue alpha: &alpha];
1883   if (red == green && red == blue)
1884     {
1885       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1886             getWhite: &gray alpha: &alpha];
1887       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1888                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1889       unblock_input ();
1890       return build_string (buf);
1891     }
1893   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1894             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1896   unblock_input ();
1897   return build_string (buf);
1901 void
1902 ns_query_color(void *col, XColor *color_def, int setPixel)
1903 /* --------------------------------------------------------------------------
1904          Get ARGB values out of NSColor col and put them into color_def.
1905          If setPixel, set the pixel to a concatenated version.
1906          and set color_def pixel to the resulting index.
1907    -------------------------------------------------------------------------- */
1909   EmacsCGFloat r, g, b, a;
1911   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1912   color_def->red   = r * 65535;
1913   color_def->green = g * 65535;
1914   color_def->blue  = b * 65535;
1916   if (setPixel == YES)
1917     color_def->pixel
1918       = ARGB_TO_ULONG((int)(a*255),
1919                       (int)(r*255), (int)(g*255), (int)(b*255));
1923 bool
1924 ns_defined_color (struct frame *f,
1925                   const char *name,
1926                   XColor *color_def,
1927                   bool alloc,
1928                   bool makeIndex)
1929 /* --------------------------------------------------------------------------
1930          Return true if named color found, and set color_def rgb accordingly.
1931          If makeIndex and alloc are nonzero put the color in the color_table,
1932          and set color_def pixel to the resulting index.
1933          If makeIndex is zero, set color_def pixel to ARGB.
1934          Return false if not found
1935    -------------------------------------------------------------------------- */
1937   NSColor *col;
1938   NSTRACE ("ns_defined_color");
1940   block_input ();
1941   if (ns_get_color (name, &col) != 0) /* Color not found  */
1942     {
1943       unblock_input ();
1944       return 0;
1945     }
1946   if (makeIndex && alloc)
1947     color_def->pixel = ns_index_color (col, f);
1948   ns_query_color (col, color_def, !makeIndex);
1949   unblock_input ();
1950   return 1;
1954 void
1955 x_set_frame_alpha (struct frame *f)
1956 /* --------------------------------------------------------------------------
1957      change the entire-frame transparency
1958    -------------------------------------------------------------------------- */
1960   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
1961   double alpha = 1.0;
1962   double alpha_min = 1.0;
1964   if (dpyinfo->x_highlight_frame == f)
1965     alpha = f->alpha[0];
1966   else
1967     alpha = f->alpha[1];
1969   if (FLOATP (Vframe_alpha_lower_limit))
1970     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1971   else if (INTEGERP (Vframe_alpha_lower_limit))
1972     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1974   if (alpha < 0.0)
1975     return;
1976   else if (1.0 < alpha)
1977     alpha = 1.0;
1978   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1979     alpha = alpha_min;
1981 #ifdef NS_IMPL_COCOA
1982   {
1983     EmacsView *view = FRAME_NS_VIEW (f);
1984   [[view window] setAlphaValue: alpha];
1985   }
1986 #endif
1990 /* ==========================================================================
1992     Mouse handling
1994    ========================================================================== */
1997 void
1998 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1999 /* --------------------------------------------------------------------------
2000      Programmatically reposition mouse pointer in pixel coordinates
2001    -------------------------------------------------------------------------- */
2003   NSTRACE ("frame_set_mouse_pixel_position");
2004   ns_raise_frame (f);
2005 #if 0
2006   /* FIXME: this does not work, and what about GNUstep? */
2007 #ifdef NS_IMPL_COCOA
2008   [FRAME_NS_VIEW (f) lockFocus];
2009   PSsetmouse ((float)pix_x, (float)pix_y);
2010   [FRAME_NS_VIEW (f) unlockFocus];
2011 #endif
2012 #endif
2015 static int
2016 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2017 /*   ------------------------------------------------------------------------
2018      Called by EmacsView on mouseMovement events.  Passes on
2019      to emacs mainstream code if we moved off of a rect of interest
2020      known as last_mouse_glyph.
2021      ------------------------------------------------------------------------ */
2023   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2024   NSRect *r;
2026 //  NSTRACE ("note_mouse_movement");
2028   dpyinfo->last_mouse_motion_frame = frame;
2029   r = &dpyinfo->last_mouse_glyph;
2031   /* Note, this doesn't get called for enter/leave, since we don't have a
2032      position.  Those are taken care of in the corresponding NSView methods. */
2034   /* has movement gone beyond last rect we were tracking? */
2035   if (x < r->origin.x || x >= r->origin.x + r->size.width
2036       || y < r->origin.y || y >= r->origin.y + r->size.height)
2037     {
2038       ns_update_begin (frame);
2039       frame->mouse_moved = 1;
2040       note_mouse_highlight (frame, x, y);
2041       remember_mouse_glyph (frame, x, y, r);
2042       ns_update_end (frame);
2043       return 1;
2044     }
2046   return 0;
2050 static void
2051 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2052                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2053                    Time *time)
2054 /* --------------------------------------------------------------------------
2055     External (hook): inform emacs about mouse position and hit parts.
2056     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2057     x & y should be position in the scrollbar (the whole bar, not the handle)
2058     and length of scrollbar respectively
2059    -------------------------------------------------------------------------- */
2061   id view;
2062   NSPoint position;
2063   Lisp_Object frame, tail;
2064   struct frame *f;
2065   struct ns_display_info *dpyinfo;
2067   NSTRACE ("ns_mouse_position");
2069   if (*fp == NULL)
2070     {
2071       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2072       return;
2073     }
2075   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2077   block_input ();
2079   /* Clear the mouse-moved flag for every frame on this display.  */
2080   FOR_EACH_FRAME (tail, frame)
2081     if (FRAME_NS_P (XFRAME (frame))
2082         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2083       XFRAME (frame)->mouse_moved = 0;
2085   dpyinfo->last_mouse_scroll_bar = nil;
2086   if (dpyinfo->last_mouse_frame
2087       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2088     f = dpyinfo->last_mouse_frame;
2089   else
2090     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2092   if (f && FRAME_NS_P (f))
2093     {
2094       view = FRAME_NS_VIEW (*fp);
2096       position = [[view window] mouseLocationOutsideOfEventStream];
2097       position = [view convertPoint: position fromView: nil];
2098       remember_mouse_glyph (f, position.x, position.y,
2099                             &dpyinfo->last_mouse_glyph);
2100 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
2102       if (bar_window) *bar_window = Qnil;
2103       if (part) *part = scroll_bar_above_handle;
2105       if (x) XSETINT (*x, lrint (position.x));
2106       if (y) XSETINT (*y, lrint (position.y));
2107       if (time)
2108         *time = dpyinfo->last_mouse_movement_time;
2109       *fp = f;
2110     }
2112   unblock_input ();
2116 static void
2117 ns_frame_up_to_date (struct frame *f)
2118 /* --------------------------------------------------------------------------
2119     External (hook): Fix up mouse highlighting right after a full update.
2120     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2121    -------------------------------------------------------------------------- */
2123   NSTRACE ("ns_frame_up_to_date");
2125   if (FRAME_NS_P (f))
2126     {
2127       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2128       if (f == hlinfo->mouse_face_mouse_frame)
2129         {
2130           block_input ();
2131           ns_update_begin(f);
2132           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2133                                 hlinfo->mouse_face_mouse_x,
2134                                 hlinfo->mouse_face_mouse_y);
2135           ns_update_end(f);
2136           unblock_input ();
2137         }
2138     }
2142 static void
2143 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2144 /* --------------------------------------------------------------------------
2145     External (RIF): set frame mouse pointer type.
2146    -------------------------------------------------------------------------- */
2148   NSTRACE ("ns_define_frame_cursor");
2149   if (FRAME_POINTER_TYPE (f) != cursor)
2150     {
2151       EmacsView *view = FRAME_NS_VIEW (f);
2152       FRAME_POINTER_TYPE (f) = cursor;
2153       [[view window] invalidateCursorRectsForView: view];
2154       /* Redisplay assumes this function also draws the changed frame
2155          cursor, but this function doesn't, so do it explicitly.  */
2156       x_update_cursor (f, 1);
2157     }
2162 /* ==========================================================================
2164     Keyboard handling
2166    ========================================================================== */
2169 static unsigned
2170 ns_convert_key (unsigned code)
2171 /* --------------------------------------------------------------------------
2172     Internal call used by NSView-keyDown.
2173    -------------------------------------------------------------------------- */
2175   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2176   unsigned keysym;
2177   /* An array would be faster, but less easy to read. */
2178   for (keysym = 0; keysym < last_keysym; keysym += 2)
2179     if (code == convert_ns_to_X_keysym[keysym])
2180       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2181   return 0;
2182 /* if decide to use keyCode and Carbon table, use this line:
2183      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2187 char *
2188 x_get_keysym_name (int keysym)
2189 /* --------------------------------------------------------------------------
2190     Called by keyboard.c.  Not sure if the return val is important, except
2191     that it be unique.
2192    -------------------------------------------------------------------------- */
2194   static char value[16];
2195   NSTRACE ("x_get_keysym_name");
2196   sprintf (value, "%d", keysym);
2197   return value;
2202 /* ==========================================================================
2204     Block drawing operations
2206    ========================================================================== */
2209 static void
2210 ns_redraw_scroll_bars (struct frame *f)
2212   int i;
2213   id view;
2214   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2215   NSTRACE ("ns_redraw_scroll_bars");
2216   for (i =[subviews count]-1; i >= 0; i--)
2217     {
2218       view = [subviews objectAtIndex: i];
2219       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2220       [view display];
2221     }
2225 void
2226 ns_clear_frame (struct frame *f)
2227 /* --------------------------------------------------------------------------
2228       External (hook): Erase the entire frame
2229    -------------------------------------------------------------------------- */
2231   NSView *view = FRAME_NS_VIEW (f);
2232   NSRect r;
2234   NSTRACE ("ns_clear_frame");
2236  /* comes on initial frame because we have
2237     after-make-frame-functions = select-frame */
2238  if (!FRAME_DEFAULT_FACE (f))
2239    return;
2241   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2243   r = [view bounds];
2245   block_input ();
2246   ns_focus (f, &r, 1);
2247   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2248   NSRectFill (r);
2249   ns_unfocus (f);
2251   /* as of 2006/11 or so this is now needed */
2252   ns_redraw_scroll_bars (f);
2253   unblock_input ();
2257 static void
2258 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2259 /* --------------------------------------------------------------------------
2260     External (RIF):  Clear section of frame
2261    -------------------------------------------------------------------------- */
2263   NSRect r = NSMakeRect (x, y, width, height);
2264   NSView *view = FRAME_NS_VIEW (f);
2265   struct face *face = FRAME_DEFAULT_FACE (f);
2267   if (!view || !face)
2268     return;
2270   NSTRACE ("ns_clear_frame_area");
2272   r = NSIntersectionRect (r, [view frame]);
2273   ns_focus (f, &r, 1);
2274   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2276   NSRectFill (r);
2278   ns_unfocus (f);
2279   return;
2282 static void
2283 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2285   if (FRAME_NS_VIEW (f))
2286     {
2287       ns_focus (f, &dest, 1);
2288       [FRAME_NS_VIEW (f) scrollRect: src
2289                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2290                                                  dest.origin.y - src.origin.y)];
2291       ns_unfocus (f);
2292     }
2295 static void
2296 ns_scroll_run (struct window *w, struct run *run)
2297 /* --------------------------------------------------------------------------
2298     External (RIF):  Insert or delete n lines at line vpos
2299    -------------------------------------------------------------------------- */
2301   struct frame *f = XFRAME (w->frame);
2302   int x, y, width, height, from_y, to_y, bottom_y;
2304   NSTRACE ("ns_scroll_run");
2306   /* begin copy from other terms */
2307   /* Get frame-relative bounding box of the text display area of W,
2308      without mode lines.  Include in this box the left and right
2309      fringe of W.  */
2310   window_box (w, ANY_AREA, &x, &y, &width, &height);
2312   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2313   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2314   bottom_y = y + height;
2316   if (to_y < from_y)
2317     {
2318       /* Scrolling up.  Make sure we don't copy part of the mode
2319          line at the bottom.  */
2320       if (from_y + run->height > bottom_y)
2321         height = bottom_y - from_y;
2322       else
2323         height = run->height;
2324     }
2325   else
2326     {
2327       /* Scrolling down.  Make sure we don't copy over the mode line.
2328          at the bottom.  */
2329       if (to_y + run->height > bottom_y)
2330         height = bottom_y - to_y;
2331       else
2332         height = run->height;
2333     }
2334   /* end copy from other terms */
2336   if (height == 0)
2337       return;
2339   block_input ();
2341   x_clear_cursor (w);
2343   {
2344     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2345     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2347     ns_copy_bits (f, srcRect , dstRect);
2348   }
2350   unblock_input ();
2354 static void
2355 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2356 /* --------------------------------------------------------------------------
2357     External (RIF): preparatory to fringe update after text was updated
2358    -------------------------------------------------------------------------- */
2360   struct frame *f;
2361   int width, height;
2363   NSTRACE ("ns_after_update_window_line");
2365   /* begin copy from other terms */
2366   eassert (w);
2368   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2369     desired_row->redraw_fringe_bitmaps_p = 1;
2371   /* When a window has disappeared, make sure that no rest of
2372      full-width rows stays visible in the internal border.  */
2373   if (windows_or_buffers_changed
2374       && desired_row->full_width_p
2375       && (f = XFRAME (w->frame),
2376           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2377           width != 0)
2378       && (height = desired_row->visible_height,
2379           height > 0))
2380     {
2381       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2383       block_input ();
2384       ns_clear_frame_area (f, 0, y, width, height);
2385       ns_clear_frame_area (f,
2386                            FRAME_PIXEL_WIDTH (f) - width,
2387                            y, width, height);
2388       unblock_input ();
2389     }
2393 static void
2394 ns_shift_glyphs_for_insert (struct frame *f,
2395                            int x, int y, int width, int height,
2396                            int shift_by)
2397 /* --------------------------------------------------------------------------
2398     External (RIF): copy an area horizontally, don't worry about clearing src
2399    -------------------------------------------------------------------------- */
2401   NSRect srcRect = NSMakeRect (x, y, width, height);
2402   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2404   NSTRACE ("ns_shift_glyphs_for_insert");
2406   ns_copy_bits (f, srcRect, dstRect);
2411 /* ==========================================================================
2413     Character encoding and metrics
2415    ========================================================================== */
2418 static void
2419 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2420 /* --------------------------------------------------------------------------
2421      External (RIF); compute left/right overhang of whole string and set in s
2422    -------------------------------------------------------------------------- */
2424   struct font *font = s->font;
2426   if (s->char2b)
2427     {
2428       struct font_metrics metrics;
2429       unsigned int codes[2];
2430       codes[0] = *(s->char2b);
2431       codes[1] = *(s->char2b + s->nchars - 1);
2433       font->driver->text_extents (font, codes, 2, &metrics);
2434       s->left_overhang = -metrics.lbearing;
2435       s->right_overhang
2436         = metrics.rbearing > metrics.width
2437         ? metrics.rbearing - metrics.width : 0;
2438     }
2439   else
2440     {
2441       s->left_overhang = 0;
2442       if (EQ (font->driver->type, Qns))
2443         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2444           FONT_HEIGHT (font) * 0.2 : 0;
2445       else
2446         s->right_overhang = 0;
2447     }
2452 /* ==========================================================================
2454     Fringe and cursor drawing
2456    ========================================================================== */
2459 extern int max_used_fringe_bitmap;
2460 static void
2461 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2462                       struct draw_fringe_bitmap_params *p)
2463 /* --------------------------------------------------------------------------
2464     External (RIF); fringe-related
2465    -------------------------------------------------------------------------- */
2467   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2468      periodic bitmap is used to create a continuous pattern.  Since a
2469      bitmap is rendered one text line at a time, the start offset (dh)
2470      of the bitmap varies.  Concretely, this is used for the empty
2471      line indicator.
2473      For a bitmap, "h + dh" is the full height and is always
2474      invariant.  For a normal bitmap "dh" is zero.
2476      For example, when the period is three and the full height is 72
2477      the following combinations exists:
2479        h=72 dh=0
2480        h=71 dh=1
2481        h=70 dh=2 */
2483   struct frame *f = XFRAME (WINDOW_FRAME (w));
2484   struct face *face = p->face;
2485   static EmacsImage **bimgs = NULL;
2486   static int nBimgs = 0;
2488   NSTRACE ("ns_draw_fringe_bitmap");
2489   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2490                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2492   /* grow bimgs if needed */
2493   if (nBimgs < max_used_fringe_bitmap)
2494     {
2495       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2496       memset (bimgs + nBimgs, 0,
2497               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2498       nBimgs = max_used_fringe_bitmap;
2499     }
2501   /* Must clip because of partially visible lines.  */
2502   ns_clip_to_row (w, row, ANY_AREA, YES);
2504   if (!p->overlay_p)
2505     {
2506       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2508       if (bx >= 0 && nx > 0)
2509         {
2510           NSRect r = NSMakeRect (bx, by, nx, ny);
2511           NSRectClip (r);
2512           [ns_lookup_indexed_color (face->background, f) set];
2513           NSRectFill (r);
2514         }
2515     }
2517   if (p->which)
2518     {
2519       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2520       EmacsImage *img = bimgs[p->which - 1];
2522       if (!img)
2523         {
2524           // Note: For "periodic" images, allocate one EmacsImage for
2525           // the base image, and use it for all dh:s.
2526           unsigned short *bits = p->bits;
2527           int full_height = p->h + p->dh;
2528           int i;
2529           unsigned char *cbits = xmalloc (full_height);
2531           for (i = 0; i < full_height; i++)
2532             cbits[i] = bits[i];
2533           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2534                                          height: full_height
2535                                              fg: 0 bg: 0];
2536           bimgs[p->which - 1] = img;
2537           xfree (cbits);
2538         }
2540       NSTRACE_RECT ("r", r);
2542       NSRectClip (r);
2543       /* Since we composite the bitmap instead of just blitting it, we need
2544          to erase the whole background. */
2545       [ns_lookup_indexed_color(face->background, f) set];
2546       NSRectFill (r);
2548       {
2549         NSColor *bm_color;
2550         if (!p->cursor_p)
2551           bm_color = ns_lookup_indexed_color(face->foreground, f);
2552         else if (p->overlay_p)
2553           bm_color = ns_lookup_indexed_color(face->background, f);
2554         else
2555           bm_color = f->output_data.ns->cursor_color;
2556         [img setXBMColor: bm_color];
2557       }
2559       // Note: For periodic images, the full image height is "h + hd".
2560       // By using the height h, a suitable part of the image is used.
2561       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2563       NSTRACE_RECT ("fromRect", fromRect);
2565 #ifdef NS_IMPL_COCOA
2566       [img drawInRect: r
2567               fromRect: fromRect
2568              operation: NSCompositeSourceOver
2569               fraction: 1.0
2570            respectFlipped: YES
2571                 hints: nil];
2572 #else
2573       {
2574         NSPoint pt = r.origin;
2575         pt.y += p->h;
2576         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2577       }
2578 #endif
2579     }
2580   ns_unfocus (f);
2584 static void
2585 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2586                        int x, int y, enum text_cursor_kinds cursor_type,
2587                        int cursor_width, bool on_p, bool active_p)
2588 /* --------------------------------------------------------------------------
2589      External call (RIF): draw cursor.
2590      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2591    -------------------------------------------------------------------------- */
2593   NSRect r, s;
2594   int fx, fy, h, cursor_height;
2595   struct frame *f = WINDOW_XFRAME (w);
2596   struct glyph *phys_cursor_glyph;
2597   struct glyph *cursor_glyph;
2598   struct face *face;
2599   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2601   /* If cursor is out of bounds, don't draw garbage.  This can happen
2602      in mini-buffer windows when switching between echo area glyphs
2603      and mini-buffer.  */
2605   NSTRACE ("dumpcursor");
2607   if (!on_p)
2608     return;
2610   w->phys_cursor_type = cursor_type;
2611   w->phys_cursor_on_p = on_p;
2613   if (cursor_type == NO_CURSOR)
2614     {
2615       w->phys_cursor_width = 0;
2616       return;
2617     }
2619   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2620     {
2621       if (glyph_row->exact_window_width_line_p
2622           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2623         {
2624           glyph_row->cursor_in_fringe_p = 1;
2625           draw_fringe_bitmap (w, glyph_row, 0);
2626         }
2627       return;
2628     }
2630   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2631      (other terminals do it the other way round).  We must set
2632      w->phys_cursor_width to the cursor width.  For bar cursors, that
2633      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2634   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2636   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2637      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2638   if (cursor_type == BAR_CURSOR)
2639     {
2640       if (cursor_width < 1)
2641         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2642       w->phys_cursor_width = cursor_width;
2643     }
2644   /* If we have an HBAR, "cursor_width" MAY specify height. */
2645   else if (cursor_type == HBAR_CURSOR)
2646     {
2647       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2648       if (cursor_height > glyph_row->height)
2649         cursor_height = glyph_row->height;
2650       if (h > cursor_height) // Cursor smaller than line height, move down
2651         fy += h - cursor_height;
2652       h = cursor_height;
2653     }
2655   r.origin.x = fx, r.origin.y = fy;
2656   r.size.height = h;
2657   r.size.width = w->phys_cursor_width;
2659   /* TODO: only needed in rare cases with last-resort font in HELLO..
2660      should we do this more efficiently? */
2661   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2664   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2665   if (face && NS_FACE_BACKGROUND (face)
2666       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2667     {
2668       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2669       hollow_color = FRAME_CURSOR_COLOR (f);
2670     }
2671   else
2672     [FRAME_CURSOR_COLOR (f) set];
2674 #ifdef NS_IMPL_COCOA
2675   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2676            atomic.  Cleaner ways of doing this should be investigated.
2677            One way would be to set a global variable DRAWING_CURSOR
2678            when making the call to draw_phys..(), don't focus in that
2679            case, then move the ns_unfocus() here after that call. */
2680   NSDisableScreenUpdates ();
2681 #endif
2683   switch (cursor_type)
2684     {
2685     case DEFAULT_CURSOR:
2686     case NO_CURSOR:
2687       break;
2688     case FILLED_BOX_CURSOR:
2689       NSRectFill (r);
2690       break;
2691     case HOLLOW_BOX_CURSOR:
2692       NSRectFill (r);
2693       [hollow_color set];
2694       NSRectFill (NSInsetRect (r, 1, 1));
2695       [FRAME_CURSOR_COLOR (f) set];
2696       break;
2697     case HBAR_CURSOR:
2698       NSRectFill (r);
2699       break;
2700     case BAR_CURSOR:
2701       s = r;
2702       /* If the character under cursor is R2L, draw the bar cursor
2703          on the right of its glyph, rather than on the left.  */
2704       cursor_glyph = get_phys_cursor_glyph (w);
2705       if ((cursor_glyph->resolved_level & 1) != 0)
2706         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2708       NSRectFill (s);
2709       break;
2710     }
2711   ns_unfocus (f);
2713   /* draw the character under the cursor */
2714   if (cursor_type != NO_CURSOR)
2715     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2717 #ifdef NS_IMPL_COCOA
2718   NSEnableScreenUpdates ();
2719 #endif
2724 static void
2725 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2726 /* --------------------------------------------------------------------------
2727      External (RIF): Draw a vertical line.
2728    -------------------------------------------------------------------------- */
2730   struct frame *f = XFRAME (WINDOW_FRAME (w));
2731   struct face *face;
2732   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2734   NSTRACE ("ns_draw_vertical_window_border");
2736   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2737   if (face)
2738       [ns_lookup_indexed_color(face->foreground, f) set];
2740   ns_focus (f, &r, 1);
2741   NSRectFill(r);
2742   ns_unfocus (f);
2746 static void
2747 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2748 /* --------------------------------------------------------------------------
2749      External (RIF): Draw a window divider.
2750    -------------------------------------------------------------------------- */
2752   struct frame *f = XFRAME (WINDOW_FRAME (w));
2753   struct face *face;
2754   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2756   NSTRACE ("ns_draw_window_divider");
2758   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2759   if (face)
2760       [ns_lookup_indexed_color(face->foreground, f) set];
2762   ns_focus (f, &r, 1);
2763   NSRectFill(r);
2764   ns_unfocus (f);
2767 static void
2768 ns_show_hourglass (struct frame *f)
2770   /* TODO: add NSProgressIndicator to all frames.  */
2773 static void
2774 ns_hide_hourglass (struct frame *f)
2776   /* TODO: remove NSProgressIndicator from all frames.  */
2779 /* ==========================================================================
2781     Glyph drawing operations
2783    ========================================================================== */
2785 static int
2786 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2787 /* --------------------------------------------------------------------------
2788     Wrapper utility to account for internal border width on full-width lines,
2789     and allow top full-width rows to hit the frame top.  nr should be pointer
2790     to two successive NSRects.  Number of rects actually used is returned.
2791    -------------------------------------------------------------------------- */
2793   int n = get_glyph_string_clip_rects (s, nr, 2);
2794   return n;
2797 /* --------------------------------------------------------------------
2798    Draw a wavy line under glyph string s. The wave fills wave_height
2799    pixels from y.
2801                     x          wave_length = 2
2802                                  --
2803                 y    *   *   *   *   *
2804                      |* * * * * * * * *
2805     wave_height = 3  | *   *   *   *
2806   --------------------------------------------------------------------- */
2808 static void
2809 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2811   int wave_height = 3, wave_length = 2;
2812   int y, dx, dy, odd, xmax;
2813   NSPoint a, b;
2814   NSRect waveClip;
2816   dx = wave_length;
2817   dy = wave_height - 1;
2818   y =  s->ybase - wave_height + 3;
2819   xmax = x + width;
2821   /* Find and set clipping rectangle */
2822   waveClip = NSMakeRect (x, y, width, wave_height);
2823   [[NSGraphicsContext currentContext] saveGraphicsState];
2824   NSRectClip (waveClip);
2826   /* Draw the waves */
2827   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2828   b.x = a.x + dx;
2829   odd = (int)(a.x/dx) % 2;
2830   a.y = b.y = y + 0.5;
2832   if (odd)
2833     a.y += dy;
2834   else
2835     b.y += dy;
2837   while (a.x <= xmax)
2838     {
2839       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2840       a.x = b.x, a.y = b.y;
2841       b.x += dx, b.y = y + 0.5 + odd*dy;
2842       odd = !odd;
2843     }
2845   /* Restore previous clipping rectangle(s) */
2846   [[NSGraphicsContext currentContext] restoreGraphicsState];
2851 void
2852 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2853                          NSColor *defaultCol, CGFloat width, CGFloat x)
2854 /* --------------------------------------------------------------------------
2855    Draw underline, overline, and strike-through on glyph string s.
2856    -------------------------------------------------------------------------- */
2858   if (s->for_overlaps)
2859     return;
2861   /* Do underline. */
2862   if (face->underline_p)
2863     {
2864       if (s->face->underline_type == FACE_UNDER_WAVE)
2865         {
2866           if (face->underline_defaulted_p)
2867             [defaultCol set];
2868           else
2869             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2871           ns_draw_underwave (s, width, x);
2872         }
2873       else if (s->face->underline_type == FACE_UNDER_LINE)
2874         {
2876           NSRect r;
2877           unsigned long thickness, position;
2879           /* If the prev was underlined, match its appearance. */
2880           if (s->prev && s->prev->face->underline_p
2881               && s->prev->face->underline_type == FACE_UNDER_LINE
2882               && s->prev->underline_thickness > 0)
2883             {
2884               thickness = s->prev->underline_thickness;
2885               position = s->prev->underline_position;
2886             }
2887           else
2888             {
2889               struct font *font;
2890               unsigned long descent;
2892               font=s->font;
2893               descent = s->y + s->height - s->ybase;
2895               /* Use underline thickness of font, defaulting to 1. */
2896               thickness = (font && font->underline_thickness > 0)
2897                 ? font->underline_thickness : 1;
2899               /* Determine the offset of underlining from the baseline. */
2900               if (x_underline_at_descent_line)
2901                 position = descent - thickness;
2902               else if (x_use_underline_position_properties
2903                        && font && font->underline_position >= 0)
2904                 position = font->underline_position;
2905               else if (font)
2906                 position = lround (font->descent / 2);
2907               else
2908                 position = underline_minimum_offset;
2910               position = max (position, underline_minimum_offset);
2912               /* Ensure underlining is not cropped. */
2913               if (descent <= position)
2914                 {
2915                   position = descent - 1;
2916                   thickness = 1;
2917                 }
2918               else if (descent < position + thickness)
2919                 thickness = 1;
2920             }
2922           s->underline_thickness = thickness;
2923           s->underline_position = position;
2925           r = NSMakeRect (x, s->ybase + position, width, thickness);
2927           if (face->underline_defaulted_p)
2928             [defaultCol set];
2929           else
2930             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2931           NSRectFill (r);
2932         }
2933     }
2934   /* Do overline. We follow other terms in using a thickness of 1
2935      and ignoring overline_margin. */
2936   if (face->overline_p)
2937     {
2938       NSRect r;
2939       r = NSMakeRect (x, s->y, width, 1);
2941       if (face->overline_color_defaulted_p)
2942         [defaultCol set];
2943       else
2944         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2945       NSRectFill (r);
2946     }
2948   /* Do strike-through.  We follow other terms for thickness and
2949      vertical position.*/
2950   if (face->strike_through_p)
2951     {
2952       NSRect r;
2953       unsigned long dy;
2955       dy = lrint ((s->height - 1) / 2);
2956       r = NSMakeRect (x, s->y + dy, width, 1);
2958       if (face->strike_through_color_defaulted_p)
2959         [defaultCol set];
2960       else
2961         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2962       NSRectFill (r);
2963     }
2966 static void
2967 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2968              char left_p, char right_p)
2969 /* --------------------------------------------------------------------------
2970     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2971     Note we can't just use an NSDrawRect command, because of the possibility
2972     of some sides not being drawn, and because the rect will be filled.
2973    -------------------------------------------------------------------------- */
2975   NSRect s = r;
2976   [col set];
2978   /* top, bottom */
2979   s.size.height = thickness;
2980   NSRectFill (s);
2981   s.origin.y += r.size.height - thickness;
2982   NSRectFill (s);
2984   s.size.height = r.size.height;
2985   s.origin.y = r.origin.y;
2987   /* left, right (optional) */
2988   s.size.width = thickness;
2989   if (left_p)
2990     NSRectFill (s);
2991   if (right_p)
2992     {
2993       s.origin.x += r.size.width - thickness;
2994       NSRectFill (s);
2995     }
2999 static void
3000 ns_draw_relief (NSRect r, int thickness, char raised_p,
3001                char top_p, char bottom_p, char left_p, char right_p,
3002                struct glyph_string *s)
3003 /* --------------------------------------------------------------------------
3004     Draw a relief rect inside r, optionally leaving some sides open.
3005     Note we can't just use an NSDrawBezel command, because of the possibility
3006     of some sides not being drawn, and because the rect will be filled.
3007    -------------------------------------------------------------------------- */
3009   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3010   NSColor *newBaseCol = nil;
3011   NSRect sr = r;
3013   NSTRACE ("ns_draw_relief");
3015   /* set up colors */
3017   if (s->face->use_box_color_for_shadows_p)
3018     {
3019       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3020     }
3021 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3022            && s->img->pixmap
3023            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3024        {
3025          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3026        } */
3027   else
3028     {
3029       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3030     }
3032   if (newBaseCol == nil)
3033     newBaseCol = [NSColor grayColor];
3035   if (newBaseCol != baseCol)  /* TODO: better check */
3036     {
3037       [baseCol release];
3038       baseCol = [newBaseCol retain];
3039       [lightCol release];
3040       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3041       [darkCol release];
3042       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3043     }
3045   [(raised_p ? lightCol : darkCol) set];
3047   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3049   /* top */
3050   sr.size.height = thickness;
3051   if (top_p) NSRectFill (sr);
3053   /* left */
3054   sr.size.height = r.size.height;
3055   sr.size.width = thickness;
3056   if (left_p) NSRectFill (sr);
3058   [(raised_p ? darkCol : lightCol) set];
3060   /* bottom */
3061   sr.size.width = r.size.width;
3062   sr.size.height = thickness;
3063   sr.origin.y += r.size.height - thickness;
3064   if (bottom_p) NSRectFill (sr);
3066   /* right */
3067   sr.size.height = r.size.height;
3068   sr.origin.y = r.origin.y;
3069   sr.size.width = thickness;
3070   sr.origin.x += r.size.width - thickness;
3071   if (right_p) NSRectFill (sr);
3075 static void
3076 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3077 /* --------------------------------------------------------------------------
3078       Function modeled after x_draw_glyph_string_box ().
3079       Sets up parameters for drawing.
3080    -------------------------------------------------------------------------- */
3082   int right_x, last_x;
3083   char left_p, right_p;
3084   struct glyph *last_glyph;
3085   NSRect r;
3086   int thickness;
3087   struct face *face;
3089   if (s->hl == DRAW_MOUSE_FACE)
3090     {
3091       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3092       if (!face)
3093         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3094     }
3095   else
3096     face = s->face;
3098   thickness = face->box_line_width;
3100   NSTRACE ("ns_dumpglyphs_box_or_relief");
3102   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3103             ? WINDOW_RIGHT_EDGE_X (s->w)
3104             : window_box_right (s->w, s->area));
3105   last_glyph = (s->cmp || s->img
3106                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3108   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3109               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3111   left_p = (s->first_glyph->left_box_line_p
3112             || (s->hl == DRAW_MOUSE_FACE
3113                 && (s->prev == NULL || s->prev->hl != s->hl)));
3114   right_p = (last_glyph->right_box_line_p
3115              || (s->hl == DRAW_MOUSE_FACE
3116                  && (s->next == NULL || s->next->hl != s->hl)));
3118   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3120   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3121   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3122     {
3123       ns_draw_box (r, abs (thickness),
3124                    ns_lookup_indexed_color (face->box_color, s->f),
3125                   left_p, right_p);
3126     }
3127   else
3128     {
3129       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3130                      1, 1, left_p, right_p, s);
3131     }
3135 static void
3136 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3137 /* --------------------------------------------------------------------------
3138       Modeled after x_draw_glyph_string_background, which draws BG in
3139       certain cases.  Others are left to the text rendering routine.
3140    -------------------------------------------------------------------------- */
3142   NSTRACE ("ns_maybe_dumpglyphs_background");
3144   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3145     {
3146       int box_line_width = max (s->face->box_line_width, 0);
3147       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3148           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3149              dimensions, since the actual glyphs might be much
3150              smaller.  So in that case we always clear the rectangle
3151              with background color.  */
3152           || FONT_TOO_HIGH (s->font)
3153           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3154         {
3155           struct face *face;
3156           if (s->hl == DRAW_MOUSE_FACE)
3157             {
3158               face = FACE_FROM_ID (s->f,
3159                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3160               if (!face)
3161                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3162             }
3163           else
3164             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3165           if (!face->stipple)
3166             [(NS_FACE_BACKGROUND (face) != 0
3167               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3168               : FRAME_BACKGROUND_COLOR (s->f)) set];
3169           else
3170             {
3171               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3172               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3173             }
3175           if (s->hl != DRAW_CURSOR)
3176             {
3177               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3178                                     s->background_width,
3179                                     s->height-2*box_line_width);
3180               NSRectFill (r);
3181             }
3183           s->background_filled_p = 1;
3184         }
3185     }
3189 static void
3190 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3191 /* --------------------------------------------------------------------------
3192       Renders an image and associated borders.
3193    -------------------------------------------------------------------------- */
3195   EmacsImage *img = s->img->pixmap;
3196   int box_line_vwidth = max (s->face->box_line_width, 0);
3197   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3198   int bg_x, bg_y, bg_height;
3199   int th;
3200   char raised_p;
3201   NSRect br;
3202   struct face *face;
3203   NSColor *tdCol;
3205   NSTRACE ("ns_dumpglyphs_image");
3207   if (s->face->box != FACE_NO_BOX
3208       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3209     x += abs (s->face->box_line_width);
3211   bg_x = x;
3212   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3213   bg_height = s->height;
3214   /* other terms have this, but was causing problems w/tabbar mode */
3215   /* - 2 * box_line_vwidth; */
3217   if (s->slice.x == 0) x += s->img->hmargin;
3218   if (s->slice.y == 0) y += s->img->vmargin;
3220   /* Draw BG: if we need larger area than image itself cleared, do that,
3221      otherwise, since we composite the image under NS (instead of mucking
3222      with its background color), we must clear just the image area. */
3223   if (s->hl == DRAW_MOUSE_FACE)
3224     {
3225       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3226       if (!face)
3227        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3228     }
3229   else
3230     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3232   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3234   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3235       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3236     {
3237       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3238       s->background_filled_p = 1;
3239     }
3240   else
3241     {
3242       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3243     }
3245   NSRectFill (br);
3247   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3248   if (img != nil)
3249     {
3250 #ifdef NS_IMPL_COCOA
3251       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3252       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3253                               s->slice.width, s->slice.height);
3254       [img drawInRect: dr
3255              fromRect: ir
3256              operation: NSCompositeSourceOver
3257               fraction: 1.0
3258            respectFlipped: YES
3259                 hints: nil];
3260 #else
3261       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3262                   operation: NSCompositeSourceOver];
3263 #endif
3264     }
3266   if (s->hl == DRAW_CURSOR)
3267     {
3268     [FRAME_CURSOR_COLOR (s->f) set];
3269     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3270       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3271     else
3272       /* Currently on NS img->mask is always 0. Since
3273          get_window_cursor_type specifies a hollow box cursor when on
3274          a non-masked image we never reach this clause. But we put it
3275          in in anticipation of better support for image masks on
3276          NS. */
3277       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3278     }
3279   else
3280     {
3281       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3282     }
3284   /* Draw underline, overline, strike-through. */
3285   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3287   /* Draw relief, if requested */
3288   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3289     {
3290       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3291         {
3292           th = tool_bar_button_relief >= 0 ?
3293             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3294           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3295         }
3296       else
3297         {
3298           th = abs (s->img->relief);
3299           raised_p = (s->img->relief > 0);
3300         }
3302       r.origin.x = x - th;
3303       r.origin.y = y - th;
3304       r.size.width = s->slice.width + 2*th-1;
3305       r.size.height = s->slice.height + 2*th-1;
3306       ns_draw_relief (r, th, raised_p,
3307                       s->slice.y == 0,
3308                       s->slice.y + s->slice.height == s->img->height,
3309                       s->slice.x == 0,
3310                       s->slice.x + s->slice.width == s->img->width, s);
3311     }
3313   /* If there is no mask, the background won't be seen,
3314      so draw a rectangle on the image for the cursor.
3315      Do this for all images, getting transparency right is not reliable.  */
3316   if (s->hl == DRAW_CURSOR)
3317     {
3318       int thickness = abs (s->img->relief);
3319       if (thickness == 0) thickness = 1;
3320       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3321     }
3325 static void
3326 ns_dumpglyphs_stretch (struct glyph_string *s)
3328   NSRect r[2];
3329   int n, i;
3330   struct face *face;
3331   NSColor *fgCol, *bgCol;
3333   if (!s->background_filled_p)
3334     {
3335       n = ns_get_glyph_string_clip_rect (s, r);
3336       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3338       ns_focus (s->f, r, n);
3340       if (s->hl == DRAW_MOUSE_FACE)
3341        {
3342          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3343          if (!face)
3344            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3345        }
3346       else
3347        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3349       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3350       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3352       for (i = 0; i < n; ++i)
3353         {
3354           if (!s->row->full_width_p)
3355             {
3356               int overrun, leftoverrun;
3358               /* truncate to avoid overwriting fringe and/or scrollbar */
3359               overrun = max (0, (s->x + s->background_width)
3360                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3361                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3362               r[i].size.width -= overrun;
3364               /* truncate to avoid overwriting to left of the window box */
3365               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3366                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3368               if (leftoverrun > 0)
3369                 {
3370                   r[i].origin.x += leftoverrun;
3371                   r[i].size.width -= leftoverrun;
3372                 }
3374               /* XXX: Try to work between problem where a stretch glyph on
3375                  a partially-visible bottom row will clear part of the
3376                  modeline, and another where list-buffers headers and similar
3377                  rows erroneously have visible_height set to 0.  Not sure
3378                  where this is coming from as other terms seem not to show. */
3379               r[i].size.height = min (s->height, s->row->visible_height);
3380             }
3382           [bgCol set];
3384           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3385              overwriting cursor (usually when cursor on a tab) */
3386           if (s->hl == DRAW_CURSOR)
3387             {
3388               CGFloat x, width;
3390               x = r[i].origin.x;
3391               width = s->w->phys_cursor_width;
3392               r[i].size.width -= width;
3393               r[i].origin.x += width;
3395               NSRectFill (r[i]);
3397               /* Draw overlining, etc. on the cursor. */
3398               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3399                 ns_draw_text_decoration (s, face, bgCol, width, x);
3400               else
3401                 ns_draw_text_decoration (s, face, fgCol, width, x);
3402             }
3403           else
3404             {
3405               NSRectFill (r[i]);
3406             }
3408           /* Draw overlining, etc. on the stretch glyph (or the part
3409              of the stretch glyph after the cursor). */
3410           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3411                                    r[i].origin.x);
3412         }
3413       ns_unfocus (s->f);
3414       s->background_filled_p = 1;
3415     }
3419 static void
3420 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3422   int i, j, x;
3423   struct font *font = s->font;
3425   /* If first glyph of S has a left box line, start drawing the text
3426      of S to the right of that box line.  */
3427   if (s->face && s->face->box != FACE_NO_BOX
3428       && s->first_glyph->left_box_line_p)
3429     x = s->x + eabs (s->face->box_line_width);
3430   else
3431     x = s->x;
3433   /* S is a glyph string for a composition.  S->cmp_from is the index
3434      of the first character drawn for glyphs of this composition.
3435      S->cmp_from == 0 means we are drawing the very first character of
3436      this composition.  */
3438   /* Draw a rectangle for the composition if the font for the very
3439      first character of the composition could not be loaded.  */
3440   if (s->font_not_found_p)
3441     {
3442       if (s->cmp_from == 0)
3443         {
3444           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3445           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3446         }
3447     }
3448   else if (! s->first_glyph->u.cmp.automatic)
3449     {
3450       int y = s->ybase;
3452       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3453         /* TAB in a composition means display glyphs with padding
3454            space on the left or right.  */
3455         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3456           {
3457             int xx = x + s->cmp->offsets[j * 2];
3458             int yy = y - s->cmp->offsets[j * 2 + 1];
3460             font->driver->draw (s, j, j + 1, xx, yy, false);
3461             if (s->face->overstrike)
3462               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3463           }
3464     }
3465   else
3466     {
3467       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3468       Lisp_Object glyph;
3469       int y = s->ybase;
3470       int width = 0;
3472       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3473         {
3474           glyph = LGSTRING_GLYPH (gstring, i);
3475           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3476             width += LGLYPH_WIDTH (glyph);
3477           else
3478             {
3479               int xoff, yoff, wadjust;
3481               if (j < i)
3482                 {
3483                   font->driver->draw (s, j, i, x, y, false);
3484                   if (s->face->overstrike)
3485                     font->driver->draw (s, j, i, x + 1, y, false);
3486                   x += width;
3487                 }
3488               xoff = LGLYPH_XOFF (glyph);
3489               yoff = LGLYPH_YOFF (glyph);
3490               wadjust = LGLYPH_WADJUST (glyph);
3491               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3492               if (s->face->overstrike)
3493                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3494                                     false);
3495               x += wadjust;
3496               j = i + 1;
3497               width = 0;
3498             }
3499         }
3500       if (j < i)
3501         {
3502           font->driver->draw (s, j, i, x, y, false);
3503           if (s->face->overstrike)
3504             font->driver->draw (s, j, i, x + 1, y, false);
3505         }
3506     }
3509 static void
3510 ns_draw_glyph_string (struct glyph_string *s)
3511 /* --------------------------------------------------------------------------
3512       External (RIF): Main draw-text call.
3513    -------------------------------------------------------------------------- */
3515   /* TODO (optimize): focus for box and contents draw */
3516   NSRect r[2];
3517   int n, flags;
3518   char box_drawn_p = 0;
3519   struct font *font = s->face->font;
3520   if (! font) font = FRAME_FONT (s->f);
3522   NSTRACE ("ns_draw_glyph_string");
3524   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3525     {
3526       int width;
3527       struct glyph_string *next;
3529       for (width = 0, next = s->next;
3530            next && width < s->right_overhang;
3531            width += next->width, next = next->next)
3532         if (next->first_glyph->type != IMAGE_GLYPH)
3533           {
3534             if (next->first_glyph->type != STRETCH_GLYPH)
3535               {
3536                 n = ns_get_glyph_string_clip_rect (s->next, r);
3537                 ns_focus (s->f, r, n);
3538                 ns_maybe_dumpglyphs_background (s->next, 1);
3539                 ns_unfocus (s->f);
3540               }
3541             else
3542               {
3543                 ns_dumpglyphs_stretch (s->next);
3544               }
3545             next->num_clips = 0;
3546           }
3547     }
3549   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3550         && (s->first_glyph->type == CHAR_GLYPH
3551             || s->first_glyph->type == COMPOSITE_GLYPH))
3552     {
3553       n = ns_get_glyph_string_clip_rect (s, r);
3554       ns_focus (s->f, r, n);
3555       ns_maybe_dumpglyphs_background (s, 1);
3556       ns_dumpglyphs_box_or_relief (s);
3557       ns_unfocus (s->f);
3558       box_drawn_p = 1;
3559     }
3561   switch (s->first_glyph->type)
3562     {
3564     case IMAGE_GLYPH:
3565       n = ns_get_glyph_string_clip_rect (s, r);
3566       ns_focus (s->f, r, n);
3567       ns_dumpglyphs_image (s, r[0]);
3568       ns_unfocus (s->f);
3569       break;
3571     case STRETCH_GLYPH:
3572       ns_dumpglyphs_stretch (s);
3573       break;
3575     case CHAR_GLYPH:
3576     case COMPOSITE_GLYPH:
3577       n = ns_get_glyph_string_clip_rect (s, r);
3578       ns_focus (s->f, r, n);
3580       if (s->for_overlaps || (s->cmp_from > 0
3581                               && ! s->first_glyph->u.cmp.automatic))
3582         s->background_filled_p = 1;
3583       else
3584         ns_maybe_dumpglyphs_background
3585           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3587       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3588         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3589          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3590           NS_DUMPGLYPH_NORMAL));
3592       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3593         {
3594           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3595           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3596           NS_FACE_FOREGROUND (s->face) = tmp;
3597         }
3599       {
3600         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3602         if (isComposite)
3603           ns_draw_composite_glyph_string_foreground (s);
3604         else
3605           font->driver->draw
3606             (s, s->cmp_from, s->nchars, s->x, s->ybase,
3607              (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3608              || flags == NS_DUMPGLYPH_MOUSEFACE);
3609       }
3611       {
3612         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3613                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3614                                                    s->f)
3615                         : FRAME_FOREGROUND_COLOR (s->f));
3616         [col set];
3618         /* Draw underline, overline, strike-through. */
3619         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3620       }
3622       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3623         {
3624           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3625           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3626           NS_FACE_FOREGROUND (s->face) = tmp;
3627         }
3629       ns_unfocus (s->f);
3630       break;
3632     case GLYPHLESS_GLYPH:
3633       n = ns_get_glyph_string_clip_rect (s, r);
3634       ns_focus (s->f, r, n);
3636       if (s->for_overlaps || (s->cmp_from > 0
3637                               && ! s->first_glyph->u.cmp.automatic))
3638         s->background_filled_p = 1;
3639       else
3640         ns_maybe_dumpglyphs_background
3641           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3642       /* ... */
3643       /* Not yet implemented.  */
3644       /* ... */
3645       ns_unfocus (s->f);
3646       break;
3648     default:
3649       emacs_abort ();
3650     }
3652   /* Draw box if not done already. */
3653   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3654     {
3655       n = ns_get_glyph_string_clip_rect (s, r);
3656       ns_focus (s->f, r, n);
3657       ns_dumpglyphs_box_or_relief (s);
3658       ns_unfocus (s->f);
3659     }
3661   s->num_clips = 0;
3666 /* ==========================================================================
3668     Event loop
3670    ========================================================================== */
3673 static void
3674 ns_send_appdefined (int value)
3675 /* --------------------------------------------------------------------------
3676     Internal: post an appdefined event which EmacsApp-sendEvent will
3677               recognize and take as a command to halt the event loop.
3678    -------------------------------------------------------------------------- */
3680   NSTRACE ("ns_send_appdefined");
3682 #ifdef NS_IMPL_GNUSTEP
3683   // GNUstep needs postEvent to happen on the main thread.
3684   if (! [[NSThread currentThread] isMainThread])
3685     {
3686       EmacsApp *app = (EmacsApp *)NSApp;
3687       app->nextappdefined = value;
3688       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3689                             withObject:nil
3690                          waitUntilDone:YES];
3691       return;
3692     }
3693 #endif
3695   /* Only post this event if we haven't already posted one.  This will end
3696        the [NXApp run] main loop after having processed all events queued at
3697        this moment.  */
3699 #ifdef NS_IMPL_COCOA
3700   if (! send_appdefined)
3701     {
3702       /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3703          in certain situations (rapid incoming events).
3704          So check if we have one, if not add one.  */
3705       NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3706                                           untilDate:[NSDate distantPast]
3707                                              inMode:NSDefaultRunLoopMode
3708                                             dequeue:NO];
3709       if (! appev) send_appdefined = YES;
3710     }
3711 #endif
3713   if (send_appdefined)
3714     {
3715       NSEvent *nxev;
3717       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3718       send_appdefined = NO;
3720       /* Don't need wakeup timer any more */
3721       if (timed_entry)
3722         {
3723           [timed_entry invalidate];
3724           [timed_entry release];
3725           timed_entry = nil;
3726         }
3728       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3729                                 location: NSMakePoint (0, 0)
3730                            modifierFlags: 0
3731                                timestamp: 0
3732                             windowNumber: [[NSApp mainWindow] windowNumber]
3733                                  context: [NSApp context]
3734                                  subtype: 0
3735                                    data1: value
3736                                    data2: 0];
3738       /* Post an application defined event on the event queue.  When this is
3739          received the [NXApp run] will return, thus having processed all
3740          events which are currently queued.  */
3741       [NSApp postEvent: nxev atStart: NO];
3742     }
3745 #ifdef HAVE_NATIVE_FS
3746 static void
3747 check_native_fs ()
3749   Lisp_Object frame, tail;
3751   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3752     return;
3754   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3756   FOR_EACH_FRAME (tail, frame)
3757     {
3758       struct frame *f = XFRAME (frame);
3759       if (FRAME_NS_P (f))
3760         {
3761           EmacsView *view = FRAME_NS_VIEW (f);
3762           [view updateCollectionBehavior];
3763         }
3764     }
3766 #endif
3768 /* GNUstep does not have cancelTracking.  */
3769 #ifdef NS_IMPL_COCOA
3770 /* Check if menu open should be canceled or continued as normal.  */
3771 void
3772 ns_check_menu_open (NSMenu *menu)
3774   /* Click in menu bar? */
3775   NSArray *a = [[NSApp mainMenu] itemArray];
3776   int i;
3777   BOOL found = NO;
3779   if (menu == nil) // Menu tracking ended.
3780     {
3781       if (menu_will_open_state == MENU_OPENING)
3782         menu_will_open_state = MENU_NONE;
3783       return;
3784     }
3786   for (i = 0; ! found && i < [a count]; i++)
3787     found = menu == [[a objectAtIndex:i] submenu];
3788   if (found)
3789     {
3790       if (menu_will_open_state == MENU_NONE && emacs_event)
3791         {
3792           NSEvent *theEvent = [NSApp currentEvent];
3793           struct frame *emacsframe = SELECTED_FRAME ();
3795           [menu cancelTracking];
3796           menu_will_open_state = MENU_PENDING;
3797           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3798           EV_TRAILER (theEvent);
3800           CGEventRef ourEvent = CGEventCreate (NULL);
3801           menu_mouse_point = CGEventGetLocation (ourEvent);
3802           CFRelease (ourEvent);
3803         }
3804       else if (menu_will_open_state == MENU_OPENING)
3805         {
3806           menu_will_open_state = MENU_NONE;
3807         }
3808     }
3811 /* Redo saved menu click if state is MENU_PENDING.  */
3812 void
3813 ns_check_pending_open_menu ()
3815   if (menu_will_open_state == MENU_PENDING)
3816     {
3817       CGEventSourceRef source
3818         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3820       CGEventRef event = CGEventCreateMouseEvent (source,
3821                                                   kCGEventLeftMouseDown,
3822                                                   menu_mouse_point,
3823                                                   kCGMouseButtonLeft);
3824       CGEventSetType (event, kCGEventLeftMouseDown);
3825       CGEventPost (kCGHIDEventTap, event);
3826       CFRelease (event);
3827       CFRelease (source);
3829       menu_will_open_state = MENU_OPENING;
3830     }
3832 #endif /* NS_IMPL_COCOA */
3834 static void
3835 unwind_apploopnr (Lisp_Object not_used)
3837   --apploopnr;
3838   n_emacs_events_pending = 0;
3839   ns_finish_events ();
3840   q_event_ptr = NULL;
3843 static int
3844 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3845 /* --------------------------------------------------------------------------
3846      External (hook): Post an event to ourself and keep reading events until
3847      we read it back again.  In effect process all events which were waiting.
3848      From 21+ we have to manage the event buffer ourselves.
3849    -------------------------------------------------------------------------- */
3851   struct input_event ev;
3852   int nevents;
3854 /* NSTRACE ("ns_read_socket"); */
3856 #ifdef HAVE_NATIVE_FS
3857   check_native_fs ();
3858 #endif
3860   if ([NSApp modalWindow] != nil)
3861     return -1;
3863   if (hold_event_q.nr > 0)
3864     {
3865       int i;
3866       for (i = 0; i < hold_event_q.nr; ++i)
3867         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3868       hold_event_q.nr = 0;
3869       return i;
3870     }
3872   block_input ();
3873   n_emacs_events_pending = 0;
3874   ns_init_events (&ev);
3875   q_event_ptr = hold_quit;
3877   /* we manage autorelease pools by allocate/reallocate each time around
3878      the loop; strict nesting is occasionally violated but seems not to
3879      matter.. earlier methods using full nesting caused major memory leaks */
3880   [outerpool release];
3881   outerpool = [[NSAutoreleasePool alloc] init];
3883   /* If have pending open-file requests, attend to the next one of those. */
3884   if (ns_pending_files && [ns_pending_files count] != 0
3885       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3886     {
3887       [ns_pending_files removeObjectAtIndex: 0];
3888     }
3889   /* Deal with pending service requests. */
3890   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3891     && [(EmacsApp *)
3892          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3893                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3894     {
3895       [ns_pending_service_names removeObjectAtIndex: 0];
3896       [ns_pending_service_args removeObjectAtIndex: 0];
3897     }
3898   else
3899     {
3900       ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3901       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3902          to ourself, otherwise [NXApp run] will never exit.  */
3903       send_appdefined = YES;
3904       ns_send_appdefined (-1);
3906       if (++apploopnr != 1)
3907         {
3908           emacs_abort ();
3909         }
3910       record_unwind_protect (unwind_apploopnr, Qt);
3911       [NSApp run];
3912       unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
3913     }
3915   nevents = n_emacs_events_pending;
3916   n_emacs_events_pending = 0;
3917   ns_finish_events ();
3918   q_event_ptr = NULL;
3919   unblock_input ();
3921   return nevents;
3926 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3927            fd_set *exceptfds, struct timespec const *timeout,
3928            sigset_t const *sigmask)
3929 /* --------------------------------------------------------------------------
3930      Replacement for select, checking for events
3931    -------------------------------------------------------------------------- */
3933   int result;
3934   int t, k, nr = 0;
3935   struct input_event event;
3936   char c;
3938 /*  NSTRACE ("ns_select"); */
3940 #ifdef HAVE_NATIVE_FS
3941   check_native_fs ();
3942 #endif
3944   if (hold_event_q.nr > 0)
3945     {
3946       /* We already have events pending. */
3947       raise (SIGIO);
3948       errno = EINTR;
3949       return -1;
3950     }
3952   for (k = 0; k < nfds+1; k++)
3953     {
3954       if (readfds && FD_ISSET(k, readfds)) ++nr;
3955       if (writefds && FD_ISSET(k, writefds)) ++nr;
3956     }
3958   if (NSApp == nil
3959       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3960     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3962   [outerpool release];
3963   outerpool = [[NSAutoreleasePool alloc] init];
3966   send_appdefined = YES;
3967   if (nr > 0)
3968     {
3969       pthread_mutex_lock (&select_mutex);
3970       select_nfds = nfds;
3971       select_valid = 0;
3972       if (readfds)
3973         {
3974           select_readfds = *readfds;
3975           select_valid += SELECT_HAVE_READ;
3976         }
3977       if (writefds)
3978         {
3979           select_writefds = *writefds;
3980           select_valid += SELECT_HAVE_WRITE;
3981         }
3983       if (timeout)
3984         {
3985           select_timeout = *timeout;
3986           select_valid += SELECT_HAVE_TMO;
3987         }
3989       pthread_mutex_unlock (&select_mutex);
3991       /* Inform fd_handler that select should be called */
3992       c = 'g';
3993       emacs_write_sig (selfds[1], &c, 1);
3994     }
3995   else if (nr == 0 && timeout)
3996     {
3997       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3998       double time = timespectod (*timeout);
3999       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4000                                                       target: NSApp
4001                                                     selector:
4002                                   @selector (timeout_handler:)
4003                                                     userInfo: 0
4004                                                      repeats: NO]
4005                       retain];
4006     }
4007   else /* No timeout and no file descriptors, can this happen?  */
4008     {
4009       /* Send appdefined so we exit from the loop */
4010       ns_send_appdefined (-1);
4011     }
4013   block_input ();
4014   ns_init_events (&event);
4015   if (++apploopnr != 1)
4016     {
4017       emacs_abort ();
4018     }
4020   {
4021     ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4022     record_unwind_protect (unwind_apploopnr, Qt);
4023     [NSApp run];
4024     unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
4025   }
4027   ns_finish_events ();
4028   if (nr > 0 && readfds)
4029     {
4030       c = 's';
4031       emacs_write_sig (selfds[1], &c, 1);
4032     }
4033   unblock_input ();
4035   t = last_appdefined_event_data;
4037   if (t != NO_APPDEFINED_DATA)
4038     {
4039       last_appdefined_event_data = NO_APPDEFINED_DATA;
4041       if (t == -2)
4042         {
4043           /* The NX_APPDEFINED event we received was a timeout. */
4044           result = 0;
4045         }
4046       else if (t == -1)
4047         {
4048           /* The NX_APPDEFINED event we received was the result of
4049              at least one real input event arriving.  */
4050           errno = EINTR;
4051           result = -1;
4052         }
4053       else
4054         {
4055           /* Received back from select () in fd_handler; copy the results */
4056           pthread_mutex_lock (&select_mutex);
4057           if (readfds) *readfds = select_readfds;
4058           if (writefds) *writefds = select_writefds;
4059           pthread_mutex_unlock (&select_mutex);
4060           result = t;
4061         }
4062     }
4063   else
4064     {
4065       errno = EINTR;
4066       result = -1;
4067     }
4069   return result;
4074 /* ==========================================================================
4076     Scrollbar handling
4078    ========================================================================== */
4081 static void
4082 ns_set_vertical_scroll_bar (struct window *window,
4083                            int portion, int whole, int position)
4084 /* --------------------------------------------------------------------------
4085       External (hook): Update or add scrollbar
4086    -------------------------------------------------------------------------- */
4088   Lisp_Object win;
4089   NSRect r, v;
4090   struct frame *f = XFRAME (WINDOW_FRAME (window));
4091   EmacsView *view = FRAME_NS_VIEW (f);
4092   EmacsScroller *bar;
4093   int window_y, window_height;
4094   int top, left, height, width;
4095   BOOL update_p = YES;
4097   /* optimization; display engine sends WAY too many of these.. */
4098   if (!NILP (window->vertical_scroll_bar))
4099     {
4100       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4101       if ([bar checkSamePosition: position portion: portion whole: whole])
4102         {
4103           if (view->scrollbarsNeedingUpdate == 0)
4104             {
4105               if (!windows_or_buffers_changed)
4106                   return;
4107             }
4108           else
4109             view->scrollbarsNeedingUpdate--;
4110           update_p = NO;
4111         }
4112     }
4114   NSTRACE ("ns_set_vertical_scroll_bar");
4116   /* Get dimensions.  */
4117   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4118   top = window_y;
4119   height = window_height;
4120   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
4121   left = WINDOW_SCROLL_BAR_AREA_X (window);
4123   r = NSMakeRect (left, top, width, height);
4124   /* the parent view is flipped, so we need to flip y value */
4125   v = [view frame];
4126   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4128   XSETWINDOW (win, window);
4129   block_input ();
4131   /* we want at least 5 lines to display a scrollbar */
4132   if (WINDOW_TOTAL_LINES (window) < 5)
4133     {
4134       if (!NILP (window->vertical_scroll_bar))
4135         {
4136           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4137           [bar removeFromSuperview];
4138           wset_vertical_scroll_bar (window, Qnil);
4139           [bar release];
4140         }
4141       ns_clear_frame_area (f, left, top, width, height);
4142       unblock_input ();
4143       return;
4144     }
4146   if (NILP (window->vertical_scroll_bar))
4147     {
4148       if (width > 0 && height > 0)
4149         ns_clear_frame_area (f, left, top, width, height);
4151       bar = [[EmacsScroller alloc] initFrame: r window: win];
4152       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4153       update_p = YES;
4154     }
4155   else
4156     {
4157       NSRect oldRect;
4158       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4159       oldRect = [bar frame];
4160       r.size.width = oldRect.size.width;
4161       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4162         {
4163           if (oldRect.origin.x != r.origin.x)
4164               ns_clear_frame_area (f, left, top, width, height);
4165           [bar setFrame: r];
4166         }
4167     }
4169   if (update_p)
4170     [bar setPosition: position portion: portion whole: whole];
4171   unblock_input ();
4175 static void
4176 ns_set_horizontal_scroll_bar (struct window *window,
4177                               int portion, int whole, int position)
4178 /* --------------------------------------------------------------------------
4179       External (hook): Update or add scrollbar
4180    -------------------------------------------------------------------------- */
4182   Lisp_Object win;
4183   NSRect r, v;
4184   struct frame *f = XFRAME (WINDOW_FRAME (window));
4185   EmacsView *view = FRAME_NS_VIEW (f);
4186   EmacsScroller *bar;
4187   int top, height, left, width;
4188   int window_x, window_width;
4189   BOOL update_p = YES;
4191   /* optimization; display engine sends WAY too many of these.. */
4192   if (!NILP (window->horizontal_scroll_bar))
4193     {
4194       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4195       if ([bar checkSamePosition: position portion: portion whole: whole])
4196         {
4197           if (view->scrollbarsNeedingUpdate == 0)
4198             {
4199               if (!windows_or_buffers_changed)
4200                   return;
4201             }
4202           else
4203             view->scrollbarsNeedingUpdate--;
4204           update_p = NO;
4205         }
4206     }
4208   NSTRACE ("ns_set_horizontal_scroll_bar");
4210   /* Get dimensions.  */
4211   window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
4212   left = window_x;
4213   width = window_width;
4214   height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
4215   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4217   r = NSMakeRect (left, top, width, height);
4218   /* the parent view is flipped, so we need to flip y value */
4219   v = [view frame];
4220   /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
4221   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4223   XSETWINDOW (win, window);
4224   block_input ();
4226   if (WINDOW_TOTAL_COLS (window) < 5)
4227     {
4228       if (!NILP (window->horizontal_scroll_bar))
4229         {
4230           bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4231           [bar removeFromSuperview];
4232           wset_horizontal_scroll_bar (window, Qnil);
4233         }
4234       ns_clear_frame_area (f, left, top, width, height);
4235       unblock_input ();
4236       return;
4237     }
4239   if (NILP (window->horizontal_scroll_bar))
4240     {
4241       if (width > 0 && height > 0)
4242         ns_clear_frame_area (f, left, top, width, height);
4244       bar = [[EmacsScroller alloc] initFrame: r window: win];
4245       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4246       update_p = YES;
4247     }
4248   else
4249     {
4250       NSRect oldRect;
4251       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4252       oldRect = [bar frame];
4253       r.size.width = oldRect.size.width;
4254       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4255         {
4256           if (oldRect.origin.x != r.origin.x)
4257               ns_clear_frame_area (f, left, top, width, height);
4258           [bar setFrame: r];
4259           update_p = YES;
4260         }
4261     }
4263   if (update_p)
4264     [bar setPosition: position portion: portion whole: whole];
4265   unblock_input ();
4269 static void
4270 ns_condemn_scroll_bars (struct frame *f)
4271 /* --------------------------------------------------------------------------
4272      External (hook): arrange for all frame's scrollbars to be removed
4273      at next call to judge_scroll_bars, except for those redeemed.
4274    -------------------------------------------------------------------------- */
4276   int i;
4277   id view;
4278   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4280   NSTRACE ("ns_condemn_scroll_bars");
4282   for (i =[subviews count]-1; i >= 0; i--)
4283     {
4284       view = [subviews objectAtIndex: i];
4285       if ([view isKindOfClass: [EmacsScroller class]])
4286         [view condemn];
4287     }
4291 static void
4292 ns_redeem_scroll_bar (struct window *window)
4293 /* --------------------------------------------------------------------------
4294      External (hook): arrange to spare this window's scrollbar
4295      at next call to judge_scroll_bars.
4296    -------------------------------------------------------------------------- */
4298   id bar;
4299   NSTRACE ("ns_redeem_scroll_bar");
4300   if (!NILP (window->vertical_scroll_bar))
4301     {
4302       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4303       [bar reprieve];
4304     }
4306   if (!NILP (window->horizontal_scroll_bar))
4307     {
4308       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4309       [bar reprieve];
4310     }
4314 static void
4315 ns_judge_scroll_bars (struct frame *f)
4316 /* --------------------------------------------------------------------------
4317      External (hook): destroy all scrollbars on frame that weren't
4318      redeemed after call to condemn_scroll_bars.
4319    -------------------------------------------------------------------------- */
4321   int i;
4322   id view;
4323   EmacsView *eview = FRAME_NS_VIEW (f);
4324   NSArray *subviews = [[eview superview] subviews];
4325   BOOL removed = NO;
4327   NSTRACE ("ns_judge_scroll_bars");
4328   for (i = [subviews count]-1; i >= 0; --i)
4329     {
4330       view = [subviews objectAtIndex: i];
4331       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4332       if ([view judge])
4333         removed = YES;
4334     }
4336   if (removed)
4337     [eview updateFrameSize: NO];
4340 /* ==========================================================================
4342     Initialization
4344    ========================================================================== */
4347 x_display_pixel_height (struct ns_display_info *dpyinfo)
4349   NSArray *screens = [NSScreen screens];
4350   NSEnumerator *enumerator = [screens objectEnumerator];
4351   NSScreen *screen;
4352   NSRect frame;
4354   frame = NSZeroRect;
4355   while ((screen = [enumerator nextObject]) != nil)
4356     frame = NSUnionRect (frame, [screen frame]);
4358   return NSHeight (frame);
4362 x_display_pixel_width (struct ns_display_info *dpyinfo)
4364   NSArray *screens = [NSScreen screens];
4365   NSEnumerator *enumerator = [screens objectEnumerator];
4366   NSScreen *screen;
4367   NSRect frame;
4369   frame = NSZeroRect;
4370   while ((screen = [enumerator nextObject]) != nil)
4371     frame = NSUnionRect (frame, [screen frame]);
4373   return NSWidth (frame);
4377 static Lisp_Object ns_string_to_lispmod (const char *s)
4378 /* --------------------------------------------------------------------------
4379      Convert modifier name to lisp symbol
4380    -------------------------------------------------------------------------- */
4382   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4383     return Qmeta;
4384   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4385     return Qsuper;
4386   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4387     return Qcontrol;
4388   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4389     return Qalt;
4390   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4391     return Qhyper;
4392   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4393     return Qnone;
4394   else
4395     return Qnil;
4399 static void
4400 ns_default (const char *parameter, Lisp_Object *result,
4401            Lisp_Object yesval, Lisp_Object noval,
4402            BOOL is_float, BOOL is_modstring)
4403 /* --------------------------------------------------------------------------
4404       Check a parameter value in user's preferences
4405    -------------------------------------------------------------------------- */
4407   const char *value = ns_get_defaults_value (parameter);
4409   if (value)
4410     {
4411       double f;
4412       char *pos;
4413       if (c_strcasecmp (value, "YES") == 0)
4414         *result = yesval;
4415       else if (c_strcasecmp (value, "NO") == 0)
4416         *result = noval;
4417       else if (is_float && (f = strtod (value, &pos), pos != value))
4418         *result = make_float (f);
4419       else if (is_modstring && value)
4420         *result = ns_string_to_lispmod (value);
4421       else fprintf (stderr,
4422                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4423     }
4427 static void
4428 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4429 /* --------------------------------------------------------------------------
4430       Initialize global info and storage for display.
4431    -------------------------------------------------------------------------- */
4433     NSScreen *screen = [NSScreen mainScreen];
4434     NSWindowDepth depth = [screen depth];
4436     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4437     dpyinfo->resy = 72.27;
4438     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4439                                                   NSColorSpaceFromDepth (depth)]
4440                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4441                                                  NSColorSpaceFromDepth (depth)];
4442     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4443     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4444     dpyinfo->color_table->colors = NULL;
4445     dpyinfo->root_window = 42; /* a placeholder.. */
4446     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4447     dpyinfo->n_fonts = 0;
4448     dpyinfo->smallest_font_height = 1;
4449     dpyinfo->smallest_char_width = 1;
4451     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4455 /* This and next define (many of the) public functions in this file. */
4456 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4457          with using despite presence in the "system dependent" redisplay
4458          interface.  In addition, many of the ns_ methods have code that is
4459          shared with all terms, indicating need for further refactoring. */
4460 extern frame_parm_handler ns_frame_parm_handlers[];
4461 static struct redisplay_interface ns_redisplay_interface =
4463   ns_frame_parm_handlers,
4464   x_produce_glyphs,
4465   x_write_glyphs,
4466   x_insert_glyphs,
4467   x_clear_end_of_line,
4468   ns_scroll_run,
4469   ns_after_update_window_line,
4470   ns_update_window_begin,
4471   ns_update_window_end,
4472   0, /* flush_display */
4473   x_clear_window_mouse_face,
4474   x_get_glyph_overhangs,
4475   x_fix_overlapping_area,
4476   ns_draw_fringe_bitmap,
4477   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4478   0, /* destroy_fringe_bitmap */
4479   ns_compute_glyph_string_overhangs,
4480   ns_draw_glyph_string,
4481   ns_define_frame_cursor,
4482   ns_clear_frame_area,
4483   ns_draw_window_cursor,
4484   ns_draw_vertical_window_border,
4485   ns_draw_window_divider,
4486   ns_shift_glyphs_for_insert,
4487   ns_show_hourglass,
4488   ns_hide_hourglass
4492 static void
4493 ns_delete_display (struct ns_display_info *dpyinfo)
4495   /* TODO... */
4499 /* This function is called when the last frame on a display is deleted. */
4500 static void
4501 ns_delete_terminal (struct terminal *terminal)
4503   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4505   NSTRACE ("ns_delete_terminal");
4507   /* Protect against recursive calls.  delete_frame in
4508      delete_terminal calls us back when it deletes our last frame.  */
4509   if (!terminal->name)
4510     return;
4512   block_input ();
4514   x_destroy_all_bitmaps (dpyinfo);
4515   ns_delete_display (dpyinfo);
4516   unblock_input ();
4520 static struct terminal *
4521 ns_create_terminal (struct ns_display_info *dpyinfo)
4522 /* --------------------------------------------------------------------------
4523       Set up use of NS before we make the first connection.
4524    -------------------------------------------------------------------------- */
4526   struct terminal *terminal;
4528   NSTRACE ("ns_create_terminal");
4530   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4532   terminal->display_info.ns = dpyinfo;
4533   dpyinfo->terminal = terminal;
4535   terminal->clear_frame_hook = ns_clear_frame;
4536   terminal->ring_bell_hook = ns_ring_bell;
4537   terminal->update_begin_hook = ns_update_begin;
4538   terminal->update_end_hook = ns_update_end;
4539   terminal->read_socket_hook = ns_read_socket;
4540   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4541   terminal->mouse_position_hook = ns_mouse_position;
4542   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4543   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4544   terminal->fullscreen_hook = ns_fullscreen_hook;
4545   terminal->menu_show_hook = ns_menu_show;
4546   terminal->popup_dialog_hook = ns_popup_dialog;
4547   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4548   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4549   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4550   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4551   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4552   terminal->delete_frame_hook = x_destroy_window;
4553   terminal->delete_terminal_hook = ns_delete_terminal;
4554   /* Other hooks are NULL by default.  */
4556   return terminal;
4560 struct ns_display_info *
4561 ns_term_init (Lisp_Object display_name)
4562 /* --------------------------------------------------------------------------
4563      Start the Application and get things rolling.
4564    -------------------------------------------------------------------------- */
4566   struct terminal *terminal;
4567   struct ns_display_info *dpyinfo;
4568   static int ns_initialized = 0;
4569   Lisp_Object tmp;
4571   if (ns_initialized) return x_display_list;
4572   ns_initialized = 1;
4574   block_input ();
4576   NSTRACE ("ns_term_init");
4578   [outerpool release];
4579   outerpool = [[NSAutoreleasePool alloc] init];
4581   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4582   /*GSDebugAllocationActive (YES); */
4583   block_input ();
4585   baud_rate = 38400;
4586   Fset_input_interrupt_mode (Qnil);
4588   if (selfds[0] == -1)
4589     {
4590       if (emacs_pipe (selfds) != 0)
4591         {
4592           fprintf (stderr, "Failed to create pipe: %s\n",
4593                    emacs_strerror (errno));
4594           emacs_abort ();
4595         }
4597       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4598       FD_ZERO (&select_readfds);
4599       FD_ZERO (&select_writefds);
4600       pthread_mutex_init (&select_mutex, NULL);
4601     }
4603   ns_pending_files = [[NSMutableArray alloc] init];
4604   ns_pending_service_names = [[NSMutableArray alloc] init];
4605   ns_pending_service_args = [[NSMutableArray alloc] init];
4607 /* Start app and create the main menu, window, view.
4608      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4609      The view will then ask the NSApp to stop and return to Emacs. */
4610   [EmacsApp sharedApplication];
4611   if (NSApp == nil)
4612     return NULL;
4613   [NSApp setDelegate: NSApp];
4615   /* Start the select thread.  */
4616   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4617                            toTarget:NSApp
4618                          withObject:nil];
4620   /* debugging: log all notifications */
4621   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4622                                          selector: @selector (logNotification:)
4623                                              name: nil object: nil]; */
4625   dpyinfo = xzalloc (sizeof *dpyinfo);
4627   ns_initialize_display_info (dpyinfo);
4628   terminal = ns_create_terminal (dpyinfo);
4630   terminal->kboard = allocate_kboard (Qns);
4631   /* Don't let the initial kboard remain current longer than necessary.
4632      That would cause problems if a file loaded on startup tries to
4633      prompt in the mini-buffer.  */
4634   if (current_kboard == initial_kboard)
4635     current_kboard = terminal->kboard;
4636   terminal->kboard->reference_count++;
4638   dpyinfo->next = x_display_list;
4639   x_display_list = dpyinfo;
4641   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4643   terminal->name = xlispstrdup (display_name);
4645   unblock_input ();
4647   if (!inhibit_x_resources)
4648     {
4649       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4650                  Qt, Qnil, NO, NO);
4651       tmp = Qnil;
4652       /* this is a standard variable */
4653       ns_default ("AppleAntiAliasingThreshold", &tmp,
4654                  make_float (10.0), make_float (6.0), YES, NO);
4655       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4656     }
4658   NSTRACE_MSG ("Colors");
4660   {
4661     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4663     if ( cl == nil )
4664       {
4665         Lisp_Object color_file, color_map, color;
4666         unsigned long c;
4667         char *name;
4669         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4670                          Fsymbol_value (intern ("data-directory")));
4672         color_map = Fx_load_color_file (color_file);
4673         if (NILP (color_map))
4674           fatal ("Could not read %s.\n", SDATA (color_file));
4676         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4677         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4678           {
4679             color = XCAR (color_map);
4680             name = SSDATA (XCAR (color));
4681             c = XINT (XCDR (color));
4682             [cl setColor:
4683                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4684                                       green: GREEN_FROM_ULONG (c) / 255.0
4685                                        blue: BLUE_FROM_ULONG (c) / 255.0
4686                                       alpha: 1.0]
4687                   forKey: [NSString stringWithUTF8String: name]];
4688           }
4689         [cl writeToFile: nil];
4690       }
4691   }
4693   NSTRACE_MSG ("Versions");
4695   {
4696 #ifdef NS_IMPL_GNUSTEP
4697     Vwindow_system_version = build_string (gnustep_base_version);
4698 #else
4699     /*PSnextrelease (128, c); */
4700     char c[DBL_BUFSIZE_BOUND];
4701     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4702     Vwindow_system_version = make_unibyte_string (c, len);
4703 #endif
4704   }
4706   delete_keyboard_wait_descriptor (0);
4708   ns_app_name = [[NSProcessInfo processInfo] processName];
4710   /* Set up OS X app menu */
4712   NSTRACE_MSG ("Menu init");
4714 #ifdef NS_IMPL_COCOA
4715   {
4716     NSMenu *appMenu;
4717     NSMenuItem *item;
4718     /* set up the application menu */
4719     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4720     [svcsMenu setAutoenablesItems: NO];
4721     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4722     [appMenu setAutoenablesItems: NO];
4723     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4724     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4726     [appMenu insertItemWithTitle: @"About Emacs"
4727                           action: @selector (orderFrontStandardAboutPanel:)
4728                    keyEquivalent: @""
4729                          atIndex: 0];
4730     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4731     [appMenu insertItemWithTitle: @"Preferences..."
4732                           action: @selector (showPreferencesWindow:)
4733                    keyEquivalent: @","
4734                          atIndex: 2];
4735     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4736     item = [appMenu insertItemWithTitle: @"Services"
4737                                  action: @selector (menuDown:)
4738                           keyEquivalent: @""
4739                                 atIndex: 4];
4740     [appMenu setSubmenu: svcsMenu forItem: item];
4741     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4742     [appMenu insertItemWithTitle: @"Hide Emacs"
4743                           action: @selector (hide:)
4744                    keyEquivalent: @"h"
4745                          atIndex: 6];
4746     item =  [appMenu insertItemWithTitle: @"Hide Others"
4747                           action: @selector (hideOtherApplications:)
4748                    keyEquivalent: @"h"
4749                          atIndex: 7];
4750     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4751     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4752     [appMenu insertItemWithTitle: @"Quit Emacs"
4753                           action: @selector (terminate:)
4754                    keyEquivalent: @"q"
4755                          atIndex: 9];
4757     item = [mainMenu insertItemWithTitle: ns_app_name
4758                                   action: @selector (menuDown:)
4759                            keyEquivalent: @""
4760                                  atIndex: 0];
4761     [mainMenu setSubmenu: appMenu forItem: item];
4762     [dockMenu insertItemWithTitle: @"New Frame"
4763                            action: @selector (newFrame:)
4764                     keyEquivalent: @""
4765                           atIndex: 0];
4767     [NSApp setMainMenu: mainMenu];
4768     [NSApp setAppleMenu: appMenu];
4769     [NSApp setServicesMenu: svcsMenu];
4770     /* Needed at least on Cocoa, to get dock menu to show windows */
4771     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4773     [[NSNotificationCenter defaultCenter]
4774       addObserver: mainMenu
4775          selector: @selector (trackingNotification:)
4776              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4777     [[NSNotificationCenter defaultCenter]
4778       addObserver: mainMenu
4779          selector: @selector (trackingNotification:)
4780              name: NSMenuDidEndTrackingNotification object: mainMenu];
4781   }
4782 #endif /* MAC OS X menu setup */
4784   /* Register our external input/output types, used for determining
4785      applicable services and also drag/drop eligibility. */
4787   NSTRACE_MSG ("Input/output types");
4789   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4790   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4791                       retain];
4792   ns_drag_types = [[NSArray arrayWithObjects:
4793                             NSStringPboardType,
4794                             NSTabularTextPboardType,
4795                             NSFilenamesPboardType,
4796                             NSURLPboardType, nil] retain];
4798   /* If fullscreen is in init/default-frame-alist, focus isn't set
4799      right for fullscreen windows, so set this.  */
4800   [NSApp activateIgnoringOtherApps:YES];
4802   NSTRACE_MSG ("Call NSApp run");
4804   [NSApp run];
4805   ns_do_open_file = YES;
4807 #ifdef NS_IMPL_GNUSTEP
4808   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4809      We must re-catch it so subprocess works.  */
4810   catch_child_signal ();
4811 #endif
4813   NSTRACE_MSG ("ns_term_init done");
4815   unblock_input ();
4817   return dpyinfo;
4821 void
4822 ns_term_shutdown (int sig)
4824   [[NSUserDefaults standardUserDefaults] synchronize];
4826   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4827   if (STRINGP (Vauto_save_list_file_name))
4828     unlink (SSDATA (Vauto_save_list_file_name));
4830   if (sig == 0 || sig == SIGTERM)
4831     {
4832       [NSApp terminate: NSApp];
4833     }
4834   else // force a stack trace to happen
4835     {
4836       emacs_abort ();
4837     }
4841 /* ==========================================================================
4843     EmacsApp implementation
4845    ========================================================================== */
4848 @implementation EmacsApp
4850 - (id)init
4852   NSTRACE ("[EmacsApp init]");
4854   if ((self = [super init]))
4855     {
4856 #ifdef NS_IMPL_COCOA
4857       self->isFirst = YES;
4858 #endif
4859 #ifdef NS_IMPL_GNUSTEP
4860       self->applicationDidFinishLaunchingCalled = NO;
4861 #endif
4862     }
4864   return self;
4867 #ifdef NS_IMPL_COCOA
4868 - (void)run
4870   NSTRACE ("[EmacsApp run]");
4872 #ifndef NSAppKitVersionNumber10_9
4873 #define NSAppKitVersionNumber10_9 1265
4874 #endif
4876     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
4877       {
4878         [super run];
4879         return;
4880       }
4882   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4884   if (isFirst) [self finishLaunching];
4885   isFirst = NO;
4887   shouldKeepRunning = YES;
4888   do
4889     {
4890       [pool release];
4891       pool = [[NSAutoreleasePool alloc] init];
4893       NSEvent *event =
4894         [self nextEventMatchingMask:NSAnyEventMask
4895                           untilDate:[NSDate distantFuture]
4896                              inMode:NSDefaultRunLoopMode
4897                             dequeue:YES];
4899       [self sendEvent:event];
4900       [self updateWindows];
4901     } while (shouldKeepRunning);
4903   [pool release];
4906 - (void)stop: (id)sender
4908   NSTRACE ("[EmacsApp stop]");
4910     shouldKeepRunning = NO;
4911     // Stop possible dialog also.  Noop if no dialog present.
4912     // The file dialog still leaks 7k - 10k on 10.9 though.
4913     [super stop:sender];
4915 #endif /* NS_IMPL_COCOA */
4917 - (void)logNotification: (NSNotification *)notification
4919   NSTRACE ("[EmacsApp logNotification]");
4921   const char *name = [[notification name] UTF8String];
4922   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4923       && !strstr (name, "WindowNumber"))
4924     NSLog (@"notification: '%@'", [notification name]);
4928 - (void)sendEvent: (NSEvent *)theEvent
4929 /* --------------------------------------------------------------------------
4930      Called when NSApp is running for each event received.  Used to stop
4931      the loop when we choose, since there's no way to just run one iteration.
4932    -------------------------------------------------------------------------- */
4934   int type = [theEvent type];
4935   NSWindow *window = [theEvent window];
4937   NSTRACE ("[EmacsApp sendEvent]");
4938 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4940 #ifdef NS_IMPL_GNUSTEP
4941   // Keyboard events aren't propagated to file dialogs for some reason.
4942   if ([NSApp modalWindow] != nil &&
4943       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4944     {
4945       [[NSApp modalWindow] sendEvent: theEvent];
4946       return;
4947     }
4948 #endif
4950   if (represented_filename != nil && represented_frame)
4951     {
4952       NSString *fstr = represented_filename;
4953       NSView *view = FRAME_NS_VIEW (represented_frame);
4954 #ifdef NS_IMPL_COCOA
4955       /* work around a bug observed on 10.3 and later where
4956          setTitleWithRepresentedFilename does not clear out previous state
4957          if given filename does not exist */
4958       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
4959         [[view window] setRepresentedFilename: @""];
4960 #endif
4961       [[view window] setRepresentedFilename: fstr];
4962       [represented_filename release];
4963       represented_filename = nil;
4964       represented_frame = NULL;
4965     }
4967   if (type == NSApplicationDefined)
4968     {
4969       switch ([theEvent data2])
4970         {
4971 #ifdef NS_IMPL_COCOA
4972         case NSAPP_DATA2_RUNASSCRIPT:
4973           ns_run_ascript ();
4974           [self stop: self];
4975           return;
4976 #endif
4977         case NSAPP_DATA2_RUNFILEDIALOG:
4978           ns_run_file_dialog ();
4979           [self stop: self];
4980           return;
4981         }
4982     }
4984   if (type == NSCursorUpdate && window == nil)
4985     {
4986       fprintf (stderr, "Dropping external cursor update event.\n");
4987       return;
4988     }
4990   if (type == NSApplicationDefined)
4991     {
4992       /* Events posted by ns_send_appdefined interrupt the run loop here.
4993          But, if a modal window is up, an appdefined can still come through,
4994          (e.g., from a makeKeyWindow event) but stopping self also stops the
4995          modal loop. Just defer it until later. */
4996       if ([NSApp modalWindow] == nil)
4997         {
4998           last_appdefined_event_data = [theEvent data1];
4999           [self stop: self];
5000         }
5001       else
5002         {
5003           send_appdefined = YES;
5004         }
5005     }
5008 #ifdef NS_IMPL_COCOA
5009   /* If no dialog and none of our frames have focus and it is a move, skip it.
5010      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
5011      such as Wifi, sound, date or similar.
5012      This prevents "spooky" highlighting in the frame under the menu.  */
5013   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
5014     {
5015       struct ns_display_info *di;
5016       BOOL has_focus = NO;
5017       for (di = x_display_list; ! has_focus && di; di = di->next)
5018         has_focus = di->x_focus_frame != 0;
5019       if (! has_focus)
5020         return;
5021     }
5022 #endif
5024   [super sendEvent: theEvent];
5028 - (void)showPreferencesWindow: (id)sender
5030   struct frame *emacsframe = SELECTED_FRAME ();
5031   NSEvent *theEvent = [NSApp currentEvent];
5033   if (!emacs_event)
5034     return;
5035   emacs_event->kind = NS_NONKEY_EVENT;
5036   emacs_event->code = KEY_NS_SHOW_PREFS;
5037   emacs_event->modifiers = 0;
5038   EV_TRAILER (theEvent);
5042 - (void)newFrame: (id)sender
5044   NSTRACE ("[EmacsApp newFrame]");
5046   struct frame *emacsframe = SELECTED_FRAME ();
5047   NSEvent *theEvent = [NSApp currentEvent];
5049   if (!emacs_event)
5050     return;
5051   emacs_event->kind = NS_NONKEY_EVENT;
5052   emacs_event->code = KEY_NS_NEW_FRAME;
5053   emacs_event->modifiers = 0;
5054   EV_TRAILER (theEvent);
5058 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5059 - (BOOL) openFile: (NSString *)fileName
5061   NSTRACE ("[EmacsApp openFile]");
5063   struct frame *emacsframe = SELECTED_FRAME ();
5064   NSEvent *theEvent = [NSApp currentEvent];
5066   if (!emacs_event)
5067     return NO;
5069   emacs_event->kind = NS_NONKEY_EVENT;
5070   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5071   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5072   ns_input_line = Qnil; /* can be start or cons start,end */
5073   emacs_event->modifiers =0;
5074   EV_TRAILER (theEvent);
5076   return YES;
5080 /* **************************************************************************
5082       EmacsApp delegate implementation
5084    ************************************************************************** */
5086 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5087 /* --------------------------------------------------------------------------
5088      When application is loaded, terminate event loop in ns_term_init
5089    -------------------------------------------------------------------------- */
5091   NSTRACE ("[EmacsApp applicationDidFinishLaunching]");
5093 #ifdef NS_IMPL_GNUSTEP
5094   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5095 #endif
5096   [NSApp setServicesProvider: NSApp];
5098   [self antialiasThresholdDidChange:nil];
5099 #ifdef NS_IMPL_COCOA
5100   [[NSNotificationCenter defaultCenter]
5101     addObserver:self
5102        selector:@selector(antialiasThresholdDidChange:)
5103            name:NSAntialiasThresholdChangedNotification
5104          object:nil];
5105 #endif
5107   ns_send_appdefined (-2);
5110 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5112 #ifdef NS_IMPL_COCOA
5113   macfont_update_antialias_threshold ();
5114 #endif
5118 /* Termination sequences:
5119     C-x C-c:
5120     Cmd-Q:
5121     MenuBar | File | Exit:
5122     Select Quit from App menubar:
5123         -terminate
5124         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5125         ns_term_shutdown()
5127     Select Quit from Dock menu:
5128     Logout attempt:
5129         -appShouldTerminate
5130           Cancel -> Nothing else
5131           Accept ->
5133           -terminate
5134           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5135           ns_term_shutdown()
5139 - (void) terminate: (id)sender
5141   NSTRACE ("[EmacsApp terminate]");
5143   struct frame *emacsframe = SELECTED_FRAME ();
5145   if (!emacs_event)
5146     return;
5148   emacs_event->kind = NS_NONKEY_EVENT;
5149   emacs_event->code = KEY_NS_POWER_OFF;
5150   emacs_event->arg = Qt; /* mark as non-key event */
5151   EV_TRAILER ((id)nil);
5154 static bool
5155 runAlertPanel(NSString *title,
5156               NSString *msgFormat,
5157               NSString *defaultButton,
5158               NSString *alternateButton)
5160 #if !defined (NS_IMPL_COCOA) || \
5161   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5162   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5163     == NSAlertDefaultReturn;
5164 #else
5165   NSAlert *alert = [[NSAlert alloc] init];
5166   [alert setAlertStyle: NSCriticalAlertStyle];
5167   [alert setMessageText: msgFormat];
5168   [alert addButtonWithTitle: defaultButton];
5169   [alert addButtonWithTitle: alternateButton];
5170   NSInteger ret = [alert runModal];
5171   [alert release];
5172   return ret == NSAlertFirstButtonReturn;
5173 #endif
5177 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5179   NSTRACE ("[EmacsApp applicationShouldTerminate]");
5181   bool ret;
5183   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5184     return NSTerminateNow;
5186     ret = runAlertPanel(ns_app_name,
5187                         @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5188                         @"Save Buffers and Exit", @"Cancel");
5190     if (ret)
5191         return NSTerminateNow;
5192     else
5193         return NSTerminateCancel;
5194     return NSTerminateNow;  /* just in case */
5197 static int
5198 not_in_argv (NSString *arg)
5200   int k;
5201   const char *a = [arg UTF8String];
5202   for (k = 1; k < initial_argc; ++k)
5203     if (strcmp (a, initial_argv[k]) == 0) return 0;
5204   return 1;
5207 /*   Notification from the Workspace to open a file */
5208 - (BOOL)application: sender openFile: (NSString *)file
5210   if (ns_do_open_file || not_in_argv (file))
5211     [ns_pending_files addObject: file];
5212   return YES;
5216 /*   Open a file as a temporary file */
5217 - (BOOL)application: sender openTempFile: (NSString *)file
5219   if (ns_do_open_file || not_in_argv (file))
5220     [ns_pending_files addObject: file];
5221   return YES;
5225 /*   Notification from the Workspace to open a file noninteractively (?) */
5226 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5228   if (ns_do_open_file || not_in_argv (file))
5229     [ns_pending_files addObject: file];
5230   return YES;
5233 /*   Notification from the Workspace to open multiple files */
5234 - (void)application: sender openFiles: (NSArray *)fileList
5236   NSEnumerator *files = [fileList objectEnumerator];
5237   NSString *file;
5238   /* Don't open files from the command line unconditionally,
5239      Cocoa parses the command line wrong, --option value tries to open value
5240      if --option is the last option.  */
5241   while ((file = [files nextObject]) != nil)
5242     if (ns_do_open_file || not_in_argv (file))
5243       [ns_pending_files addObject: file];
5245   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5250 /* Handle dock menu requests.  */
5251 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5253   return dockMenu;
5257 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5258 - (void)applicationWillBecomeActive: (NSNotification *)notification
5260   NSTRACE ("[EmacsApp applicationWillBecomeActive]");
5261   //ns_app_active=YES;
5264 - (void)applicationDidBecomeActive: (NSNotification *)notification
5266   NSTRACE ("[EmacsApp applicationDidBecomeActive]");
5268 #ifdef NS_IMPL_GNUSTEP
5269   if (! applicationDidFinishLaunchingCalled)
5270     [self applicationDidFinishLaunching:notification];
5271 #endif
5272   //ns_app_active=YES;
5274   ns_update_auto_hide_menu_bar ();
5275   // No constraining takes place when the application is not active.
5276   ns_constrain_all_frames ();
5278 - (void)applicationDidResignActive: (NSNotification *)notification
5280   NSTRACE ("[EmacsApp applicationDidResignActive]");
5282   //ns_app_active=NO;
5283   ns_send_appdefined (-1);
5288 /* ==========================================================================
5290     EmacsApp aux handlers for managing event loop
5292    ========================================================================== */
5295 - (void)timeout_handler: (NSTimer *)timedEntry
5296 /* --------------------------------------------------------------------------
5297      The timeout specified to ns_select has passed.
5298    -------------------------------------------------------------------------- */
5300   /*NSTRACE ("timeout_handler"); */
5301   ns_send_appdefined (-2);
5304 #ifdef NS_IMPL_GNUSTEP
5305 - (void)sendFromMainThread:(id)unused
5307   ns_send_appdefined (nextappdefined);
5309 #endif
5311 - (void)fd_handler:(id)unused
5312 /* --------------------------------------------------------------------------
5313      Check data waiting on file descriptors and terminate if so
5314    -------------------------------------------------------------------------- */
5316   int result;
5317   int waiting = 1, nfds;
5318   char c;
5320   fd_set readfds, writefds, *wfds;
5321   struct timespec timeout, *tmo;
5322   NSAutoreleasePool *pool = nil;
5324   /* NSTRACE ("fd_handler"); */
5326   for (;;)
5327     {
5328       [pool release];
5329       pool = [[NSAutoreleasePool alloc] init];
5331       if (waiting)
5332         {
5333           fd_set fds;
5334           FD_ZERO (&fds);
5335           FD_SET (selfds[0], &fds);
5336           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5337           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5338             waiting = 0;
5339         }
5340       else
5341         {
5342           pthread_mutex_lock (&select_mutex);
5343           nfds = select_nfds;
5345           if (select_valid & SELECT_HAVE_READ)
5346             readfds = select_readfds;
5347           else
5348             FD_ZERO (&readfds);
5350           if (select_valid & SELECT_HAVE_WRITE)
5351             {
5352               writefds = select_writefds;
5353               wfds = &writefds;
5354             }
5355           else
5356             wfds = NULL;
5357           if (select_valid & SELECT_HAVE_TMO)
5358             {
5359               timeout = select_timeout;
5360               tmo = &timeout;
5361             }
5362           else
5363             tmo = NULL;
5365           pthread_mutex_unlock (&select_mutex);
5367           FD_SET (selfds[0], &readfds);
5368           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5370           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5372           if (result == 0)
5373             ns_send_appdefined (-2);
5374           else if (result > 0)
5375             {
5376               if (FD_ISSET (selfds[0], &readfds))
5377                 {
5378                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5379                     waiting = 1;
5380                 }
5381               else
5382                 {
5383                   pthread_mutex_lock (&select_mutex);
5384                   if (select_valid & SELECT_HAVE_READ)
5385                     select_readfds = readfds;
5386                   if (select_valid & SELECT_HAVE_WRITE)
5387                     select_writefds = writefds;
5388                   if (select_valid & SELECT_HAVE_TMO)
5389                     select_timeout = timeout;
5390                   pthread_mutex_unlock (&select_mutex);
5392                   ns_send_appdefined (result);
5393                 }
5394             }
5395           waiting = 1;
5396         }
5397     }
5402 /* ==========================================================================
5404     Service provision
5406    ========================================================================== */
5408 /* called from system: queue for next pass through event loop */
5409 - (void)requestService: (NSPasteboard *)pboard
5410               userData: (NSString *)userData
5411                  error: (NSString **)error
5413   [ns_pending_service_names addObject: userData];
5414   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5415       SSDATA (ns_string_from_pasteboard (pboard))]];
5419 /* called from ns_read_socket to clear queue */
5420 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5422   struct frame *emacsframe = SELECTED_FRAME ();
5423   NSEvent *theEvent = [NSApp currentEvent];
5425   if (!emacs_event)
5426     return NO;
5428   emacs_event->kind = NS_NONKEY_EVENT;
5429   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5430   ns_input_spi_name = build_string ([name UTF8String]);
5431   ns_input_spi_arg = build_string ([arg UTF8String]);
5432   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5433   EV_TRAILER (theEvent);
5435   return YES;
5439 @end  /* EmacsApp */
5443 /* ==========================================================================
5445     EmacsView implementation
5447    ========================================================================== */
5450 @implementation EmacsView
5452 /* needed to inform when window closed from LISP */
5453 - (void) setWindowClosing: (BOOL)closing
5455   windowClosing = closing;
5459 - (void)dealloc
5461   NSTRACE ("EmacsView_dealloc");
5462   [toolbar release];
5463   if (fs_state == FULLSCREEN_BOTH)
5464     [nonfs_window release];
5465   [super dealloc];
5469 /* called on font panel selection */
5470 - (void)changeFont: (id)sender
5472   NSEvent *e = [[self window] currentEvent];
5473   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5474   struct font *font = face->font;
5475   id newFont;
5476   CGFloat size;
5477   NSFont *nsfont;
5479   NSTRACE ("changeFont");
5481   if (!emacs_event)
5482     return;
5484 #ifdef NS_IMPL_GNUSTEP
5485   nsfont = ((struct nsfont_info *)font)->nsfont;
5486 #endif
5487 #ifdef NS_IMPL_COCOA
5488   nsfont = (NSFont *) macfont_get_nsctfont (font);
5489 #endif
5491   if ((newFont = [sender convertFont: nsfont]))
5492     {
5493       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5495       emacs_event->kind = NS_NONKEY_EVENT;
5496       emacs_event->modifiers = 0;
5497       emacs_event->code = KEY_NS_CHANGE_FONT;
5499       size = [newFont pointSize];
5500       ns_input_fontsize = make_number (lrint (size));
5501       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5502       EV_TRAILER (e);
5503     }
5507 - (BOOL)acceptsFirstResponder
5509   NSTRACE ("acceptsFirstResponder");
5510   return YES;
5514 - (void)resetCursorRects
5516   NSRect visible = [self visibleRect];
5517   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5518   NSTRACE ("resetCursorRects");
5520   if (currentCursor == nil)
5521     currentCursor = [NSCursor arrowCursor];
5523   if (!NSIsEmptyRect (visible))
5524     [self addCursorRect: visible cursor: currentCursor];
5525   [currentCursor setOnMouseEntered: YES];
5530 /*****************************************************************************/
5531 /* Keyboard handling. */
5532 #define NS_KEYLOG 0
5534 - (void)keyDown: (NSEvent *)theEvent
5536   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5537   int code;
5538   unsigned fnKeysym = 0;
5539   static NSMutableArray *nsEvArray;
5540   int left_is_none;
5541   unsigned int flags = [theEvent modifierFlags];
5543   NSTRACE ("keyDown");
5545   /* Rhapsody and OS X give up and down events for the arrow keys */
5546   if (ns_fake_keydown == YES)
5547     ns_fake_keydown = NO;
5548   else if ([theEvent type] != NSKeyDown)
5549     return;
5551   if (!emacs_event)
5552     return;
5554  if (![[self window] isKeyWindow]
5555      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5556      /* we must avoid an infinite loop here. */
5557      && (EmacsView *)[[theEvent window] delegate] != self)
5558    {
5559      /* XXX: There is an occasional condition in which, when Emacs display
5560          updates a different frame from the current one, and temporarily
5561          selects it, then processes some interrupt-driven input
5562          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5563          for some reason that window has its first responder set to the NSView
5564          most recently updated (I guess), which is not the correct one. */
5565      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5566      return;
5567    }
5569   if (nsEvArray == nil)
5570     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5572   [NSCursor setHiddenUntilMouseMoves: YES];
5574   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5575     {
5576       clear_mouse_face (hlinfo);
5577       hlinfo->mouse_face_hidden = 1;
5578     }
5580   if (!processingCompose)
5581     {
5582       /* When using screen sharing, no left or right information is sent,
5583          so use Left key in those cases.  */
5584       int is_left_key, is_right_key;
5586       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5587         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5589       /* (Carbon way: [theEvent keyCode]) */
5591       /* is it a "function key"? */
5592       /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5593          flag set (this is probably a bug in the OS).
5594       */
5595       if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5596         {
5597           fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5598         }
5599       if (fnKeysym == 0)
5600         {
5601           fnKeysym = ns_convert_key (code);
5602         }
5604       if (fnKeysym)
5605         {
5606           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5607              because Emacs treats Delete and KP-Delete same (in simple.el). */
5608           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5609 #ifdef NS_IMPL_GNUSTEP
5610               /*  GNUstep uses incompatible keycodes, even for those that are
5611                   supposed to be hardware independent.  Just check for delete.
5612                   Keypad delete does not have keysym 0xFFFF.
5613                   See http://savannah.gnu.org/bugs/?25395
5614               */
5615               || (fnKeysym == 0xFFFF && code == 127)
5616 #endif
5617             )
5618             code = 0xFF08; /* backspace */
5619           else
5620             code = fnKeysym;
5621         }
5623       /* are there modifiers? */
5624       emacs_event->modifiers = 0;
5626       if (flags & NSHelpKeyMask)
5627           emacs_event->modifiers |= hyper_modifier;
5629       if (flags & NSShiftKeyMask)
5630         emacs_event->modifiers |= shift_modifier;
5632       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5633       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5634         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5636       if (is_right_key)
5637         emacs_event->modifiers |= parse_solitary_modifier
5638           (EQ (ns_right_command_modifier, Qleft)
5639            ? ns_command_modifier
5640            : ns_right_command_modifier);
5642       if (is_left_key)
5643         {
5644           emacs_event->modifiers |= parse_solitary_modifier
5645             (ns_command_modifier);
5647           /* if super (default), take input manager's word so things like
5648              dvorak / qwerty layout work */
5649           if (EQ (ns_command_modifier, Qsuper)
5650               && !fnKeysym
5651               && [[theEvent characters] length] != 0)
5652             {
5653               /* XXX: the code we get will be unshifted, so if we have
5654                  a shift modifier, must convert ourselves */
5655               if (!(flags & NSShiftKeyMask))
5656                 code = [[theEvent characters] characterAtIndex: 0];
5657 #if 0
5658               /* this is ugly and also requires linking w/Carbon framework
5659                  (for LMGetKbdType) so for now leave this rare (?) case
5660                  undealt with.. in future look into CGEvent methods */
5661               else
5662                 {
5663                   long smv = GetScriptManagerVariable (smKeyScript);
5664                   Handle uchrHandle = GetResource
5665                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5666                   UInt32 dummy = 0;
5667                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5668                                  [[theEvent characters] characterAtIndex: 0],
5669                                  kUCKeyActionDisplay,
5670                                  (flags & ~NSCommandKeyMask) >> 8,
5671                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5672                                  &dummy, 1, &dummy, &code);
5673                   code &= 0xFF;
5674                 }
5675 #endif
5676             }
5677         }
5679       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5680       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5681         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5683       if (is_right_key)
5684           emacs_event->modifiers |= parse_solitary_modifier
5685               (EQ (ns_right_control_modifier, Qleft)
5686                ? ns_control_modifier
5687                : ns_right_control_modifier);
5689       if (is_left_key)
5690         emacs_event->modifiers |= parse_solitary_modifier
5691           (ns_control_modifier);
5693       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5694           emacs_event->modifiers |=
5695             parse_solitary_modifier (ns_function_modifier);
5697       left_is_none = NILP (ns_alternate_modifier)
5698         || EQ (ns_alternate_modifier, Qnone);
5700       is_right_key = (flags & NSRightAlternateKeyMask)
5701         == NSRightAlternateKeyMask;
5702       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5703         || (! is_right_key
5704             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5706       if (is_right_key)
5707         {
5708           if ((NILP (ns_right_alternate_modifier)
5709                || EQ (ns_right_alternate_modifier, Qnone)
5710                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5711               && !fnKeysym)
5712             {   /* accept pre-interp alt comb */
5713               if ([[theEvent characters] length] > 0)
5714                 code = [[theEvent characters] characterAtIndex: 0];
5715               /*HACK: clear lone shift modifier to stop next if from firing */
5716               if (emacs_event->modifiers == shift_modifier)
5717                 emacs_event->modifiers = 0;
5718             }
5719           else
5720             emacs_event->modifiers |= parse_solitary_modifier
5721               (EQ (ns_right_alternate_modifier, Qleft)
5722                ? ns_alternate_modifier
5723                : ns_right_alternate_modifier);
5724         }
5726       if (is_left_key) /* default = meta */
5727         {
5728           if (left_is_none && !fnKeysym)
5729             {   /* accept pre-interp alt comb */
5730               if ([[theEvent characters] length] > 0)
5731                 code = [[theEvent characters] characterAtIndex: 0];
5732               /*HACK: clear lone shift modifier to stop next if from firing */
5733               if (emacs_event->modifiers == shift_modifier)
5734                 emacs_event->modifiers = 0;
5735             }
5736           else
5737               emacs_event->modifiers |=
5738                 parse_solitary_modifier (ns_alternate_modifier);
5739         }
5741   if (NS_KEYLOG)
5742     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5743              code, fnKeysym, flags, emacs_event->modifiers);
5745       /* if it was a function key or had modifiers, pass it directly to emacs */
5746       if (fnKeysym || (emacs_event->modifiers
5747                        && (emacs_event->modifiers != shift_modifier)
5748                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5749 /*[[theEvent characters] length] */
5750         {
5751           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5752           if (code < 0x20)
5753             code |= (1<<28)|(3<<16);
5754           else if (code == 0x7f)
5755             code |= (1<<28)|(3<<16);
5756           else if (!fnKeysym)
5757             emacs_event->kind = code > 0xFF
5758               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5760           emacs_event->code = code;
5761           EV_TRAILER (theEvent);
5762           processingCompose = NO;
5763           return;
5764         }
5765     }
5768   if (NS_KEYLOG && !processingCompose)
5769     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5771   processingCompose = YES;
5772   [nsEvArray addObject: theEvent];
5773   [self interpretKeyEvents: nsEvArray];
5774   [nsEvArray removeObject: theEvent];
5778 #ifdef NS_IMPL_COCOA
5779 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5780    decided not to send key-down for.
5781    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5782    This only applies on Tiger and earlier.
5783    If it matches one of these, send it on to keyDown. */
5784 -(void)keyUp: (NSEvent *)theEvent
5786   int flags = [theEvent modifierFlags];
5787   int code = [theEvent keyCode];
5788   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5789       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5790     {
5791       if (NS_KEYLOG)
5792         fprintf (stderr, "keyUp: passed test");
5793       ns_fake_keydown = YES;
5794       [self keyDown: theEvent];
5795     }
5797 #endif
5800 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5803 /* <NSTextInput>: called when done composing;
5804    NOTE: also called when we delete over working text, followed immed.
5805          by doCommandBySelector: deleteBackward: */
5806 - (void)insertText: (id)aString
5808   int code;
5809   int len = [(NSString *)aString length];
5810   int i;
5812   if (NS_KEYLOG)
5813     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5814   processingCompose = NO;
5816   if (!emacs_event)
5817     return;
5819   /* first, clear any working text */
5820   if (workingText != nil)
5821     [self deleteWorkingText];
5823   /* now insert the string as keystrokes */
5824   for (i =0; i<len; i++)
5825     {
5826       code = [aString characterAtIndex: i];
5827       /* TODO: still need this? */
5828       if (code == 0x2DC)
5829         code = '~'; /* 0x7E */
5830       if (code != 32) /* Space */
5831         emacs_event->modifiers = 0;
5832       emacs_event->kind
5833         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5834       emacs_event->code = code;
5835       EV_TRAILER ((id)nil);
5836     }
5840 /* <NSTextInput>: inserts display of composing characters */
5841 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5843   NSString *str = [aString respondsToSelector: @selector (string)] ?
5844     [aString string] : aString;
5845   if (NS_KEYLOG)
5846     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5847            str, (unsigned long)[str length],
5848            (unsigned long)selRange.length,
5849            (unsigned long)selRange.location);
5851   if (workingText != nil)
5852     [self deleteWorkingText];
5853   if ([str length] == 0)
5854     return;
5856   if (!emacs_event)
5857     return;
5859   processingCompose = YES;
5860   workingText = [str copy];
5861   ns_working_text = build_string ([workingText UTF8String]);
5863   emacs_event->kind = NS_TEXT_EVENT;
5864   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5865   EV_TRAILER ((id)nil);
5869 /* delete display of composing characters [not in <NSTextInput>] */
5870 - (void)deleteWorkingText
5872   if (workingText == nil)
5873     return;
5874   if (NS_KEYLOG)
5875     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5876   [workingText release];
5877   workingText = nil;
5878   processingCompose = NO;
5880   if (!emacs_event)
5881     return;
5883   emacs_event->kind = NS_TEXT_EVENT;
5884   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5885   EV_TRAILER ((id)nil);
5889 - (BOOL)hasMarkedText
5891   return workingText != nil;
5895 - (NSRange)markedRange
5897   NSRange rng = workingText != nil
5898     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5899   if (NS_KEYLOG)
5900     NSLog (@"markedRange request");
5901   return rng;
5905 - (void)unmarkText
5907   if (NS_KEYLOG)
5908     NSLog (@"unmark (accept) text");
5909   [self deleteWorkingText];
5910   processingCompose = NO;
5914 /* used to position char selection windows, etc. */
5915 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5917   NSRect rect;
5918   NSPoint pt;
5919   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5920   if (NS_KEYLOG)
5921     NSLog (@"firstRectForCharRange request");
5923   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5924   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5925   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5926   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5927                                        +FRAME_LINE_HEIGHT (emacsframe));
5929   pt = [self convertPoint: pt toView: nil];
5930   pt = [[self window] convertBaseToScreen: pt];
5931   rect.origin = pt;
5932   return rect;
5936 - (NSInteger)conversationIdentifier
5938   return (NSInteger)self;
5942 - (void)doCommandBySelector: (SEL)aSelector
5944   if (NS_KEYLOG)
5945     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5947   processingCompose = NO;
5948   if (aSelector == @selector (deleteBackward:))
5949     {
5950       /* happens when user backspaces over an ongoing composition:
5951          throw a 'delete' into the event queue */
5952       if (!emacs_event)
5953         return;
5954       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5955       emacs_event->code = 0xFF08;
5956       EV_TRAILER ((id)nil);
5957     }
5960 - (NSArray *)validAttributesForMarkedText
5962   static NSArray *arr = nil;
5963   if (arr == nil) arr = [NSArray new];
5964  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5965   return arr;
5968 - (NSRange)selectedRange
5970   if (NS_KEYLOG)
5971     NSLog (@"selectedRange request");
5972   return NSMakeRange (NSNotFound, 0);
5975 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5976     GNUSTEP_GUI_MINOR_VERSION > 22
5977 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5978 #else
5979 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5980 #endif
5982   if (NS_KEYLOG)
5983     NSLog (@"characterIndexForPoint request");
5984   return 0;
5987 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5989   static NSAttributedString *str = nil;
5990   if (str == nil) str = [NSAttributedString new];
5991   if (NS_KEYLOG)
5992     NSLog (@"attributedSubstringFromRange request");
5993   return str;
5996 /* End <NSTextInput> impl. */
5997 /*****************************************************************************/
6000 /* This is what happens when the user presses a mouse button.  */
6001 - (void)mouseDown: (NSEvent *)theEvent
6003   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6004   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6006   NSTRACE ("mouseDown");
6008   [self deleteWorkingText];
6010   if (!emacs_event)
6011     return;
6013   dpyinfo->last_mouse_frame = emacsframe;
6014   /* appears to be needed to prevent spurious movement events generated on
6015      button clicks */
6016   emacsframe->mouse_moved = 0;
6018   if ([theEvent type] == NSScrollWheel)
6019     {
6020       CGFloat delta = [theEvent deltaY];
6021       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6022       if (delta == 0)
6023         {
6024           delta = [theEvent deltaX];
6025           if (delta == 0)
6026             {
6027               NSTRACE ("deltaIsZero");
6028               return;
6029             }
6030           emacs_event->kind = HORIZ_WHEEL_EVENT;
6031         }
6032       else
6033         emacs_event->kind = WHEEL_EVENT;
6035       emacs_event->code = 0;
6036       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6037         ((delta > 0) ? up_modifier : down_modifier);
6038     }
6039   else
6040     {
6041       emacs_event->kind = MOUSE_CLICK_EVENT;
6042       emacs_event->code = EV_BUTTON (theEvent);
6043       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6044                              | EV_UDMODIFIERS (theEvent);
6045     }
6046   XSETINT (emacs_event->x, lrint (p.x));
6047   XSETINT (emacs_event->y, lrint (p.y));
6048   EV_TRAILER (theEvent);
6052 - (void)rightMouseDown: (NSEvent *)theEvent
6054   NSTRACE ("rightMouseDown");
6055   [self mouseDown: theEvent];
6059 - (void)otherMouseDown: (NSEvent *)theEvent
6061   NSTRACE ("otherMouseDown");
6062   [self mouseDown: theEvent];
6066 - (void)mouseUp: (NSEvent *)theEvent
6068   NSTRACE ("mouseUp");
6069   [self mouseDown: theEvent];
6073 - (void)rightMouseUp: (NSEvent *)theEvent
6075   NSTRACE ("rightMouseUp");
6076   [self mouseDown: theEvent];
6080 - (void)otherMouseUp: (NSEvent *)theEvent
6082   NSTRACE ("otherMouseUp");
6083   [self mouseDown: theEvent];
6087 - (void) scrollWheel: (NSEvent *)theEvent
6089   NSTRACE ("scrollWheel");
6090   [self mouseDown: theEvent];
6094 /* Tell emacs the mouse has moved. */
6095 - (void)mouseMoved: (NSEvent *)e
6097   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6098   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6099   Lisp_Object frame;
6100   NSPoint pt;
6102 //  NSTRACE ("mouseMoved");
6104   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6105   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6106   dpyinfo->last_mouse_motion_x = pt.x;
6107   dpyinfo->last_mouse_motion_y = pt.y;
6109   /* update any mouse face */
6110   if (hlinfo->mouse_face_hidden)
6111     {
6112       hlinfo->mouse_face_hidden = 0;
6113       clear_mouse_face (hlinfo);
6114     }
6116   /* tooltip handling */
6117   previous_help_echo_string = help_echo_string;
6118   help_echo_string = Qnil;
6120   if (!NILP (Vmouse_autoselect_window))
6121     {
6122       NSTRACE ("mouse_autoselect_window");
6123       static Lisp_Object last_mouse_window;
6124       Lisp_Object window
6125         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6127       if (WINDOWP (window)
6128           && !EQ (window, last_mouse_window)
6129           && !EQ (window, selected_window)
6130           && (focus_follows_mouse
6131               || (EQ (XWINDOW (window)->frame,
6132                       XWINDOW (selected_window)->frame))))
6133         {
6134           NSTRACE ("in_window");
6135           emacs_event->kind = SELECT_WINDOW_EVENT;
6136           emacs_event->frame_or_window = window;
6137           EV_TRAILER2 (e);
6138         }
6139       /* Remember the last window where we saw the mouse.  */
6140       last_mouse_window = window;
6141     }
6143   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6144     help_echo_string = previous_help_echo_string;
6146   XSETFRAME (frame, emacsframe);
6147   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6148     {
6149       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6150          (note_mouse_highlight), which is called through the
6151          note_mouse_movement () call above */
6152       any_help_event_p = YES;
6153       gen_help_event (help_echo_string, frame, help_echo_window,
6154                       help_echo_object, help_echo_pos);
6155     }
6157   if (emacsframe->mouse_moved && send_appdefined)
6158     ns_send_appdefined (-1);
6162 - (void)mouseDragged: (NSEvent *)e
6164   NSTRACE ("mouseDragged");
6165   [self mouseMoved: e];
6169 - (void)rightMouseDragged: (NSEvent *)e
6171   NSTRACE ("rightMouseDragged");
6172   [self mouseMoved: e];
6176 - (void)otherMouseDragged: (NSEvent *)e
6178   NSTRACE ("otherMouseDragged");
6179   [self mouseMoved: e];
6183 - (BOOL)windowShouldClose: (id)sender
6185   NSEvent *e =[[self window] currentEvent];
6187   NSTRACE ("windowShouldClose");
6188   windowClosing = YES;
6189   if (!emacs_event)
6190     return NO;
6191   emacs_event->kind = DELETE_WINDOW_EVENT;
6192   emacs_event->modifiers = 0;
6193   emacs_event->code = 0;
6194   EV_TRAILER (e);
6195   /* Don't close this window, let this be done from lisp code.  */
6196   return NO;
6199 - (void) updateFrameSize: (BOOL) delay;
6201   NSWindow *window = [self window];
6202   NSRect wr = [window frame];
6203   int extra = 0;
6204   int oldc = cols, oldr = rows;
6205   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6206   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6207   int neww, newh;
6209   NSTRACE ("updateFrameSize");
6210   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6211   NSTRACE_RECT ("Original frame", wr);
6212   NSTRACE_MSG  ("Original columns: %d", cols);
6213   NSTRACE_MSG  ("Original rows: %d", rows);
6215   if (! [self isFullscreen])
6216     {
6217 #ifdef NS_IMPL_GNUSTEP
6218       // GNUstep does not always update the tool bar height.  Force it.
6219       if (toolbar && [toolbar isVisible])
6220           update_frame_tool_bar (emacsframe);
6221 #endif
6223       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6224         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6225     }
6227   if (wait_for_tool_bar)
6228     {
6229       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6230         {
6231           NSTRACE_MSG ("Waiting for toolbar");
6232           return;
6233         }
6234       wait_for_tool_bar = NO;
6235     }
6237   neww = (int)wr.size.width - emacsframe->border_width;
6238   newh = (int)wr.size.height - extra;
6240   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6241   NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height);
6243   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6244   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6246   if (cols < MINWIDTH)
6247     cols = MINWIDTH;
6249   if (rows < MINHEIGHT)
6250     rows = MINHEIGHT;
6252   NSTRACE_MSG  ("New columns: %d", cols);
6253   NSTRACE_MSG  ("New rows: %d", rows);
6255   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6256     {
6257       NSView *view = FRAME_NS_VIEW (emacsframe);
6258       NSWindow *win = [view window];
6260       change_frame_size (emacsframe,
6261                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6262                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6263                          0, delay, 0, 1);
6264       SET_FRAME_GARBAGED (emacsframe);
6265       cancel_mouse_face (emacsframe);
6267       wr = NSMakeRect (0, 0, neww, newh);
6268       NSTRACE_RECT ("setFrame", wr);
6269       [view setFrame: wr];
6270       // to do: consider using [NSNotificationCenter postNotificationName:].
6271       [self windowDidMove: // Update top/left.
6272               [NSNotification notificationWithName:NSWindowDidMoveNotification
6273                                             object:[view window]]];
6274     }
6275   else
6276     {
6277       NSTRACE_MSG ("No change");
6278     }
6281 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6282 /* normalize frame to gridded text size */
6284   int extra = 0;
6286   NSTRACE ("windowWillResize: toSize: " NSTRACE_FMT_SIZE,
6287            NSTRACE_ARG_SIZE (frameSize));
6288   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6289   NSTRACE_FSTYPE ("fs_state", fs_state);
6291   if (fs_state == FULLSCREEN_MAXIMIZED
6292       && (maximized_width != (int)frameSize.width
6293           || maximized_height != (int)frameSize.height))
6294     [self setFSValue: FULLSCREEN_NONE];
6295   else if (fs_state == FULLSCREEN_WIDTH
6296            && maximized_width != (int)frameSize.width)
6297     [self setFSValue: FULLSCREEN_NONE];
6298   else if (fs_state == FULLSCREEN_HEIGHT
6299            && maximized_height != (int)frameSize.height)
6300     [self setFSValue: FULLSCREEN_NONE];
6302   if (fs_state == FULLSCREEN_NONE)
6303     maximized_width = maximized_height = -1;
6305   if (! [self isFullscreen])
6306     {
6307       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6308         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6309     }
6311   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6312   if (cols < MINWIDTH)
6313     cols = MINWIDTH;
6315   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6316                                            frameSize.height - extra);
6317   if (rows < MINHEIGHT)
6318     rows = MINHEIGHT;
6319 #ifdef NS_IMPL_COCOA
6320   {
6321     /* this sets window title to have size in it; the wm does this under GS */
6322     NSRect r = [[self window] frame];
6323     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6324       {
6325         if (old_title != 0)
6326           {
6327             xfree (old_title);
6328             old_title = 0;
6329           }
6330       }
6331     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6332       {
6333         char *size_title;
6334         NSWindow *window = [self window];
6335         if (old_title == 0)
6336           {
6337             char *t = strdup ([[[self window] title] UTF8String]);
6338             char *pos = strstr (t, "  â€”  ");
6339             if (pos)
6340               *pos = '\0';
6341             old_title = t;
6342           }
6343         size_title = xmalloc (strlen (old_title) + 40);
6344         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6345         [window setTitle: [NSString stringWithUTF8String: size_title]];
6346         [window display];
6347         xfree (size_title);
6348       }
6349   }
6350 #endif /* NS_IMPL_COCOA */
6352   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6354   /* Restrict the new size to the text gird.
6356      Don't restrict the width if the user only adjusted the height, and
6357      vice versa.  (Without this, the frame would shrink, and move
6358      slightly, if the window was resized by dragging one of its
6359      borders.) */
6360   if (!frame_resize_pixelwise)
6361     {
6362       NSRect r = [[self window] frame];
6364       if (r.size.width != frameSize.width)
6365         {
6366           frameSize.width =
6367             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6368         }
6370       if (r.size.height != frameSize.height)
6371         {
6372           frameSize.height =
6373             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6374         }
6375     }
6377   NSTRACE_RETURN_SIZE (frameSize);
6379   return frameSize;
6383 - (void)windowDidResize: (NSNotification *)notification
6385   NSTRACE ("windowDidResize");
6386   if (!FRAME_LIVE_P (emacsframe))
6387     {
6388       NSTRACE_MSG ("Ignored (frame dead)");
6389       return;
6390     }
6391   if (emacsframe->output_data.ns->in_animation)
6392     {
6393       NSTRACE_MSG ("Ignored (in animation)");
6394       return;
6395     }
6397   if (! [self fsIsNative])
6398     {
6399       NSWindow *theWindow = [notification object];
6400       /* We can get notification on the non-FS window when in
6401          fullscreen mode.  */
6402       if ([self window] != theWindow) return;
6403     }
6405   NSTRACE_RECT ("frame", [[notification object] frame]);
6407 #ifdef NS_IMPL_GNUSTEP
6408   NSWindow *theWindow = [notification object];
6410    /* In GNUstep, at least currently, it's possible to get a didResize
6411       without getting a willResize.. therefore we need to act as if we got
6412       the willResize now */
6413   NSSize sz = [theWindow frame].size;
6414   sz = [self windowWillResize: theWindow toSize: sz];
6415 #endif /* NS_IMPL_GNUSTEP */
6417   if (cols > 0 && rows > 0)
6418     {
6419       [self updateFrameSize: YES];
6420     }
6422   ns_send_appdefined (-1);
6425 #ifdef NS_IMPL_COCOA
6426 - (void)viewDidEndLiveResize
6428   [super viewDidEndLiveResize];
6429   if (old_title != 0)
6430     {
6431       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6432       xfree (old_title);
6433       old_title = 0;
6434     }
6435   maximizing_resize = NO;
6437 #endif /* NS_IMPL_COCOA */
6440 - (void)windowDidBecomeKey: (NSNotification *)notification
6441 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6443   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6444   struct frame *old_focus = dpyinfo->x_focus_frame;
6446   NSTRACE ("windowDidBecomeKey");
6448   if (emacsframe != old_focus)
6449     dpyinfo->x_focus_frame = emacsframe;
6451   ns_frame_rehighlight (emacsframe);
6453   if (emacs_event)
6454     {
6455       emacs_event->kind = FOCUS_IN_EVENT;
6456       EV_TRAILER ((id)nil);
6457     }
6461 - (void)windowDidResignKey: (NSNotification *)notification
6462 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6464   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6465   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6466   NSTRACE ("windowDidResignKey");
6468   if (is_focus_frame)
6469     dpyinfo->x_focus_frame = 0;
6471   emacsframe->mouse_moved = 0;
6472   ns_frame_rehighlight (emacsframe);
6474   /* FIXME: for some reason needed on second and subsequent clicks away
6475             from sole-frame Emacs to get hollow box to show */
6476   if (!windowClosing && [[self window] isVisible] == YES)
6477     {
6478       x_update_cursor (emacsframe, 1);
6479       x_set_frame_alpha (emacsframe);
6480     }
6482   if (any_help_event_p)
6483     {
6484       Lisp_Object frame;
6485       XSETFRAME (frame, emacsframe);
6486       help_echo_string = Qnil;
6487       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6488     }
6490   if (emacs_event && is_focus_frame)
6491     {
6492       [self deleteWorkingText];
6493       emacs_event->kind = FOCUS_OUT_EVENT;
6494       EV_TRAILER ((id)nil);
6495     }
6499 - (void)windowWillMiniaturize: sender
6501   NSTRACE ("windowWillMiniaturize");
6505 - (BOOL)isFlipped
6507   return YES;
6511 - (BOOL)isOpaque
6513   return NO;
6517 - initFrameFromEmacs: (struct frame *)f
6519   NSRect r, wr;
6520   Lisp_Object tem;
6521   NSWindow *win;
6522   NSColor *col;
6523   NSString *name;
6525   NSTRACE ("initFrameFromEmacs");
6527   windowClosing = NO;
6528   processingCompose = NO;
6529   scrollbarsNeedingUpdate = 0;
6530   fs_state = FULLSCREEN_NONE;
6531   fs_before_fs = next_maximized = -1;
6532 #ifdef HAVE_NATIVE_FS
6533   fs_is_native = ns_use_native_fullscreen;
6534 #else
6535   fs_is_native = NO;
6536 #endif
6537   maximized_width = maximized_height = -1;
6538   nonfs_window = nil;
6540 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
6542   ns_userRect = NSMakeRect (0, 0, 0, 0);
6543   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6544                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6545   [self initWithFrame: r];
6546   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6548   FRAME_NS_VIEW (f) = self;
6549   emacsframe = f;
6550 #ifdef NS_IMPL_COCOA
6551   old_title = 0;
6552   maximizing_resize = NO;
6553 #endif
6555   win = [[EmacsWindow alloc]
6556             initWithContentRect: r
6557                       styleMask: (NSResizableWindowMask |
6558 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6559                                   NSTitledWindowMask |
6560 #endif
6561                                   NSMiniaturizableWindowMask |
6562                                   NSClosableWindowMask)
6563                         backing: NSBackingStoreBuffered
6564                           defer: YES];
6566 #ifdef HAVE_NATIVE_FS
6567     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6568 #endif
6570   wr = [win frame];
6571   bwidth = f->border_width = wr.size.width - r.size.width;
6572   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6574   [win setAcceptsMouseMovedEvents: YES];
6575   [win setDelegate: self];
6576 #if !defined (NS_IMPL_COCOA) || \
6577   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6578   [win useOptimizedDrawing: YES];
6579 #endif
6581   [[win contentView] addSubview: self];
6583   if (ns_drag_types)
6584     [self registerForDraggedTypes: ns_drag_types];
6586   tem = f->name;
6587   name = [NSString stringWithUTF8String:
6588                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6589   [win setTitle: name];
6591   /* toolbar support */
6592   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6593                          [NSString stringWithFormat: @"Emacs Frame %d",
6594                                    ns_window_num]];
6595   [win setToolbar: toolbar];
6596   [toolbar setVisible: NO];
6598   /* Don't set frame garbaged until tool bar is up to date?
6599      This avoids an extra clear and redraw (flicker) at frame creation.  */
6600   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6601   else wait_for_tool_bar = NO;
6604 #ifdef NS_IMPL_COCOA
6605   {
6606     NSButton *toggleButton;
6607   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6608   [toggleButton setTarget: self];
6609   [toggleButton setAction: @selector (toggleToolbar: )];
6610   }
6611 #endif
6612   FRAME_TOOLBAR_HEIGHT (f) = 0;
6614   tem = f->icon_name;
6615   if (!NILP (tem))
6616     [win setMiniwindowTitle:
6617            [NSString stringWithUTF8String: SSDATA (tem)]];
6619   {
6620     NSScreen *screen = [win screen];
6622     if (screen != 0)
6623       {
6624         NSPoint pt = NSMakePoint
6625           (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6626            IN_BOUND (-SCREENMAX,
6627                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
6629         NSTRACE_POINT ("setFrameTopLeftPoint", pt);
6631         [win setFrameTopLeftPoint: pt];
6633         NSTRACE_RECT ("new frame", [win frame]);
6634       }
6635   }
6637   [win makeFirstResponder: self];
6639   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6640                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6641   [win setBackgroundColor: col];
6642   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6643     [win setOpaque: NO];
6645 #if !defined (NS_IMPL_COCOA) || \
6646   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6647   [self allocateGState];
6648 #endif
6649   [NSApp registerServicesMenuSendTypes: ns_send_types
6650                            returnTypes: nil];
6652   ns_window_num++;
6653   return self;
6657 - (void)windowDidMove: sender
6659   NSWindow *win = [self window];
6660   NSRect r = [win frame];
6661   NSArray *screens = [NSScreen screens];
6662   NSScreen *screen = [screens objectAtIndex: 0];
6664   NSTRACE ("windowDidMove");
6666   if (!emacsframe->output_data.ns)
6667     return;
6668   if (screen != nil)
6669     {
6670       emacsframe->left_pos = r.origin.x;
6671       emacsframe->top_pos =
6672         [screen frame].size.height - (r.origin.y + r.size.height);
6673     }
6677 /* Called AFTER method below, but before our windowWillResize call there leads
6678    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6679    location so set_window_size moves the frame. */
6680 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6682   NSTRACE (("[windowShouldZoom:win toFrame:" NSTRACE_FMT_RECT "]"
6683             NSTRACE_FMT_RETURN "YES"),
6684            NSTRACE_ARG_RECT (newFrame));
6686   emacsframe->output_data.ns->zooming = 1;
6687   return YES;
6691 /* Override to do something slightly nonstandard, but nice.  First click on
6692    zoom button will zoom vertically.  Second will zoom completely.  Third
6693    returns to original. */
6694 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6695                         defaultFrame:(NSRect)defaultFrame
6697   // TODO: Rename to "currentFrame" and assign "result" properly in
6698   // all paths.
6699   NSRect result = [sender frame];
6701   NSTRACE (("[windowWillUseStandardFrame: defaultFrame:"
6702             NSTRACE_FMT_RECT "]"),
6703            NSTRACE_ARG_RECT (defaultFrame));
6704   NSTRACE_FSTYPE ("fs_state", fs_state);
6705   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
6706   NSTRACE_FSTYPE ("next_maximized", next_maximized);
6707   NSTRACE_RECT   ("ns_userRect", ns_userRect);
6708   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6710   if (fs_before_fs != -1) /* Entering fullscreen */
6711     {
6712       NSTRACE_MSG ("Entering fullscreen");
6713       result = defaultFrame;
6714     }
6715   else
6716     {
6717       // Save the window size and position (frame) before the resize.
6718       if (fs_state != FULLSCREEN_MAXIMIZED
6719           && fs_state != FULLSCREEN_WIDTH)
6720         {
6721           ns_userRect.size.width = result.size.width;
6722           ns_userRect.origin.x   = result.origin.x;
6723         }
6725       if (fs_state != FULLSCREEN_MAXIMIZED
6726           && fs_state != FULLSCREEN_HEIGHT)
6727         {
6728           ns_userRect.size.height = result.size.height;
6729           ns_userRect.origin.y    = result.origin.y;
6730         }
6732       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
6734       if (next_maximized == FULLSCREEN_HEIGHT
6735           || (next_maximized == -1
6736               && abs ((int)(defaultFrame.size.height - result.size.height))
6737               > FRAME_LINE_HEIGHT (emacsframe)))
6738         {
6739           /* first click */
6740           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
6741           maximized_height = result.size.height = defaultFrame.size.height;
6742           maximized_width = -1;
6743           result.origin.y = defaultFrame.origin.y;
6744           if (ns_userRect.size.height != 0)
6745             {
6746               result.origin.x = ns_userRect.origin.x;
6747               result.size.width = ns_userRect.size.width;
6748             }
6749           [self setFSValue: FULLSCREEN_HEIGHT];
6750 #ifdef NS_IMPL_COCOA
6751           maximizing_resize = YES;
6752 #endif
6753         }
6754       else if (next_maximized == FULLSCREEN_WIDTH)
6755         {
6756           NSTRACE_MSG ("FULLSCREEN_WIDTH");
6757           maximized_width = result.size.width = defaultFrame.size.width;
6758           maximized_height = -1;
6759           result.origin.x = defaultFrame.origin.x;
6760           if (ns_userRect.size.width != 0)
6761             {
6762               result.origin.y = ns_userRect.origin.y;
6763               result.size.height = ns_userRect.size.height;
6764             }
6765           [self setFSValue: FULLSCREEN_WIDTH];
6766         }
6767       else if (next_maximized == FULLSCREEN_MAXIMIZED
6768                || (next_maximized == -1
6769                    && abs ((int)(defaultFrame.size.width - result.size.width))
6770                    > FRAME_COLUMN_WIDTH (emacsframe)))
6771         {
6772           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
6774           result = defaultFrame;  /* second click */
6775           maximized_width = result.size.width;
6776           maximized_height = result.size.height;
6777           [self setFSValue: FULLSCREEN_MAXIMIZED];
6778 #ifdef NS_IMPL_COCOA
6779           maximizing_resize = YES;
6780 #endif
6781         }
6782       else
6783         {
6784           /* restore */
6785           NSTRACE_MSG ("Restore");
6786           result = ns_userRect.size.height ? ns_userRect : result;
6787           NSTRACE_RECT ("restore (2)", result);
6788           ns_userRect = NSMakeRect (0, 0, 0, 0);
6789 #ifdef NS_IMPL_COCOA
6790           maximizing_resize = fs_state != FULLSCREEN_NONE;
6791 #endif
6792           [self setFSValue: FULLSCREEN_NONE];
6793           maximized_width = maximized_height = -1;
6794         }
6795     }
6797   if (fs_before_fs == -1) next_maximized = -1;
6799   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
6800   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
6801   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
6802   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
6804   [self windowWillResize: sender toSize: result.size];
6806   NSTRACE_RETURN_RECT (result);
6808   return result;
6812 - (void)windowDidDeminiaturize: sender
6814   NSTRACE ("windowDidDeminiaturize");
6815   if (!emacsframe->output_data.ns)
6816     return;
6818   SET_FRAME_ICONIFIED (emacsframe, 0);
6819   SET_FRAME_VISIBLE (emacsframe, 1);
6820   windows_or_buffers_changed = 63;
6822   if (emacs_event)
6823     {
6824       emacs_event->kind = DEICONIFY_EVENT;
6825       EV_TRAILER ((id)nil);
6826     }
6830 - (void)windowDidExpose: sender
6832   NSTRACE ("windowDidExpose");
6833   if (!emacsframe->output_data.ns)
6834     return;
6836   SET_FRAME_VISIBLE (emacsframe, 1);
6837   SET_FRAME_GARBAGED (emacsframe);
6839   if (send_appdefined)
6840     ns_send_appdefined (-1);
6844 - (void)windowDidMiniaturize: sender
6846   NSTRACE ("windowDidMiniaturize");
6847   if (!emacsframe->output_data.ns)
6848     return;
6850   SET_FRAME_ICONIFIED (emacsframe, 1);
6851   SET_FRAME_VISIBLE (emacsframe, 0);
6853   if (emacs_event)
6854     {
6855       emacs_event->kind = ICONIFY_EVENT;
6856       EV_TRAILER ((id)nil);
6857     }
6860 #ifdef HAVE_NATIVE_FS
6861 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6862       willUseFullScreenPresentationOptions:
6863   (NSApplicationPresentationOptions)proposedOptions
6865   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6867 #endif
6869 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
6870 #define NSWindowDidEnterFullScreenNotification "NSWindowDidEnterFullScreenNotification"
6871 #endif
6873 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6875   [self windowWillEnterFullScreen];
6877 - (void)windowWillEnterFullScreen /* provided for direct calls */
6879   NSTRACE ("windowWillEnterFullScreen");
6880   fs_before_fs = fs_state;
6883 - (void)windowDidEnterFullScreen /* provided for direct calls */
6885   [self windowDidEnterFullScreen:
6886               [NSNotification notificationWithName:NSWindowDidEnterFullScreenNotification
6887                                             object:[self window]]];
6889 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6891   NSTRACE ("windowDidEnterFullScreen");
6892   [self setFSValue: FULLSCREEN_BOTH];
6893   if (! [self fsIsNative])
6894     {
6895       [self windowDidBecomeKey:notification];
6896       [nonfs_window orderOut:self];
6897     }
6898   else
6899     {
6900       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6901 #ifdef NS_IMPL_COCOA
6902 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6903       unsigned val = (unsigned)[NSApp presentationOptions];
6905       // OSX 10.7 bug fix, the menu won't appear without this.
6906       // val is non-zero on other OSX versions.
6907       if (val == 0)
6908         {
6909           NSApplicationPresentationOptions options
6910             = NSApplicationPresentationAutoHideDock
6911             | NSApplicationPresentationAutoHideMenuBar
6912             | NSApplicationPresentationFullScreen
6913             | NSApplicationPresentationAutoHideToolbar;
6915           [NSApp setPresentationOptions: options];
6916         }
6917 #endif
6918 #endif
6919       [toolbar setVisible:tbar_visible];
6920     }
6923 - (void)windowWillExitFullScreen:(NSNotification *)notification
6925   [self windowWillExitFullScreen];
6928 - (void)windowWillExitFullScreen /* provided for direct calls */
6930   NSTRACE ("windowWillExitFullScreen");
6931   if (!FRAME_LIVE_P (emacsframe))
6932     {
6933       NSTRACE_MSG ("Ignored (frame dead)");
6934       return;
6935     }
6936   if (next_maximized != -1)
6937     fs_before_fs = next_maximized;
6940 - (void)windowDidExitFullScreen:(NSNotification *)notification
6942   [self windowDidExitFullScreen];
6945 - (void)windowDidExitFullScreen /* provided for direct calls */
6947   NSTRACE ("windowDidExitFullScreen");
6948   if (!FRAME_LIVE_P (emacsframe))
6949     {
6950       NSTRACE_MSG ("Ignored (frame dead)");
6951       return;
6952     }
6953   [self setFSValue: fs_before_fs];
6954   fs_before_fs = -1;
6955 #ifdef HAVE_NATIVE_FS
6956   [self updateCollectionBehavior];
6957 #endif
6958   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6959     {
6960       [toolbar setVisible:YES];
6961       update_frame_tool_bar (emacsframe);
6962       [self updateFrameSize:YES];
6963       [[self window] display];
6964     }
6965   else
6966     [toolbar setVisible:NO];
6968   if (next_maximized != -1)
6969     [[self window] performZoom:self];
6972 - (BOOL)fsIsNative
6974   return fs_is_native;
6977 - (BOOL)isFullscreen
6979   if (! fs_is_native) return nonfs_window != nil;
6980 #ifdef HAVE_NATIVE_FS
6981   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6982 #else
6983   return NO;
6984 #endif
6987 #ifdef HAVE_NATIVE_FS
6988 - (void)updateCollectionBehavior
6990   if (! [self isFullscreen])
6991     {
6992       NSWindow *win = [self window];
6993       NSWindowCollectionBehavior b = [win collectionBehavior];
6994       if (ns_use_native_fullscreen)
6995         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6996       else
6997         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6999       [win setCollectionBehavior: b];
7000       fs_is_native = ns_use_native_fullscreen;
7001     }
7003 #endif
7005 - (void)toggleFullScreen: (id)sender
7007   NSWindow *w, *fw;
7008   BOOL onFirstScreen;
7009   struct frame *f;
7010   NSRect r, wr;
7011   NSColor *col;
7013   NSTRACE ("toggleFullScreen");
7015   if (fs_is_native)
7016     {
7017 #ifdef HAVE_NATIVE_FS
7018       [[self window] toggleFullScreen:sender];
7019 #endif
7020       return;
7021     }
7023   w = [self window];
7024   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7025   f = emacsframe;
7026   wr = [w frame];
7027   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7028                                  (FRAME_DEFAULT_FACE (f)),
7029                                  f);
7031   if (fs_state != FULLSCREEN_BOTH)
7032     {
7033       NSScreen *screen = [w screen];
7035 #if defined (NS_IMPL_COCOA) && \
7036   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7037       /* Hide ghost menu bar on secondary monitor? */
7038       if (! onFirstScreen)
7039         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7040 #endif
7041       /* Hide dock and menubar if we are on the primary screen.  */
7042       if (onFirstScreen)
7043         {
7044 #ifdef NS_IMPL_COCOA
7045           NSApplicationPresentationOptions options
7046             = NSApplicationPresentationAutoHideDock
7047             | NSApplicationPresentationAutoHideMenuBar;
7049           [NSApp setPresentationOptions: options];
7050 #else
7051           [NSMenu setMenuBarVisible:NO];
7052 #endif
7053         }
7055       fw = [[EmacsFSWindow alloc]
7056                        initWithContentRect:[w contentRectForFrameRect:wr]
7057                                  styleMask:NSBorderlessWindowMask
7058                                    backing:NSBackingStoreBuffered
7059                                      defer:YES
7060                                     screen:screen];
7062       [fw setContentView:[w contentView]];
7063       [fw setTitle:[w title]];
7064       [fw setDelegate:self];
7065       [fw setAcceptsMouseMovedEvents: YES];
7066 #if !defined (NS_IMPL_COCOA) || \
7067   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7068       [fw useOptimizedDrawing: YES];
7069 #endif
7070       [fw setBackgroundColor: col];
7071       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7072         [fw setOpaque: NO];
7074       f->border_width = 0;
7075       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
7076       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
7077       FRAME_TOOLBAR_HEIGHT (f) = 0;
7079       nonfs_window = w;
7081       [self windowWillEnterFullScreen];
7082       [fw makeKeyAndOrderFront:NSApp];
7083       [fw makeFirstResponder:self];
7084       [w orderOut:self];
7085       r = [fw frameRectForContentRect:[screen frame]];
7086       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7087       [self windowDidEnterFullScreen];
7088       [fw display];
7089     }
7090   else
7091     {
7092       fw = w;
7093       w = nonfs_window;
7094       nonfs_window = nil;
7096       if (onFirstScreen)
7097         {
7098 #ifdef NS_IMPL_COCOA
7099           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7100 #else
7101           [NSMenu setMenuBarVisible:YES];
7102 #endif
7103         }
7105       [w setContentView:[fw contentView]];
7106       [w setBackgroundColor: col];
7107       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7108         [w setOpaque: NO];
7110       f->border_width = bwidth;
7111       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
7112       if (FRAME_EXTERNAL_TOOL_BAR (f))
7113         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
7115       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7117       [self windowWillExitFullScreen];
7118       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7119       [fw close];
7120       [w makeKeyAndOrderFront:NSApp];
7121       [self windowDidExitFullScreen];
7122       [self updateFrameSize:YES];
7123     }
7126 - (void)handleFS
7128   NSTRACE ("handleFS");
7130   if (fs_state != emacsframe->want_fullscreen)
7131     {
7132       if (fs_state == FULLSCREEN_BOTH)
7133         {
7134           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7135           [self toggleFullScreen:self];
7136         }
7138       switch (emacsframe->want_fullscreen)
7139         {
7140         case FULLSCREEN_BOTH:
7141           NSTRACE_MSG ("FULLSCREEN_BOTH");
7142           [self toggleFullScreen:self];
7143           break;
7144         case FULLSCREEN_WIDTH:
7145           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7146           next_maximized = FULLSCREEN_WIDTH;
7147           if (fs_state != FULLSCREEN_BOTH)
7148             [[self window] performZoom:self];
7149           break;
7150         case FULLSCREEN_HEIGHT:
7151           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7152           next_maximized = FULLSCREEN_HEIGHT;
7153           if (fs_state != FULLSCREEN_BOTH)
7154             [[self window] performZoom:self];
7155           break;
7156         case FULLSCREEN_MAXIMIZED:
7157           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7158           next_maximized = FULLSCREEN_MAXIMIZED;
7159           if (fs_state != FULLSCREEN_BOTH)
7160             [[self window] performZoom:self];
7161           break;
7162         case FULLSCREEN_NONE:
7163           NSTRACE_MSG ("FULLSCREEN_NONE");
7164           if (fs_state != FULLSCREEN_BOTH)
7165             {
7166               next_maximized = FULLSCREEN_NONE;
7167               [[self window] performZoom:self];
7168             }
7169           break;
7170         }
7172       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7173     }
7177 - (void) setFSValue: (int)value
7179   NSTRACE ("setFSValue");
7180   NSTRACE_FSTYPE ("value", value);
7182   Lisp_Object lval = Qnil;
7183   switch (value)
7184     {
7185     case FULLSCREEN_BOTH:
7186       lval = Qfullboth;
7187       break;
7188     case FULLSCREEN_WIDTH:
7189       lval = Qfullwidth;
7190       break;
7191     case FULLSCREEN_HEIGHT:
7192       lval = Qfullheight;
7193       break;
7194     case FULLSCREEN_MAXIMIZED:
7195       lval = Qmaximized;
7196       break;
7197     }
7198   store_frame_param (emacsframe, Qfullscreen, lval);
7199   fs_state = value;
7202 - (void)mouseEntered: (NSEvent *)theEvent
7204   NSTRACE ("mouseEntered");
7205   if (emacsframe)
7206     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7207       = EV_TIMESTAMP (theEvent);
7211 - (void)mouseExited: (NSEvent *)theEvent
7213   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7215   NSTRACE ("mouseExited");
7217   if (!hlinfo)
7218     return;
7220   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7221     = EV_TIMESTAMP (theEvent);
7223   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7224     {
7225       clear_mouse_face (hlinfo);
7226       hlinfo->mouse_face_mouse_frame = 0;
7227     }
7231 - menuDown: sender
7233   NSTRACE ("menuDown");
7234   if (context_menu_value == -1)
7235     context_menu_value = [sender tag];
7236   else
7237     {
7238       NSInteger tag = [sender tag];
7239       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7240                                     emacsframe->menu_bar_vector,
7241                                     (void *)tag);
7242     }
7244   ns_send_appdefined (-1);
7245   return self;
7249 - (EmacsToolbar *)toolbar
7251   return toolbar;
7255 /* this gets called on toolbar button click */
7256 - toolbarClicked: (id)item
7258   NSEvent *theEvent;
7259   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7261   NSTRACE ("toolbarClicked");
7263   if (!emacs_event)
7264     return self;
7266   /* send first event (for some reason two needed) */
7267   theEvent = [[self window] currentEvent];
7268   emacs_event->kind = TOOL_BAR_EVENT;
7269   XSETFRAME (emacs_event->arg, emacsframe);
7270   EV_TRAILER (theEvent);
7272   emacs_event->kind = TOOL_BAR_EVENT;
7273 /*   XSETINT (emacs_event->code, 0); */
7274   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7275                            idx + TOOL_BAR_ITEM_KEY);
7276   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7277   EV_TRAILER (theEvent);
7278   return self;
7282 - toggleToolbar: (id)sender
7284   if (!emacs_event)
7285     return self;
7287   emacs_event->kind = NS_NONKEY_EVENT;
7288   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7289   EV_TRAILER ((id)nil);
7290   return self;
7294 - (void)drawRect: (NSRect)rect
7296   int x = NSMinX (rect), y = NSMinY (rect);
7297   int width = NSWidth (rect), height = NSHeight (rect);
7299   NSTRACE ("drawRect");
7300   NSTRACE_RECT ("input", rect);
7302   if (!emacsframe || !emacsframe->output_data.ns)
7303     return;
7305   ns_clear_frame_area (emacsframe, x, y, width, height);
7306   block_input ();
7307   expose_frame (emacsframe, x, y, width, height);
7308   unblock_input ();
7310   /*
7311     drawRect: may be called (at least in OS X 10.5) for invisible
7312     views as well for some reason.  Thus, do not infer visibility
7313     here.
7315     emacsframe->async_visible = 1;
7316     emacsframe->async_iconified = 0;
7317   */
7321 /* NSDraggingDestination protocol methods.  Actually this is not really a
7322    protocol, but a category of Object.  O well...  */
7324 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7326   NSTRACE ("draggingEntered");
7327   return NSDragOperationGeneric;
7331 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7333   return YES;
7337 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7339   id pb;
7340   int x, y;
7341   NSString *type;
7342   NSEvent *theEvent = [[self window] currentEvent];
7343   NSPoint position;
7344   NSDragOperation op = [sender draggingSourceOperationMask];
7345   int modifiers = 0;
7347   NSTRACE ("performDragOperation");
7349   if (!emacs_event)
7350     return NO;
7352   position = [self convertPoint: [sender draggingLocation] fromView: nil];
7353   x = lrint (position.x);  y = lrint (position.y);
7355   pb = [sender draggingPasteboard];
7356   type = [pb availableTypeFromArray: ns_drag_types];
7358   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7359       // URL drags contain all operations (0xf), don't allow all to be set.
7360       (op & 0xf) != 0xf)
7361     {
7362       if (op & NSDragOperationLink)
7363         modifiers |= NSControlKeyMask;
7364       if (op & NSDragOperationCopy)
7365         modifiers |= NSAlternateKeyMask;
7366       if (op & NSDragOperationGeneric)
7367         modifiers |= NSCommandKeyMask;
7368     }
7370   modifiers = EV_MODIFIERS2 (modifiers);
7371   if (type == 0)
7372     {
7373       return NO;
7374     }
7375   else if ([type isEqualToString: NSFilenamesPboardType])
7376     {
7377       NSArray *files;
7378       NSEnumerator *fenum;
7379       NSString *file;
7381       if (!(files = [pb propertyListForType: type]))
7382         return NO;
7384       fenum = [files objectEnumerator];
7385       while ( (file = [fenum nextObject]) )
7386         {
7387           emacs_event->kind = DRAG_N_DROP_EVENT;
7388           XSETINT (emacs_event->x, x);
7389           XSETINT (emacs_event->y, y);
7390           ns_input_file = append2 (ns_input_file,
7391                                    build_string ([file UTF8String]));
7392           emacs_event->modifiers = modifiers;
7393           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
7394           EV_TRAILER (theEvent);
7395         }
7396       return YES;
7397     }
7398   else if ([type isEqualToString: NSURLPboardType])
7399     {
7400       NSURL *url = [NSURL URLFromPasteboard: pb];
7401       if (url == nil) return NO;
7403       emacs_event->kind = DRAG_N_DROP_EVENT;
7404       XSETINT (emacs_event->x, x);
7405       XSETINT (emacs_event->y, y);
7406       emacs_event->modifiers = modifiers;
7407       emacs_event->arg =  list2 (Qurl,
7408                                  build_string ([[url absoluteString]
7409                                                  UTF8String]));
7410       EV_TRAILER (theEvent);
7412       if ([url isFileURL] != NO)
7413         {
7414           NSString *file = [url path];
7415           ns_input_file = append2 (ns_input_file,
7416                                    build_string ([file UTF8String]));
7417         }
7418       return YES;
7419     }
7420   else if ([type isEqualToString: NSStringPboardType]
7421            || [type isEqualToString: NSTabularTextPboardType])
7422     {
7423       NSString *data;
7425       if (! (data = [pb stringForType: type]))
7426         return NO;
7428       emacs_event->kind = DRAG_N_DROP_EVENT;
7429       XSETINT (emacs_event->x, x);
7430       XSETINT (emacs_event->y, y);
7431       emacs_event->modifiers = modifiers;
7432       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
7433       EV_TRAILER (theEvent);
7434       return YES;
7435     }
7436   else
7437     {
7438       fprintf (stderr, "Invalid data type in dragging pasteboard");
7439       return NO;
7440     }
7444 - (id) validRequestorForSendType: (NSString *)typeSent
7445                       returnType: (NSString *)typeReturned
7447   NSTRACE ("validRequestorForSendType");
7448   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7449       && typeReturned == nil)
7450     {
7451       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7452         return self;
7453     }
7455   return [super validRequestorForSendType: typeSent
7456                                returnType: typeReturned];
7460 /* The next two methods are part of NSServicesRequests informal protocol,
7461    supposedly called when a services menu item is chosen from this app.
7462    But this should not happen because we override the services menu with our
7463    own entries which call ns-perform-service.
7464    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7465    So let's at least stub them out until further investigation can be done. */
7467 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7469   /* we could call ns_string_from_pasteboard(pboard) here but then it should
7470      be written into the buffer in place of the existing selection..
7471      ordinary service calls go through functions defined in ns-win.el */
7472   return NO;
7475 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7477   NSArray *typesDeclared;
7478   Lisp_Object val;
7480   /* We only support NSStringPboardType */
7481   if ([types containsObject:NSStringPboardType] == NO) {
7482     return NO;
7483   }
7485   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7486   if (CONSP (val) && SYMBOLP (XCAR (val)))
7487     {
7488       val = XCDR (val);
7489       if (CONSP (val) && NILP (XCDR (val)))
7490         val = XCAR (val);
7491     }
7492   if (! STRINGP (val))
7493     return NO;
7495   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7496   [pb declareTypes:typesDeclared owner:nil];
7497   ns_string_to_pasteboard (pb, val);
7498   return YES;
7502 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7503    (gives a miniaturized version of the window); currently we use the latter for
7504    frames whose active buffer doesn't correspond to any file
7505    (e.g., '*scratch*') */
7506 - setMiniwindowImage: (BOOL) setMini
7508   id image = [[self window] miniwindowImage];
7509   NSTRACE ("setMiniwindowImage");
7511   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7512      about "AppleDockIconEnabled" notwithstanding, however the set message
7513      below has its effect nonetheless. */
7514   if (image != emacsframe->output_data.ns->miniimage)
7515     {
7516       if (image && [image isKindOfClass: [EmacsImage class]])
7517         [image release];
7518       [[self window] setMiniwindowImage:
7519                        setMini ? emacsframe->output_data.ns->miniimage : nil];
7520     }
7522   return self;
7526 - (void) setRows: (int) r andColumns: (int) c
7528   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7529   rows = r;
7530   cols = c;
7533 - (int) fullscreenState
7535   return fs_state;
7538 @end  /* EmacsView */
7542 /* ==========================================================================
7544     EmacsWindow implementation
7546    ========================================================================== */
7548 @implementation EmacsWindow
7550 #ifdef NS_IMPL_COCOA
7551 - (id)accessibilityAttributeValue:(NSString *)attribute
7553   Lisp_Object str = Qnil;
7554   struct frame *f = SELECTED_FRAME ();
7555   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7557   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7558     return NSAccessibilityTextFieldRole;
7560   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7561       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7562     {
7563       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7564     }
7565   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7566     {
7567       if (! NILP (BVAR (curbuf, mark_active)))
7568           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7570       if (NILP (str))
7571         {
7572           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7573           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7574           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7576           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7577             str = make_uninit_multibyte_string (range, byte_range);
7578           else
7579             str = make_uninit_string (range);
7580           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7581              Is this a problem?  */
7582           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7583         }
7584     }
7587   if (! NILP (str))
7588     {
7589       if (CONSP (str) && SYMBOLP (XCAR (str)))
7590         {
7591           str = XCDR (str);
7592           if (CONSP (str) && NILP (XCDR (str)))
7593             str = XCAR (str);
7594         }
7595       if (STRINGP (str))
7596         {
7597           const char *utfStr = SSDATA (str);
7598           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7599           return nsStr;
7600         }
7601     }
7603   return [super accessibilityAttributeValue:attribute];
7605 #endif /* NS_IMPL_COCOA */
7607 /* Constrain size and placement of a frame.
7609    By returning the original "frameRect", the frame is not
7610    constrained. This can lead to unwanted situations where, for
7611    example, the menu bar covers the frame.
7613    The default implementation (accessed using "super") constrains the
7614    frame to the visible area of SCREEN, minus the menu bar (if
7615    present) and the Dock.  Note that default implementation also calls
7616    windowWillResize, with the frame it thinks should have.  (This can
7617    make the frame exit maximized mode.)
7619    Note that this should work in situations where multiple monitors
7620    are present.  Common configurations are side-by-side monitors and a
7621    monitor on top of another (e.g. when a laptop is placed under a
7622    large screen). */
7623 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7625   NSTRACE ("constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:",
7626              NSTRACE_ARG_RECT (frameRect));
7628 #ifdef NS_IMPL_COCOA
7629 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7630   // If separate spaces is on, it is like each screen is independent.  There is
7631   // no spanning of frames across screens.
7632   if ([NSScreen screensHaveSeparateSpaces])
7633     {
7634       NSTRACE_MSG ("Screens have separate spaces");
7635       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
7636       NSTRACE_RETURN_RECT (frameRect);
7637       return frameRect;
7638     }
7639 #endif
7640 #endif
7642   return constrain_frame_rect(frameRect);
7646 - (void)performZoom:(id)sender
7648   NSTRACE ("performZoom");
7650   return [super performZoom:sender];
7653 - (void)zoom:(id)sender
7655   struct frame * f = SELECTED_FRAME ();
7657   NSTRACE ("zoom");
7659   ns_update_auto_hide_menu_bar();
7661   // Below are three zoom implementations.  In the final commit, the
7662   // idea is that the last should be included.
7664 #if 0
7665   // Native zoom done using the standard zoom animation.  Size of the
7666   // resulting frame reduced to accommodate the Dock and, if present,
7667   // the menu-bar.
7668   [super zoom:sender];
7670 #elsif 0
7671   // Native zoom done using the standard zoom animation, plus an
7672   // explicit resize to cover the full screen.
7673   [super zoom:sender];
7675   // After the native zoom, resize the resulting frame to fill the
7676   // entire screen, except the menu-bar.
7677   //
7678   // This works for all practical purposes.  (The only minor oddity is
7679   // when transiting from full-height frame to a maximized, the
7680   // animation reduces the height of the frame slightly (to the 4
7681   // pixels needed to accommodate the Doc) before it snaps back into
7682   // full height.  The user would need a very trained eye to spot
7683   // this.)
7684   NSScreen * screen = [self screen];
7685   if (screen != nil)
7686     {
7687       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
7689       NSTRACE_FSTYPE ("fullscreenState", fs_state);
7691       NSRect sr = [screen frame];
7692       NSRect wr = [self frame];
7693       NSTRACE_RECT ("Rect after zoom", wr);
7695       NSRect newWr = wr;
7697       if (fs_state == FULLSCREEN_MAXIMIZED
7698           || fs_state == FULLSCREEN_HEIGHT)
7699         {
7700           newWr.origin.x = 0;
7701           newWr.size.height = sr.size.height - ns_menu_bar_height(screen);
7702         }
7704       if (fs_state == FULLSCREEN_MAXIMIZED
7705           || fs_state == FULLSCREEN_WIDTH)
7706         {
7707           newWr.origin.y = 0;
7708           newWr.size.width = sr.size.width;
7709         }
7711       if (newWr.size.width     != wr.size.width
7712           || newWr.size.height != wr.size.height
7713           || newWr.origin.x    != wr.origin.x
7714           || newWr.origin.y    != wr.origin.y)
7715         {
7716           NSTRACE_RECT ("Corrected rect", newWr);
7717           [self setFrame: newWr display: NO];
7718         }
7719     }
7720 #else
7721   // Non-native zoom which is done instantaneously.  The resulting frame
7722   // covers the entire screen, except the menu-bar, if present.
7723   NSScreen * screen = [self screen];
7724   if (screen != nil)
7725     {
7726       NSRect sr = [screen frame];
7727       sr.size.height -= ns_menu_bar_height (screen);
7729       sr = [[self delegate] windowWillUseStandardFrame:self
7730                                           defaultFrame:sr];
7731       [self setFrame: sr display: NO];
7732     }
7733 #endif
7736 @end /* EmacsWindow */
7739 @implementation EmacsFSWindow
7741 - (BOOL)canBecomeKeyWindow
7743   return YES;
7746 - (BOOL)canBecomeMainWindow
7748   return YES;
7751 @end
7753 /* ==========================================================================
7755     EmacsScroller implementation
7757    ========================================================================== */
7760 @implementation EmacsScroller
7762 /* for repeat button push */
7763 #define SCROLL_BAR_FIRST_DELAY 0.5
7764 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7766 + (CGFloat) scrollerWidth
7768   /* TODO: if we want to allow variable widths, this is the place to do it,
7769            however neither GNUstep nor Cocoa support it very well */
7770   CGFloat r;
7771 #if !defined (NS_IMPL_COCOA) || \
7772   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
7773   r = [NSScroller scrollerWidth];
7774 #else
7775   r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
7776                                 scrollerStyle: NSScrollerStyleLegacy];
7777 #endif
7778   return r;
7782 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7784   NSTRACE ("EmacsScroller_initFrame");
7786   r.size.width = [EmacsScroller scrollerWidth];
7787   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7788   [self setContinuous: YES];
7789   [self setEnabled: YES];
7791   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7792      locked against the top and bottom edges, and right edge on OS X, where
7793      scrollers are on right. */
7794 #ifdef NS_IMPL_GNUSTEP
7795   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7796 #else
7797   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7798 #endif
7800   window = XWINDOW (nwin);
7801   condemned = NO;
7802   pixel_height = NSHeight (r);
7803   if (pixel_height == 0) pixel_height = 1;
7804   min_portion = 20 / pixel_height;
7806   frame = XFRAME (window->frame);
7807   if (FRAME_LIVE_P (frame))
7808     {
7809       int i;
7810       EmacsView *view = FRAME_NS_VIEW (frame);
7811       NSView *sview = [[view window] contentView];
7812       NSArray *subs = [sview subviews];
7814       /* disable optimization stopping redraw of other scrollbars */
7815       view->scrollbarsNeedingUpdate = 0;
7816       for (i =[subs count]-1; i >= 0; i--)
7817         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7818           view->scrollbarsNeedingUpdate++;
7819       [sview addSubview: self];
7820     }
7822 /*  [self setFrame: r]; */
7824   return self;
7828 - (void)setFrame: (NSRect)newRect
7830   NSTRACE ("EmacsScroller_setFrame");
7831 /*  block_input (); */
7832   pixel_height = NSHeight (newRect);
7833   if (pixel_height == 0) pixel_height = 1;
7834   min_portion = 20 / pixel_height;
7835   [super setFrame: newRect];
7836 /*  unblock_input (); */
7840 - (void)dealloc
7842   NSTRACE ("EmacsScroller_dealloc");
7843   if (window)
7844     wset_vertical_scroll_bar (window, Qnil);
7845   window = 0;
7846   [super dealloc];
7850 - condemn
7852   NSTRACE ("condemn");
7853   condemned =YES;
7854   return self;
7858 - reprieve
7860   NSTRACE ("reprieve");
7861   condemned =NO;
7862   return self;
7866 -(bool)judge
7868   NSTRACE ("judge");
7869   bool ret = condemned;
7870   if (condemned)
7871     {
7872       EmacsView *view;
7873       block_input ();
7874       /* ensure other scrollbar updates after deletion */
7875       view = (EmacsView *)FRAME_NS_VIEW (frame);
7876       if (view != nil)
7877         view->scrollbarsNeedingUpdate++;
7878       if (window)
7879         wset_vertical_scroll_bar (window, Qnil);
7880       window = 0;
7881       [self removeFromSuperview];
7882       [self release];
7883       unblock_input ();
7884     }
7885   return ret;
7889 - (void)resetCursorRects
7891   NSRect visible = [self visibleRect];
7892   NSTRACE ("resetCursorRects");
7894   if (!NSIsEmptyRect (visible))
7895     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
7896   [[NSCursor arrowCursor] setOnMouseEntered: YES];
7900 - (int) checkSamePosition: (int) position portion: (int) portion
7901                     whole: (int) whole
7903   return em_position ==position && em_portion ==portion && em_whole ==whole
7904     && portion != whole; /* needed for resize empty buf */
7908 - setPosition: (int)position portion: (int)portion whole: (int)whole
7910   NSTRACE ("setPosition");
7912   em_position = position;
7913   em_portion = portion;
7914   em_whole = whole;
7916   if (portion >= whole)
7917     {
7918 #ifdef NS_IMPL_COCOA
7919       [self setKnobProportion: 1.0];
7920       [self setDoubleValue: 1.0];
7921 #else
7922       [self setFloatValue: 0.0 knobProportion: 1.0];
7923 #endif
7924     }
7925   else
7926     {
7927       float pos;
7928       CGFloat por;
7929       portion = max ((float)whole*min_portion/pixel_height, portion);
7930       pos = (float)position / (whole - portion);
7931       por = (CGFloat)portion/whole;
7932 #ifdef NS_IMPL_COCOA
7933       [self setKnobProportion: por];
7934       [self setDoubleValue: pos];
7935 #else
7936       [self setFloatValue: pos knobProportion: por];
7937 #endif
7938     }
7940   return self;
7943 /* set up emacs_event */
7944 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
7946   Lisp_Object win;
7947   if (!emacs_event)
7948     return;
7950   emacs_event->part = last_hit_part;
7951   emacs_event->code = 0;
7952   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
7953   XSETWINDOW (win, window);
7954   emacs_event->frame_or_window = win;
7955   emacs_event->timestamp = EV_TIMESTAMP (e);
7956   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
7957   emacs_event->arg = Qnil;
7958   XSETINT (emacs_event->x, loc * pixel_height);
7959   XSETINT (emacs_event->y, pixel_height-20);
7961   if (q_event_ptr)
7962     {
7963       n_emacs_events_pending++;
7964       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
7965     }
7966   else
7967     hold_event (emacs_event);
7968   EVENT_INIT (*emacs_event);
7969   ns_send_appdefined (-1);
7973 /* called manually thru timer to implement repeated button action w/hold-down */
7974 - repeatScroll: (NSTimer *)scrollEntry
7976   NSEvent *e = [[self window] currentEvent];
7977   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7978   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7980   /* clear timer if need be */
7981   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7982     {
7983         [scroll_repeat_entry invalidate];
7984         [scroll_repeat_entry release];
7985         scroll_repeat_entry = nil;
7987         if (inKnob)
7988           return self;
7990         scroll_repeat_entry
7991           = [[NSTimer scheduledTimerWithTimeInterval:
7992                         SCROLL_BAR_CONTINUOUS_DELAY
7993                                             target: self
7994                                           selector: @selector (repeatScroll:)
7995                                           userInfo: 0
7996                                            repeats: YES]
7997               retain];
7998     }
8000   [self sendScrollEventAtLoc: 0 fromEvent: e];
8001   return self;
8005 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8006    mouseDragged events without going into a modal loop. */
8007 - (void)mouseDown: (NSEvent *)e
8009   NSRect sr, kr;
8010   /* hitPart is only updated AFTER event is passed on */
8011   NSScrollerPart part = [self testPart: [e locationInWindow]];
8012   CGFloat inc = 0.0, loc, kloc, pos;
8013   int edge = 0;
8015   NSTRACE ("EmacsScroller_mouseDown");
8017   switch (part)
8018     {
8019     case NSScrollerDecrementPage:
8020         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
8021     case NSScrollerIncrementPage:
8022         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
8023     case NSScrollerDecrementLine:
8024       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
8025     case NSScrollerIncrementLine:
8026       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
8027     case NSScrollerKnob:
8028       last_hit_part = scroll_bar_handle; break;
8029     case NSScrollerKnobSlot:  /* GNUstep-only */
8030       last_hit_part = scroll_bar_move_ratio; break;
8031     default:  /* NSScrollerNoPart? */
8032       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
8033                (long) part);
8034       return;
8035     }
8037   if (inc != 0.0)
8038     {
8039       pos = 0;      /* ignored */
8041       /* set a timer to repeat, as we can't let superclass do this modally */
8042       scroll_repeat_entry
8043         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8044                                             target: self
8045                                           selector: @selector (repeatScroll:)
8046                                           userInfo: 0
8047                                            repeats: YES]
8048             retain];
8049     }
8050   else
8051     {
8052       /* handle, or on GNUstep possibly slot */
8053       NSEvent *fake_event;
8055       /* compute float loc in slot and mouse offset on knob */
8056       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8057                       toView: nil];
8058       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8059       if (loc <= 0.0)
8060         {
8061           loc = 0.0;
8062           edge = -1;
8063         }
8064       else if (loc >= NSHeight (sr))
8065         {
8066           loc = NSHeight (sr);
8067           edge = 1;
8068         }
8070       if (edge)
8071         kloc = 0.5 * edge;
8072       else
8073         {
8074           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8075                           toView: nil];
8076           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8077         }
8078       last_mouse_offset = kloc;
8080       /* if knob, tell emacs a location offset by knob pos
8081          (to indicate top of handle) */
8082       if (part == NSScrollerKnob)
8083           pos = (loc - last_mouse_offset) / NSHeight (sr);
8084       else
8085         /* else this is a slot click on GNUstep: go straight there */
8086         pos = loc / NSHeight (sr);
8088       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8089       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
8090                                       location: [e locationInWindow]
8091                                  modifierFlags: [e modifierFlags]
8092                                      timestamp: [e timestamp]
8093                                   windowNumber: [e windowNumber]
8094                                        context: [e context]
8095                                    eventNumber: [e eventNumber]
8096                                     clickCount: [e clickCount]
8097                                       pressure: [e pressure]];
8098       [super mouseUp: fake_event];
8099     }
8101   if (part != NSScrollerKnob)
8102     [self sendScrollEventAtLoc: pos fromEvent: e];
8106 /* Called as we manually track scroller drags, rather than superclass. */
8107 - (void)mouseDragged: (NSEvent *)e
8109     NSRect sr;
8110     double loc, pos;
8112     NSTRACE ("EmacsScroller_mouseDragged");
8114       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8115                       toView: nil];
8116       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8118       if (loc <= 0.0)
8119         {
8120           loc = 0.0;
8121         }
8122       else if (loc >= NSHeight (sr) + last_mouse_offset)
8123         {
8124           loc = NSHeight (sr) + last_mouse_offset;
8125         }
8127       pos = (loc - last_mouse_offset) / NSHeight (sr);
8128       [self sendScrollEventAtLoc: pos fromEvent: e];
8132 - (void)mouseUp: (NSEvent *)e
8134   if (scroll_repeat_entry)
8135     {
8136       [scroll_repeat_entry invalidate];
8137       [scroll_repeat_entry release];
8138       scroll_repeat_entry = nil;
8139     }
8140   last_hit_part = scroll_bar_above_handle;
8144 /* treat scrollwheel events in the bar as though they were in the main window */
8145 - (void) scrollWheel: (NSEvent *)theEvent
8147   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8148   [view mouseDown: theEvent];
8151 @end  /* EmacsScroller */
8154 #ifdef NS_IMPL_GNUSTEP
8155 /* Dummy class to get rid of startup warnings.  */
8156 @implementation EmacsDocument
8158 @end
8159 #endif
8162 /* ==========================================================================
8164    Font-related functions; these used to be in nsfaces.m
8166    ========================================================================== */
8169 Lisp_Object
8170 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8172   struct font *font = XFONT_OBJECT (font_object);
8173   EmacsView *view = FRAME_NS_VIEW (f);
8174   int font_ascent, font_descent;
8176   if (fontset < 0)
8177     fontset = fontset_from_font (font_object);
8178   FRAME_FONTSET (f) = fontset;
8180   if (FRAME_FONT (f) == font)
8181     /* This font is already set in frame F.  There's nothing more to
8182        do.  */
8183     return font_object;
8185   FRAME_FONT (f) = font;
8187   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8188   FRAME_COLUMN_WIDTH (f) = font->average_width;
8189   get_font_ascent_descent (font, &font_ascent, &font_descent);
8190   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8192   /* Compute the scroll bar width in character columns.  */
8193   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8194     {
8195       int wid = FRAME_COLUMN_WIDTH (f);
8196       FRAME_CONFIG_SCROLL_BAR_COLS (f)
8197         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8198     }
8199   else
8200     {
8201       int wid = FRAME_COLUMN_WIDTH (f);
8202       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8203     }
8205   /* Compute the scroll bar height in character lines.  */
8206   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8207     {
8208       int height = FRAME_LINE_HEIGHT (f);
8209       FRAME_CONFIG_SCROLL_BAR_LINES (f)
8210         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8211     }
8212   else
8213     {
8214       int height = FRAME_LINE_HEIGHT (f);
8215       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8216     }
8218   /* Now make the frame display the given font.  */
8219   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8220     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8221                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8222                        false, Qfont);
8224   return font_object;
8228 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8229 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8230          in 1.43. */
8232 const char *
8233 ns_xlfd_to_fontname (const char *xlfd)
8234 /* --------------------------------------------------------------------------
8235     Convert an X font name (XLFD) to an NS font name.
8236     Only family is used.
8237     The string returned is temporarily allocated.
8238    -------------------------------------------------------------------------- */
8240   char *name = xmalloc (180);
8241   int i, len;
8242   const char *ret;
8244   if (!strncmp (xlfd, "--", 2))
8245     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8246   else
8247     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8249   /* stopgap for malformed XLFD input */
8250   if (strlen (name) == 0)
8251     strcpy (name, "Monaco");
8253   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8254      also uppercase after '-' or ' ' */
8255   name[0] = c_toupper (name[0]);
8256   for (len =strlen (name), i =0; i<len; i++)
8257     {
8258       if (name[i] == '$')
8259         {
8260           name[i] = '-';
8261           if (i+1<len)
8262             name[i+1] = c_toupper (name[i+1]);
8263         }
8264       else if (name[i] == '_')
8265         {
8266           name[i] = ' ';
8267           if (i+1<len)
8268             name[i+1] = c_toupper (name[i+1]);
8269         }
8270     }
8271 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
8272   ret = [[NSString stringWithUTF8String: name] UTF8String];
8273   xfree (name);
8274   return ret;
8278 void
8279 syms_of_nsterm (void)
8281   NSTRACE ("syms_of_nsterm");
8283   ns_antialias_threshold = 10.0;
8285   /* from 23+ we need to tell emacs what modifiers there are.. */
8286   DEFSYM (Qmodifier_value, "modifier-value");
8287   DEFSYM (Qalt, "alt");
8288   DEFSYM (Qhyper, "hyper");
8289   DEFSYM (Qmeta, "meta");
8290   DEFSYM (Qsuper, "super");
8291   DEFSYM (Qcontrol, "control");
8292   DEFSYM (QUTF8_STRING, "UTF8_STRING");
8294   DEFSYM (Qfile, "file");
8295   DEFSYM (Qurl, "url");
8297   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8298   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8299   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8300   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8301   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8303   DEFVAR_LISP ("ns-input-file", ns_input_file,
8304               "The file specified in the last NS event.");
8305   ns_input_file =Qnil;
8307   DEFVAR_LISP ("ns-working-text", ns_working_text,
8308               "String for visualizing working composition sequence.");
8309   ns_working_text =Qnil;
8311   DEFVAR_LISP ("ns-input-font", ns_input_font,
8312               "The font specified in the last NS event.");
8313   ns_input_font =Qnil;
8315   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8316               "The fontsize specified in the last NS event.");
8317   ns_input_fontsize =Qnil;
8319   DEFVAR_LISP ("ns-input-line", ns_input_line,
8320                "The line specified in the last NS event.");
8321   ns_input_line =Qnil;
8323   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8324                "The service name specified in the last NS event.");
8325   ns_input_spi_name =Qnil;
8327   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8328                "The service argument specified in the last NS event.");
8329   ns_input_spi_arg =Qnil;
8331   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8332                "This variable describes the behavior of the alternate or option key.\n\
8333 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8334 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8335 at all, allowing it to be used at a lower level for accented character entry.");
8336   ns_alternate_modifier = Qmeta;
8338   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8339                "This variable describes the behavior of the right alternate or option key.\n\
8340 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8341 Set to left means be the same key as `ns-alternate-modifier'.\n\
8342 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8343 at all, allowing it to be used at a lower level for accented character entry.");
8344   ns_right_alternate_modifier = Qleft;
8346   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8347                "This variable describes the behavior of the command key.\n\
8348 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8349   ns_command_modifier = Qsuper;
8351   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8352                "This variable describes the behavior of the right command key.\n\
8353 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8354 Set to left means be the same key as `ns-command-modifier'.\n\
8355 Set to none means that the command / option key is not interpreted by Emacs\n\
8356 at all, allowing it to be used at a lower level for accented character entry.");
8357   ns_right_command_modifier = Qleft;
8359   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8360                "This variable describes the behavior of the control key.\n\
8361 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8362   ns_control_modifier = Qcontrol;
8364   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8365                "This variable describes the behavior of the right control key.\n\
8366 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8367 Set to left means be the same key as `ns-control-modifier'.\n\
8368 Set to none means that the control / option key is not interpreted by Emacs\n\
8369 at all, allowing it to be used at a lower level for accented character entry.");
8370   ns_right_control_modifier = Qleft;
8372   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8373                "This variable describes the behavior of the function key (on laptops).\n\
8374 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8375 Set to none means that the function key is not interpreted by Emacs at all,\n\
8376 allowing it to be used at a lower level for accented character entry.");
8377   ns_function_modifier = Qnone;
8379   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8380                "Non-nil (the default) means to render text antialiased.");
8381   ns_antialias_text = Qt;
8383   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8384                "Whether to confirm application quit using dialog.");
8385   ns_confirm_quit = Qnil;
8387   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8388                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8389 Only works on OSX 10.6 or later.  */);
8390   ns_auto_hide_menu_bar = Qnil;
8392   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8393      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
8394 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
8395 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
8396 Default is t for OSX >= 10.7, nil otherwise.  */);
8397 #ifdef HAVE_NATIVE_FS
8398   ns_use_native_fullscreen = YES;
8399 #else
8400   ns_use_native_fullscreen = NO;
8401 #endif
8402   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8404   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8405      doc: /*Non-nil means use animation on non-native fullscreen.
8406 For native fullscreen, this does nothing.
8407 Default is nil.  */);
8408   ns_use_fullscreen_animation = NO;
8410   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8411      doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
8412 Note that this does not apply to images.
8413 This variable is ignored on OSX < 10.7 and GNUstep.  */);
8414   ns_use_srgb_colorspace = YES;
8416   /* TODO: move to common code */
8417   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8418                doc: /* Which toolkit scroll bars Emacs uses, if any.
8419 A value of nil means Emacs doesn't use toolkit scroll bars.
8420 With the X Window system, the value is a symbol describing the
8421 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
8422 With MS Windows or Nextstep, the value is t.  */);
8423   Vx_toolkit_scroll_bars = Qt;
8425   DEFVAR_BOOL ("x-use-underline-position-properties",
8426                x_use_underline_position_properties,
8427      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8428 A value of nil means ignore them.  If you encounter fonts with bogus
8429 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8430 to 4.1, set this to nil. */);
8431   x_use_underline_position_properties = 0;
8433   DEFVAR_BOOL ("x-underline-at-descent-line",
8434                x_underline_at_descent_line,
8435      doc: /* Non-nil means to draw the underline at the same place as the descent line.
8436 A value of nil means to draw the underline according to the value of the
8437 variable `x-use-underline-position-properties', which is usually at the
8438 baseline level.  The default value is nil.  */);
8439   x_underline_at_descent_line = 0;
8441   /* Tell Emacs about this window system.  */
8442   Fprovide (Qns, Qnil);
8444   DEFSYM (Qcocoa, "cocoa");
8445   DEFSYM (Qgnustep, "gnustep");
8447 #ifdef NS_IMPL_COCOA
8448   Fprovide (Qcocoa, Qnil);
8449   syms_of_macfont ();
8450 #else
8451   Fprovide (Qgnustep, Qnil);
8452   syms_of_nsfont ();
8453 #endif