Doc tweaks.
[emacs.git] / src / nsterm.m
blob36e08c60575f58da7df3a642656f7b6259aa3867
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 /* ==========================================================================
77    NSTRACE, Trace support.
79    ========================================================================== */
81 #if NSTRACE_ENABLED
83 /* The following use "volatile" since they can be accessed from
84    parallel threads. */
85 volatile int nstrace_num = 0;
86 volatile int nstrace_depth = 0;
88 /* When 0, no trace is emitted.  This is used by NSTRACE_WHEN and
89    NSTRACE_UNLESS to silence functions called.
91    TODO: This should really be a thread-local variable, to avoid that
92    a function with disabled trace thread silence trace output in
93    another.  However, in practice this seldom is a problem. */
94 volatile int nstrace_enabled_global = 1;
96 /* Called when nstrace_enabled goes out of scope. */
97 void nstrace_leave(int * pointer_to_nstrace_enabled)
99   if (*pointer_to_nstrace_enabled)
100     {
101       --nstrace_depth;
102     }
106 /* Called when nstrace_saved_enabled_global goes out of scope. */
107 void nstrace_restore_global_trace_state(int * pointer_to_saved_enabled_global)
109   nstrace_enabled_global = *pointer_to_saved_enabled_global;
113 char const * nstrace_fullscreen_type_name (int fs_type)
115   switch (fs_type)
116     {
117     case -1:                   return "-1";
118     case FULLSCREEN_NONE:      return "FULLSCREEN_NONE";
119     case FULLSCREEN_WIDTH:     return "FULLSCREEN_WIDTH";
120     case FULLSCREEN_HEIGHT:    return "FULLSCREEN_HEIGHT";
121     case FULLSCREEN_BOTH:      return "FULLSCREEN_BOTH";
122     case FULLSCREEN_MAXIMIZED: return "FULLSCREEN_MAXIMIZED";
123     default:                   return "FULLSCREEN_?????";
124     }
126 #endif
129 /* ==========================================================================
131    NSColor, EmacsColor category.
133    ========================================================================== */
134 @implementation NSColor (EmacsColor)
135 + (NSColor *)colorForEmacsRed:(CGFloat)red green:(CGFloat)green
136                          blue:(CGFloat)blue alpha:(CGFloat)alpha
138 #ifdef NS_IMPL_COCOA
139 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
140   if (ns_use_srgb_colorspace)
141       return [NSColor colorWithSRGBRed: red
142                                  green: green
143                                   blue: blue
144                                  alpha: alpha];
145 #endif
146 #endif
147   return [NSColor colorWithCalibratedRed: red
148                                    green: green
149                                     blue: blue
150                                    alpha: alpha];
153 - (NSColor *)colorUsingDefaultColorSpace
155 #ifdef NS_IMPL_COCOA
156 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
157   if (ns_use_srgb_colorspace)
158     return [self colorUsingColorSpace: [NSColorSpace sRGBColorSpace]];
159 #endif
160 #endif
161   return [self colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
164 @end
166 /* ==========================================================================
168     Local declarations
170    ========================================================================== */
172 /* Convert a symbol indexed with an NSxxx value to a value as defined
173    in keyboard.c (lispy_function_key). I hope this is a correct way
174    of doing things... */
175 static unsigned convert_ns_to_X_keysym[] =
177   NSHomeFunctionKey,            0x50,
178   NSLeftArrowFunctionKey,       0x51,
179   NSUpArrowFunctionKey,         0x52,
180   NSRightArrowFunctionKey,      0x53,
181   NSDownArrowFunctionKey,       0x54,
182   NSPageUpFunctionKey,          0x55,
183   NSPageDownFunctionKey,        0x56,
184   NSEndFunctionKey,             0x57,
185   NSBeginFunctionKey,           0x58,
186   NSSelectFunctionKey,          0x60,
187   NSPrintFunctionKey,           0x61,
188   NSClearLineFunctionKey,       0x0B,
189   NSExecuteFunctionKey,         0x62,
190   NSInsertFunctionKey,          0x63,
191   NSUndoFunctionKey,            0x65,
192   NSRedoFunctionKey,            0x66,
193   NSMenuFunctionKey,            0x67,
194   NSFindFunctionKey,            0x68,
195   NSHelpFunctionKey,            0x6A,
196   NSBreakFunctionKey,           0x6B,
198   NSF1FunctionKey,              0xBE,
199   NSF2FunctionKey,              0xBF,
200   NSF3FunctionKey,              0xC0,
201   NSF4FunctionKey,              0xC1,
202   NSF5FunctionKey,              0xC2,
203   NSF6FunctionKey,              0xC3,
204   NSF7FunctionKey,              0xC4,
205   NSF8FunctionKey,              0xC5,
206   NSF9FunctionKey,              0xC6,
207   NSF10FunctionKey,             0xC7,
208   NSF11FunctionKey,             0xC8,
209   NSF12FunctionKey,             0xC9,
210   NSF13FunctionKey,             0xCA,
211   NSF14FunctionKey,             0xCB,
212   NSF15FunctionKey,             0xCC,
213   NSF16FunctionKey,             0xCD,
214   NSF17FunctionKey,             0xCE,
215   NSF18FunctionKey,             0xCF,
216   NSF19FunctionKey,             0xD0,
217   NSF20FunctionKey,             0xD1,
218   NSF21FunctionKey,             0xD2,
219   NSF22FunctionKey,             0xD3,
220   NSF23FunctionKey,             0xD4,
221   NSF24FunctionKey,             0xD5,
223   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
224   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
225   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
227   NSTabCharacter,               0x09,
228   0x19,                         0x09,  /* left tab->regular since pass shift */
229   NSCarriageReturnCharacter,    0x0D,
230   NSNewlineCharacter,           0x0D,
231   NSEnterCharacter,             0x8D,
233   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
234   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
235   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
236   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
237   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
238   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
239   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
240   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
241   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
242   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
243   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
244   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
245   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
246   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
247   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
248   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
250   0x1B,                         0x1B   /* escape */
253 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
254    the maximum font size to NOT antialias.  On GNUstep there is currently
255    no way to control this behavior. */
256 float ns_antialias_threshold;
258 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
259 NSString *ns_app_name = @"Emacs";  /* default changed later */
261 /* Display variables */
262 struct ns_display_info *x_display_list; /* Chain of existing displays */
263 long context_menu_value = 0;
265 /* display update */
266 static struct frame *ns_updating_frame;
267 static NSView *focus_view = NULL;
268 static int ns_window_num = 0;
269 #ifdef NS_IMPL_GNUSTEP
270 static NSRect uRect;            // TODO: This is dead, remove it?
271 #endif
272 static BOOL gsaved = NO;
273 static BOOL ns_fake_keydown = NO;
274 #ifdef NS_IMPL_COCOA
275 static BOOL ns_menu_bar_is_hidden = NO;
276 #endif
277 /*static int debug_lock = 0; */
279 /* event loop */
280 static BOOL send_appdefined = YES;
281 #define NO_APPDEFINED_DATA (-8)
282 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
283 static NSTimer *timed_entry = 0;
284 static NSTimer *scroll_repeat_entry = nil;
285 static fd_set select_readfds, select_writefds;
286 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
287 static int select_nfds = 0, select_valid = 0;
288 static struct timespec select_timeout = { 0, 0 };
289 static int selfds[2] = { -1, -1 };
290 static pthread_mutex_t select_mutex;
291 static int apploopnr = 0;
292 static NSAutoreleasePool *outerpool;
293 static struct input_event *emacs_event = NULL;
294 static struct input_event *q_event_ptr = NULL;
295 static int n_emacs_events_pending = 0;
296 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
297   *ns_pending_service_args;
298 static BOOL ns_do_open_file = NO;
299 static BOOL ns_last_use_native_fullscreen;
301 /* Non-zero means that a HELP_EVENT has been generated since Emacs
302    start.  */
304 static BOOL any_help_event_p = NO;
306 static struct {
307   struct input_event *q;
308   int nr, cap;
309 } hold_event_q = {
310   NULL, 0, 0
313 static NSString *represented_filename = nil;
314 static struct frame *represented_frame = 0;
316 #ifdef NS_IMPL_COCOA
318  * State for pending menu activation:
319  * MENU_NONE     Normal state
320  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
321  *               run lisp to update the menu.
322  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
323  *               will open.
324  */
325 #define MENU_NONE 0
326 #define MENU_PENDING 1
327 #define MENU_OPENING 2
328 static int menu_will_open_state = MENU_NONE;
330 /* Saved position for menu click.  */
331 static CGPoint menu_mouse_point;
332 #endif
334 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
335 #define NS_FUNCTION_KEY_MASK 0x800000
336 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
337 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
338 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
339 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
340 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
341 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
342 #define EV_MODIFIERS2(flags)                          \
343     (((flags & NSHelpKeyMask) ?           \
344            hyper_modifier : 0)                        \
345      | (!EQ (ns_right_alternate_modifier, Qleft) && \
346         ((flags & NSRightAlternateKeyMask) \
347          == NSRightAlternateKeyMask) ? \
348            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
349      | ((flags & NSAlternateKeyMask) ?                 \
350            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
351      | ((flags & NSShiftKeyMask) ?     \
352            shift_modifier : 0)                        \
353      | (!EQ (ns_right_control_modifier, Qleft) && \
354         ((flags & NSRightControlKeyMask) \
355          == NSRightControlKeyMask) ? \
356            parse_solitary_modifier (ns_right_control_modifier) : 0) \
357      | ((flags & NSControlKeyMask) ?      \
358            parse_solitary_modifier (ns_control_modifier) : 0)     \
359      | ((flags & NS_FUNCTION_KEY_MASK) ?  \
360            parse_solitary_modifier (ns_function_modifier) : 0)    \
361      | (!EQ (ns_right_command_modifier, Qleft) && \
362         ((flags & NSRightCommandKeyMask) \
363          == NSRightCommandKeyMask) ? \
364            parse_solitary_modifier (ns_right_command_modifier) : 0) \
365      | ((flags & NSCommandKeyMask) ?      \
366            parse_solitary_modifier (ns_command_modifier):0))
367 #define EV_MODIFIERS(e) EV_MODIFIERS2 ([e modifierFlags])
369 #define EV_UDMODIFIERS(e)                                      \
370     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
371      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
372      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
373      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
374      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
375      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
376      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
377      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
378      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
380 #define EV_BUTTON(e)                                                         \
381     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
382       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
383      [e buttonNumber] - 1)
385 /* Convert the time field to a timestamp in milliseconds. */
386 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
388 /* This is a piece of code which is common to all the event handling
389    methods.  Maybe it should even be a function.  */
390 #define EV_TRAILER(e)                                                   \
391   {                                                                     \
392     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
393     EV_TRAILER2 (e);                                                    \
394   }
396 #define EV_TRAILER2(e)                                                  \
397   {                                                                     \
398       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
399       if (q_event_ptr)                                                  \
400         {                                                               \
401           Lisp_Object tem = Vinhibit_quit;                              \
402           Vinhibit_quit = Qt;                                           \
403           n_emacs_events_pending++;                                     \
404           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
405           Vinhibit_quit = tem;                                          \
406         }                                                               \
407       else                                                              \
408         hold_event (emacs_event);                                       \
409       EVENT_INIT (*emacs_event);                                        \
410       ns_send_appdefined (-1);                                          \
411     }
413 /* TODO: get rid of need for these forward declarations */
414 static void ns_condemn_scroll_bars (struct frame *f);
415 static void ns_judge_scroll_bars (struct frame *f);
416 void x_set_frame_alpha (struct frame *f);
419 /* ==========================================================================
421     Utilities
423    ========================================================================== */
425 void
426 ns_set_represented_filename (NSString* fstr, struct frame *f)
428   represented_filename = [fstr retain];
429   represented_frame = f;
432 void
433 ns_init_events (struct input_event* ev)
435   EVENT_INIT (*ev);
436   emacs_event = ev;
439 void
440 ns_finish_events ()
442   emacs_event = NULL;
445 static void
446 hold_event (struct input_event *event)
448   if (hold_event_q.nr == hold_event_q.cap)
449     {
450       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
451       else hold_event_q.cap *= 2;
452       hold_event_q.q =
453         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
454     }
456   hold_event_q.q[hold_event_q.nr++] = *event;
457   /* Make sure ns_read_socket is called, i.e. we have input.  */
458   raise (SIGIO);
459   send_appdefined = YES;
462 static Lisp_Object
463 append2 (Lisp_Object list, Lisp_Object item)
464 /* --------------------------------------------------------------------------
465    Utility to append to a list
466    -------------------------------------------------------------------------- */
468   return CALLN (Fnconc, list, list1 (item));
472 const char *
473 ns_etc_directory (void)
474 /* If running as a self-contained app bundle, return as a string the
475    filename of the etc directory, if present; else nil.  */
477   NSBundle *bundle = [NSBundle mainBundle];
478   NSString *resourceDir = [bundle resourcePath];
479   NSString *resourcePath;
480   NSFileManager *fileManager = [NSFileManager defaultManager];
481   BOOL isDir;
483   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
484   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
485     {
486       if (isDir) return [resourcePath UTF8String];
487     }
488   return NULL;
492 const char *
493 ns_exec_path (void)
494 /* If running as a self-contained app bundle, return as a path string
495    the filenames of the libexec and bin directories, ie libexec:bin.
496    Otherwise, return nil.
497    Normally, Emacs does not add its own bin/ directory to the PATH.
498    However, a self-contained NS build has a different layout, with
499    bin/ and libexec/ subdirectories in the directory that contains
500    Emacs.app itself.
501    We put libexec first, because init_callproc_1 uses the first
502    element to initialize exec-directory.  An alternative would be
503    for init_callproc to check for invocation-directory/libexec.
506   NSBundle *bundle = [NSBundle mainBundle];
507   NSString *resourceDir = [bundle resourcePath];
508   NSString *binDir = [bundle bundlePath];
509   NSString *resourcePath, *resourcePaths;
510   NSRange range;
511   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
512   NSFileManager *fileManager = [NSFileManager defaultManager];
513   NSArray *paths;
514   NSEnumerator *pathEnum;
515   BOOL isDir;
517   range = [resourceDir rangeOfString: @"Contents"];
518   if (range.location != NSNotFound)
519     {
520       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
521 #ifdef NS_IMPL_COCOA
522       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
523 #endif
524     }
526   paths = [binDir stringsByAppendingPaths:
527                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
528   pathEnum = [paths objectEnumerator];
529   resourcePaths = @"";
531   while ((resourcePath = [pathEnum nextObject]))
532     {
533       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
534         if (isDir)
535           {
536             if ([resourcePaths length] > 0)
537               resourcePaths
538                 = [resourcePaths stringByAppendingString: pathSeparator];
539             resourcePaths
540               = [resourcePaths stringByAppendingString: resourcePath];
541           }
542     }
543   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
545   return NULL;
549 const char *
550 ns_load_path (void)
551 /* If running as a self-contained app bundle, return as a path string
552    the filenames of the site-lisp and lisp directories.
553    Ie, site-lisp:lisp.  Otherwise, return nil.  */
555   NSBundle *bundle = [NSBundle mainBundle];
556   NSString *resourceDir = [bundle resourcePath];
557   NSString *resourcePath, *resourcePaths;
558   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
559   NSFileManager *fileManager = [NSFileManager defaultManager];
560   BOOL isDir;
561   NSArray *paths = [resourceDir stringsByAppendingPaths:
562                               [NSArray arrayWithObjects:
563                                          @"site-lisp", @"lisp", nil]];
564   NSEnumerator *pathEnum = [paths objectEnumerator];
565   resourcePaths = @"";
567   /* Hack to skip site-lisp.  */
568   if (no_site_lisp) resourcePath = [pathEnum nextObject];
570   while ((resourcePath = [pathEnum nextObject]))
571     {
572       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
573         if (isDir)
574           {
575             if ([resourcePaths length] > 0)
576               resourcePaths
577                 = [resourcePaths stringByAppendingString: pathSeparator];
578             resourcePaths
579               = [resourcePaths stringByAppendingString: resourcePath];
580           }
581     }
582   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
584   return NULL;
588 void
589 ns_release_object (void *obj)
590 /* --------------------------------------------------------------------------
591     Release an object (callable from C)
592    -------------------------------------------------------------------------- */
594     [(id)obj release];
598 void
599 ns_retain_object (void *obj)
600 /* --------------------------------------------------------------------------
601     Retain an object (callable from C)
602    -------------------------------------------------------------------------- */
604     [(id)obj retain];
608 void *
609 ns_alloc_autorelease_pool (void)
610 /* --------------------------------------------------------------------------
611      Allocate a pool for temporary objects (callable from C)
612    -------------------------------------------------------------------------- */
614   return [[NSAutoreleasePool alloc] init];
618 void
619 ns_release_autorelease_pool (void *pool)
620 /* --------------------------------------------------------------------------
621      Free a pool and temporary objects it refers to (callable from C)
622    -------------------------------------------------------------------------- */
624   ns_release_object (pool);
628 /* True, if the menu bar should be hidden.  */
630 static BOOL
631 ns_menu_bar_should_be_hidden (void)
633   return !NILP (ns_auto_hide_menu_bar)
634     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
638 static CGFloat
639 ns_menu_bar_height (NSScreen *screen)
640 /* The height of the menu bar, if visible. */
642   //  NSTRACE ("ns_menu_bar_height");
644   CGFloat res;
646   if (ns_menu_bar_should_be_hidden())
647     {
648       res = 0;
649     }
650   else
651     {
652       NSRect screenFrame = [screen frame];
653       NSRect screenVisibleFrame = [screen visibleFrame];
655       CGFloat frameTop = screenFrame.origin.y + screenFrame.size.height;
656       CGFloat visibleFrameTop = (screenVisibleFrame.origin.y
657                                  + screenVisibleFrame.size.height);
659       res = frameTop - visibleFrameTop;
661     }
663   // NSTRACE_MSG (NSTRACE_FMT_RETURN "%.0f", res);
665   return res;
669 /* ==========================================================================
671     Focus (clipping) and screen update
673    ========================================================================== */
676 // Window constraining
677 // -------------------
679 // To ensure that the windows are not placed under the menu bar, they
680 // are typically moved by the call-back constrainFrameRect. However,
681 // by overriding it, it's possible to inhibit this, leaving the window
682 // in it's original position.
684 // It's possible to hide the menu bar. However, technically, it's only
685 // possible to hide it when the application is active. To ensure that
686 // this work properly, the menu bar and window constraining are
687 // deferred until the application becomes active.
689 // Even though it's not possible to manually move a window above the
690 // top of the screen, it is allowed if it's done programmatically,
691 // when the menu is hidden. This allows the editable area to cover the
692 // full screen height.
694 // Test cases
695 // ----------
697 // Use the following extra files:
699 //    init.el:
700 //       ;; Hide menu and place frame slightly above the top of the screen.
701 //       (setq ns-auto-hide-menu-bar t)
702 //       (set-frame-position (selected-frame) 0 -20)
704 // Test 1:
706 //    emacs -Q -l init.el
708 //    Result: No menu bar, and the title bar should be above the screen.
710 // Test 2:
712 //    emacs -Q
714 //    Result: Menu bar visible, frame placed immediately below the menu.
717 static NSRect constrain_frame_rect(NSRect frameRect)
719   NSTRACE ("constrain_frame_rect(" NSTRACE_FMT_RECT ")",
720              NSTRACE_ARG_RECT (frameRect));
722   // --------------------
723   // Collect information about the screen the frame is covering.
724   //
726   NSArray *screens = [NSScreen screens];
727   NSUInteger nr_screens = [screens count];
729   int i;
731   // The height of the menu bar, if present in any screen the frame is
732   // displayed in.
733   int menu_bar_height = 0;
735   // A rectangle covering all the screen the frame is displayed in.
736   NSRect multiscreenRect = NSMakeRect(0, 0, 0, 0);
737   for (i = 0; i < nr_screens; ++i )
738     {
739       NSScreen *s = [screens objectAtIndex: i];
740       NSRect scrRect = [s frame];
742       NSTRACE_MSG ("Screen %d: " NSTRACE_FMT_RECT,
743                    i, NSTRACE_ARG_RECT (scrRect));
745       if (NSIntersectionRect (frameRect, scrRect).size.height != 0)
746         {
747           multiscreenRect = NSUnionRect (multiscreenRect, scrRect);
749           menu_bar_height = max(menu_bar_height, ns_menu_bar_height (s));
750         }
751     }
753   NSTRACE_RECT ("multiscreenRect", multiscreenRect);
755   NSTRACE_MSG ("menu_bar_height: %d", menu_bar_height);
757   if (multiscreenRect.size.width == 0
758       || multiscreenRect.size.height == 0)
759     {
760       // Failed to find any monitor, give up.
761       NSTRACE_MSG ("multiscreenRect empty");
762       NSTRACE_RETURN_RECT (frameRect);
763       return frameRect;
764     }
767   // --------------------
768   // Find a suitable placement.
769   //
771   if (ns_menu_bar_should_be_hidden())
772     {
773       // When the menu bar is hidden, the user may place part of the
774       // frame above the top of the screen, for example to hide the
775       // title bar.
776       //
777       // Hence, keep the original position.
778     }
779   else
780     {
781       // Ensure that the frame is below the menu bar, or below the top
782       // of the screen.
783       //
784       // This assume that the menu bar is placed at the top in the
785       // rectangle that covers the monitors.  (It doesn't have to be,
786       // but if it's not it's hard to do anything useful.)
787       CGFloat topOfWorkArea = (multiscreenRect.origin.y
788                                + multiscreenRect.size.height
789                                - menu_bar_height);
791       CGFloat topOfFrame = frameRect.origin.y + frameRect.size.height;
792       if (topOfFrame > topOfWorkArea)
793         {
794           frameRect.origin.y -= topOfFrame - topOfWorkArea;
795           NSTRACE_RECT ("After placement adjust", frameRect);
796         }
797     }
799   // Include the following section to restrict frame to the screens.
800   // (If so, update it to allow the frame to stretch down below the
801   // screen.)
802 #if 0
803   // --------------------
804   // Ensure frame doesn't stretch below the screens.
805   //
807   CGFloat diff = multiscreenRect.origin.y - frameRect.origin.y;
809   if (diff > 0)
810     {
811       frameRect.origin.y = multiscreenRect.origin.y;
812       frameRect.size.height -= diff;
813     }
814 #endif
816   NSTRACE_RETURN_RECT (frameRect);
817   return frameRect;
821 static void
822 ns_constrain_all_frames (void)
823 /* --------------------------------------------------------------------------
824      Ensure that the menu bar doesn't cover any frames.
825    -------------------------------------------------------------------------- */
827   Lisp_Object tail, frame;
829   NSTRACE ("ns_constrain_all_frames");
831   block_input ();
833   FOR_EACH_FRAME (tail, frame)
834     {
835       struct frame *f = XFRAME (frame);
836       if (FRAME_NS_P (f))
837         {
838           EmacsView *view = FRAME_NS_VIEW (f);
840           if (![view isFullscreen])
841             {
842               [[view window]
843                 setFrame:constrain_frame_rect([[view window] frame])
844                  display:NO];
845             }
846         }
847     }
849   unblock_input ();
853 static void
854 ns_update_auto_hide_menu_bar (void)
855 /* --------------------------------------------------------------------------
856      Show or hide the menu bar, based on user setting.
857    -------------------------------------------------------------------------- */
859 #ifdef NS_IMPL_COCOA
860   NSTRACE ("ns_update_auto_hide_menu_bar");
862   block_input ();
864   if (NSApp != nil && [NSApp isActive])
865     {
866       // Note, "setPresentationOptions" triggers an error unless the
867       // application is active.
868       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
870       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
871         {
872           NSApplicationPresentationOptions options
873             = NSApplicationPresentationDefault;
875           if (menu_bar_should_be_hidden)
876             options |= NSApplicationPresentationAutoHideMenuBar
877               | NSApplicationPresentationAutoHideDock;
879           [NSApp setPresentationOptions: options];
881           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
883           if (!ns_menu_bar_is_hidden)
884             {
885               ns_constrain_all_frames ();
886             }
887         }
888     }
890   unblock_input ();
891 #endif
895 static void
896 ns_update_begin (struct frame *f)
897 /* --------------------------------------------------------------------------
898    Prepare for a grouped sequence of drawing calls
899    external (RIF) call; whole frame, called before update_window_begin
900    -------------------------------------------------------------------------- */
902   EmacsView *view = FRAME_NS_VIEW (f);
903   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_begin");
905   ns_update_auto_hide_menu_bar ();
907 #ifdef NS_IMPL_COCOA
908   if ([view isFullscreen] && [view fsIsNative])
909   {
910     // Fix reappearing tool bar in fullscreen for OSX 10.7
911     BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (f) ? YES : NO;
912     NSToolbar *toolbar = [FRAME_NS_VIEW (f) toolbar];
913     if (! tbar_visible != ! [toolbar isVisible])
914       [toolbar setVisible: tbar_visible];
915   }
916 #endif
918   ns_updating_frame = f;
919   [view lockFocus];
921   /* drawRect may have been called for say the minibuffer, and then clip path
922      is for the minibuffer.  But the display engine may draw more because
923      we have set the frame as garbaged.  So reset clip path to the whole
924      view.  */
925 #ifdef NS_IMPL_COCOA
926   {
927     NSBezierPath *bp;
928     NSRect r = [view frame];
929     NSRect cr = [[view window] frame];
930     /* If a large frame size is set, r may be larger than the window frame
931        before constrained.  In that case don't change the clip path, as we
932        will clear in to the tool bar and title bar.  */
933     if (r.size.height
934         + FRAME_NS_TITLEBAR_HEIGHT (f)
935         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
936       {
937         bp = [[NSBezierPath bezierPathWithRect: r] retain];
938         [bp setClip];
939         [bp release];
940       }
941   }
942 #endif
944 #ifdef NS_IMPL_GNUSTEP
945   uRect = NSMakeRect (0, 0, 0, 0);
946 #endif
950 static void
951 ns_update_window_begin (struct window *w)
952 /* --------------------------------------------------------------------------
953    Prepare for a grouped sequence of drawing calls
954    external (RIF) call; for one window, called after update_begin
955    -------------------------------------------------------------------------- */
957   struct frame *f = XFRAME (WINDOW_FRAME (w));
958   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
960   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_begin");
961   w->output_cursor = w->cursor;
963   block_input ();
965   if (f == hlinfo->mouse_face_mouse_frame)
966     {
967       /* Don't do highlighting for mouse motion during the update.  */
968       hlinfo->mouse_face_defer = 1;
970         /* If the frame needs to be redrawn,
971            simply forget about any prior mouse highlighting.  */
972       if (FRAME_GARBAGED_P (f))
973         hlinfo->mouse_face_window = Qnil;
975       /* (further code for mouse faces ifdef'd out in other terms elided) */
976     }
978   unblock_input ();
982 static void
983 ns_update_window_end (struct window *w, bool cursor_on_p,
984                       bool mouse_face_overwritten_p)
985 /* --------------------------------------------------------------------------
986    Finished a grouped sequence of drawing calls
987    external (RIF) call; for one window called before update_end
988    -------------------------------------------------------------------------- */
990   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_window_end");
992   /* note: this fn is nearly identical in all terms */
993   if (!w->pseudo_window_p)
994     {
995       block_input ();
997       if (cursor_on_p)
998         display_and_set_cursor (w, 1,
999                                 w->output_cursor.hpos, w->output_cursor.vpos,
1000                                 w->output_cursor.x, w->output_cursor.y);
1002       if (draw_window_fringes (w, 1))
1003         {
1004           if (WINDOW_RIGHT_DIVIDER_WIDTH (w))
1005             x_draw_right_divider (w);
1006           else
1007             x_draw_vertical_border (w);
1008         }
1010       unblock_input ();
1011     }
1013   /* If a row with mouse-face was overwritten, arrange for
1014      frame_up_to_date to redisplay the mouse highlight.  */
1015   if (mouse_face_overwritten_p)
1016     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
1020 static void
1021 ns_update_end (struct frame *f)
1022 /* --------------------------------------------------------------------------
1023    Finished a grouped sequence of drawing calls
1024    external (RIF) call; for whole frame, called after update_window_end
1025    -------------------------------------------------------------------------- */
1027   EmacsView *view = FRAME_NS_VIEW (f);
1029   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_update_end");
1031 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
1032   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
1034   block_input ();
1036   [view unlockFocus];
1037   [[view window] flushWindow];
1039   unblock_input ();
1040   ns_updating_frame = NULL;
1043 static void
1044 ns_focus (struct frame *f, NSRect *r, int n)
1045 /* --------------------------------------------------------------------------
1046    Internal: Focus on given frame.  During small local updates this is used to
1047      draw, however during large updates, ns_update_begin and ns_update_end are
1048      called to wrap the whole thing, in which case these calls are stubbed out.
1049      Except, on GNUstep, we accumulate the rectangle being drawn into, because
1050      the back end won't do this automatically, and will just end up flushing
1051      the entire window.
1052    -------------------------------------------------------------------------- */
1054   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_focus");
1055   if (r != NULL)
1056     {
1057       NSTRACE_RECT ("r", *r);
1058     }
1060   if (f != ns_updating_frame)
1061     {
1062       NSView *view = FRAME_NS_VIEW (f);
1063       if (view != focus_view)
1064         {
1065           if (focus_view != NULL)
1066             {
1067               [focus_view unlockFocus];
1068               [[focus_view window] flushWindow];
1069 /*debug_lock--; */
1070             }
1072           if (view)
1073             [view lockFocus];
1074           focus_view = view;
1075 /*if (view) debug_lock++; */
1076         }
1077     }
1079   /* clipping */
1080   if (r)
1081     {
1082       [[NSGraphicsContext currentContext] saveGraphicsState];
1083       if (n == 2)
1084         NSRectClipList (r, 2);
1085       else
1086         NSRectClip (*r);
1087       gsaved = YES;
1088     }
1092 static void
1093 ns_unfocus (struct frame *f)
1094 /* --------------------------------------------------------------------------
1095      Internal: Remove focus on given frame
1096    -------------------------------------------------------------------------- */
1098   NSTRACE_WHEN (NSTRACE_GROUP_FOCUS, "ns_unfocus");
1100   if (gsaved)
1101     {
1102       [[NSGraphicsContext currentContext] restoreGraphicsState];
1103       gsaved = NO;
1104     }
1106   if (f != ns_updating_frame)
1107     {
1108       if (focus_view != NULL)
1109         {
1110           [focus_view unlockFocus];
1111           [[focus_view window] flushWindow];
1112           focus_view = NULL;
1113 /*debug_lock--; */
1114         }
1115     }
1119 static void
1120 ns_clip_to_row (struct window *w, struct glyph_row *row,
1121                 enum glyph_row_area area, BOOL gc)
1122 /* --------------------------------------------------------------------------
1123      Internal (but parallels other terms): Focus drawing on given row
1124    -------------------------------------------------------------------------- */
1126   struct frame *f = XFRAME (WINDOW_FRAME (w));
1127   NSRect clip_rect;
1128   int window_x, window_y, window_width;
1130   window_box (w, area, &window_x, &window_y, &window_width, 0);
1132   clip_rect.origin.x = window_x;
1133   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
1134   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
1135   clip_rect.size.width = window_width;
1136   clip_rect.size.height = row->visible_height;
1138   ns_focus (f, &clip_rect, 1);
1142 /* ==========================================================================
1144     Visible bell and beep.
1146    ========================================================================== */
1149 @interface EmacsBell : NSImageView
1151   // Number of currently active bell:s.
1152   unsigned int nestCount;
1154 - (void)show:(NSView *)view;
1155 - (void)hide;
1156 @end
1158 @implementation EmacsBell
1160 - (id)init;
1162   if ((self = [super init]))
1163     {
1164       nestCount = 0;
1165       self.image = [NSImage imageNamed:NSImageNameCaution];
1166     }
1167   return self;
1170 - (void)show:(NSView *)view
1172   NSTRACE ("[EmacsBell show:]");
1173   NSTRACE_MSG ("nestCount: %u", nestCount);
1175   // Show the image, unless it's already shown.
1176   if (nestCount == 0)
1177     {
1178       NSRect rect = [view bounds];
1179       NSPoint pos;
1180       pos.x = rect.origin.x + (rect.size.width  - self.image.size.width )/2;
1181       pos.y = rect.origin.y + (rect.size.height - self.image.size.height)/2;
1183       [self setFrameOrigin:pos];
1184       [self setFrameSize:self.image.size];
1186       [[[view window] contentView] addSubview:self
1187                                    positioned:NSWindowAbove
1188                                    relativeTo:nil];
1189     }
1191   ++nestCount;
1193   [self performSelector:@selector(hide) withObject:self afterDelay:0.5];
1197 - (void)hide
1199   // Note: Trace output from this method isn't shown, reason unknown.
1200   // NSTRACE ("[EmacsBell hide]");
1202   --nestCount;
1204   // Remove the image once the last bell became inactive.
1205   if (nestCount == 0)
1206     {
1207       [self removeFromSuperview];
1208     }
1211 @end
1213 static void
1214 ns_ring_bell (struct frame *f)
1215 /* --------------------------------------------------------------------------
1216      "Beep" routine
1217    -------------------------------------------------------------------------- */
1219   NSTRACE ("ns_ring_bell");
1220   if (visible_bell)
1221     {
1222       struct frame *frame = SELECTED_FRAME ();
1223       NSView *view;
1225       static EmacsBell * bell_view = nil;
1226       if (bell_view == nil)
1227         {
1228           bell_view = [[EmacsBell alloc] init];
1229           [bell_view retain];
1230         }
1232       block_input ();
1234       view = FRAME_NS_VIEW (frame);
1235       if (view != nil)
1236         {
1237           [bell_view show:view];
1238         }
1240       unblock_input ();
1241     }
1242   else
1243     {
1244       NSBeep ();
1245     }
1249 /* ==========================================================================
1251     Frame / window manager related functions
1253    ========================================================================== */
1256 static void
1257 ns_raise_frame (struct frame *f)
1258 /* --------------------------------------------------------------------------
1259      Bring window to foreground and make it active
1260    -------------------------------------------------------------------------- */
1262   NSView *view;
1264   check_window_system (f);
1265   view = FRAME_NS_VIEW (f);
1266   block_input ();
1267   if (FRAME_VISIBLE_P (f))
1268     [[view window] makeKeyAndOrderFront: NSApp];
1269   unblock_input ();
1273 static void
1274 ns_lower_frame (struct frame *f)
1275 /* --------------------------------------------------------------------------
1276      Send window to back
1277    -------------------------------------------------------------------------- */
1279   NSView *view;
1281   check_window_system (f);
1282   view = FRAME_NS_VIEW (f);
1283   block_input ();
1284   [[view window] orderBack: NSApp];
1285   unblock_input ();
1289 static void
1290 ns_frame_raise_lower (struct frame *f, bool raise)
1291 /* --------------------------------------------------------------------------
1292      External (hook)
1293    -------------------------------------------------------------------------- */
1295   NSTRACE ("ns_frame_raise_lower");
1297   if (raise)
1298     ns_raise_frame (f);
1299   else
1300     ns_lower_frame (f);
1304 static void
1305 ns_frame_rehighlight (struct frame *frame)
1306 /* --------------------------------------------------------------------------
1307      External (hook): called on things like window switching within frame
1308    -------------------------------------------------------------------------- */
1310   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
1311   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1313   NSTRACE ("ns_frame_rehighlight");
1314   if (dpyinfo->x_focus_frame)
1315     {
1316       dpyinfo->x_highlight_frame
1317         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1318            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1319            : dpyinfo->x_focus_frame);
1320       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1321         {
1322           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1323           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1324         }
1325     }
1326   else
1327       dpyinfo->x_highlight_frame = 0;
1329   if (dpyinfo->x_highlight_frame &&
1330          dpyinfo->x_highlight_frame != old_highlight)
1331     {
1332       if (old_highlight)
1333         {
1334           x_update_cursor (old_highlight, 1);
1335           x_set_frame_alpha (old_highlight);
1336         }
1337       if (dpyinfo->x_highlight_frame)
1338         {
1339           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1340           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1341         }
1342     }
1346 void
1347 x_make_frame_visible (struct frame *f)
1348 /* --------------------------------------------------------------------------
1349      External: Show the window (X11 semantics)
1350    -------------------------------------------------------------------------- */
1352   NSTRACE ("x_make_frame_visible");
1353   /* XXX: at some points in past this was not needed, as the only place that
1354      called this (frame.c:Fraise_frame ()) also called raise_lower;
1355      if this ends up the case again, comment this out again. */
1356   if (!FRAME_VISIBLE_P (f))
1357     {
1358       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1360       SET_FRAME_VISIBLE (f, 1);
1361       ns_raise_frame (f);
1363       /* Making a new frame from a fullscreen frame will make the new frame
1364          fullscreen also.  So skip handleFS as this will print an error.  */
1365       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1366           && [view isFullscreen])
1367         return;
1369       if (f->want_fullscreen != FULLSCREEN_NONE)
1370         {
1371           block_input ();
1372           [view handleFS];
1373           unblock_input ();
1374         }
1375     }
1379 void
1380 x_make_frame_invisible (struct frame *f)
1381 /* --------------------------------------------------------------------------
1382      External: Hide the window (X11 semantics)
1383    -------------------------------------------------------------------------- */
1385   NSView *view;
1386   NSTRACE ("x_make_frame_invisible");
1387   check_window_system (f);
1388   view = FRAME_NS_VIEW (f);
1389   [[view window] orderOut: NSApp];
1390   SET_FRAME_VISIBLE (f, 0);
1391   SET_FRAME_ICONIFIED (f, 0);
1395 void
1396 x_iconify_frame (struct frame *f)
1397 /* --------------------------------------------------------------------------
1398      External: Iconify window
1399    -------------------------------------------------------------------------- */
1401   NSView *view;
1402   struct ns_display_info *dpyinfo;
1404   NSTRACE ("x_iconify_frame");
1405   check_window_system (f);
1406   view = FRAME_NS_VIEW (f);
1407   dpyinfo = FRAME_DISPLAY_INFO (f);
1409   if (dpyinfo->x_highlight_frame == f)
1410     dpyinfo->x_highlight_frame = 0;
1412   if ([[view window] windowNumber] <= 0)
1413     {
1414       /* the window is still deferred.  Make it very small, bring it
1415          on screen and order it out. */
1416       NSRect s = { { 100, 100}, {0, 0} };
1417       NSRect t;
1418       t = [[view window] frame];
1419       [[view window] setFrame: s display: NO];
1420       [[view window] orderBack: NSApp];
1421       [[view window] orderOut: NSApp];
1422       [[view window] setFrame: t display: NO];
1423     }
1424   [[view window] miniaturize: NSApp];
1427 /* Free X resources of frame F.  */
1429 void
1430 x_free_frame_resources (struct frame *f)
1432   NSView *view;
1433   struct ns_display_info *dpyinfo;
1434   Mouse_HLInfo *hlinfo;
1436   NSTRACE ("x_free_frame_resources");
1437   check_window_system (f);
1438   view = FRAME_NS_VIEW (f);
1439   dpyinfo = FRAME_DISPLAY_INFO (f);
1440   hlinfo = MOUSE_HL_INFO (f);
1442   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1444   block_input ();
1446   free_frame_menubar (f);
1447   free_frame_faces (f);
1449   if (f == dpyinfo->x_focus_frame)
1450     dpyinfo->x_focus_frame = 0;
1451   if (f == dpyinfo->x_highlight_frame)
1452     dpyinfo->x_highlight_frame = 0;
1453   if (f == hlinfo->mouse_face_mouse_frame)
1454     reset_mouse_highlight (hlinfo);
1456   if (f->output_data.ns->miniimage != nil)
1457     [f->output_data.ns->miniimage release];
1459   [[view window] close];
1460   [view release];
1462   xfree (f->output_data.ns);
1464   unblock_input ();
1467 void
1468 x_destroy_window (struct frame *f)
1469 /* --------------------------------------------------------------------------
1470      External: Delete the window
1471    -------------------------------------------------------------------------- */
1473   NSTRACE ("x_destroy_window");
1474   check_window_system (f);
1475   x_free_frame_resources (f);
1476   ns_window_num--;
1480 void
1481 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1482 /* --------------------------------------------------------------------------
1483      External: Position the window
1484    -------------------------------------------------------------------------- */
1486   NSView *view = FRAME_NS_VIEW (f);
1487   NSArray *screens = [NSScreen screens];
1488   NSScreen *fscreen = [screens objectAtIndex: 0];
1489   NSScreen *screen = [[view window] screen];
1491   NSTRACE ("x_set_offset");
1493   block_input ();
1495   f->left_pos = xoff;
1496   f->top_pos = yoff;
1498   if (view != nil && screen && fscreen)
1499     {
1500       f->left_pos = f->size_hint_flags & XNegative
1501         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1502         : f->left_pos;
1503       /* We use visibleFrame here to take menu bar into account.
1504          Ideally we should also adjust left/top with visibleFrame.origin.  */
1506       f->top_pos = f->size_hint_flags & YNegative
1507         ? ([screen visibleFrame].size.height + f->top_pos
1508            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1509            - FRAME_TOOLBAR_HEIGHT (f))
1510         : f->top_pos;
1511 #ifdef NS_IMPL_GNUSTEP
1512       if (f->left_pos < 100)
1513         f->left_pos = 100;  /* don't overlap menu */
1514 #endif
1515       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1516          menu bar.  */
1517       NSPoint pt = NSMakePoint (SCREENMAXBOUND (f->left_pos),
1518                                 SCREENMAXBOUND ([fscreen frame].size.height
1519                                                 - NS_TOP_POS (f)));
1520       NSTRACE_POINT ("setFrameTopLeftPoint", pt);
1521       [[view window] setFrameTopLeftPoint: pt];
1522       f->size_hint_flags &= ~(XNegative|YNegative);
1523     }
1525   unblock_input ();
1529 void
1530 x_set_window_size (struct frame *f,
1531                    bool change_gravity,
1532                    int width,
1533                    int height,
1534                    bool pixelwise)
1535 /* --------------------------------------------------------------------------
1536      Adjust window pixel size based on given character grid size
1537      Impl is a bit more complex than other terms, need to do some
1538      internal clipping.
1539    -------------------------------------------------------------------------- */
1541   EmacsView *view = FRAME_NS_VIEW (f);
1542   NSWindow *window = [view window];
1543   NSRect wr = [window frame];
1544   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1545   int pixelwidth, pixelheight;
1546   int rows, cols;
1547   int orig_height = wr.size.height;
1549   NSTRACE ("x_set_window_size");
1551   if (view == nil)
1552     return;
1554   NSTRACE_RECT ("current", wr);
1555   NSTRACE_MSG ("Width:%d Height:%d Pixelwise:%d", width, height, pixelwise);
1556   NSTRACE_MSG ("Font %d x %d", FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f));
1558   block_input ();
1560   if (pixelwise)
1561     {
1562       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
1563       pixelheight = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
1564       cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (f, pixelwidth);
1565       rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (f, pixelheight);
1566     }
1567   else
1568     {
1569       pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, width);
1570       pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, height);
1571       cols = width;
1572       rows = height;
1573     }
1575   /* If we have a toolbar, take its height into account. */
1576   if (tb && ! [view isFullscreen])
1577     {
1578     /* NOTE: previously this would generate wrong result if toolbar not
1579              yet displayed and fixing toolbar_height=32 helped, but
1580              now (200903) seems no longer needed */
1581     FRAME_TOOLBAR_HEIGHT (f) =
1582       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1583         - FRAME_NS_TITLEBAR_HEIGHT (f);
1584 #if 0
1585       /* Only breaks things here, removed by martin 2015-09-30.  */
1586 #ifdef NS_IMPL_GNUSTEP
1587       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1588 #endif
1589 #endif
1590     }
1591   else
1592     FRAME_TOOLBAR_HEIGHT (f) = 0;
1594   wr.size.width = pixelwidth + f->border_width;
1595   wr.size.height = pixelheight;
1596   if (! [view isFullscreen])
1597     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1598       + FRAME_TOOLBAR_HEIGHT (f);
1600   /* Do not try to constrain to this screen.  We may have multiple
1601      screens, and want Emacs to span those.  Constraining to screen
1602      prevents that, and that is not nice to the user.  */
1603  if (f->output_data.ns->zooming)
1604    f->output_data.ns->zooming = 0;
1605  else
1606    wr.origin.y += orig_height - wr.size.height;
1608  frame_size_history_add
1609    (f, Qx_set_window_size_1, width, height,
1610     list5 (Fcons (make_number (pixelwidth), make_number (pixelheight)),
1611            Fcons (make_number (wr.size.width), make_number (wr.size.height)),
1612            make_number (f->border_width),
1613            make_number (FRAME_NS_TITLEBAR_HEIGHT (f)),
1614            make_number (FRAME_TOOLBAR_HEIGHT (f))));
1616   [window setFrame: wr display: YES];
1618   /* This is a trick to compensate for Emacs' managing the scrollbar area
1619      as a fixed number of standard character columns.  Instead of leaving
1620      blank space for the extra, we chopped it off above.  Now for
1621      left-hand scrollbars, we shift all rendering to the left by the
1622      difference between the real width and Emacs' imagined one.  For
1623      right-hand bars, don't worry about it since the extra is never used.
1624      (Obviously doesn't work for vertically split windows tho..) */
1625   {
1626     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1627       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1628                      - NS_SCROLL_BAR_WIDTH (f), 0)
1629       : NSMakePoint (0, 0);
1631     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1632     [view setBoundsOrigin: origin];
1633   }
1635   [view updateFrameSize: NO];
1636   unblock_input ();
1640 static void
1641 ns_fullscreen_hook (struct frame *f)
1643   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1645   NSTRACE ("ns_fullscreen_hook");
1647   if (!FRAME_VISIBLE_P (f))
1648     return;
1650    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1651     {
1652       /* Old style fs don't initiate correctly if created from
1653          init/default-frame alist, so use a timer (not nice...).
1654       */
1655       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1656                                      selector: @selector (handleFS)
1657                                      userInfo: nil repeats: NO];
1658       return;
1659     }
1661   block_input ();
1662   [view handleFS];
1663   unblock_input ();
1666 /* ==========================================================================
1668     Color management
1670    ========================================================================== */
1673 NSColor *
1674 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1676   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1677   if (idx < 1 || idx >= color_table->avail)
1678     return nil;
1679   return color_table->colors[idx];
1683 unsigned long
1684 ns_index_color (NSColor *color, struct frame *f)
1686   struct ns_color_table *color_table = FRAME_DISPLAY_INFO (f)->color_table;
1687   ptrdiff_t idx;
1688   ptrdiff_t i;
1690   if (!color_table->colors)
1691     {
1692       color_table->size = NS_COLOR_CAPACITY;
1693       color_table->avail = 1; /* skip idx=0 as marker */
1694       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1695       color_table->colors[0] = nil;
1696       color_table->empty_indices = [[NSMutableSet alloc] init];
1697     }
1699   /* Do we already have this color?  */
1700   for (i = 1; i < color_table->avail; i++)
1701     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1702       return i;
1704   if ([color_table->empty_indices count] > 0)
1705     {
1706       NSNumber *index = [color_table->empty_indices anyObject];
1707       [color_table->empty_indices removeObject: index];
1708       idx = [index unsignedLongValue];
1709     }
1710   else
1711     {
1712       if (color_table->avail == color_table->size)
1713         color_table->colors =
1714           xpalloc (color_table->colors, &color_table->size, 1,
1715                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1716       idx = color_table->avail++;
1717     }
1719   color_table->colors[idx] = color;
1720   [color retain];
1721 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1722   return idx;
1726 void
1727 ns_free_indexed_color (unsigned long idx, struct frame *f)
1729   struct ns_color_table *color_table;
1730   NSColor *color;
1731   NSNumber *index;
1733   if (!f)
1734     return;
1736   color_table = FRAME_DISPLAY_INFO (f)->color_table;
1738   if (idx <= 0 || idx >= color_table->size) {
1739     message1 ("ns_free_indexed_color: Color index out of range.\n");
1740     return;
1741   }
1743   index = [NSNumber numberWithUnsignedInt: idx];
1744   if ([color_table->empty_indices containsObject: index]) {
1745     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1746     return;
1747   }
1749   color = color_table->colors[idx];
1750   [color release];
1751   color_table->colors[idx] = nil;
1752   [color_table->empty_indices addObject: index];
1753 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1757 static int
1758 ns_get_color (const char *name, NSColor **col)
1759 /* --------------------------------------------------------------------------
1760      Parse a color name
1761    -------------------------------------------------------------------------- */
1762 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1763    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1764    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1766   NSColor *new = nil;
1767   static char hex[20];
1768   int scaling = 0;
1769   float r = -1.0, g, b;
1770   NSString *nsname = [NSString stringWithUTF8String: name];
1772   NSTRACE ("ns_get_color(%s, **)", name);
1774   block_input ();
1776   if ([nsname isEqualToString: @"ns_selection_bg_color"])
1777     {
1778 #ifdef NS_IMPL_COCOA
1779       NSString *defname = [[NSUserDefaults standardUserDefaults]
1780                             stringForKey: @"AppleHighlightColor"];
1781       if (defname != nil)
1782         nsname = defname;
1783       else
1784 #endif
1785       if ((new = [NSColor selectedTextBackgroundColor]) != nil)
1786         {
1787           *col = [new colorUsingDefaultColorSpace];
1788           unblock_input ();
1789           return 0;
1790         }
1791       else
1792         nsname = NS_SELECTION_BG_COLOR_DEFAULT;
1794       name = [nsname UTF8String];
1795     }
1796   else if ([nsname isEqualToString: @"ns_selection_fg_color"])
1797     {
1798       /* NOTE: OSX applications normally don't set foreground selection, but
1799          text may be unreadable if we don't.
1800       */
1801       if ((new = [NSColor selectedTextColor]) != nil)
1802         {
1803           *col = [new colorUsingDefaultColorSpace];
1804           unblock_input ();
1805           return 0;
1806         }
1808       nsname = NS_SELECTION_FG_COLOR_DEFAULT;
1809       name = [nsname UTF8String];
1810     }
1812   /* First, check for some sort of numeric specification. */
1813   hex[0] = '\0';
1815   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1816     {
1817       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1818       [scanner scanFloat: &r];
1819       [scanner scanFloat: &g];
1820       [scanner scanFloat: &b];
1821     }
1822   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1823     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1824   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1825     {
1826       int len = (strlen(name) - 1);
1827       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1828       int i;
1829       scaling = strlen(name+start) / 3;
1830       for (i = 0; i < 3; i++)
1831         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1832                  name + start + i * scaling);
1833       hex[3 * (scaling + 1) - 1] = '\0';
1834     }
1836   if (hex[0])
1837     {
1838       int rr, gg, bb;
1839       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1840       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1841         {
1842           r = rr / fscale;
1843           g = gg / fscale;
1844           b = bb / fscale;
1845         }
1846     }
1848   if (r >= 0.0F)
1849     {
1850       *col = [NSColor colorForEmacsRed: r green: g blue: b alpha: 1.0];
1851       unblock_input ();
1852       return 0;
1853     }
1855   /* Otherwise, color is expected to be from a list */
1856   {
1857     NSEnumerator *lenum, *cenum;
1858     NSString *name;
1859     NSColorList *clist;
1861 #ifdef NS_IMPL_GNUSTEP
1862     /* XXX: who is wrong, the requestor or the implementation? */
1863     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1864         == NSOrderedSame)
1865       nsname = @"highlightColor";
1866 #endif
1868     lenum = [[NSColorList availableColorLists] objectEnumerator];
1869     while ( (clist = [lenum nextObject]) && new == nil)
1870       {
1871         cenum = [[clist allKeys] objectEnumerator];
1872         while ( (name = [cenum nextObject]) && new == nil )
1873           {
1874             if ([name compare: nsname
1875                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1876               new = [clist colorWithKey: name];
1877           }
1878       }
1879   }
1881   if (new)
1882     *col = [new colorUsingDefaultColorSpace];
1883   unblock_input ();
1884   return new ? 0 : 1;
1889 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1890 /* --------------------------------------------------------------------------
1891      Convert a Lisp string object to a NS color
1892    -------------------------------------------------------------------------- */
1894   NSTRACE ("ns_lisp_to_color");
1895   if (STRINGP (color))
1896     return ns_get_color (SSDATA (color), col);
1897   else if (SYMBOLP (color))
1898     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1899   return 1;
1903 Lisp_Object
1904 ns_color_to_lisp (NSColor *col)
1905 /* --------------------------------------------------------------------------
1906      Convert a color to a lisp string with the RGB equivalent
1907    -------------------------------------------------------------------------- */
1909   EmacsCGFloat red, green, blue, alpha, gray;
1910   char buf[1024];
1911   const char *str;
1912   NSTRACE ("ns_color_to_lisp");
1914   block_input ();
1915   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1917       if ((str =[[col colorNameComponent] UTF8String]))
1918         {
1919           unblock_input ();
1920           return build_string ((char *)str);
1921         }
1923     [[col colorUsingDefaultColorSpace]
1924         getRed: &red green: &green blue: &blue alpha: &alpha];
1925   if (red == green && red == blue)
1926     {
1927       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1928             getWhite: &gray alpha: &alpha];
1929       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1930                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1931       unblock_input ();
1932       return build_string (buf);
1933     }
1935   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1936             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1938   unblock_input ();
1939   return build_string (buf);
1943 void
1944 ns_query_color(void *col, XColor *color_def, int setPixel)
1945 /* --------------------------------------------------------------------------
1946          Get ARGB values out of NSColor col and put them into color_def.
1947          If setPixel, set the pixel to a concatenated version.
1948          and set color_def pixel to the resulting index.
1949    -------------------------------------------------------------------------- */
1951   EmacsCGFloat r, g, b, a;
1953   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1954   color_def->red   = r * 65535;
1955   color_def->green = g * 65535;
1956   color_def->blue  = b * 65535;
1958   if (setPixel == YES)
1959     color_def->pixel
1960       = ARGB_TO_ULONG((int)(a*255),
1961                       (int)(r*255), (int)(g*255), (int)(b*255));
1965 bool
1966 ns_defined_color (struct frame *f,
1967                   const char *name,
1968                   XColor *color_def,
1969                   bool alloc,
1970                   bool makeIndex)
1971 /* --------------------------------------------------------------------------
1972          Return true if named color found, and set color_def rgb accordingly.
1973          If makeIndex and alloc are nonzero put the color in the color_table,
1974          and set color_def pixel to the resulting index.
1975          If makeIndex is zero, set color_def pixel to ARGB.
1976          Return false if not found
1977    -------------------------------------------------------------------------- */
1979   NSColor *col;
1980   NSTRACE_WHEN (NSTRACE_GROUP_COLOR, "ns_defined_color");
1982   block_input ();
1983   if (ns_get_color (name, &col) != 0) /* Color not found  */
1984     {
1985       unblock_input ();
1986       return 0;
1987     }
1988   if (makeIndex && alloc)
1989     color_def->pixel = ns_index_color (col, f);
1990   ns_query_color (col, color_def, !makeIndex);
1991   unblock_input ();
1992   return 1;
1996 void
1997 x_set_frame_alpha (struct frame *f)
1998 /* --------------------------------------------------------------------------
1999      change the entire-frame transparency
2000    -------------------------------------------------------------------------- */
2002   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
2003   double alpha = 1.0;
2004   double alpha_min = 1.0;
2006   NSTRACE ("x_set_frame_alpha");
2008   if (dpyinfo->x_highlight_frame == f)
2009     alpha = f->alpha[0];
2010   else
2011     alpha = f->alpha[1];
2013   if (FLOATP (Vframe_alpha_lower_limit))
2014     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
2015   else if (INTEGERP (Vframe_alpha_lower_limit))
2016     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
2018   if (alpha < 0.0)
2019     return;
2020   else if (1.0 < alpha)
2021     alpha = 1.0;
2022   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
2023     alpha = alpha_min;
2025 #ifdef NS_IMPL_COCOA
2026   {
2027     EmacsView *view = FRAME_NS_VIEW (f);
2028   [[view window] setAlphaValue: alpha];
2029   }
2030 #endif
2034 /* ==========================================================================
2036     Mouse handling
2038    ========================================================================== */
2041 void
2042 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
2043 /* --------------------------------------------------------------------------
2044      Programmatically reposition mouse pointer in pixel coordinates
2045    -------------------------------------------------------------------------- */
2047   NSTRACE ("frame_set_mouse_pixel_position");
2048   ns_raise_frame (f);
2049 #if 0
2050   /* FIXME: this does not work, and what about GNUstep? */
2051 #ifdef NS_IMPL_COCOA
2052   [FRAME_NS_VIEW (f) lockFocus];
2053   PSsetmouse ((float)pix_x, (float)pix_y);
2054   [FRAME_NS_VIEW (f) unlockFocus];
2055 #endif
2056 #endif
2059 static int
2060 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
2061 /*   ------------------------------------------------------------------------
2062      Called by EmacsView on mouseMovement events.  Passes on
2063      to emacs mainstream code if we moved off of a rect of interest
2064      known as last_mouse_glyph.
2065      ------------------------------------------------------------------------ */
2067   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
2068   NSRect *r;
2070 //  NSTRACE ("note_mouse_movement");
2072   dpyinfo->last_mouse_motion_frame = frame;
2073   r = &dpyinfo->last_mouse_glyph;
2075   /* Note, this doesn't get called for enter/leave, since we don't have a
2076      position.  Those are taken care of in the corresponding NSView methods. */
2078   /* has movement gone beyond last rect we were tracking? */
2079   if (x < r->origin.x || x >= r->origin.x + r->size.width
2080       || y < r->origin.y || y >= r->origin.y + r->size.height)
2081     {
2082       ns_update_begin (frame);
2083       frame->mouse_moved = 1;
2084       note_mouse_highlight (frame, x, y);
2085       remember_mouse_glyph (frame, x, y, r);
2086       ns_update_end (frame);
2087       return 1;
2088     }
2090   return 0;
2094 static void
2095 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
2096                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
2097                    Time *time)
2098 /* --------------------------------------------------------------------------
2099     External (hook): inform emacs about mouse position and hit parts.
2100     If a scrollbar is being dragged, set bar_window, part, x, y, time.
2101     x & y should be position in the scrollbar (the whole bar, not the handle)
2102     and length of scrollbar respectively
2103    -------------------------------------------------------------------------- */
2105   id view;
2106   NSPoint position;
2107   Lisp_Object frame, tail;
2108   struct frame *f;
2109   struct ns_display_info *dpyinfo;
2111   NSTRACE ("ns_mouse_position");
2113   if (*fp == NULL)
2114     {
2115       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
2116       return;
2117     }
2119   dpyinfo = FRAME_DISPLAY_INFO (*fp);
2121   block_input ();
2123   /* Clear the mouse-moved flag for every frame on this display.  */
2124   FOR_EACH_FRAME (tail, frame)
2125     if (FRAME_NS_P (XFRAME (frame))
2126         && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
2127       XFRAME (frame)->mouse_moved = 0;
2129   dpyinfo->last_mouse_scroll_bar = nil;
2130   if (dpyinfo->last_mouse_frame
2131       && FRAME_LIVE_P (dpyinfo->last_mouse_frame))
2132     f = dpyinfo->last_mouse_frame;
2133   else
2134     f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame : SELECTED_FRAME ();
2136   if (f && FRAME_NS_P (f))
2137     {
2138       view = FRAME_NS_VIEW (*fp);
2140       position = [[view window] mouseLocationOutsideOfEventStream];
2141       position = [view convertPoint: position fromView: nil];
2142       remember_mouse_glyph (f, position.x, position.y,
2143                             &dpyinfo->last_mouse_glyph);
2144       NSTRACE_POINT ("position", position);
2146       if (bar_window) *bar_window = Qnil;
2147       if (part) *part = scroll_bar_above_handle;
2149       if (x) XSETINT (*x, lrint (position.x));
2150       if (y) XSETINT (*y, lrint (position.y));
2151       if (time)
2152         *time = dpyinfo->last_mouse_movement_time;
2153       *fp = f;
2154     }
2156   unblock_input ();
2160 static void
2161 ns_frame_up_to_date (struct frame *f)
2162 /* --------------------------------------------------------------------------
2163     External (hook): Fix up mouse highlighting right after a full update.
2164     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
2165    -------------------------------------------------------------------------- */
2167   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_frame_up_to_date");
2169   if (FRAME_NS_P (f))
2170     {
2171       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
2172       if (f == hlinfo->mouse_face_mouse_frame)
2173         {
2174           block_input ();
2175           ns_update_begin(f);
2176           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
2177                                 hlinfo->mouse_face_mouse_x,
2178                                 hlinfo->mouse_face_mouse_y);
2179           ns_update_end(f);
2180           unblock_input ();
2181         }
2182     }
2186 static void
2187 ns_define_frame_cursor (struct frame *f, Cursor cursor)
2188 /* --------------------------------------------------------------------------
2189     External (RIF): set frame mouse pointer type.
2190    -------------------------------------------------------------------------- */
2192   NSTRACE ("ns_define_frame_cursor");
2193   if (FRAME_POINTER_TYPE (f) != cursor)
2194     {
2195       EmacsView *view = FRAME_NS_VIEW (f);
2196       FRAME_POINTER_TYPE (f) = cursor;
2197       [[view window] invalidateCursorRectsForView: view];
2198       /* Redisplay assumes this function also draws the changed frame
2199          cursor, but this function doesn't, so do it explicitly.  */
2200       x_update_cursor (f, 1);
2201     }
2206 /* ==========================================================================
2208     Keyboard handling
2210    ========================================================================== */
2213 static unsigned
2214 ns_convert_key (unsigned code)
2215 /* --------------------------------------------------------------------------
2216     Internal call used by NSView-keyDown.
2217    -------------------------------------------------------------------------- */
2219   const unsigned last_keysym = ARRAYELTS (convert_ns_to_X_keysym);
2220   unsigned keysym;
2221   /* An array would be faster, but less easy to read. */
2222   for (keysym = 0; keysym < last_keysym; keysym += 2)
2223     if (code == convert_ns_to_X_keysym[keysym])
2224       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
2225   return 0;
2226 /* if decide to use keyCode and Carbon table, use this line:
2227      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
2231 char *
2232 x_get_keysym_name (int keysym)
2233 /* --------------------------------------------------------------------------
2234     Called by keyboard.c.  Not sure if the return val is important, except
2235     that it be unique.
2236    -------------------------------------------------------------------------- */
2238   static char value[16];
2239   NSTRACE ("x_get_keysym_name");
2240   sprintf (value, "%d", keysym);
2241   return value;
2246 /* ==========================================================================
2248     Block drawing operations
2250    ========================================================================== */
2253 static void
2254 ns_redraw_scroll_bars (struct frame *f)
2256   int i;
2257   id view;
2258   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
2259   NSTRACE ("ns_redraw_scroll_bars");
2260   for (i =[subviews count]-1; i >= 0; i--)
2261     {
2262       view = [subviews objectAtIndex: i];
2263       if (![view isKindOfClass: [EmacsScroller class]]) continue;
2264       [view display];
2265     }
2269 void
2270 ns_clear_frame (struct frame *f)
2271 /* --------------------------------------------------------------------------
2272       External (hook): Erase the entire frame
2273    -------------------------------------------------------------------------- */
2275   NSView *view = FRAME_NS_VIEW (f);
2276   NSRect r;
2278   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame");
2280  /* comes on initial frame because we have
2281     after-make-frame-functions = select-frame */
2282  if (!FRAME_DEFAULT_FACE (f))
2283    return;
2285   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2287   r = [view bounds];
2289   block_input ();
2290   ns_focus (f, &r, 1);
2291   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2292   NSRectFill (r);
2293   ns_unfocus (f);
2295   /* as of 2006/11 or so this is now needed */
2296   ns_redraw_scroll_bars (f);
2297   unblock_input ();
2301 static void
2302 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2303 /* --------------------------------------------------------------------------
2304     External (RIF):  Clear section of frame
2305    -------------------------------------------------------------------------- */
2307   NSRect r = NSMakeRect (x, y, width, height);
2308   NSView *view = FRAME_NS_VIEW (f);
2309   struct face *face = FRAME_DEFAULT_FACE (f);
2311   if (!view || !face)
2312     return;
2314   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_clear_frame_area");
2316   r = NSIntersectionRect (r, [view frame]);
2317   ns_focus (f, &r, 1);
2318   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2320   NSRectFill (r);
2322   ns_unfocus (f);
2323   return;
2326 static void
2327 ns_copy_bits (struct frame *f, NSRect src, NSRect dest)
2329   if (FRAME_NS_VIEW (f))
2330     {
2331       ns_focus (f, &dest, 1);
2332       [FRAME_NS_VIEW (f) scrollRect: src
2333                                  by: NSMakeSize (dest.origin.x - src.origin.x,
2334                                                  dest.origin.y - src.origin.y)];
2335       ns_unfocus (f);
2336     }
2339 static void
2340 ns_scroll_run (struct window *w, struct run *run)
2341 /* --------------------------------------------------------------------------
2342     External (RIF):  Insert or delete n lines at line vpos
2343    -------------------------------------------------------------------------- */
2345   struct frame *f = XFRAME (w->frame);
2346   int x, y, width, height, from_y, to_y, bottom_y;
2348   NSTRACE ("ns_scroll_run");
2350   /* begin copy from other terms */
2351   /* Get frame-relative bounding box of the text display area of W,
2352      without mode lines.  Include in this box the left and right
2353      fringe of W.  */
2354   window_box (w, ANY_AREA, &x, &y, &width, &height);
2356   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2357   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2358   bottom_y = y + height;
2360   if (to_y < from_y)
2361     {
2362       /* Scrolling up.  Make sure we don't copy part of the mode
2363          line at the bottom.  */
2364       if (from_y + run->height > bottom_y)
2365         height = bottom_y - from_y;
2366       else
2367         height = run->height;
2368     }
2369   else
2370     {
2371       /* Scrolling down.  Make sure we don't copy over the mode line.
2372          at the bottom.  */
2373       if (to_y + run->height > bottom_y)
2374         height = bottom_y - to_y;
2375       else
2376         height = run->height;
2377     }
2378   /* end copy from other terms */
2380   if (height == 0)
2381       return;
2383   block_input ();
2385   x_clear_cursor (w);
2387   {
2388     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2389     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2391     ns_copy_bits (f, srcRect , dstRect);
2392   }
2394   unblock_input ();
2398 static void
2399 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2400 /* --------------------------------------------------------------------------
2401     External (RIF): preparatory to fringe update after text was updated
2402    -------------------------------------------------------------------------- */
2404   struct frame *f;
2405   int width, height;
2407   NSTRACE_WHEN (NSTRACE_GROUP_UPDATES, "ns_after_update_window_line");
2409   /* begin copy from other terms */
2410   eassert (w);
2412   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2413     desired_row->redraw_fringe_bitmaps_p = 1;
2415   /* When a window has disappeared, make sure that no rest of
2416      full-width rows stays visible in the internal border.  */
2417   if (windows_or_buffers_changed
2418       && desired_row->full_width_p
2419       && (f = XFRAME (w->frame),
2420           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2421           width != 0)
2422       && (height = desired_row->visible_height,
2423           height > 0))
2424     {
2425       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2427       block_input ();
2428       ns_clear_frame_area (f, 0, y, width, height);
2429       ns_clear_frame_area (f,
2430                            FRAME_PIXEL_WIDTH (f) - width,
2431                            y, width, height);
2432       unblock_input ();
2433     }
2437 static void
2438 ns_shift_glyphs_for_insert (struct frame *f,
2439                            int x, int y, int width, int height,
2440                            int shift_by)
2441 /* --------------------------------------------------------------------------
2442     External (RIF): copy an area horizontally, don't worry about clearing src
2443    -------------------------------------------------------------------------- */
2445   NSRect srcRect = NSMakeRect (x, y, width, height);
2446   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2448   NSTRACE ("ns_shift_glyphs_for_insert");
2450   ns_copy_bits (f, srcRect, dstRect);
2455 /* ==========================================================================
2457     Character encoding and metrics
2459    ========================================================================== */
2462 static void
2463 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2464 /* --------------------------------------------------------------------------
2465      External (RIF); compute left/right overhang of whole string and set in s
2466    -------------------------------------------------------------------------- */
2468   struct font *font = s->font;
2470   if (s->char2b)
2471     {
2472       struct font_metrics metrics;
2473       unsigned int codes[2];
2474       codes[0] = *(s->char2b);
2475       codes[1] = *(s->char2b + s->nchars - 1);
2477       font->driver->text_extents (font, codes, 2, &metrics);
2478       s->left_overhang = -metrics.lbearing;
2479       s->right_overhang
2480         = metrics.rbearing > metrics.width
2481         ? metrics.rbearing - metrics.width : 0;
2482     }
2483   else
2484     {
2485       s->left_overhang = 0;
2486       if (EQ (font->driver->type, Qns))
2487         s->right_overhang = ((struct nsfont_info *)font)->ital ?
2488           FONT_HEIGHT (font) * 0.2 : 0;
2489       else
2490         s->right_overhang = 0;
2491     }
2496 /* ==========================================================================
2498     Fringe and cursor drawing
2500    ========================================================================== */
2503 extern int max_used_fringe_bitmap;
2504 static void
2505 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2506                       struct draw_fringe_bitmap_params *p)
2507 /* --------------------------------------------------------------------------
2508     External (RIF); fringe-related
2509    -------------------------------------------------------------------------- */
2511   /* Fringe bitmaps comes in two variants, normal and periodic.  A
2512      periodic bitmap is used to create a continuous pattern.  Since a
2513      bitmap is rendered one text line at a time, the start offset (dh)
2514      of the bitmap varies.  Concretely, this is used for the empty
2515      line indicator.
2517      For a bitmap, "h + dh" is the full height and is always
2518      invariant.  For a normal bitmap "dh" is zero.
2520      For example, when the period is three and the full height is 72
2521      the following combinations exists:
2523        h=72 dh=0
2524        h=71 dh=1
2525        h=70 dh=2 */
2527   struct frame *f = XFRAME (WINDOW_FRAME (w));
2528   struct face *face = p->face;
2529   static EmacsImage **bimgs = NULL;
2530   static int nBimgs = 0;
2532   NSTRACE_WHEN (NSTRACE_GROUP_FRINGE, "ns_draw_fringe_bitmap");
2533   NSTRACE_MSG ("which:%d cursor:%d overlay:%d width:%d height:%d period:%d",
2534                p->which, p->cursor_p, p->overlay_p, p->wd, p->h, p->dh);
2536   /* grow bimgs if needed */
2537   if (nBimgs < max_used_fringe_bitmap)
2538     {
2539       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2540       memset (bimgs + nBimgs, 0,
2541               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2542       nBimgs = max_used_fringe_bitmap;
2543     }
2545   /* Must clip because of partially visible lines.  */
2546   ns_clip_to_row (w, row, ANY_AREA, YES);
2548   if (!p->overlay_p)
2549     {
2550       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2552       if (bx >= 0 && nx > 0)
2553         {
2554           NSRect r = NSMakeRect (bx, by, nx, ny);
2555           NSRectClip (r);
2556           [ns_lookup_indexed_color (face->background, f) set];
2557           NSRectFill (r);
2558         }
2559     }
2561   if (p->which)
2562     {
2563       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2564       EmacsImage *img = bimgs[p->which - 1];
2566       if (!img)
2567         {
2568           // Note: For "periodic" images, allocate one EmacsImage for
2569           // the base image, and use it for all dh:s.
2570           unsigned short *bits = p->bits;
2571           int full_height = p->h + p->dh;
2572           int i;
2573           unsigned char *cbits = xmalloc (full_height);
2575           for (i = 0; i < full_height; i++)
2576             cbits[i] = bits[i];
2577           img = [[EmacsImage alloc] initFromXBM: cbits width: 8
2578                                          height: full_height
2579                                              fg: 0 bg: 0];
2580           bimgs[p->which - 1] = img;
2581           xfree (cbits);
2582         }
2584       NSTRACE_RECT ("r", r);
2586       NSRectClip (r);
2587       /* Since we composite the bitmap instead of just blitting it, we need
2588          to erase the whole background. */
2589       [ns_lookup_indexed_color(face->background, f) set];
2590       NSRectFill (r);
2592       {
2593         NSColor *bm_color;
2594         if (!p->cursor_p)
2595           bm_color = ns_lookup_indexed_color(face->foreground, f);
2596         else if (p->overlay_p)
2597           bm_color = ns_lookup_indexed_color(face->background, f);
2598         else
2599           bm_color = f->output_data.ns->cursor_color;
2600         [img setXBMColor: bm_color];
2601       }
2603       // Note: For periodic images, the full image height is "h + hd".
2604       // By using the height h, a suitable part of the image is used.
2605       NSRect fromRect = NSMakeRect(0, 0, p->wd, p->h);
2607       NSTRACE_RECT ("fromRect", fromRect);
2609 #ifdef NS_IMPL_COCOA
2610       [img drawInRect: r
2611               fromRect: fromRect
2612              operation: NSCompositeSourceOver
2613               fraction: 1.0
2614            respectFlipped: YES
2615                 hints: nil];
2616 #else
2617       {
2618         NSPoint pt = r.origin;
2619         pt.y += p->h;
2620         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2621       }
2622 #endif
2623     }
2624   ns_unfocus (f);
2628 static void
2629 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2630                        int x, int y, enum text_cursor_kinds cursor_type,
2631                        int cursor_width, bool on_p, bool active_p)
2632 /* --------------------------------------------------------------------------
2633      External call (RIF): draw cursor.
2634      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2635    -------------------------------------------------------------------------- */
2637   NSRect r, s;
2638   int fx, fy, h, cursor_height;
2639   struct frame *f = WINDOW_XFRAME (w);
2640   struct glyph *phys_cursor_glyph;
2641   struct glyph *cursor_glyph;
2642   struct face *face;
2643   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2645   /* If cursor is out of bounds, don't draw garbage.  This can happen
2646      in mini-buffer windows when switching between echo area glyphs
2647      and mini-buffer.  */
2649   NSTRACE ("ns_draw_window_cursor");
2651   if (!on_p)
2652     return;
2654   w->phys_cursor_type = cursor_type;
2655   w->phys_cursor_on_p = on_p;
2657   if (cursor_type == NO_CURSOR)
2658     {
2659       w->phys_cursor_width = 0;
2660       return;
2661     }
2663   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2664     {
2665       if (glyph_row->exact_window_width_line_p
2666           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2667         {
2668           glyph_row->cursor_in_fringe_p = 1;
2669           draw_fringe_bitmap (w, glyph_row, 0);
2670         }
2671       return;
2672     }
2674   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2675      (other terminals do it the other way round).  We must set
2676      w->phys_cursor_width to the cursor width.  For bar cursors, that
2677      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2678   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2680   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2681      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2682   if (cursor_type == BAR_CURSOR)
2683     {
2684       if (cursor_width < 1)
2685         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2686       w->phys_cursor_width = cursor_width;
2687     }
2688   /* If we have an HBAR, "cursor_width" MAY specify height. */
2689   else if (cursor_type == HBAR_CURSOR)
2690     {
2691       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2692       if (cursor_height > glyph_row->height)
2693         cursor_height = glyph_row->height;
2694       if (h > cursor_height) // Cursor smaller than line height, move down
2695         fy += h - cursor_height;
2696       h = cursor_height;
2697     }
2699   r.origin.x = fx, r.origin.y = fy;
2700   r.size.height = h;
2701   r.size.width = w->phys_cursor_width;
2703   /* TODO: only needed in rare cases with last-resort font in HELLO..
2704      should we do this more efficiently? */
2705   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2708   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2709   if (face && NS_FACE_BACKGROUND (face)
2710       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2711     {
2712       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2713       hollow_color = FRAME_CURSOR_COLOR (f);
2714     }
2715   else
2716     [FRAME_CURSOR_COLOR (f) set];
2718 #ifdef NS_IMPL_COCOA
2719   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2720            atomic.  Cleaner ways of doing this should be investigated.
2721            One way would be to set a global variable DRAWING_CURSOR
2722            when making the call to draw_phys..(), don't focus in that
2723            case, then move the ns_unfocus() here after that call. */
2724   NSDisableScreenUpdates ();
2725 #endif
2727   switch (cursor_type)
2728     {
2729     case DEFAULT_CURSOR:
2730     case NO_CURSOR:
2731       break;
2732     case FILLED_BOX_CURSOR:
2733       NSRectFill (r);
2734       break;
2735     case HOLLOW_BOX_CURSOR:
2736       NSRectFill (r);
2737       [hollow_color set];
2738       NSRectFill (NSInsetRect (r, 1, 1));
2739       [FRAME_CURSOR_COLOR (f) set];
2740       break;
2741     case HBAR_CURSOR:
2742       NSRectFill (r);
2743       break;
2744     case BAR_CURSOR:
2745       s = r;
2746       /* If the character under cursor is R2L, draw the bar cursor
2747          on the right of its glyph, rather than on the left.  */
2748       cursor_glyph = get_phys_cursor_glyph (w);
2749       if ((cursor_glyph->resolved_level & 1) != 0)
2750         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2752       NSRectFill (s);
2753       break;
2754     }
2755   ns_unfocus (f);
2757   /* draw the character under the cursor */
2758   if (cursor_type != NO_CURSOR)
2759     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2761 #ifdef NS_IMPL_COCOA
2762   NSEnableScreenUpdates ();
2763 #endif
2768 static void
2769 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2770 /* --------------------------------------------------------------------------
2771      External (RIF): Draw a vertical line.
2772    -------------------------------------------------------------------------- */
2774   struct frame *f = XFRAME (WINDOW_FRAME (w));
2775   struct face *face;
2776   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2778   NSTRACE ("ns_draw_vertical_window_border");
2780   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2781   if (face)
2782       [ns_lookup_indexed_color(face->foreground, f) set];
2784   ns_focus (f, &r, 1);
2785   NSRectFill(r);
2786   ns_unfocus (f);
2790 static void
2791 ns_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
2792 /* --------------------------------------------------------------------------
2793      External (RIF): Draw a window divider.
2794    -------------------------------------------------------------------------- */
2796   struct frame *f = XFRAME (WINDOW_FRAME (w));
2797   struct face *face;
2798   NSRect r = NSMakeRect (x0, y0, x1-x0, y1-y0);
2800   NSTRACE ("ns_draw_window_divider");
2802   face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID);
2803   if (face)
2804       [ns_lookup_indexed_color(face->foreground, f) set];
2806   ns_focus (f, &r, 1);
2807   NSRectFill(r);
2808   ns_unfocus (f);
2811 static void
2812 ns_show_hourglass (struct frame *f)
2814   /* TODO: add NSProgressIndicator to all frames.  */
2817 static void
2818 ns_hide_hourglass (struct frame *f)
2820   /* TODO: remove NSProgressIndicator from all frames.  */
2823 /* ==========================================================================
2825     Glyph drawing operations
2827    ========================================================================== */
2829 static int
2830 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2831 /* --------------------------------------------------------------------------
2832     Wrapper utility to account for internal border width on full-width lines,
2833     and allow top full-width rows to hit the frame top.  nr should be pointer
2834     to two successive NSRects.  Number of rects actually used is returned.
2835    -------------------------------------------------------------------------- */
2837   int n = get_glyph_string_clip_rects (s, nr, 2);
2838   return n;
2841 /* --------------------------------------------------------------------
2842    Draw a wavy line under glyph string s. The wave fills wave_height
2843    pixels from y.
2845                     x          wave_length = 2
2846                                  --
2847                 y    *   *   *   *   *
2848                      |* * * * * * * * *
2849     wave_height = 3  | *   *   *   *
2850   --------------------------------------------------------------------- */
2852 static void
2853 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2855   int wave_height = 3, wave_length = 2;
2856   int y, dx, dy, odd, xmax;
2857   NSPoint a, b;
2858   NSRect waveClip;
2860   dx = wave_length;
2861   dy = wave_height - 1;
2862   y =  s->ybase - wave_height + 3;
2863   xmax = x + width;
2865   /* Find and set clipping rectangle */
2866   waveClip = NSMakeRect (x, y, width, wave_height);
2867   [[NSGraphicsContext currentContext] saveGraphicsState];
2868   NSRectClip (waveClip);
2870   /* Draw the waves */
2871   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2872   b.x = a.x + dx;
2873   odd = (int)(a.x/dx) % 2;
2874   a.y = b.y = y + 0.5;
2876   if (odd)
2877     a.y += dy;
2878   else
2879     b.y += dy;
2881   while (a.x <= xmax)
2882     {
2883       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2884       a.x = b.x, a.y = b.y;
2885       b.x += dx, b.y = y + 0.5 + odd*dy;
2886       odd = !odd;
2887     }
2889   /* Restore previous clipping rectangle(s) */
2890   [[NSGraphicsContext currentContext] restoreGraphicsState];
2895 void
2896 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2897                          NSColor *defaultCol, CGFloat width, CGFloat x)
2898 /* --------------------------------------------------------------------------
2899    Draw underline, overline, and strike-through on glyph string s.
2900    -------------------------------------------------------------------------- */
2902   if (s->for_overlaps)
2903     return;
2905   /* Do underline. */
2906   if (face->underline_p)
2907     {
2908       if (s->face->underline_type == FACE_UNDER_WAVE)
2909         {
2910           if (face->underline_defaulted_p)
2911             [defaultCol set];
2912           else
2913             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2915           ns_draw_underwave (s, width, x);
2916         }
2917       else if (s->face->underline_type == FACE_UNDER_LINE)
2918         {
2920           NSRect r;
2921           unsigned long thickness, position;
2923           /* If the prev was underlined, match its appearance. */
2924           if (s->prev && s->prev->face->underline_p
2925               && s->prev->face->underline_type == FACE_UNDER_LINE
2926               && s->prev->underline_thickness > 0)
2927             {
2928               thickness = s->prev->underline_thickness;
2929               position = s->prev->underline_position;
2930             }
2931           else
2932             {
2933               struct font *font;
2934               unsigned long descent;
2936               font=s->font;
2937               descent = s->y + s->height - s->ybase;
2939               /* Use underline thickness of font, defaulting to 1. */
2940               thickness = (font && font->underline_thickness > 0)
2941                 ? font->underline_thickness : 1;
2943               /* Determine the offset of underlining from the baseline. */
2944               if (x_underline_at_descent_line)
2945                 position = descent - thickness;
2946               else if (x_use_underline_position_properties
2947                        && font && font->underline_position >= 0)
2948                 position = font->underline_position;
2949               else if (font)
2950                 position = lround (font->descent / 2);
2951               else
2952                 position = underline_minimum_offset;
2954               position = max (position, underline_minimum_offset);
2956               /* Ensure underlining is not cropped. */
2957               if (descent <= position)
2958                 {
2959                   position = descent - 1;
2960                   thickness = 1;
2961                 }
2962               else if (descent < position + thickness)
2963                 thickness = 1;
2964             }
2966           s->underline_thickness = thickness;
2967           s->underline_position = position;
2969           r = NSMakeRect (x, s->ybase + position, width, thickness);
2971           if (face->underline_defaulted_p)
2972             [defaultCol set];
2973           else
2974             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2975           NSRectFill (r);
2976         }
2977     }
2978   /* Do overline. We follow other terms in using a thickness of 1
2979      and ignoring overline_margin. */
2980   if (face->overline_p)
2981     {
2982       NSRect r;
2983       r = NSMakeRect (x, s->y, width, 1);
2985       if (face->overline_color_defaulted_p)
2986         [defaultCol set];
2987       else
2988         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2989       NSRectFill (r);
2990     }
2992   /* Do strike-through.  We follow other terms for thickness and
2993      vertical position.*/
2994   if (face->strike_through_p)
2995     {
2996       NSRect r;
2997       unsigned long dy;
2999       dy = lrint ((s->height - 1) / 2);
3000       r = NSMakeRect (x, s->y + dy, width, 1);
3002       if (face->strike_through_color_defaulted_p)
3003         [defaultCol set];
3004       else
3005         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
3006       NSRectFill (r);
3007     }
3010 static void
3011 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
3012              char left_p, char right_p)
3013 /* --------------------------------------------------------------------------
3014     Draw an unfilled rect inside r, optionally leaving left and/or right open.
3015     Note we can't just use an NSDrawRect command, because of the possibility
3016     of some sides not being drawn, and because the rect will be filled.
3017    -------------------------------------------------------------------------- */
3019   NSRect s = r;
3020   [col set];
3022   /* top, bottom */
3023   s.size.height = thickness;
3024   NSRectFill (s);
3025   s.origin.y += r.size.height - thickness;
3026   NSRectFill (s);
3028   s.size.height = r.size.height;
3029   s.origin.y = r.origin.y;
3031   /* left, right (optional) */
3032   s.size.width = thickness;
3033   if (left_p)
3034     NSRectFill (s);
3035   if (right_p)
3036     {
3037       s.origin.x += r.size.width - thickness;
3038       NSRectFill (s);
3039     }
3043 static void
3044 ns_draw_relief (NSRect r, int thickness, char raised_p,
3045                char top_p, char bottom_p, char left_p, char right_p,
3046                struct glyph_string *s)
3047 /* --------------------------------------------------------------------------
3048     Draw a relief rect inside r, optionally leaving some sides open.
3049     Note we can't just use an NSDrawBezel command, because of the possibility
3050     of some sides not being drawn, and because the rect will be filled.
3051    -------------------------------------------------------------------------- */
3053   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
3054   NSColor *newBaseCol = nil;
3055   NSRect sr = r;
3057   NSTRACE ("ns_draw_relief");
3059   /* set up colors */
3061   if (s->face->use_box_color_for_shadows_p)
3062     {
3063       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
3064     }
3065 /*     else if (s->first_glyph->type == IMAGE_GLYPH
3066            && s->img->pixmap
3067            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
3068        {
3069          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
3070        } */
3071   else
3072     {
3073       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
3074     }
3076   if (newBaseCol == nil)
3077     newBaseCol = [NSColor grayColor];
3079   if (newBaseCol != baseCol)  /* TODO: better check */
3080     {
3081       [baseCol release];
3082       baseCol = [newBaseCol retain];
3083       [lightCol release];
3084       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
3085       [darkCol release];
3086       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
3087     }
3089   [(raised_p ? lightCol : darkCol) set];
3091   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
3093   /* top */
3094   sr.size.height = thickness;
3095   if (top_p) NSRectFill (sr);
3097   /* left */
3098   sr.size.height = r.size.height;
3099   sr.size.width = thickness;
3100   if (left_p) NSRectFill (sr);
3102   [(raised_p ? darkCol : lightCol) set];
3104   /* bottom */
3105   sr.size.width = r.size.width;
3106   sr.size.height = thickness;
3107   sr.origin.y += r.size.height - thickness;
3108   if (bottom_p) NSRectFill (sr);
3110   /* right */
3111   sr.size.height = r.size.height;
3112   sr.origin.y = r.origin.y;
3113   sr.size.width = thickness;
3114   sr.origin.x += r.size.width - thickness;
3115   if (right_p) NSRectFill (sr);
3119 static void
3120 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
3121 /* --------------------------------------------------------------------------
3122       Function modeled after x_draw_glyph_string_box ().
3123       Sets up parameters for drawing.
3124    -------------------------------------------------------------------------- */
3126   int right_x, last_x;
3127   char left_p, right_p;
3128   struct glyph *last_glyph;
3129   NSRect r;
3130   int thickness;
3131   struct face *face;
3133   if (s->hl == DRAW_MOUSE_FACE)
3134     {
3135       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3136       if (!face)
3137         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3138     }
3139   else
3140     face = s->face;
3142   thickness = face->box_line_width;
3144   NSTRACE ("ns_dumpglyphs_box_or_relief");
3146   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
3147             ? WINDOW_RIGHT_EDGE_X (s->w)
3148             : window_box_right (s->w, s->area));
3149   last_glyph = (s->cmp || s->img
3150                 ? s->first_glyph : s->first_glyph + s->nchars-1);
3152   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
3153               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
3155   left_p = (s->first_glyph->left_box_line_p
3156             || (s->hl == DRAW_MOUSE_FACE
3157                 && (s->prev == NULL || s->prev->hl != s->hl)));
3158   right_p = (last_glyph->right_box_line_p
3159              || (s->hl == DRAW_MOUSE_FACE
3160                  && (s->next == NULL || s->next->hl != s->hl)));
3162   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
3164   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
3165   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
3166     {
3167       ns_draw_box (r, abs (thickness),
3168                    ns_lookup_indexed_color (face->box_color, s->f),
3169                   left_p, right_p);
3170     }
3171   else
3172     {
3173       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
3174                      1, 1, left_p, right_p, s);
3175     }
3179 static void
3180 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
3181 /* --------------------------------------------------------------------------
3182       Modeled after x_draw_glyph_string_background, which draws BG in
3183       certain cases.  Others are left to the text rendering routine.
3184    -------------------------------------------------------------------------- */
3186   NSTRACE ("ns_maybe_dumpglyphs_background");
3188   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
3189     {
3190       int box_line_width = max (s->face->box_line_width, 0);
3191       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
3192           /* When xdisp.c ignores FONT_HEIGHT, we cannot trust font
3193              dimensions, since the actual glyphs might be much
3194              smaller.  So in that case we always clear the rectangle
3195              with background color.  */
3196           || FONT_TOO_HIGH (s->font)
3197           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
3198         {
3199           struct face *face;
3200           if (s->hl == DRAW_MOUSE_FACE)
3201             {
3202               face = FACE_FROM_ID (s->f,
3203                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3204               if (!face)
3205                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3206             }
3207           else
3208             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3209           if (!face->stipple)
3210             [(NS_FACE_BACKGROUND (face) != 0
3211               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
3212               : FRAME_BACKGROUND_COLOR (s->f)) set];
3213           else
3214             {
3215               struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (s->f);
3216               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
3217             }
3219           if (s->hl != DRAW_CURSOR)
3220             {
3221               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
3222                                     s->background_width,
3223                                     s->height-2*box_line_width);
3224               NSRectFill (r);
3225             }
3227           s->background_filled_p = 1;
3228         }
3229     }
3233 static void
3234 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
3235 /* --------------------------------------------------------------------------
3236       Renders an image and associated borders.
3237    -------------------------------------------------------------------------- */
3239   EmacsImage *img = s->img->pixmap;
3240   int box_line_vwidth = max (s->face->box_line_width, 0);
3241   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
3242   int bg_x, bg_y, bg_height;
3243   int th;
3244   char raised_p;
3245   NSRect br;
3246   struct face *face;
3247   NSColor *tdCol;
3249   NSTRACE ("ns_dumpglyphs_image");
3251   if (s->face->box != FACE_NO_BOX
3252       && s->first_glyph->left_box_line_p && s->slice.x == 0)
3253     x += abs (s->face->box_line_width);
3255   bg_x = x;
3256   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
3257   bg_height = s->height;
3258   /* other terms have this, but was causing problems w/tabbar mode */
3259   /* - 2 * box_line_vwidth; */
3261   if (s->slice.x == 0) x += s->img->hmargin;
3262   if (s->slice.y == 0) y += s->img->vmargin;
3264   /* Draw BG: if we need larger area than image itself cleared, do that,
3265      otherwise, since we composite the image under NS (instead of mucking
3266      with its background color), we must clear just the image area. */
3267   if (s->hl == DRAW_MOUSE_FACE)
3268     {
3269       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3270       if (!face)
3271        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3272     }
3273   else
3274     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3276   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
3278   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
3279       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
3280     {
3281       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
3282       s->background_filled_p = 1;
3283     }
3284   else
3285     {
3286       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3287     }
3289   NSRectFill (br);
3291   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3292   if (img != nil)
3293     {
3294 #ifdef NS_IMPL_COCOA
3295       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3296       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3297                               s->slice.width, s->slice.height);
3298       [img drawInRect: dr
3299              fromRect: ir
3300              operation: NSCompositeSourceOver
3301               fraction: 1.0
3302            respectFlipped: YES
3303                 hints: nil];
3304 #else
3305       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3306                   operation: NSCompositeSourceOver];
3307 #endif
3308     }
3310   if (s->hl == DRAW_CURSOR)
3311     {
3312     [FRAME_CURSOR_COLOR (s->f) set];
3313     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3314       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3315     else
3316       /* Currently on NS img->mask is always 0. Since
3317          get_window_cursor_type specifies a hollow box cursor when on
3318          a non-masked image we never reach this clause. But we put it
3319          in in anticipation of better support for image masks on
3320          NS. */
3321       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3322     }
3323   else
3324     {
3325       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3326     }
3328   /* Draw underline, overline, strike-through. */
3329   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3331   /* Draw relief, if requested */
3332   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3333     {
3334       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3335         {
3336           th = tool_bar_button_relief >= 0 ?
3337             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3338           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3339         }
3340       else
3341         {
3342           th = abs (s->img->relief);
3343           raised_p = (s->img->relief > 0);
3344         }
3346       r.origin.x = x - th;
3347       r.origin.y = y - th;
3348       r.size.width = s->slice.width + 2*th-1;
3349       r.size.height = s->slice.height + 2*th-1;
3350       ns_draw_relief (r, th, raised_p,
3351                       s->slice.y == 0,
3352                       s->slice.y + s->slice.height == s->img->height,
3353                       s->slice.x == 0,
3354                       s->slice.x + s->slice.width == s->img->width, s);
3355     }
3357   /* If there is no mask, the background won't be seen,
3358      so draw a rectangle on the image for the cursor.
3359      Do this for all images, getting transparency right is not reliable.  */
3360   if (s->hl == DRAW_CURSOR)
3361     {
3362       int thickness = abs (s->img->relief);
3363       if (thickness == 0) thickness = 1;
3364       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3365     }
3369 static void
3370 ns_dumpglyphs_stretch (struct glyph_string *s)
3372   NSRect r[2];
3373   int n, i;
3374   struct face *face;
3375   NSColor *fgCol, *bgCol;
3377   if (!s->background_filled_p)
3378     {
3379       n = ns_get_glyph_string_clip_rect (s, r);
3380       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3382       ns_focus (s->f, r, n);
3384       if (s->hl == DRAW_MOUSE_FACE)
3385        {
3386          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3387          if (!face)
3388            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3389        }
3390       else
3391        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3393       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3394       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3396       for (i = 0; i < n; ++i)
3397         {
3398           if (!s->row->full_width_p)
3399             {
3400               int overrun, leftoverrun;
3402               /* truncate to avoid overwriting fringe and/or scrollbar */
3403               overrun = max (0, (s->x + s->background_width)
3404                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3405                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3406               r[i].size.width -= overrun;
3408               /* truncate to avoid overwriting to left of the window box */
3409               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3410                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3412               if (leftoverrun > 0)
3413                 {
3414                   r[i].origin.x += leftoverrun;
3415                   r[i].size.width -= leftoverrun;
3416                 }
3418               /* XXX: Try to work between problem where a stretch glyph on
3419                  a partially-visible bottom row will clear part of the
3420                  modeline, and another where list-buffers headers and similar
3421                  rows erroneously have visible_height set to 0.  Not sure
3422                  where this is coming from as other terms seem not to show. */
3423               r[i].size.height = min (s->height, s->row->visible_height);
3424             }
3426           [bgCol set];
3428           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3429              overwriting cursor (usually when cursor on a tab) */
3430           if (s->hl == DRAW_CURSOR)
3431             {
3432               CGFloat x, width;
3434               x = r[i].origin.x;
3435               width = s->w->phys_cursor_width;
3436               r[i].size.width -= width;
3437               r[i].origin.x += width;
3439               NSRectFill (r[i]);
3441               /* Draw overlining, etc. on the cursor. */
3442               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3443                 ns_draw_text_decoration (s, face, bgCol, width, x);
3444               else
3445                 ns_draw_text_decoration (s, face, fgCol, width, x);
3446             }
3447           else
3448             {
3449               NSRectFill (r[i]);
3450             }
3452           /* Draw overlining, etc. on the stretch glyph (or the part
3453              of the stretch glyph after the cursor). */
3454           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3455                                    r[i].origin.x);
3456         }
3457       ns_unfocus (s->f);
3458       s->background_filled_p = 1;
3459     }
3463 static void
3464 ns_draw_composite_glyph_string_foreground (struct glyph_string *s)
3466   int i, j, x;
3467   struct font *font = s->font;
3469   /* If first glyph of S has a left box line, start drawing the text
3470      of S to the right of that box line.  */
3471   if (s->face && s->face->box != FACE_NO_BOX
3472       && s->first_glyph->left_box_line_p)
3473     x = s->x + eabs (s->face->box_line_width);
3474   else
3475     x = s->x;
3477   /* S is a glyph string for a composition.  S->cmp_from is the index
3478      of the first character drawn for glyphs of this composition.
3479      S->cmp_from == 0 means we are drawing the very first character of
3480      this composition.  */
3482   /* Draw a rectangle for the composition if the font for the very
3483      first character of the composition could not be loaded.  */
3484   if (s->font_not_found_p)
3485     {
3486       if (s->cmp_from == 0)
3487         {
3488           NSRect r = NSMakeRect (s->x, s->y, s->width-1, s->height -1);
3489           ns_draw_box (r, 1, FRAME_CURSOR_COLOR (s->f), 1, 1);
3490         }
3491     }
3492   else if (! s->first_glyph->u.cmp.automatic)
3493     {
3494       int y = s->ybase;
3496       for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
3497         /* TAB in a composition means display glyphs with padding
3498            space on the left or right.  */
3499         if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
3500           {
3501             int xx = x + s->cmp->offsets[j * 2];
3502             int yy = y - s->cmp->offsets[j * 2 + 1];
3504             font->driver->draw (s, j, j + 1, xx, yy, false);
3505             if (s->face->overstrike)
3506               font->driver->draw (s, j, j + 1, xx + 1, yy, false);
3507           }
3508     }
3509   else
3510     {
3511       Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
3512       Lisp_Object glyph;
3513       int y = s->ybase;
3514       int width = 0;
3516       for (i = j = s->cmp_from; i < s->cmp_to; i++)
3517         {
3518           glyph = LGSTRING_GLYPH (gstring, i);
3519           if (NILP (LGLYPH_ADJUSTMENT (glyph)))
3520             width += LGLYPH_WIDTH (glyph);
3521           else
3522             {
3523               int xoff, yoff, wadjust;
3525               if (j < i)
3526                 {
3527                   font->driver->draw (s, j, i, x, y, false);
3528                   if (s->face->overstrike)
3529                     font->driver->draw (s, j, i, x + 1, y, false);
3530                   x += width;
3531                 }
3532               xoff = LGLYPH_XOFF (glyph);
3533               yoff = LGLYPH_YOFF (glyph);
3534               wadjust = LGLYPH_WADJUST (glyph);
3535               font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
3536               if (s->face->overstrike)
3537                 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
3538                                     false);
3539               x += wadjust;
3540               j = i + 1;
3541               width = 0;
3542             }
3543         }
3544       if (j < i)
3545         {
3546           font->driver->draw (s, j, i, x, y, false);
3547           if (s->face->overstrike)
3548             font->driver->draw (s, j, i, x + 1, y, false);
3549         }
3550     }
3553 static void
3554 ns_draw_glyph_string (struct glyph_string *s)
3555 /* --------------------------------------------------------------------------
3556       External (RIF): Main draw-text call.
3557    -------------------------------------------------------------------------- */
3559   /* TODO (optimize): focus for box and contents draw */
3560   NSRect r[2];
3561   int n, flags;
3562   char box_drawn_p = 0;
3563   struct font *font = s->face->font;
3564   if (! font) font = FRAME_FONT (s->f);
3566   NSTRACE_WHEN (NSTRACE_GROUP_GLYPHS, "ns_draw_glyph_string");
3568   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3569     {
3570       int width;
3571       struct glyph_string *next;
3573       for (width = 0, next = s->next;
3574            next && width < s->right_overhang;
3575            width += next->width, next = next->next)
3576         if (next->first_glyph->type != IMAGE_GLYPH)
3577           {
3578             if (next->first_glyph->type != STRETCH_GLYPH)
3579               {
3580                 n = ns_get_glyph_string_clip_rect (s->next, r);
3581                 ns_focus (s->f, r, n);
3582                 ns_maybe_dumpglyphs_background (s->next, 1);
3583                 ns_unfocus (s->f);
3584               }
3585             else
3586               {
3587                 ns_dumpglyphs_stretch (s->next);
3588               }
3589             next->num_clips = 0;
3590           }
3591     }
3593   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3594         && (s->first_glyph->type == CHAR_GLYPH
3595             || s->first_glyph->type == COMPOSITE_GLYPH))
3596     {
3597       n = ns_get_glyph_string_clip_rect (s, r);
3598       ns_focus (s->f, r, n);
3599       ns_maybe_dumpglyphs_background (s, 1);
3600       ns_dumpglyphs_box_or_relief (s);
3601       ns_unfocus (s->f);
3602       box_drawn_p = 1;
3603     }
3605   switch (s->first_glyph->type)
3606     {
3608     case IMAGE_GLYPH:
3609       n = ns_get_glyph_string_clip_rect (s, r);
3610       ns_focus (s->f, r, n);
3611       ns_dumpglyphs_image (s, r[0]);
3612       ns_unfocus (s->f);
3613       break;
3615     case STRETCH_GLYPH:
3616       ns_dumpglyphs_stretch (s);
3617       break;
3619     case CHAR_GLYPH:
3620     case COMPOSITE_GLYPH:
3621       n = ns_get_glyph_string_clip_rect (s, r);
3622       ns_focus (s->f, r, n);
3624       if (s->for_overlaps || (s->cmp_from > 0
3625                               && ! s->first_glyph->u.cmp.automatic))
3626         s->background_filled_p = 1;
3627       else
3628         ns_maybe_dumpglyphs_background
3629           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3631       flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3632         (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3633          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3634           NS_DUMPGLYPH_NORMAL));
3636       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3637         {
3638           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3639           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3640           NS_FACE_FOREGROUND (s->face) = tmp;
3641         }
3643       {
3644         BOOL isComposite = s->first_glyph->type == COMPOSITE_GLYPH;
3646         if (isComposite)
3647           ns_draw_composite_glyph_string_foreground (s);
3648         else
3649           font->driver->draw
3650             (s, s->cmp_from, s->nchars, s->x, s->ybase,
3651              (flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3652              || flags == NS_DUMPGLYPH_MOUSEFACE);
3653       }
3655       {
3656         NSColor *col = (NS_FACE_FOREGROUND (s->face) != 0
3657                         ? ns_lookup_indexed_color (NS_FACE_FOREGROUND (s->face),
3658                                                    s->f)
3659                         : FRAME_FOREGROUND_COLOR (s->f));
3660         [col set];
3662         /* Draw underline, overline, strike-through. */
3663         ns_draw_text_decoration (s, s->face, col, s->width, s->x);
3664       }
3666       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3667         {
3668           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3669           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3670           NS_FACE_FOREGROUND (s->face) = tmp;
3671         }
3673       ns_unfocus (s->f);
3674       break;
3676     case GLYPHLESS_GLYPH:
3677       n = ns_get_glyph_string_clip_rect (s, r);
3678       ns_focus (s->f, r, n);
3680       if (s->for_overlaps || (s->cmp_from > 0
3681                               && ! s->first_glyph->u.cmp.automatic))
3682         s->background_filled_p = 1;
3683       else
3684         ns_maybe_dumpglyphs_background
3685           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3686       /* ... */
3687       /* Not yet implemented.  */
3688       /* ... */
3689       ns_unfocus (s->f);
3690       break;
3692     default:
3693       emacs_abort ();
3694     }
3696   /* Draw box if not done already. */
3697   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3698     {
3699       n = ns_get_glyph_string_clip_rect (s, r);
3700       ns_focus (s->f, r, n);
3701       ns_dumpglyphs_box_or_relief (s);
3702       ns_unfocus (s->f);
3703     }
3705   s->num_clips = 0;
3710 /* ==========================================================================
3712     Event loop
3714    ========================================================================== */
3717 static void
3718 ns_send_appdefined (int value)
3719 /* --------------------------------------------------------------------------
3720     Internal: post an appdefined event which EmacsApp-sendEvent will
3721               recognize and take as a command to halt the event loop.
3722    -------------------------------------------------------------------------- */
3724   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_send_appdefined(%d)", value);
3726 #ifdef NS_IMPL_GNUSTEP
3727   // GNUstep needs postEvent to happen on the main thread.
3728   if (! [[NSThread currentThread] isMainThread])
3729     {
3730       EmacsApp *app = (EmacsApp *)NSApp;
3731       app->nextappdefined = value;
3732       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3733                             withObject:nil
3734                          waitUntilDone:YES];
3735       return;
3736     }
3737 #endif
3739   /* Only post this event if we haven't already posted one.  This will end
3740        the [NXApp run] main loop after having processed all events queued at
3741        this moment.  */
3743 #ifdef NS_IMPL_COCOA
3744   if (! send_appdefined)
3745     {
3746       /* OSX 10.10.1 swallows the AppDefined event we are sending ourselves
3747          in certain situations (rapid incoming events).
3748          So check if we have one, if not add one.  */
3749       NSEvent *appev = [NSApp nextEventMatchingMask:NSApplicationDefinedMask
3750                                           untilDate:[NSDate distantPast]
3751                                              inMode:NSDefaultRunLoopMode
3752                                             dequeue:NO];
3753       if (! appev) send_appdefined = YES;
3754     }
3755 #endif
3757   if (send_appdefined)
3758     {
3759       NSEvent *nxev;
3761       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3762       send_appdefined = NO;
3764       /* Don't need wakeup timer any more */
3765       if (timed_entry)
3766         {
3767           [timed_entry invalidate];
3768           [timed_entry release];
3769           timed_entry = nil;
3770         }
3772       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3773                                 location: NSMakePoint (0, 0)
3774                            modifierFlags: 0
3775                                timestamp: 0
3776                             windowNumber: [[NSApp mainWindow] windowNumber]
3777                                  context: [NSApp context]
3778                                  subtype: 0
3779                                    data1: value
3780                                    data2: 0];
3782       /* Post an application defined event on the event queue.  When this is
3783          received the [NXApp run] will return, thus having processed all
3784          events which are currently queued.  */
3785       [NSApp postEvent: nxev atStart: NO];
3786     }
3789 #ifdef HAVE_NATIVE_FS
3790 static void
3791 check_native_fs ()
3793   Lisp_Object frame, tail;
3795   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3796     return;
3798   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3800   FOR_EACH_FRAME (tail, frame)
3801     {
3802       struct frame *f = XFRAME (frame);
3803       if (FRAME_NS_P (f))
3804         {
3805           EmacsView *view = FRAME_NS_VIEW (f);
3806           [view updateCollectionBehavior];
3807         }
3808     }
3810 #endif
3812 /* GNUstep does not have cancelTracking.  */
3813 #ifdef NS_IMPL_COCOA
3814 /* Check if menu open should be canceled or continued as normal.  */
3815 void
3816 ns_check_menu_open (NSMenu *menu)
3818   /* Click in menu bar? */
3819   NSArray *a = [[NSApp mainMenu] itemArray];
3820   int i;
3821   BOOL found = NO;
3823   if (menu == nil) // Menu tracking ended.
3824     {
3825       if (menu_will_open_state == MENU_OPENING)
3826         menu_will_open_state = MENU_NONE;
3827       return;
3828     }
3830   for (i = 0; ! found && i < [a count]; i++)
3831     found = menu == [[a objectAtIndex:i] submenu];
3832   if (found)
3833     {
3834       if (menu_will_open_state == MENU_NONE && emacs_event)
3835         {
3836           NSEvent *theEvent = [NSApp currentEvent];
3837           struct frame *emacsframe = SELECTED_FRAME ();
3839           [menu cancelTracking];
3840           menu_will_open_state = MENU_PENDING;
3841           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3842           EV_TRAILER (theEvent);
3844           CGEventRef ourEvent = CGEventCreate (NULL);
3845           menu_mouse_point = CGEventGetLocation (ourEvent);
3846           CFRelease (ourEvent);
3847         }
3848       else if (menu_will_open_state == MENU_OPENING)
3849         {
3850           menu_will_open_state = MENU_NONE;
3851         }
3852     }
3855 /* Redo saved menu click if state is MENU_PENDING.  */
3856 void
3857 ns_check_pending_open_menu ()
3859   if (menu_will_open_state == MENU_PENDING)
3860     {
3861       CGEventSourceRef source
3862         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3864       CGEventRef event = CGEventCreateMouseEvent (source,
3865                                                   kCGEventLeftMouseDown,
3866                                                   menu_mouse_point,
3867                                                   kCGMouseButtonLeft);
3868       CGEventSetType (event, kCGEventLeftMouseDown);
3869       CGEventPost (kCGHIDEventTap, event);
3870       CFRelease (event);
3871       CFRelease (source);
3873       menu_will_open_state = MENU_OPENING;
3874     }
3876 #endif /* NS_IMPL_COCOA */
3878 static void
3879 unwind_apploopnr (Lisp_Object not_used)
3881   --apploopnr;
3882   n_emacs_events_pending = 0;
3883   ns_finish_events ();
3884   q_event_ptr = NULL;
3887 static int
3888 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3889 /* --------------------------------------------------------------------------
3890      External (hook): Post an event to ourself and keep reading events until
3891      we read it back again.  In effect process all events which were waiting.
3892      From 21+ we have to manage the event buffer ourselves.
3893    -------------------------------------------------------------------------- */
3895   struct input_event ev;
3896   int nevents;
3898   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_read_socket");
3900 #ifdef HAVE_NATIVE_FS
3901   check_native_fs ();
3902 #endif
3904   if ([NSApp modalWindow] != nil)
3905     return -1;
3907   if (hold_event_q.nr > 0)
3908     {
3909       int i;
3910       for (i = 0; i < hold_event_q.nr; ++i)
3911         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3912       hold_event_q.nr = 0;
3913       return i;
3914     }
3916   block_input ();
3917   n_emacs_events_pending = 0;
3918   ns_init_events (&ev);
3919   q_event_ptr = hold_quit;
3921   /* we manage autorelease pools by allocate/reallocate each time around
3922      the loop; strict nesting is occasionally violated but seems not to
3923      matter.. earlier methods using full nesting caused major memory leaks */
3924   [outerpool release];
3925   outerpool = [[NSAutoreleasePool alloc] init];
3927   /* If have pending open-file requests, attend to the next one of those. */
3928   if (ns_pending_files && [ns_pending_files count] != 0
3929       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3930     {
3931       [ns_pending_files removeObjectAtIndex: 0];
3932     }
3933   /* Deal with pending service requests. */
3934   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3935     && [(EmacsApp *)
3936          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3937                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3938     {
3939       [ns_pending_service_names removeObjectAtIndex: 0];
3940       [ns_pending_service_args removeObjectAtIndex: 0];
3941     }
3942   else
3943     {
3944       ptrdiff_t specpdl_count = SPECPDL_INDEX ();
3945       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3946          to ourself, otherwise [NXApp run] will never exit.  */
3947       send_appdefined = YES;
3948       ns_send_appdefined (-1);
3950       if (++apploopnr != 1)
3951         {
3952           emacs_abort ();
3953         }
3954       record_unwind_protect (unwind_apploopnr, Qt);
3955       [NSApp run];
3956       unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
3957     }
3959   nevents = n_emacs_events_pending;
3960   n_emacs_events_pending = 0;
3961   ns_finish_events ();
3962   q_event_ptr = NULL;
3963   unblock_input ();
3965   return nevents;
3970 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3971            fd_set *exceptfds, struct timespec const *timeout,
3972            sigset_t const *sigmask)
3973 /* --------------------------------------------------------------------------
3974      Replacement for select, checking for events
3975    -------------------------------------------------------------------------- */
3977   int result;
3978   int t, k, nr = 0;
3979   struct input_event event;
3980   char c;
3982   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "ns_select");
3984 #ifdef HAVE_NATIVE_FS
3985   check_native_fs ();
3986 #endif
3988   if (hold_event_q.nr > 0)
3989     {
3990       /* We already have events pending. */
3991       raise (SIGIO);
3992       errno = EINTR;
3993       return -1;
3994     }
3996   for (k = 0; k < nfds+1; k++)
3997     {
3998       if (readfds && FD_ISSET(k, readfds)) ++nr;
3999       if (writefds && FD_ISSET(k, writefds)) ++nr;
4000     }
4002   if (NSApp == nil
4003       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
4004     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
4006   [outerpool release];
4007   outerpool = [[NSAutoreleasePool alloc] init];
4010   send_appdefined = YES;
4011   if (nr > 0)
4012     {
4013       pthread_mutex_lock (&select_mutex);
4014       select_nfds = nfds;
4015       select_valid = 0;
4016       if (readfds)
4017         {
4018           select_readfds = *readfds;
4019           select_valid += SELECT_HAVE_READ;
4020         }
4021       if (writefds)
4022         {
4023           select_writefds = *writefds;
4024           select_valid += SELECT_HAVE_WRITE;
4025         }
4027       if (timeout)
4028         {
4029           select_timeout = *timeout;
4030           select_valid += SELECT_HAVE_TMO;
4031         }
4033       pthread_mutex_unlock (&select_mutex);
4035       /* Inform fd_handler that select should be called */
4036       c = 'g';
4037       emacs_write_sig (selfds[1], &c, 1);
4038     }
4039   else if (nr == 0 && timeout)
4040     {
4041       /* No file descriptor, just a timeout, no need to wake fd_handler  */
4042       double time = timespectod (*timeout);
4043       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
4044                                                       target: NSApp
4045                                                     selector:
4046                                   @selector (timeout_handler:)
4047                                                     userInfo: 0
4048                                                      repeats: NO]
4049                       retain];
4050     }
4051   else /* No timeout and no file descriptors, can this happen?  */
4052     {
4053       /* Send appdefined so we exit from the loop */
4054       ns_send_appdefined (-1);
4055     }
4057   block_input ();
4058   ns_init_events (&event);
4059   if (++apploopnr != 1)
4060     {
4061       emacs_abort ();
4062     }
4064   {
4065     ptrdiff_t specpdl_count = SPECPDL_INDEX ();
4066     record_unwind_protect (unwind_apploopnr, Qt);
4067     [NSApp run];
4068     unbind_to (specpdl_count, Qnil);  /* calls unwind_apploopnr */
4069   }
4071   ns_finish_events ();
4072   if (nr > 0 && readfds)
4073     {
4074       c = 's';
4075       emacs_write_sig (selfds[1], &c, 1);
4076     }
4077   unblock_input ();
4079   t = last_appdefined_event_data;
4081   if (t != NO_APPDEFINED_DATA)
4082     {
4083       last_appdefined_event_data = NO_APPDEFINED_DATA;
4085       if (t == -2)
4086         {
4087           /* The NX_APPDEFINED event we received was a timeout. */
4088           result = 0;
4089         }
4090       else if (t == -1)
4091         {
4092           /* The NX_APPDEFINED event we received was the result of
4093              at least one real input event arriving.  */
4094           errno = EINTR;
4095           result = -1;
4096         }
4097       else
4098         {
4099           /* Received back from select () in fd_handler; copy the results */
4100           pthread_mutex_lock (&select_mutex);
4101           if (readfds) *readfds = select_readfds;
4102           if (writefds) *writefds = select_writefds;
4103           pthread_mutex_unlock (&select_mutex);
4104           result = t;
4105         }
4106     }
4107   else
4108     {
4109       errno = EINTR;
4110       result = -1;
4111     }
4113   return result;
4118 /* ==========================================================================
4120     Scrollbar handling
4122    ========================================================================== */
4125 static void
4126 ns_set_vertical_scroll_bar (struct window *window,
4127                            int portion, int whole, int position)
4128 /* --------------------------------------------------------------------------
4129       External (hook): Update or add scrollbar
4130    -------------------------------------------------------------------------- */
4132   Lisp_Object win;
4133   NSRect r, v;
4134   struct frame *f = XFRAME (WINDOW_FRAME (window));
4135   EmacsView *view = FRAME_NS_VIEW (f);
4136   EmacsScroller *bar;
4137   int window_y, window_height;
4138   int top, left, height, width;
4139   BOOL update_p = YES;
4141   /* optimization; display engine sends WAY too many of these.. */
4142   if (!NILP (window->vertical_scroll_bar))
4143     {
4144       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4145       if ([bar checkSamePosition: position portion: portion whole: whole])
4146         {
4147           if (view->scrollbarsNeedingUpdate == 0)
4148             {
4149               if (!windows_or_buffers_changed)
4150                   return;
4151             }
4152           else
4153             view->scrollbarsNeedingUpdate--;
4154           update_p = NO;
4155         }
4156     }
4158   NSTRACE ("ns_set_vertical_scroll_bar");
4160   /* Get dimensions.  */
4161   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
4162   top = window_y;
4163   height = window_height;
4164   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
4165   left = WINDOW_SCROLL_BAR_AREA_X (window);
4167   r = NSMakeRect (left, top, width, height);
4168   /* the parent view is flipped, so we need to flip y value */
4169   v = [view frame];
4170   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4172   XSETWINDOW (win, window);
4173   block_input ();
4175   /* we want at least 5 lines to display a scrollbar */
4176   if (WINDOW_TOTAL_LINES (window) < 5)
4177     {
4178       if (!NILP (window->vertical_scroll_bar))
4179         {
4180           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4181           [bar removeFromSuperview];
4182           wset_vertical_scroll_bar (window, Qnil);
4183           [bar release];
4184         }
4185       ns_clear_frame_area (f, left, top, width, height);
4186       unblock_input ();
4187       return;
4188     }
4190   if (NILP (window->vertical_scroll_bar))
4191     {
4192       if (width > 0 && height > 0)
4193         ns_clear_frame_area (f, left, top, width, height);
4195       bar = [[EmacsScroller alloc] initFrame: r window: win];
4196       wset_vertical_scroll_bar (window, make_save_ptr (bar));
4197       update_p = YES;
4198     }
4199   else
4200     {
4201       NSRect oldRect;
4202       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4203       oldRect = [bar frame];
4204       r.size.width = oldRect.size.width;
4205       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4206         {
4207           if (oldRect.origin.x != r.origin.x)
4208               ns_clear_frame_area (f, left, top, width, height);
4209           [bar setFrame: r];
4210         }
4211     }
4213   if (update_p)
4214     [bar setPosition: position portion: portion whole: whole];
4215   unblock_input ();
4219 static void
4220 ns_set_horizontal_scroll_bar (struct window *window,
4221                               int portion, int whole, int position)
4222 /* --------------------------------------------------------------------------
4223       External (hook): Update or add scrollbar
4224    -------------------------------------------------------------------------- */
4226   Lisp_Object win;
4227   NSRect r, v;
4228   struct frame *f = XFRAME (WINDOW_FRAME (window));
4229   EmacsView *view = FRAME_NS_VIEW (f);
4230   EmacsScroller *bar;
4231   int top, height, left, width;
4232   int window_x, window_width;
4233   BOOL update_p = YES;
4235   /* optimization; display engine sends WAY too many of these.. */
4236   if (!NILP (window->horizontal_scroll_bar))
4237     {
4238       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4239       if ([bar checkSamePosition: position portion: portion whole: whole])
4240         {
4241           if (view->scrollbarsNeedingUpdate == 0)
4242             {
4243               if (!windows_or_buffers_changed)
4244                   return;
4245             }
4246           else
4247             view->scrollbarsNeedingUpdate--;
4248           update_p = NO;
4249         }
4250     }
4252   NSTRACE ("ns_set_horizontal_scroll_bar");
4254   /* Get dimensions.  */
4255   window_box (window, ANY_AREA, 0, &window_x, &window_width, 0);
4256   left = window_x;
4257   width = window_width;
4258   height = WINDOW_CONFIG_SCROLL_BAR_LINES (window) * FRAME_LINE_HEIGHT (f);
4259   top = WINDOW_SCROLL_BAR_AREA_Y (window);
4261   r = NSMakeRect (left, top, width, height);
4262   /* the parent view is flipped, so we need to flip y value */
4263   v = [view frame];
4264   /* ??????? PXW/scrollbars !!!!!!!!!!!!!!!!!!!! */
4265   r.origin.y = (v.size.height - r.size.height - r.origin.y);
4267   XSETWINDOW (win, window);
4268   block_input ();
4270   if (WINDOW_TOTAL_COLS (window) < 5)
4271     {
4272       if (!NILP (window->horizontal_scroll_bar))
4273         {
4274           bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4275           [bar removeFromSuperview];
4276           wset_horizontal_scroll_bar (window, Qnil);
4277         }
4278       ns_clear_frame_area (f, left, top, width, height);
4279       unblock_input ();
4280       return;
4281     }
4283   if (NILP (window->horizontal_scroll_bar))
4284     {
4285       if (width > 0 && height > 0)
4286         ns_clear_frame_area (f, left, top, width, height);
4288       bar = [[EmacsScroller alloc] initFrame: r window: win];
4289       wset_horizontal_scroll_bar (window, make_save_ptr (bar));
4290       update_p = YES;
4291     }
4292   else
4293     {
4294       NSRect oldRect;
4295       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4296       oldRect = [bar frame];
4297       r.size.width = oldRect.size.width;
4298       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
4299         {
4300           if (oldRect.origin.x != r.origin.x)
4301               ns_clear_frame_area (f, left, top, width, height);
4302           [bar setFrame: r];
4303           update_p = YES;
4304         }
4305     }
4307   if (update_p)
4308     [bar setPosition: position portion: portion whole: whole];
4309   unblock_input ();
4313 static void
4314 ns_condemn_scroll_bars (struct frame *f)
4315 /* --------------------------------------------------------------------------
4316      External (hook): arrange for all frame's scrollbars to be removed
4317      at next call to judge_scroll_bars, except for those redeemed.
4318    -------------------------------------------------------------------------- */
4320   int i;
4321   id view;
4322   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
4324   NSTRACE ("ns_condemn_scroll_bars");
4326   for (i =[subviews count]-1; i >= 0; i--)
4327     {
4328       view = [subviews objectAtIndex: i];
4329       if ([view isKindOfClass: [EmacsScroller class]])
4330         [view condemn];
4331     }
4335 static void
4336 ns_redeem_scroll_bar (struct window *window)
4337 /* --------------------------------------------------------------------------
4338      External (hook): arrange to spare this window's scrollbar
4339      at next call to judge_scroll_bars.
4340    -------------------------------------------------------------------------- */
4342   id bar;
4343   NSTRACE ("ns_redeem_scroll_bar");
4344   if (!NILP (window->vertical_scroll_bar))
4345     {
4346       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
4347       [bar reprieve];
4348     }
4350   if (!NILP (window->horizontal_scroll_bar))
4351     {
4352       bar = XNS_SCROLL_BAR (window->horizontal_scroll_bar);
4353       [bar reprieve];
4354     }
4358 static void
4359 ns_judge_scroll_bars (struct frame *f)
4360 /* --------------------------------------------------------------------------
4361      External (hook): destroy all scrollbars on frame that weren't
4362      redeemed after call to condemn_scroll_bars.
4363    -------------------------------------------------------------------------- */
4365   int i;
4366   id view;
4367   EmacsView *eview = FRAME_NS_VIEW (f);
4368   NSArray *subviews = [[eview superview] subviews];
4369   BOOL removed = NO;
4371   NSTRACE ("ns_judge_scroll_bars");
4372   for (i = [subviews count]-1; i >= 0; --i)
4373     {
4374       view = [subviews objectAtIndex: i];
4375       if (![view isKindOfClass: [EmacsScroller class]]) continue;
4376       if ([view judge])
4377         removed = YES;
4378     }
4380   if (removed)
4381     [eview updateFrameSize: NO];
4384 /* ==========================================================================
4386     Initialization
4388    ========================================================================== */
4391 x_display_pixel_height (struct ns_display_info *dpyinfo)
4393   NSArray *screens = [NSScreen screens];
4394   NSEnumerator *enumerator = [screens objectEnumerator];
4395   NSScreen *screen;
4396   NSRect frame;
4398   frame = NSZeroRect;
4399   while ((screen = [enumerator nextObject]) != nil)
4400     frame = NSUnionRect (frame, [screen frame]);
4402   return NSHeight (frame);
4406 x_display_pixel_width (struct ns_display_info *dpyinfo)
4408   NSArray *screens = [NSScreen screens];
4409   NSEnumerator *enumerator = [screens objectEnumerator];
4410   NSScreen *screen;
4411   NSRect frame;
4413   frame = NSZeroRect;
4414   while ((screen = [enumerator nextObject]) != nil)
4415     frame = NSUnionRect (frame, [screen frame]);
4417   return NSWidth (frame);
4421 static Lisp_Object ns_string_to_lispmod (const char *s)
4422 /* --------------------------------------------------------------------------
4423      Convert modifier name to lisp symbol
4424    -------------------------------------------------------------------------- */
4426   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
4427     return Qmeta;
4428   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
4429     return Qsuper;
4430   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
4431     return Qcontrol;
4432   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
4433     return Qalt;
4434   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
4435     return Qhyper;
4436   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
4437     return Qnone;
4438   else
4439     return Qnil;
4443 static void
4444 ns_default (const char *parameter, Lisp_Object *result,
4445            Lisp_Object yesval, Lisp_Object noval,
4446            BOOL is_float, BOOL is_modstring)
4447 /* --------------------------------------------------------------------------
4448       Check a parameter value in user's preferences
4449    -------------------------------------------------------------------------- */
4451   const char *value = ns_get_defaults_value (parameter);
4453   if (value)
4454     {
4455       double f;
4456       char *pos;
4457       if (c_strcasecmp (value, "YES") == 0)
4458         *result = yesval;
4459       else if (c_strcasecmp (value, "NO") == 0)
4460         *result = noval;
4461       else if (is_float && (f = strtod (value, &pos), pos != value))
4462         *result = make_float (f);
4463       else if (is_modstring && value)
4464         *result = ns_string_to_lispmod (value);
4465       else fprintf (stderr,
4466                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
4467     }
4471 static void
4472 ns_initialize_display_info (struct ns_display_info *dpyinfo)
4473 /* --------------------------------------------------------------------------
4474       Initialize global info and storage for display.
4475    -------------------------------------------------------------------------- */
4477     NSScreen *screen = [NSScreen mainScreen];
4478     NSWindowDepth depth = [screen depth];
4480     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
4481     dpyinfo->resy = 72.27;
4482     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
4483                                                   NSColorSpaceFromDepth (depth)]
4484                 && ![NSCalibratedWhiteColorSpace isEqualToString:
4485                                                  NSColorSpaceFromDepth (depth)];
4486     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
4487     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
4488     dpyinfo->color_table->colors = NULL;
4489     dpyinfo->root_window = 42; /* a placeholder.. */
4490     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
4491     dpyinfo->n_fonts = 0;
4492     dpyinfo->smallest_font_height = 1;
4493     dpyinfo->smallest_char_width = 1;
4495     reset_mouse_highlight (&dpyinfo->mouse_highlight);
4499 /* This and next define (many of the) public functions in this file. */
4500 /* x_... are generic versions in xdisp.c that we, and other terms, get away
4501          with using despite presence in the "system dependent" redisplay
4502          interface.  In addition, many of the ns_ methods have code that is
4503          shared with all terms, indicating need for further refactoring. */
4504 extern frame_parm_handler ns_frame_parm_handlers[];
4505 static struct redisplay_interface ns_redisplay_interface =
4507   ns_frame_parm_handlers,
4508   x_produce_glyphs,
4509   x_write_glyphs,
4510   x_insert_glyphs,
4511   x_clear_end_of_line,
4512   ns_scroll_run,
4513   ns_after_update_window_line,
4514   ns_update_window_begin,
4515   ns_update_window_end,
4516   0, /* flush_display */
4517   x_clear_window_mouse_face,
4518   x_get_glyph_overhangs,
4519   x_fix_overlapping_area,
4520   ns_draw_fringe_bitmap,
4521   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
4522   0, /* destroy_fringe_bitmap */
4523   ns_compute_glyph_string_overhangs,
4524   ns_draw_glyph_string,
4525   ns_define_frame_cursor,
4526   ns_clear_frame_area,
4527   ns_draw_window_cursor,
4528   ns_draw_vertical_window_border,
4529   ns_draw_window_divider,
4530   ns_shift_glyphs_for_insert,
4531   ns_show_hourglass,
4532   ns_hide_hourglass
4536 static void
4537 ns_delete_display (struct ns_display_info *dpyinfo)
4539   /* TODO... */
4543 /* This function is called when the last frame on a display is deleted. */
4544 static void
4545 ns_delete_terminal (struct terminal *terminal)
4547   struct ns_display_info *dpyinfo = terminal->display_info.ns;
4549   NSTRACE ("ns_delete_terminal");
4551   /* Protect against recursive calls.  delete_frame in
4552      delete_terminal calls us back when it deletes our last frame.  */
4553   if (!terminal->name)
4554     return;
4556   block_input ();
4558   x_destroy_all_bitmaps (dpyinfo);
4559   ns_delete_display (dpyinfo);
4560   unblock_input ();
4564 static struct terminal *
4565 ns_create_terminal (struct ns_display_info *dpyinfo)
4566 /* --------------------------------------------------------------------------
4567       Set up use of NS before we make the first connection.
4568    -------------------------------------------------------------------------- */
4570   struct terminal *terminal;
4572   NSTRACE ("ns_create_terminal");
4574   terminal = create_terminal (output_ns, &ns_redisplay_interface);
4576   terminal->display_info.ns = dpyinfo;
4577   dpyinfo->terminal = terminal;
4579   terminal->clear_frame_hook = ns_clear_frame;
4580   terminal->ring_bell_hook = ns_ring_bell;
4581   terminal->update_begin_hook = ns_update_begin;
4582   terminal->update_end_hook = ns_update_end;
4583   terminal->read_socket_hook = ns_read_socket;
4584   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4585   terminal->mouse_position_hook = ns_mouse_position;
4586   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4587   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4588   terminal->fullscreen_hook = ns_fullscreen_hook;
4589   terminal->menu_show_hook = ns_menu_show;
4590   terminal->popup_dialog_hook = ns_popup_dialog;
4591   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4592   terminal->set_horizontal_scroll_bar_hook = ns_set_horizontal_scroll_bar;
4593   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4594   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4595   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4596   terminal->delete_frame_hook = x_destroy_window;
4597   terminal->delete_terminal_hook = ns_delete_terminal;
4598   /* Other hooks are NULL by default.  */
4600   return terminal;
4604 struct ns_display_info *
4605 ns_term_init (Lisp_Object display_name)
4606 /* --------------------------------------------------------------------------
4607      Start the Application and get things rolling.
4608    -------------------------------------------------------------------------- */
4610   struct terminal *terminal;
4611   struct ns_display_info *dpyinfo;
4612   static int ns_initialized = 0;
4613   Lisp_Object tmp;
4615   if (ns_initialized) return x_display_list;
4616   ns_initialized = 1;
4618   block_input ();
4620   NSTRACE ("ns_term_init");
4622   [outerpool release];
4623   outerpool = [[NSAutoreleasePool alloc] init];
4625   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4626   /*GSDebugAllocationActive (YES); */
4627   block_input ();
4629   baud_rate = 38400;
4630   Fset_input_interrupt_mode (Qnil);
4632   if (selfds[0] == -1)
4633     {
4634       if (emacs_pipe (selfds) != 0)
4635         {
4636           fprintf (stderr, "Failed to create pipe: %s\n",
4637                    emacs_strerror (errno));
4638           emacs_abort ();
4639         }
4641       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4642       FD_ZERO (&select_readfds);
4643       FD_ZERO (&select_writefds);
4644       pthread_mutex_init (&select_mutex, NULL);
4645     }
4647   ns_pending_files = [[NSMutableArray alloc] init];
4648   ns_pending_service_names = [[NSMutableArray alloc] init];
4649   ns_pending_service_args = [[NSMutableArray alloc] init];
4651 /* Start app and create the main menu, window, view.
4652      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4653      The view will then ask the NSApp to stop and return to Emacs. */
4654   [EmacsApp sharedApplication];
4655   if (NSApp == nil)
4656     return NULL;
4657   [NSApp setDelegate: NSApp];
4659   /* Start the select thread.  */
4660   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4661                            toTarget:NSApp
4662                          withObject:nil];
4664   /* debugging: log all notifications */
4665   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4666                                          selector: @selector (logNotification:)
4667                                              name: nil object: nil]; */
4669   dpyinfo = xzalloc (sizeof *dpyinfo);
4671   ns_initialize_display_info (dpyinfo);
4672   terminal = ns_create_terminal (dpyinfo);
4674   terminal->kboard = allocate_kboard (Qns);
4675   /* Don't let the initial kboard remain current longer than necessary.
4676      That would cause problems if a file loaded on startup tries to
4677      prompt in the mini-buffer.  */
4678   if (current_kboard == initial_kboard)
4679     current_kboard = terminal->kboard;
4680   terminal->kboard->reference_count++;
4682   dpyinfo->next = x_display_list;
4683   x_display_list = dpyinfo;
4685   dpyinfo->name_list_element = Fcons (display_name, Qnil);
4687   terminal->name = xlispstrdup (display_name);
4689   unblock_input ();
4691   if (!inhibit_x_resources)
4692     {
4693       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4694                  Qt, Qnil, NO, NO);
4695       tmp = Qnil;
4696       /* this is a standard variable */
4697       ns_default ("AppleAntiAliasingThreshold", &tmp,
4698                  make_float (10.0), make_float (6.0), YES, NO);
4699       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4700     }
4702   NSTRACE_MSG ("Colors");
4704   {
4705     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4707     if ( cl == nil )
4708       {
4709         Lisp_Object color_file, color_map, color;
4710         unsigned long c;
4711         char *name;
4713         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4714                          Fsymbol_value (intern ("data-directory")));
4716         color_map = Fx_load_color_file (color_file);
4717         if (NILP (color_map))
4718           fatal ("Could not read %s.\n", SDATA (color_file));
4720         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4721         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4722           {
4723             color = XCAR (color_map);
4724             name = SSDATA (XCAR (color));
4725             c = XINT (XCDR (color));
4726             [cl setColor:
4727                   [NSColor colorForEmacsRed: RED_FROM_ULONG (c) / 255.0
4728                                       green: GREEN_FROM_ULONG (c) / 255.0
4729                                        blue: BLUE_FROM_ULONG (c) / 255.0
4730                                       alpha: 1.0]
4731                   forKey: [NSString stringWithUTF8String: name]];
4732           }
4733         [cl writeToFile: nil];
4734       }
4735   }
4737   NSTRACE_MSG ("Versions");
4739   {
4740 #ifdef NS_IMPL_GNUSTEP
4741     Vwindow_system_version = build_string (gnustep_base_version);
4742 #else
4743     /*PSnextrelease (128, c); */
4744     char c[DBL_BUFSIZE_BOUND];
4745     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4746     Vwindow_system_version = make_unibyte_string (c, len);
4747 #endif
4748   }
4750   delete_keyboard_wait_descriptor (0);
4752   ns_app_name = [[NSProcessInfo processInfo] processName];
4754   /* Set up OS X app menu */
4756   NSTRACE_MSG ("Menu init");
4758 #ifdef NS_IMPL_COCOA
4759   {
4760     NSMenu *appMenu;
4761     NSMenuItem *item;
4762     /* set up the application menu */
4763     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4764     [svcsMenu setAutoenablesItems: NO];
4765     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4766     [appMenu setAutoenablesItems: NO];
4767     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4768     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4770     [appMenu insertItemWithTitle: @"About Emacs"
4771                           action: @selector (orderFrontStandardAboutPanel:)
4772                    keyEquivalent: @""
4773                          atIndex: 0];
4774     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4775     [appMenu insertItemWithTitle: @"Preferences..."
4776                           action: @selector (showPreferencesWindow:)
4777                    keyEquivalent: @","
4778                          atIndex: 2];
4779     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4780     item = [appMenu insertItemWithTitle: @"Services"
4781                                  action: @selector (menuDown:)
4782                           keyEquivalent: @""
4783                                 atIndex: 4];
4784     [appMenu setSubmenu: svcsMenu forItem: item];
4785     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4786     [appMenu insertItemWithTitle: @"Hide Emacs"
4787                           action: @selector (hide:)
4788                    keyEquivalent: @"h"
4789                          atIndex: 6];
4790     item =  [appMenu insertItemWithTitle: @"Hide Others"
4791                           action: @selector (hideOtherApplications:)
4792                    keyEquivalent: @"h"
4793                          atIndex: 7];
4794     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4795     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4796     [appMenu insertItemWithTitle: @"Quit Emacs"
4797                           action: @selector (terminate:)
4798                    keyEquivalent: @"q"
4799                          atIndex: 9];
4801     item = [mainMenu insertItemWithTitle: ns_app_name
4802                                   action: @selector (menuDown:)
4803                            keyEquivalent: @""
4804                                  atIndex: 0];
4805     [mainMenu setSubmenu: appMenu forItem: item];
4806     [dockMenu insertItemWithTitle: @"New Frame"
4807                            action: @selector (newFrame:)
4808                     keyEquivalent: @""
4809                           atIndex: 0];
4811     [NSApp setMainMenu: mainMenu];
4812     [NSApp setAppleMenu: appMenu];
4813     [NSApp setServicesMenu: svcsMenu];
4814     /* Needed at least on Cocoa, to get dock menu to show windows */
4815     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4817     [[NSNotificationCenter defaultCenter]
4818       addObserver: mainMenu
4819          selector: @selector (trackingNotification:)
4820              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4821     [[NSNotificationCenter defaultCenter]
4822       addObserver: mainMenu
4823          selector: @selector (trackingNotification:)
4824              name: NSMenuDidEndTrackingNotification object: mainMenu];
4825   }
4826 #endif /* MAC OS X menu setup */
4828   /* Register our external input/output types, used for determining
4829      applicable services and also drag/drop eligibility. */
4831   NSTRACE_MSG ("Input/output types");
4833   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4834   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4835                       retain];
4836   ns_drag_types = [[NSArray arrayWithObjects:
4837                             NSStringPboardType,
4838                             NSTabularTextPboardType,
4839                             NSFilenamesPboardType,
4840                             NSURLPboardType, nil] retain];
4842   /* If fullscreen is in init/default-frame-alist, focus isn't set
4843      right for fullscreen windows, so set this.  */
4844   [NSApp activateIgnoringOtherApps:YES];
4846   NSTRACE_MSG ("Call NSApp run");
4848   [NSApp run];
4849   ns_do_open_file = YES;
4851 #ifdef NS_IMPL_GNUSTEP
4852   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4853      We must re-catch it so subprocess works.  */
4854   catch_child_signal ();
4855 #endif
4857   NSTRACE_MSG ("ns_term_init done");
4859   unblock_input ();
4861   return dpyinfo;
4865 void
4866 ns_term_shutdown (int sig)
4868   [[NSUserDefaults standardUserDefaults] synchronize];
4870   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4871   if (STRINGP (Vauto_save_list_file_name))
4872     unlink (SSDATA (Vauto_save_list_file_name));
4874   if (sig == 0 || sig == SIGTERM)
4875     {
4876       [NSApp terminate: NSApp];
4877     }
4878   else // force a stack trace to happen
4879     {
4880       emacs_abort ();
4881     }
4885 /* ==========================================================================
4887     EmacsApp implementation
4889    ========================================================================== */
4892 @implementation EmacsApp
4894 - (id)init
4896   NSTRACE ("[EmacsApp init]");
4898   if ((self = [super init]))
4899     {
4900 #ifdef NS_IMPL_COCOA
4901       self->isFirst = YES;
4902 #endif
4903 #ifdef NS_IMPL_GNUSTEP
4904       self->applicationDidFinishLaunchingCalled = NO;
4905 #endif
4906     }
4908   return self;
4911 #ifdef NS_IMPL_COCOA
4912 - (void)run
4914   NSTRACE ("[EmacsApp run]");
4916 #ifndef NSAppKitVersionNumber10_9
4917 #define NSAppKitVersionNumber10_9 1265
4918 #endif
4920     if ((int)NSAppKitVersionNumber != NSAppKitVersionNumber10_9)
4921       {
4922         [super run];
4923         return;
4924       }
4926   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
4928   if (isFirst) [self finishLaunching];
4929   isFirst = NO;
4931   shouldKeepRunning = YES;
4932   do
4933     {
4934       [pool release];
4935       pool = [[NSAutoreleasePool alloc] init];
4937       NSEvent *event =
4938         [self nextEventMatchingMask:NSAnyEventMask
4939                           untilDate:[NSDate distantFuture]
4940                              inMode:NSDefaultRunLoopMode
4941                             dequeue:YES];
4943       [self sendEvent:event];
4944       [self updateWindows];
4945     } while (shouldKeepRunning);
4947   [pool release];
4950 - (void)stop: (id)sender
4952   NSTRACE ("[EmacsApp stop:]");
4954     shouldKeepRunning = NO;
4955     // Stop possible dialog also.  Noop if no dialog present.
4956     // The file dialog still leaks 7k - 10k on 10.9 though.
4957     [super stop:sender];
4959 #endif /* NS_IMPL_COCOA */
4961 - (void)logNotification: (NSNotification *)notification
4963   NSTRACE ("[EmacsApp logNotification:]");
4965   const char *name = [[notification name] UTF8String];
4966   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4967       && !strstr (name, "WindowNumber"))
4968     NSLog (@"notification: '%@'", [notification name]);
4972 - (void)sendEvent: (NSEvent *)theEvent
4973 /* --------------------------------------------------------------------------
4974      Called when NSApp is running for each event received.  Used to stop
4975      the loop when we choose, since there's no way to just run one iteration.
4976    -------------------------------------------------------------------------- */
4978   int type = [theEvent type];
4979   NSWindow *window = [theEvent window];
4981   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsApp sendEvent:]");
4982   NSTRACE_MSG ("Type: %d", type);
4984 #ifdef NS_IMPL_GNUSTEP
4985   // Keyboard events aren't propagated to file dialogs for some reason.
4986   if ([NSApp modalWindow] != nil &&
4987       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4988     {
4989       [[NSApp modalWindow] sendEvent: theEvent];
4990       return;
4991     }
4992 #endif
4994   if (represented_filename != nil && represented_frame)
4995     {
4996       NSString *fstr = represented_filename;
4997       NSView *view = FRAME_NS_VIEW (represented_frame);
4998 #ifdef NS_IMPL_COCOA
4999       /* work around a bug observed on 10.3 and later where
5000          setTitleWithRepresentedFilename does not clear out previous state
5001          if given filename does not exist */
5002       if (! [[NSFileManager defaultManager] fileExistsAtPath: fstr])
5003         [[view window] setRepresentedFilename: @""];
5004 #endif
5005       [[view window] setRepresentedFilename: fstr];
5006       [represented_filename release];
5007       represented_filename = nil;
5008       represented_frame = NULL;
5009     }
5011   if (type == NSApplicationDefined)
5012     {
5013       switch ([theEvent data2])
5014         {
5015 #ifdef NS_IMPL_COCOA
5016         case NSAPP_DATA2_RUNASSCRIPT:
5017           ns_run_ascript ();
5018           [self stop: self];
5019           return;
5020 #endif
5021         case NSAPP_DATA2_RUNFILEDIALOG:
5022           ns_run_file_dialog ();
5023           [self stop: self];
5024           return;
5025         }
5026     }
5028   if (type == NSCursorUpdate && window == nil)
5029     {
5030       fprintf (stderr, "Dropping external cursor update event.\n");
5031       return;
5032     }
5034   if (type == NSApplicationDefined)
5035     {
5036       /* Events posted by ns_send_appdefined interrupt the run loop here.
5037          But, if a modal window is up, an appdefined can still come through,
5038          (e.g., from a makeKeyWindow event) but stopping self also stops the
5039          modal loop. Just defer it until later. */
5040       if ([NSApp modalWindow] == nil)
5041         {
5042           last_appdefined_event_data = [theEvent data1];
5043           [self stop: self];
5044         }
5045       else
5046         {
5047           send_appdefined = YES;
5048         }
5049     }
5052 #ifdef NS_IMPL_COCOA
5053   /* If no dialog and none of our frames have focus and it is a move, skip it.
5054      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
5055      such as Wifi, sound, date or similar.
5056      This prevents "spooky" highlighting in the frame under the menu.  */
5057   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
5058     {
5059       struct ns_display_info *di;
5060       BOOL has_focus = NO;
5061       for (di = x_display_list; ! has_focus && di; di = di->next)
5062         has_focus = di->x_focus_frame != 0;
5063       if (! has_focus)
5064         return;
5065     }
5066 #endif
5068   NSTRACE_UNSILENCE();
5070   [super sendEvent: theEvent];
5074 - (void)showPreferencesWindow: (id)sender
5076   struct frame *emacsframe = SELECTED_FRAME ();
5077   NSEvent *theEvent = [NSApp currentEvent];
5079   if (!emacs_event)
5080     return;
5081   emacs_event->kind = NS_NONKEY_EVENT;
5082   emacs_event->code = KEY_NS_SHOW_PREFS;
5083   emacs_event->modifiers = 0;
5084   EV_TRAILER (theEvent);
5088 - (void)newFrame: (id)sender
5090   NSTRACE ("[EmacsApp newFrame:]");
5092   struct frame *emacsframe = SELECTED_FRAME ();
5093   NSEvent *theEvent = [NSApp currentEvent];
5095   if (!emacs_event)
5096     return;
5097   emacs_event->kind = NS_NONKEY_EVENT;
5098   emacs_event->code = KEY_NS_NEW_FRAME;
5099   emacs_event->modifiers = 0;
5100   EV_TRAILER (theEvent);
5104 /* Open a file (used by below, after going into queue read by ns_read_socket) */
5105 - (BOOL) openFile: (NSString *)fileName
5107   NSTRACE ("[EmacsApp openFile:]");
5109   struct frame *emacsframe = SELECTED_FRAME ();
5110   NSEvent *theEvent = [NSApp currentEvent];
5112   if (!emacs_event)
5113     return NO;
5115   emacs_event->kind = NS_NONKEY_EVENT;
5116   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
5117   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
5118   ns_input_line = Qnil; /* can be start or cons start,end */
5119   emacs_event->modifiers =0;
5120   EV_TRAILER (theEvent);
5122   return YES;
5126 /* **************************************************************************
5128       EmacsApp delegate implementation
5130    ************************************************************************** */
5132 - (void)applicationDidFinishLaunching: (NSNotification *)notification
5133 /* --------------------------------------------------------------------------
5134      When application is loaded, terminate event loop in ns_term_init
5135    -------------------------------------------------------------------------- */
5137   NSTRACE ("[EmacsApp applicationDidFinishLaunching:]");
5139 #ifdef NS_IMPL_GNUSTEP
5140   ((EmacsApp *)self)->applicationDidFinishLaunchingCalled = YES;
5141 #endif
5142   [NSApp setServicesProvider: NSApp];
5144   [self antialiasThresholdDidChange:nil];
5145 #ifdef NS_IMPL_COCOA
5146   [[NSNotificationCenter defaultCenter]
5147     addObserver:self
5148        selector:@selector(antialiasThresholdDidChange:)
5149            name:NSAntialiasThresholdChangedNotification
5150          object:nil];
5151 #endif
5153   ns_send_appdefined (-2);
5156 - (void)antialiasThresholdDidChange:(NSNotification *)notification
5158 #ifdef NS_IMPL_COCOA
5159   macfont_update_antialias_threshold ();
5160 #endif
5164 /* Termination sequences:
5165     C-x C-c:
5166     Cmd-Q:
5167     MenuBar | File | Exit:
5168     Select Quit from App menubar:
5169         -terminate
5170         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5171         ns_term_shutdown()
5173     Select Quit from Dock menu:
5174     Logout attempt:
5175         -appShouldTerminate
5176           Cancel -> Nothing else
5177           Accept ->
5179           -terminate
5180           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
5181           ns_term_shutdown()
5185 - (void) terminate: (id)sender
5187   NSTRACE ("[EmacsApp terminate:]");
5189   struct frame *emacsframe = SELECTED_FRAME ();
5191   if (!emacs_event)
5192     return;
5194   emacs_event->kind = NS_NONKEY_EVENT;
5195   emacs_event->code = KEY_NS_POWER_OFF;
5196   emacs_event->arg = Qt; /* mark as non-key event */
5197   EV_TRAILER ((id)nil);
5200 static bool
5201 runAlertPanel(NSString *title,
5202               NSString *msgFormat,
5203               NSString *defaultButton,
5204               NSString *alternateButton)
5206 #if !defined (NS_IMPL_COCOA) || \
5207   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
5208   return NSRunAlertPanel(title, msgFormat, defaultButton, alternateButton, nil)
5209     == NSAlertDefaultReturn;
5210 #else
5211   NSAlert *alert = [[NSAlert alloc] init];
5212   [alert setAlertStyle: NSCriticalAlertStyle];
5213   [alert setMessageText: msgFormat];
5214   [alert addButtonWithTitle: defaultButton];
5215   [alert addButtonWithTitle: alternateButton];
5216   NSInteger ret = [alert runModal];
5217   [alert release];
5218   return ret == NSAlertFirstButtonReturn;
5219 #endif
5223 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
5225   NSTRACE ("[EmacsApp applicationShouldTerminate:]");
5227   bool ret;
5229   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
5230     return NSTerminateNow;
5232     ret = runAlertPanel(ns_app_name,
5233                         @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
5234                         @"Save Buffers and Exit", @"Cancel");
5236     if (ret)
5237         return NSTerminateNow;
5238     else
5239         return NSTerminateCancel;
5240     return NSTerminateNow;  /* just in case */
5243 static int
5244 not_in_argv (NSString *arg)
5246   int k;
5247   const char *a = [arg UTF8String];
5248   for (k = 1; k < initial_argc; ++k)
5249     if (strcmp (a, initial_argv[k]) == 0) return 0;
5250   return 1;
5253 /*   Notification from the Workspace to open a file */
5254 - (BOOL)application: sender openFile: (NSString *)file
5256   if (ns_do_open_file || not_in_argv (file))
5257     [ns_pending_files addObject: file];
5258   return YES;
5262 /*   Open a file as a temporary file */
5263 - (BOOL)application: sender openTempFile: (NSString *)file
5265   if (ns_do_open_file || not_in_argv (file))
5266     [ns_pending_files addObject: file];
5267   return YES;
5271 /*   Notification from the Workspace to open a file noninteractively (?) */
5272 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
5274   if (ns_do_open_file || not_in_argv (file))
5275     [ns_pending_files addObject: file];
5276   return YES;
5279 /*   Notification from the Workspace to open multiple files */
5280 - (void)application: sender openFiles: (NSArray *)fileList
5282   NSEnumerator *files = [fileList objectEnumerator];
5283   NSString *file;
5284   /* Don't open files from the command line unconditionally,
5285      Cocoa parses the command line wrong, --option value tries to open value
5286      if --option is the last option.  */
5287   while ((file = [files nextObject]) != nil)
5288     if (ns_do_open_file || not_in_argv (file))
5289       [ns_pending_files addObject: file];
5291   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
5296 /* Handle dock menu requests.  */
5297 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
5299   return dockMenu;
5303 /* TODO: these may help w/IO switching btwn terminal and NSApp */
5304 - (void)applicationWillBecomeActive: (NSNotification *)notification
5306   NSTRACE ("[EmacsApp applicationWillBecomeActive:]");
5307   //ns_app_active=YES;
5310 - (void)applicationDidBecomeActive: (NSNotification *)notification
5312   NSTRACE ("[EmacsApp applicationDidBecomeActive:]");
5314 #ifdef NS_IMPL_GNUSTEP
5315   if (! applicationDidFinishLaunchingCalled)
5316     [self applicationDidFinishLaunching:notification];
5317 #endif
5318   //ns_app_active=YES;
5320   ns_update_auto_hide_menu_bar ();
5321   // No constraining takes place when the application is not active.
5322   ns_constrain_all_frames ();
5324 - (void)applicationDidResignActive: (NSNotification *)notification
5326   NSTRACE ("[EmacsApp applicationDidResignActive:]");
5328   //ns_app_active=NO;
5329   ns_send_appdefined (-1);
5334 /* ==========================================================================
5336     EmacsApp aux handlers for managing event loop
5338    ========================================================================== */
5341 - (void)timeout_handler: (NSTimer *)timedEntry
5342 /* --------------------------------------------------------------------------
5343      The timeout specified to ns_select has passed.
5344    -------------------------------------------------------------------------- */
5346   /*NSTRACE ("timeout_handler"); */
5347   ns_send_appdefined (-2);
5350 #ifdef NS_IMPL_GNUSTEP
5351 - (void)sendFromMainThread:(id)unused
5353   ns_send_appdefined (nextappdefined);
5355 #endif
5357 - (void)fd_handler:(id)unused
5358 /* --------------------------------------------------------------------------
5359      Check data waiting on file descriptors and terminate if so
5360    -------------------------------------------------------------------------- */
5362   int result;
5363   int waiting = 1, nfds;
5364   char c;
5366   fd_set readfds, writefds, *wfds;
5367   struct timespec timeout, *tmo;
5368   NSAutoreleasePool *pool = nil;
5370   /* NSTRACE ("fd_handler"); */
5372   for (;;)
5373     {
5374       [pool release];
5375       pool = [[NSAutoreleasePool alloc] init];
5377       if (waiting)
5378         {
5379           fd_set fds;
5380           FD_ZERO (&fds);
5381           FD_SET (selfds[0], &fds);
5382           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
5383           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
5384             waiting = 0;
5385         }
5386       else
5387         {
5388           pthread_mutex_lock (&select_mutex);
5389           nfds = select_nfds;
5391           if (select_valid & SELECT_HAVE_READ)
5392             readfds = select_readfds;
5393           else
5394             FD_ZERO (&readfds);
5396           if (select_valid & SELECT_HAVE_WRITE)
5397             {
5398               writefds = select_writefds;
5399               wfds = &writefds;
5400             }
5401           else
5402             wfds = NULL;
5403           if (select_valid & SELECT_HAVE_TMO)
5404             {
5405               timeout = select_timeout;
5406               tmo = &timeout;
5407             }
5408           else
5409             tmo = NULL;
5411           pthread_mutex_unlock (&select_mutex);
5413           FD_SET (selfds[0], &readfds);
5414           if (selfds[0] >= nfds) nfds = selfds[0]+1;
5416           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
5418           if (result == 0)
5419             ns_send_appdefined (-2);
5420           else if (result > 0)
5421             {
5422               if (FD_ISSET (selfds[0], &readfds))
5423                 {
5424                   if (read (selfds[0], &c, 1) == 1 && c == 's')
5425                     waiting = 1;
5426                 }
5427               else
5428                 {
5429                   pthread_mutex_lock (&select_mutex);
5430                   if (select_valid & SELECT_HAVE_READ)
5431                     select_readfds = readfds;
5432                   if (select_valid & SELECT_HAVE_WRITE)
5433                     select_writefds = writefds;
5434                   if (select_valid & SELECT_HAVE_TMO)
5435                     select_timeout = timeout;
5436                   pthread_mutex_unlock (&select_mutex);
5438                   ns_send_appdefined (result);
5439                 }
5440             }
5441           waiting = 1;
5442         }
5443     }
5448 /* ==========================================================================
5450     Service provision
5452    ========================================================================== */
5454 /* called from system: queue for next pass through event loop */
5455 - (void)requestService: (NSPasteboard *)pboard
5456               userData: (NSString *)userData
5457                  error: (NSString **)error
5459   [ns_pending_service_names addObject: userData];
5460   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
5461       SSDATA (ns_string_from_pasteboard (pboard))]];
5465 /* called from ns_read_socket to clear queue */
5466 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
5468   struct frame *emacsframe = SELECTED_FRAME ();
5469   NSEvent *theEvent = [NSApp currentEvent];
5471   NSTRACE ("[EmacsApp fulfillService:withArg:]");
5473   if (!emacs_event)
5474     return NO;
5476   emacs_event->kind = NS_NONKEY_EVENT;
5477   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
5478   ns_input_spi_name = build_string ([name UTF8String]);
5479   ns_input_spi_arg = build_string ([arg UTF8String]);
5480   emacs_event->modifiers = EV_MODIFIERS (theEvent);
5481   EV_TRAILER (theEvent);
5483   return YES;
5487 @end  /* EmacsApp */
5491 /* ==========================================================================
5493     EmacsView implementation
5495    ========================================================================== */
5498 @implementation EmacsView
5500 /* needed to inform when window closed from LISP */
5501 - (void) setWindowClosing: (BOOL)closing
5503   NSTRACE ("[EmacsView setWindowClosing:%d]", closing);
5505   windowClosing = closing;
5509 - (void)dealloc
5511   NSTRACE ("[EmacsView dealloc]");
5512   [toolbar release];
5513   if (fs_state == FULLSCREEN_BOTH)
5514     [nonfs_window release];
5515   [super dealloc];
5519 /* called on font panel selection */
5520 - (void)changeFont: (id)sender
5522   NSEvent *e = [[self window] currentEvent];
5523   struct face *face = FRAME_DEFAULT_FACE (emacsframe);
5524   struct font *font = face->font;
5525   id newFont;
5526   CGFloat size;
5527   NSFont *nsfont;
5529   NSTRACE ("[EmacsView changeFont:]");
5531   if (!emacs_event)
5532     return;
5534 #ifdef NS_IMPL_GNUSTEP
5535   nsfont = ((struct nsfont_info *)font)->nsfont;
5536 #endif
5537 #ifdef NS_IMPL_COCOA
5538   nsfont = (NSFont *) macfont_get_nsctfont (font);
5539 #endif
5541   if ((newFont = [sender convertFont: nsfont]))
5542     {
5543       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
5545       emacs_event->kind = NS_NONKEY_EVENT;
5546       emacs_event->modifiers = 0;
5547       emacs_event->code = KEY_NS_CHANGE_FONT;
5549       size = [newFont pointSize];
5550       ns_input_fontsize = make_number (lrint (size));
5551       ns_input_font = build_string ([[newFont familyName] UTF8String]);
5552       EV_TRAILER (e);
5553     }
5557 - (BOOL)acceptsFirstResponder
5559   NSTRACE ("[EmacsView acceptsFirstResponder]");
5560   return YES;
5564 - (void)resetCursorRects
5566   NSRect visible = [self visibleRect];
5567   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
5568   NSTRACE ("[EmacsView resetCursorRects]");
5570   if (currentCursor == nil)
5571     currentCursor = [NSCursor arrowCursor];
5573   if (!NSIsEmptyRect (visible))
5574     [self addCursorRect: visible cursor: currentCursor];
5575   [currentCursor setOnMouseEntered: YES];
5580 /*****************************************************************************/
5581 /* Keyboard handling. */
5582 #define NS_KEYLOG 0
5584 - (void)keyDown: (NSEvent *)theEvent
5586   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5587   int code;
5588   unsigned fnKeysym = 0;
5589   static NSMutableArray *nsEvArray;
5590   int left_is_none;
5591   unsigned int flags = [theEvent modifierFlags];
5593   NSTRACE ("[EmacsView keyDown:]");
5595   /* Rhapsody and OS X give up and down events for the arrow keys */
5596   if (ns_fake_keydown == YES)
5597     ns_fake_keydown = NO;
5598   else if ([theEvent type] != NSKeyDown)
5599     return;
5601   if (!emacs_event)
5602     return;
5604  if (![[self window] isKeyWindow]
5605      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
5606      /* we must avoid an infinite loop here. */
5607      && (EmacsView *)[[theEvent window] delegate] != self)
5608    {
5609      /* XXX: There is an occasional condition in which, when Emacs display
5610          updates a different frame from the current one, and temporarily
5611          selects it, then processes some interrupt-driven input
5612          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
5613          for some reason that window has its first responder set to the NSView
5614          most recently updated (I guess), which is not the correct one. */
5615      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
5616      return;
5617    }
5619   if (nsEvArray == nil)
5620     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
5622   [NSCursor setHiddenUntilMouseMoves: YES];
5624   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5625     {
5626       clear_mouse_face (hlinfo);
5627       hlinfo->mouse_face_hidden = 1;
5628     }
5630   if (!processingCompose)
5631     {
5632       /* When using screen sharing, no left or right information is sent,
5633          so use Left key in those cases.  */
5634       int is_left_key, is_right_key;
5636       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
5637         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
5639       /* (Carbon way: [theEvent keyCode]) */
5641       /* is it a "function key"? */
5642       /* Note: Sometimes a plain key will have the NSNumericPadKeyMask
5643          flag set (this is probably a bug in the OS).
5644       */
5645       if (code < 0x00ff && (flags&NSNumericPadKeyMask))
5646         {
5647           fnKeysym = ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask);
5648         }
5649       if (fnKeysym == 0)
5650         {
5651           fnKeysym = ns_convert_key (code);
5652         }
5654       if (fnKeysym)
5655         {
5656           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
5657              because Emacs treats Delete and KP-Delete same (in simple.el). */
5658           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
5659 #ifdef NS_IMPL_GNUSTEP
5660               /*  GNUstep uses incompatible keycodes, even for those that are
5661                   supposed to be hardware independent.  Just check for delete.
5662                   Keypad delete does not have keysym 0xFFFF.
5663                   See http://savannah.gnu.org/bugs/?25395
5664               */
5665               || (fnKeysym == 0xFFFF && code == 127)
5666 #endif
5667             )
5668             code = 0xFF08; /* backspace */
5669           else
5670             code = fnKeysym;
5671         }
5673       /* are there modifiers? */
5674       emacs_event->modifiers = 0;
5676       if (flags & NSHelpKeyMask)
5677           emacs_event->modifiers |= hyper_modifier;
5679       if (flags & NSShiftKeyMask)
5680         emacs_event->modifiers |= shift_modifier;
5682       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
5683       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
5684         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
5686       if (is_right_key)
5687         emacs_event->modifiers |= parse_solitary_modifier
5688           (EQ (ns_right_command_modifier, Qleft)
5689            ? ns_command_modifier
5690            : ns_right_command_modifier);
5692       if (is_left_key)
5693         {
5694           emacs_event->modifiers |= parse_solitary_modifier
5695             (ns_command_modifier);
5697           /* if super (default), take input manager's word so things like
5698              dvorak / qwerty layout work */
5699           if (EQ (ns_command_modifier, Qsuper)
5700               && !fnKeysym
5701               && [[theEvent characters] length] != 0)
5702             {
5703               /* XXX: the code we get will be unshifted, so if we have
5704                  a shift modifier, must convert ourselves */
5705               if (!(flags & NSShiftKeyMask))
5706                 code = [[theEvent characters] characterAtIndex: 0];
5707 #if 0
5708               /* this is ugly and also requires linking w/Carbon framework
5709                  (for LMGetKbdType) so for now leave this rare (?) case
5710                  undealt with.. in future look into CGEvent methods */
5711               else
5712                 {
5713                   long smv = GetScriptManagerVariable (smKeyScript);
5714                   Handle uchrHandle = GetResource
5715                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5716                   UInt32 dummy = 0;
5717                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5718                                  [[theEvent characters] characterAtIndex: 0],
5719                                  kUCKeyActionDisplay,
5720                                  (flags & ~NSCommandKeyMask) >> 8,
5721                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5722                                  &dummy, 1, &dummy, &code);
5723                   code &= 0xFF;
5724                 }
5725 #endif
5726             }
5727         }
5729       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5730       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5731         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5733       if (is_right_key)
5734           emacs_event->modifiers |= parse_solitary_modifier
5735               (EQ (ns_right_control_modifier, Qleft)
5736                ? ns_control_modifier
5737                : ns_right_control_modifier);
5739       if (is_left_key)
5740         emacs_event->modifiers |= parse_solitary_modifier
5741           (ns_control_modifier);
5743       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5744           emacs_event->modifiers |=
5745             parse_solitary_modifier (ns_function_modifier);
5747       left_is_none = NILP (ns_alternate_modifier)
5748         || EQ (ns_alternate_modifier, Qnone);
5750       is_right_key = (flags & NSRightAlternateKeyMask)
5751         == NSRightAlternateKeyMask;
5752       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5753         || (! is_right_key
5754             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5756       if (is_right_key)
5757         {
5758           if ((NILP (ns_right_alternate_modifier)
5759                || EQ (ns_right_alternate_modifier, Qnone)
5760                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5761               && !fnKeysym)
5762             {   /* accept pre-interp alt comb */
5763               if ([[theEvent characters] length] > 0)
5764                 code = [[theEvent characters] characterAtIndex: 0];
5765               /*HACK: clear lone shift modifier to stop next if from firing */
5766               if (emacs_event->modifiers == shift_modifier)
5767                 emacs_event->modifiers = 0;
5768             }
5769           else
5770             emacs_event->modifiers |= parse_solitary_modifier
5771               (EQ (ns_right_alternate_modifier, Qleft)
5772                ? ns_alternate_modifier
5773                : ns_right_alternate_modifier);
5774         }
5776       if (is_left_key) /* default = meta */
5777         {
5778           if (left_is_none && !fnKeysym)
5779             {   /* accept pre-interp alt comb */
5780               if ([[theEvent characters] length] > 0)
5781                 code = [[theEvent characters] characterAtIndex: 0];
5782               /*HACK: clear lone shift modifier to stop next if from firing */
5783               if (emacs_event->modifiers == shift_modifier)
5784                 emacs_event->modifiers = 0;
5785             }
5786           else
5787               emacs_event->modifiers |=
5788                 parse_solitary_modifier (ns_alternate_modifier);
5789         }
5791   if (NS_KEYLOG)
5792     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5793              code, fnKeysym, flags, emacs_event->modifiers);
5795       /* if it was a function key or had modifiers, pass it directly to emacs */
5796       if (fnKeysym || (emacs_event->modifiers
5797                        && (emacs_event->modifiers != shift_modifier)
5798                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5799 /*[[theEvent characters] length] */
5800         {
5801           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5802           if (code < 0x20)
5803             code |= (1<<28)|(3<<16);
5804           else if (code == 0x7f)
5805             code |= (1<<28)|(3<<16);
5806           else if (!fnKeysym)
5807             emacs_event->kind = code > 0xFF
5808               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5810           emacs_event->code = code;
5811           EV_TRAILER (theEvent);
5812           processingCompose = NO;
5813           return;
5814         }
5815     }
5818   if (NS_KEYLOG && !processingCompose)
5819     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5821   processingCompose = YES;
5822   [nsEvArray addObject: theEvent];
5823   [self interpretKeyEvents: nsEvArray];
5824   [nsEvArray removeObject: theEvent];
5828 #ifdef NS_IMPL_COCOA
5829 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5830    decided not to send key-down for.
5831    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5832    This only applies on Tiger and earlier.
5833    If it matches one of these, send it on to keyDown. */
5834 -(void)keyUp: (NSEvent *)theEvent
5836   int flags = [theEvent modifierFlags];
5837   int code = [theEvent keyCode];
5839   NSTRACE ("[EmacsView keyUp:]");
5841   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5842       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5843     {
5844       if (NS_KEYLOG)
5845         fprintf (stderr, "keyUp: passed test");
5846       ns_fake_keydown = YES;
5847       [self keyDown: theEvent];
5848     }
5850 #endif
5853 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5856 /* <NSTextInput>: called when done composing;
5857    NOTE: also called when we delete over working text, followed immed.
5858          by doCommandBySelector: deleteBackward: */
5859 - (void)insertText: (id)aString
5861   int code;
5862   int len = [(NSString *)aString length];
5863   int i;
5865   NSTRACE ("[EmacsView insertText:]");
5867   if (NS_KEYLOG)
5868     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5869   processingCompose = NO;
5871   if (!emacs_event)
5872     return;
5874   /* first, clear any working text */
5875   if (workingText != nil)
5876     [self deleteWorkingText];
5878   /* now insert the string as keystrokes */
5879   for (i =0; i<len; i++)
5880     {
5881       code = [aString characterAtIndex: i];
5882       /* TODO: still need this? */
5883       if (code == 0x2DC)
5884         code = '~'; /* 0x7E */
5885       if (code != 32) /* Space */
5886         emacs_event->modifiers = 0;
5887       emacs_event->kind
5888         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5889       emacs_event->code = code;
5890       EV_TRAILER ((id)nil);
5891     }
5895 /* <NSTextInput>: inserts display of composing characters */
5896 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5898   NSString *str = [aString respondsToSelector: @selector (string)] ?
5899     [aString string] : aString;
5901   NSTRACE ("[EmacsView setMarkedText:selectedRange:]");
5903   if (NS_KEYLOG)
5904     NSLog (@"setMarkedText '%@' len =%lu range %lu from %lu",
5905            str, (unsigned long)[str length],
5906            (unsigned long)selRange.length,
5907            (unsigned long)selRange.location);
5909   if (workingText != nil)
5910     [self deleteWorkingText];
5911   if ([str length] == 0)
5912     return;
5914   if (!emacs_event)
5915     return;
5917   processingCompose = YES;
5918   workingText = [str copy];
5919   ns_working_text = build_string ([workingText UTF8String]);
5921   emacs_event->kind = NS_TEXT_EVENT;
5922   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5923   EV_TRAILER ((id)nil);
5927 /* delete display of composing characters [not in <NSTextInput>] */
5928 - (void)deleteWorkingText
5930   NSTRACE ("[EmacsView deleteWorkingText]");
5932   if (workingText == nil)
5933     return;
5934   if (NS_KEYLOG)
5935     NSLog(@"deleteWorkingText len =%lu\n", (unsigned long)[workingText length]);
5936   [workingText release];
5937   workingText = nil;
5938   processingCompose = NO;
5940   if (!emacs_event)
5941     return;
5943   emacs_event->kind = NS_TEXT_EVENT;
5944   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5945   EV_TRAILER ((id)nil);
5949 - (BOOL)hasMarkedText
5951   NSTRACE ("[EmacsView hasMarkedText]");
5953   return workingText != nil;
5957 - (NSRange)markedRange
5959   NSTRACE ("[EmacsView markedRange]");
5961   NSRange rng = workingText != nil
5962     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5963   if (NS_KEYLOG)
5964     NSLog (@"markedRange request");
5965   return rng;
5969 - (void)unmarkText
5971   NSTRACE ("[EmacsView unmarkText]");
5973   if (NS_KEYLOG)
5974     NSLog (@"unmark (accept) text");
5975   [self deleteWorkingText];
5976   processingCompose = NO;
5980 /* used to position char selection windows, etc. */
5981 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5983   NSRect rect;
5984   NSPoint pt;
5985   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5987   NSTRACE ("[EmacsView firstRectForCharacterRange:]");
5989   if (NS_KEYLOG)
5990     NSLog (@"firstRectForCharRange request");
5992   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5993   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5994   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5995   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5996                                        +FRAME_LINE_HEIGHT (emacsframe));
5998   pt = [self convertPoint: pt toView: nil];
5999   pt = [[self window] convertBaseToScreen: pt];
6000   rect.origin = pt;
6001   return rect;
6005 - (NSInteger)conversationIdentifier
6007   return (NSInteger)self;
6011 - (void)doCommandBySelector: (SEL)aSelector
6013   NSTRACE ("[EmacsView doCommandBySelector:]");
6015   if (NS_KEYLOG)
6016     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
6018   processingCompose = NO;
6019   if (aSelector == @selector (deleteBackward:))
6020     {
6021       /* happens when user backspaces over an ongoing composition:
6022          throw a 'delete' into the event queue */
6023       if (!emacs_event)
6024         return;
6025       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
6026       emacs_event->code = 0xFF08;
6027       EV_TRAILER ((id)nil);
6028     }
6031 - (NSArray *)validAttributesForMarkedText
6033   static NSArray *arr = nil;
6034   if (arr == nil) arr = [NSArray new];
6035  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
6036   return arr;
6039 - (NSRange)selectedRange
6041   if (NS_KEYLOG)
6042     NSLog (@"selectedRange request");
6043   return NSMakeRange (NSNotFound, 0);
6046 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
6047     GNUSTEP_GUI_MINOR_VERSION > 22
6048 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
6049 #else
6050 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
6051 #endif
6053   if (NS_KEYLOG)
6054     NSLog (@"characterIndexForPoint request");
6055   return 0;
6058 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
6060   static NSAttributedString *str = nil;
6061   if (str == nil) str = [NSAttributedString new];
6062   if (NS_KEYLOG)
6063     NSLog (@"attributedSubstringFromRange request");
6064   return str;
6067 /* End <NSTextInput> impl. */
6068 /*****************************************************************************/
6071 /* This is what happens when the user presses a mouse button.  */
6072 - (void)mouseDown: (NSEvent *)theEvent
6074   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6075   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
6077   NSTRACE ("[EmacsView mouseDown:]");
6079   [self deleteWorkingText];
6081   if (!emacs_event)
6082     return;
6084   dpyinfo->last_mouse_frame = emacsframe;
6085   /* appears to be needed to prevent spurious movement events generated on
6086      button clicks */
6087   emacsframe->mouse_moved = 0;
6089   if ([theEvent type] == NSScrollWheel)
6090     {
6091       CGFloat delta = [theEvent deltaY];
6092       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
6093       if (delta == 0)
6094         {
6095           delta = [theEvent deltaX];
6096           if (delta == 0)
6097             {
6098               NSTRACE_MSG ("deltaIsZero");
6099               return;
6100             }
6101           emacs_event->kind = HORIZ_WHEEL_EVENT;
6102         }
6103       else
6104         emacs_event->kind = WHEEL_EVENT;
6106       emacs_event->code = 0;
6107       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
6108         ((delta > 0) ? up_modifier : down_modifier);
6109     }
6110   else
6111     {
6112       emacs_event->kind = MOUSE_CLICK_EVENT;
6113       emacs_event->code = EV_BUTTON (theEvent);
6114       emacs_event->modifiers = EV_MODIFIERS (theEvent)
6115                              | EV_UDMODIFIERS (theEvent);
6116     }
6117   XSETINT (emacs_event->x, lrint (p.x));
6118   XSETINT (emacs_event->y, lrint (p.y));
6119   EV_TRAILER (theEvent);
6123 - (void)rightMouseDown: (NSEvent *)theEvent
6125   NSTRACE ("[EmacsView rightMouseDown:]");
6126   [self mouseDown: theEvent];
6130 - (void)otherMouseDown: (NSEvent *)theEvent
6132   NSTRACE ("[EmacsView otherMouseDown:]");
6133   [self mouseDown: theEvent];
6137 - (void)mouseUp: (NSEvent *)theEvent
6139   NSTRACE ("[EmacsView mouseUp:]");
6140   [self mouseDown: theEvent];
6144 - (void)rightMouseUp: (NSEvent *)theEvent
6146   NSTRACE ("[EmacsView rightMouseUp:]");
6147   [self mouseDown: theEvent];
6151 - (void)otherMouseUp: (NSEvent *)theEvent
6153   NSTRACE ("[EmacsView otherMouseUp:]");
6154   [self mouseDown: theEvent];
6158 - (void) scrollWheel: (NSEvent *)theEvent
6160   NSTRACE ("[EmacsView scrollWheel:]");
6161   [self mouseDown: theEvent];
6165 /* Tell emacs the mouse has moved. */
6166 - (void)mouseMoved: (NSEvent *)e
6168   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
6169   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6170   Lisp_Object frame;
6171   NSPoint pt;
6173   NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]");
6175   dpyinfo->last_mouse_movement_time = EV_TIMESTAMP (e);
6176   pt = [self convertPoint: [e locationInWindow] fromView: nil];
6177   dpyinfo->last_mouse_motion_x = pt.x;
6178   dpyinfo->last_mouse_motion_y = pt.y;
6180   /* update any mouse face */
6181   if (hlinfo->mouse_face_hidden)
6182     {
6183       hlinfo->mouse_face_hidden = 0;
6184       clear_mouse_face (hlinfo);
6185     }
6187   /* tooltip handling */
6188   previous_help_echo_string = help_echo_string;
6189   help_echo_string = Qnil;
6191   if (!NILP (Vmouse_autoselect_window))
6192     {
6193       NSTRACE_MSG ("mouse_autoselect_window");
6194       static Lisp_Object last_mouse_window;
6195       Lisp_Object window
6196         = window_from_coordinates (emacsframe, pt.x, pt.y, 0, 0);
6198       if (WINDOWP (window)
6199           && !EQ (window, last_mouse_window)
6200           && !EQ (window, selected_window)
6201           && (focus_follows_mouse
6202               || (EQ (XWINDOW (window)->frame,
6203                       XWINDOW (selected_window)->frame))))
6204         {
6205           NSTRACE_MSG ("in_window");
6206           emacs_event->kind = SELECT_WINDOW_EVENT;
6207           emacs_event->frame_or_window = window;
6208           EV_TRAILER2 (e);
6209         }
6210       /* Remember the last window where we saw the mouse.  */
6211       last_mouse_window = window;
6212     }
6214   if (!note_mouse_movement (emacsframe, pt.x, pt.y))
6215     help_echo_string = previous_help_echo_string;
6217   XSETFRAME (frame, emacsframe);
6218   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
6219     {
6220       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
6221          (note_mouse_highlight), which is called through the
6222          note_mouse_movement () call above */
6223       any_help_event_p = YES;
6224       gen_help_event (help_echo_string, frame, help_echo_window,
6225                       help_echo_object, help_echo_pos);
6226     }
6228   if (emacsframe->mouse_moved && send_appdefined)
6229     ns_send_appdefined (-1);
6233 - (void)mouseDragged: (NSEvent *)e
6235   NSTRACE ("[EmacsView mouseDragged:]");
6236   [self mouseMoved: e];
6240 - (void)rightMouseDragged: (NSEvent *)e
6242   NSTRACE ("[EmacsView rightMouseDragged:]");
6243   [self mouseMoved: e];
6247 - (void)otherMouseDragged: (NSEvent *)e
6249   NSTRACE ("[EmacsView otherMouseDragged:]");
6250   [self mouseMoved: e];
6254 - (BOOL)windowShouldClose: (id)sender
6256   NSEvent *e =[[self window] currentEvent];
6258   NSTRACE ("[EmacsView windowShouldClose:]");
6259   windowClosing = YES;
6260   if (!emacs_event)
6261     return NO;
6262   emacs_event->kind = DELETE_WINDOW_EVENT;
6263   emacs_event->modifiers = 0;
6264   emacs_event->code = 0;
6265   EV_TRAILER (e);
6266   /* Don't close this window, let this be done from lisp code.  */
6267   return NO;
6270 - (void) updateFrameSize: (BOOL) delay;
6272   NSWindow *window = [self window];
6273   NSRect wr = [window frame];
6274   int extra = 0;
6275   int oldc = cols, oldr = rows;
6276   int oldw = FRAME_PIXEL_WIDTH (emacsframe);
6277   int oldh = FRAME_PIXEL_HEIGHT (emacsframe);
6278   int neww, newh;
6280   NSTRACE ("[EmacsView updateFrameSize:]");
6281   NSTRACE_SIZE ("Original size", NSMakeSize (oldw, oldh));
6282   NSTRACE_RECT ("Original frame", wr);
6283   NSTRACE_MSG  ("Original columns: %d", cols);
6284   NSTRACE_MSG  ("Original rows: %d", rows);
6286   if (! [self isFullscreen])
6287     {
6288 #ifdef NS_IMPL_GNUSTEP
6289       // GNUstep does not always update the tool bar height.  Force it.
6290       if (toolbar && [toolbar isVisible])
6291           update_frame_tool_bar (emacsframe);
6292 #endif
6294       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6295         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6296     }
6298   if (wait_for_tool_bar)
6299     {
6300       if (FRAME_TOOLBAR_HEIGHT (emacsframe) == 0)
6301         {
6302           NSTRACE_MSG ("Waiting for toolbar");
6303           return;
6304         }
6305       wait_for_tool_bar = NO;
6306     }
6308   neww = (int)wr.size.width - emacsframe->border_width;
6309   newh = (int)wr.size.height - extra;
6311   NSTRACE_SIZE ("New size", NSMakeSize (neww, newh));
6312   NSTRACE_MSG ("tool_bar_height: %d", emacsframe->tool_bar_height);
6314   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, neww);
6315   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, newh);
6317   if (cols < MINWIDTH)
6318     cols = MINWIDTH;
6320   if (rows < MINHEIGHT)
6321     rows = MINHEIGHT;
6323   NSTRACE_MSG ("New columns: %d", cols);
6324   NSTRACE_MSG ("New rows: %d", rows);
6326   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
6327     {
6328       NSView *view = FRAME_NS_VIEW (emacsframe);
6329       NSWindow *win = [view window];
6331       change_frame_size (emacsframe,
6332                          FRAME_PIXEL_TO_TEXT_WIDTH (emacsframe, neww),
6333                          FRAME_PIXEL_TO_TEXT_HEIGHT (emacsframe, newh),
6334                          0, delay, 0, 1);
6335       SET_FRAME_GARBAGED (emacsframe);
6336       cancel_mouse_face (emacsframe);
6338       wr = NSMakeRect (0, 0, neww, newh);
6340       [view setFrame: wr];
6342       // to do: consider using [NSNotificationCenter postNotificationName:].
6343       [self windowDidMove: // Update top/left.
6344               [NSNotification notificationWithName:NSWindowDidMoveNotification
6345                                             object:[view window]]];
6346     }
6347   else
6348     {
6349       NSTRACE_MSG ("No change");
6350     }
6353 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
6354 /* normalize frame to gridded text size */
6356   int extra = 0;
6358   NSTRACE ("[EmacsView windowWillResize:toSize: " NSTRACE_FMT_SIZE "]",
6359            NSTRACE_ARG_SIZE (frameSize));
6360   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6361   NSTRACE_FSTYPE ("fs_state", fs_state);
6363   if (fs_state == FULLSCREEN_MAXIMIZED
6364       && (maximized_width != (int)frameSize.width
6365           || maximized_height != (int)frameSize.height))
6366     [self setFSValue: FULLSCREEN_NONE];
6367   else if (fs_state == FULLSCREEN_WIDTH
6368            && maximized_width != (int)frameSize.width)
6369     [self setFSValue: FULLSCREEN_NONE];
6370   else if (fs_state == FULLSCREEN_HEIGHT
6371            && maximized_height != (int)frameSize.height)
6372     [self setFSValue: FULLSCREEN_NONE];
6374   if (fs_state == FULLSCREEN_NONE)
6375     maximized_width = maximized_height = -1;
6377   if (! [self isFullscreen])
6378     {
6379       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
6380         + FRAME_TOOLBAR_HEIGHT (emacsframe);
6381     }
6383   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, frameSize.width);
6384   if (cols < MINWIDTH)
6385     cols = MINWIDTH;
6387   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
6388                                            frameSize.height - extra);
6389   if (rows < MINHEIGHT)
6390     rows = MINHEIGHT;
6391 #ifdef NS_IMPL_COCOA
6392   {
6393     /* this sets window title to have size in it; the wm does this under GS */
6394     NSRect r = [[self window] frame];
6395     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
6396       {
6397         if (old_title != 0)
6398           {
6399             xfree (old_title);
6400             old_title = 0;
6401           }
6402       }
6403     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
6404       {
6405         char *size_title;
6406         NSWindow *window = [self window];
6407         if (old_title == 0)
6408           {
6409             char *t = strdup ([[[self window] title] UTF8String]);
6410             char *pos = strstr (t, "  â€”  ");
6411             if (pos)
6412               *pos = '\0';
6413             old_title = t;
6414           }
6415         size_title = xmalloc (strlen (old_title) + 40);
6416         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
6417         [window setTitle: [NSString stringWithUTF8String: size_title]];
6418         [window display];
6419         xfree (size_title);
6420       }
6421   }
6422 #endif /* NS_IMPL_COCOA */
6424   NSTRACE_MSG ("cols: %d  rows: %d", cols, rows);
6426   /* Restrict the new size to the text gird.
6428      Don't restrict the width if the user only adjusted the height, and
6429      vice versa.  (Without this, the frame would shrink, and move
6430      slightly, if the window was resized by dragging one of its
6431      borders.) */
6432   if (!frame_resize_pixelwise)
6433     {
6434       NSRect r = [[self window] frame];
6436       if (r.size.width != frameSize.width)
6437         {
6438           frameSize.width =
6439             FRAME_TEXT_COLS_TO_PIXEL_WIDTH  (emacsframe, cols);
6440         }
6442       if (r.size.height != frameSize.height)
6443         {
6444           frameSize.height =
6445             FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (emacsframe, rows) + extra;
6446         }
6447     }
6449   NSTRACE_RETURN_SIZE (frameSize);
6451   return frameSize;
6455 - (void)windowDidResize: (NSNotification *)notification
6457   NSTRACE ("[EmacsView windowDidResize:]");
6458   if (!FRAME_LIVE_P (emacsframe))
6459     {
6460       NSTRACE_MSG ("Ignored (frame dead)");
6461       return;
6462     }
6463   if (emacsframe->output_data.ns->in_animation)
6464     {
6465       NSTRACE_MSG ("Ignored (in animation)");
6466       return;
6467     }
6469   if (! [self fsIsNative])
6470     {
6471       NSWindow *theWindow = [notification object];
6472       /* We can get notification on the non-FS window when in
6473          fullscreen mode.  */
6474       if ([self window] != theWindow) return;
6475     }
6477   NSTRACE_RECT ("frame", [[notification object] frame]);
6479 #ifdef NS_IMPL_GNUSTEP
6480   NSWindow *theWindow = [notification object];
6482    /* In GNUstep, at least currently, it's possible to get a didResize
6483       without getting a willResize.. therefore we need to act as if we got
6484       the willResize now */
6485   NSSize sz = [theWindow frame].size;
6486   sz = [self windowWillResize: theWindow toSize: sz];
6487 #endif /* NS_IMPL_GNUSTEP */
6489   if (cols > 0 && rows > 0)
6490     {
6491       [self updateFrameSize: YES];
6492     }
6494   ns_send_appdefined (-1);
6497 #ifdef NS_IMPL_COCOA
6498 - (void)viewDidEndLiveResize
6500   NSTRACE ("[EmacsView viewDidEndLiveResize]");
6502   [super viewDidEndLiveResize];
6503   if (old_title != 0)
6504     {
6505       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
6506       xfree (old_title);
6507       old_title = 0;
6508     }
6509   maximizing_resize = NO;
6511 #endif /* NS_IMPL_COCOA */
6514 - (void)windowDidBecomeKey: (NSNotification *)notification
6515 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6517   [self windowDidBecomeKey];
6521 - (void)windowDidBecomeKey      /* for direct calls */
6523   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6524   struct frame *old_focus = dpyinfo->x_focus_frame;
6526   NSTRACE ("[EmacsView windowDidBecomeKey]");
6528   if (emacsframe != old_focus)
6529     dpyinfo->x_focus_frame = emacsframe;
6531   ns_frame_rehighlight (emacsframe);
6533   if (emacs_event)
6534     {
6535       emacs_event->kind = FOCUS_IN_EVENT;
6536       EV_TRAILER ((id)nil);
6537     }
6541 - (void)windowDidResignKey: (NSNotification *)notification
6542 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
6544   struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe);
6545   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
6546   NSTRACE ("[EmacsView windowDidResignKey:]");
6548   if (is_focus_frame)
6549     dpyinfo->x_focus_frame = 0;
6551   emacsframe->mouse_moved = 0;
6552   ns_frame_rehighlight (emacsframe);
6554   /* FIXME: for some reason needed on second and subsequent clicks away
6555             from sole-frame Emacs to get hollow box to show */
6556   if (!windowClosing && [[self window] isVisible] == YES)
6557     {
6558       x_update_cursor (emacsframe, 1);
6559       x_set_frame_alpha (emacsframe);
6560     }
6562   if (any_help_event_p)
6563     {
6564       Lisp_Object frame;
6565       XSETFRAME (frame, emacsframe);
6566       help_echo_string = Qnil;
6567       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
6568     }
6570   if (emacs_event && is_focus_frame)
6571     {
6572       [self deleteWorkingText];
6573       emacs_event->kind = FOCUS_OUT_EVENT;
6574       EV_TRAILER ((id)nil);
6575     }
6579 - (void)windowWillMiniaturize: sender
6581   NSTRACE ("[EmacsView windowWillMiniaturize:]");
6585 - (void)setFrame:(NSRect)frameRect;
6587   NSTRACE ("[EmacsView setFrame:" NSTRACE_FMT_RECT "]",
6588            NSTRACE_ARG_RECT (frameRect));
6590   [super setFrame:(NSRect)frameRect];
6594 - (BOOL)isFlipped
6596   return YES;
6600 - (BOOL)isOpaque
6602   return NO;
6606 - initFrameFromEmacs: (struct frame *)f
6608   NSRect r, wr;
6609   Lisp_Object tem;
6610   NSWindow *win;
6611   NSColor *col;
6612   NSString *name;
6614   NSTRACE ("[EmacsView initFrameFromEmacs:]");
6615   NSTRACE_MSG ("cols:%d lines:%d\n", f->text_cols, f->text_lines);
6617   windowClosing = NO;
6618   processingCompose = NO;
6619   scrollbarsNeedingUpdate = 0;
6620   fs_state = FULLSCREEN_NONE;
6621   fs_before_fs = next_maximized = -1;
6622 #ifdef HAVE_NATIVE_FS
6623   fs_is_native = ns_use_native_fullscreen;
6624 #else
6625   fs_is_native = NO;
6626 #endif
6627   maximized_width = maximized_height = -1;
6628   nonfs_window = nil;
6630   ns_userRect = NSMakeRect (0, 0, 0, 0);
6631   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
6632                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
6633   [self initWithFrame: r];
6634   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
6636   FRAME_NS_VIEW (f) = self;
6637   emacsframe = f;
6638 #ifdef NS_IMPL_COCOA
6639   old_title = 0;
6640   maximizing_resize = NO;
6641 #endif
6643   win = [[EmacsWindow alloc]
6644             initWithContentRect: r
6645                       styleMask: (NSResizableWindowMask |
6646 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6647                                   NSTitledWindowMask |
6648 #endif
6649                                   NSMiniaturizableWindowMask |
6650                                   NSClosableWindowMask)
6651                         backing: NSBackingStoreBuffered
6652                           defer: YES];
6654 #ifdef HAVE_NATIVE_FS
6655     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
6656 #endif
6658   wr = [win frame];
6659   bwidth = f->border_width = wr.size.width - r.size.width;
6660   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
6662   [win setAcceptsMouseMovedEvents: YES];
6663   [win setDelegate: self];
6664 #if !defined (NS_IMPL_COCOA) || \
6665   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6666   [win useOptimizedDrawing: YES];
6667 #endif
6669   [[win contentView] addSubview: self];
6671   if (ns_drag_types)
6672     [self registerForDraggedTypes: ns_drag_types];
6674   tem = f->name;
6675   name = [NSString stringWithUTF8String:
6676                    NILP (tem) ? "Emacs" : SSDATA (tem)];
6677   [win setTitle: name];
6679   /* toolbar support */
6680   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
6681                          [NSString stringWithFormat: @"Emacs Frame %d",
6682                                    ns_window_num]];
6683   [win setToolbar: toolbar];
6684   [toolbar setVisible: NO];
6686   /* Don't set frame garbaged until tool bar is up to date?
6687      This avoids an extra clear and redraw (flicker) at frame creation.  */
6688   if (FRAME_EXTERNAL_TOOL_BAR (f)) wait_for_tool_bar = YES;
6689   else wait_for_tool_bar = NO;
6692 #ifdef NS_IMPL_COCOA
6693   {
6694     NSButton *toggleButton;
6695   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
6696   [toggleButton setTarget: self];
6697   [toggleButton setAction: @selector (toggleToolbar: )];
6698   }
6699 #endif
6700   FRAME_TOOLBAR_HEIGHT (f) = 0;
6702   tem = f->icon_name;
6703   if (!NILP (tem))
6704     [win setMiniwindowTitle:
6705            [NSString stringWithUTF8String: SSDATA (tem)]];
6707   {
6708     NSScreen *screen = [win screen];
6710     if (screen != 0)
6711       {
6712         NSPoint pt = NSMakePoint
6713           (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
6714            IN_BOUND (-SCREENMAX,
6715                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX));
6717         [win setFrameTopLeftPoint: pt];
6719         NSTRACE_RECT ("new frame", [win frame]);
6720       }
6721   }
6723   [win makeFirstResponder: self];
6725   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6726                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
6727   [win setBackgroundColor: col];
6728   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6729     [win setOpaque: NO];
6731 #if !defined (NS_IMPL_COCOA) || \
6732   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
6733   [self allocateGState];
6734 #endif
6735   [NSApp registerServicesMenuSendTypes: ns_send_types
6736                            returnTypes: nil];
6738   ns_window_num++;
6739   return self;
6743 - (void)windowDidMove: sender
6745   NSWindow *win = [self window];
6746   NSRect r = [win frame];
6747   NSArray *screens = [NSScreen screens];
6748   NSScreen *screen = [screens objectAtIndex: 0];
6750   NSTRACE ("[EmacsView windowDidMove:]");
6752   if (!emacsframe->output_data.ns)
6753     return;
6754   if (screen != nil)
6755     {
6756       emacsframe->left_pos = r.origin.x;
6757       emacsframe->top_pos =
6758         [screen frame].size.height - (r.origin.y + r.size.height);
6759     }
6763 /* Called AFTER method below, but before our windowWillResize call there leads
6764    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
6765    location so set_window_size moves the frame. */
6766 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
6768   NSTRACE (("[EmacsView windowShouldZoom:toFrame:" NSTRACE_FMT_RECT "]"
6769             NSTRACE_FMT_RETURN "YES"),
6770            NSTRACE_ARG_RECT (newFrame));
6772   emacsframe->output_data.ns->zooming = 1;
6773   return YES;
6777 /* Override to do something slightly nonstandard, but nice.  First click on
6778    zoom button will zoom vertically.  Second will zoom completely.  Third
6779    returns to original. */
6780 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
6781                         defaultFrame:(NSRect)defaultFrame
6783   // TODO: Rename to "currentFrame" and assign "result" properly in
6784   // all paths.
6785   NSRect result = [sender frame];
6787   NSTRACE (("[EmacsView windowWillUseStandardFrame:defaultFrame:"
6788             NSTRACE_FMT_RECT "]"),
6789            NSTRACE_ARG_RECT (defaultFrame));
6790   NSTRACE_FSTYPE ("fs_state", fs_state);
6791   NSTRACE_FSTYPE ("fs_before_fs", fs_before_fs);
6792   NSTRACE_FSTYPE ("next_maximized", next_maximized);
6793   NSTRACE_RECT   ("ns_userRect", ns_userRect);
6794   NSTRACE_RECT   ("[sender frame]", [sender frame]);
6796   if (fs_before_fs != -1) /* Entering fullscreen */
6797     {
6798       NSTRACE_MSG ("Entering fullscreen");
6799       result = defaultFrame;
6800     }
6801   else
6802     {
6803       // Save the window size and position (frame) before the resize.
6804       if (fs_state != FULLSCREEN_MAXIMIZED
6805           && fs_state != FULLSCREEN_WIDTH)
6806         {
6807           ns_userRect.size.width = result.size.width;
6808           ns_userRect.origin.x   = result.origin.x;
6809         }
6811       if (fs_state != FULLSCREEN_MAXIMIZED
6812           && fs_state != FULLSCREEN_HEIGHT)
6813         {
6814           ns_userRect.size.height = result.size.height;
6815           ns_userRect.origin.y    = result.origin.y;
6816         }
6818       NSTRACE_RECT ("ns_userRect (2)", ns_userRect);
6820       if (next_maximized == FULLSCREEN_HEIGHT
6821           || (next_maximized == -1
6822               && abs ((int)(defaultFrame.size.height - result.size.height))
6823               > FRAME_LINE_HEIGHT (emacsframe)))
6824         {
6825           /* first click */
6826           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
6827           maximized_height = result.size.height = defaultFrame.size.height;
6828           maximized_width = -1;
6829           result.origin.y = defaultFrame.origin.y;
6830           if (ns_userRect.size.height != 0)
6831             {
6832               result.origin.x = ns_userRect.origin.x;
6833               result.size.width = ns_userRect.size.width;
6834             }
6835           [self setFSValue: FULLSCREEN_HEIGHT];
6836 #ifdef NS_IMPL_COCOA
6837           maximizing_resize = YES;
6838 #endif
6839         }
6840       else if (next_maximized == FULLSCREEN_WIDTH)
6841         {
6842           NSTRACE_MSG ("FULLSCREEN_WIDTH");
6843           maximized_width = result.size.width = defaultFrame.size.width;
6844           maximized_height = -1;
6845           result.origin.x = defaultFrame.origin.x;
6846           if (ns_userRect.size.width != 0)
6847             {
6848               result.origin.y = ns_userRect.origin.y;
6849               result.size.height = ns_userRect.size.height;
6850             }
6851           [self setFSValue: FULLSCREEN_WIDTH];
6852         }
6853       else if (next_maximized == FULLSCREEN_MAXIMIZED
6854                || (next_maximized == -1
6855                    && abs ((int)(defaultFrame.size.width - result.size.width))
6856                    > FRAME_COLUMN_WIDTH (emacsframe)))
6857         {
6858           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
6860           result = defaultFrame;  /* second click */
6861           maximized_width = result.size.width;
6862           maximized_height = result.size.height;
6863           [self setFSValue: FULLSCREEN_MAXIMIZED];
6864 #ifdef NS_IMPL_COCOA
6865           maximizing_resize = YES;
6866 #endif
6867         }
6868       else
6869         {
6870           /* restore */
6871           NSTRACE_MSG ("Restore");
6872           result = ns_userRect.size.height ? ns_userRect : result;
6873           NSTRACE_RECT ("restore (2)", result);
6874           ns_userRect = NSMakeRect (0, 0, 0, 0);
6875 #ifdef NS_IMPL_COCOA
6876           maximizing_resize = fs_state != FULLSCREEN_NONE;
6877 #endif
6878           [self setFSValue: FULLSCREEN_NONE];
6879           maximized_width = maximized_height = -1;
6880         }
6881     }
6883   if (fs_before_fs == -1) next_maximized = -1;
6885   NSTRACE_RECT   ("Final ns_userRect", ns_userRect);
6886   NSTRACE_MSG    ("Final maximized_width: %d", maximized_width);
6887   NSTRACE_MSG    ("Final maximized_height: %d", maximized_height);
6888   NSTRACE_FSTYPE ("Final next_maximized", next_maximized);
6890   [self windowWillResize: sender toSize: result.size];
6892   NSTRACE_RETURN_RECT (result);
6894   return result;
6898 - (void)windowDidDeminiaturize: sender
6900   NSTRACE ("[EmacsView windowDidDeminiaturize:]");
6901   if (!emacsframe->output_data.ns)
6902     return;
6904   SET_FRAME_ICONIFIED (emacsframe, 0);
6905   SET_FRAME_VISIBLE (emacsframe, 1);
6906   windows_or_buffers_changed = 63;
6908   if (emacs_event)
6909     {
6910       emacs_event->kind = DEICONIFY_EVENT;
6911       EV_TRAILER ((id)nil);
6912     }
6916 - (void)windowDidExpose: sender
6918   NSTRACE ("[EmacsView windowDidExpose:]");
6919   if (!emacsframe->output_data.ns)
6920     return;
6922   SET_FRAME_VISIBLE (emacsframe, 1);
6923   SET_FRAME_GARBAGED (emacsframe);
6925   if (send_appdefined)
6926     ns_send_appdefined (-1);
6930 - (void)windowDidMiniaturize: sender
6932   NSTRACE ("[EmacsView windowDidMiniaturize:]");
6933   if (!emacsframe->output_data.ns)
6934     return;
6936   SET_FRAME_ICONIFIED (emacsframe, 1);
6937   SET_FRAME_VISIBLE (emacsframe, 0);
6939   if (emacs_event)
6940     {
6941       emacs_event->kind = ICONIFY_EVENT;
6942       EV_TRAILER ((id)nil);
6943     }
6946 #ifdef HAVE_NATIVE_FS
6947 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6948       willUseFullScreenPresentationOptions:
6949   (NSApplicationPresentationOptions)proposedOptions
6951   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6953 #endif
6955 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6957   NSTRACE ("[EmacsView windowWillEnterFullScreen:]");
6958   [self windowWillEnterFullScreen];
6960 - (void)windowWillEnterFullScreen /* provided for direct calls */
6962   NSTRACE ("[EmacsView windowWillEnterFullScreen]");
6963   fs_before_fs = fs_state;
6966 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6968   NSTRACE ("[EmacsView windowDidEnterFullScreen:]");
6969   [self windowDidEnterFullScreen];
6972 - (void)windowDidEnterFullScreen /* provided for direct calls */
6974   NSTRACE ("[EmacsView windowDidEnterFullScreen]");
6975   [self setFSValue: FULLSCREEN_BOTH];
6976   if (! [self fsIsNative])
6977     {
6978       [self windowDidBecomeKey];
6979       [nonfs_window orderOut:self];
6980     }
6981   else
6982     {
6983       BOOL tbar_visible = FRAME_EXTERNAL_TOOL_BAR (emacsframe) ? YES : NO;
6984 #ifdef NS_IMPL_COCOA
6985 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
6986       unsigned val = (unsigned)[NSApp presentationOptions];
6988       // OSX 10.7 bug fix, the menu won't appear without this.
6989       // val is non-zero on other OSX versions.
6990       if (val == 0)
6991         {
6992           NSApplicationPresentationOptions options
6993             = NSApplicationPresentationAutoHideDock
6994             | NSApplicationPresentationAutoHideMenuBar
6995             | NSApplicationPresentationFullScreen
6996             | NSApplicationPresentationAutoHideToolbar;
6998           [NSApp setPresentationOptions: options];
6999         }
7000 #endif
7001 #endif
7002       [toolbar setVisible:tbar_visible];
7003     }
7006 - (void)windowWillExitFullScreen:(NSNotification *)notification
7008   NSTRACE ("[EmacsView windowWillExitFullScreen:]");
7009   [self windowWillExitFullScreen];
7012 - (void)windowWillExitFullScreen /* provided for direct calls */
7014   NSTRACE ("[EmacsView windowWillExitFullScreen]");
7015   if (!FRAME_LIVE_P (emacsframe))
7016     {
7017       NSTRACE_MSG ("Ignored (frame dead)");
7018       return;
7019     }
7020   if (next_maximized != -1)
7021     fs_before_fs = next_maximized;
7024 - (void)windowDidExitFullScreen:(NSNotification *)notification
7026   NSTRACE ("[EmacsView windowDidExitFullScreen:]");
7027   [self windowDidExitFullScreen];
7030 - (void)windowDidExitFullScreen /* provided for direct calls */
7032   NSTRACE ("[EmacsView windowDidExitFullScreen]");
7033   if (!FRAME_LIVE_P (emacsframe))
7034     {
7035       NSTRACE_MSG ("Ignored (frame dead)");
7036       return;
7037     }
7038   [self setFSValue: fs_before_fs];
7039   fs_before_fs = -1;
7040 #ifdef HAVE_NATIVE_FS
7041   [self updateCollectionBehavior];
7042 #endif
7043   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
7044     {
7045       [toolbar setVisible:YES];
7046       update_frame_tool_bar (emacsframe);
7047       [self updateFrameSize:YES];
7048       [[self window] display];
7049     }
7050   else
7051     [toolbar setVisible:NO];
7053   if (next_maximized != -1)
7054     [[self window] performZoom:self];
7057 - (BOOL)fsIsNative
7059   return fs_is_native;
7062 - (BOOL)isFullscreen
7064   NSTRACE ("[EmacsView isFullscreen]");
7066   if (! fs_is_native) return nonfs_window != nil;
7067 #ifdef HAVE_NATIVE_FS
7068   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
7069 #else
7070   return NO;
7071 #endif
7074 #ifdef HAVE_NATIVE_FS
7075 - (void)updateCollectionBehavior
7077   NSTRACE ("[EmacsView updateCollectionBehavior]");
7079   if (! [self isFullscreen])
7080     {
7081       NSWindow *win = [self window];
7082       NSWindowCollectionBehavior b = [win collectionBehavior];
7083       if (ns_use_native_fullscreen)
7084         b |= NSWindowCollectionBehaviorFullScreenPrimary;
7085       else
7086         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
7088       [win setCollectionBehavior: b];
7089       fs_is_native = ns_use_native_fullscreen;
7090     }
7092 #endif
7094 - (void)toggleFullScreen: (id)sender
7096   NSWindow *w, *fw;
7097   BOOL onFirstScreen;
7098   struct frame *f;
7099   NSRect r, wr;
7100   NSColor *col;
7102   NSTRACE ("[EmacsView toggleFullScreen:]");
7104   if (fs_is_native)
7105     {
7106 #ifdef HAVE_NATIVE_FS
7107       [[self window] toggleFullScreen:sender];
7108 #endif
7109       return;
7110     }
7112   w = [self window];
7113   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
7114   f = emacsframe;
7115   wr = [w frame];
7116   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
7117                                  (FRAME_DEFAULT_FACE (f)),
7118                                  f);
7120   if (fs_state != FULLSCREEN_BOTH)
7121     {
7122       NSScreen *screen = [w screen];
7124 #if defined (NS_IMPL_COCOA) && \
7125   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7126       /* Hide ghost menu bar on secondary monitor? */
7127       if (! onFirstScreen)
7128         onFirstScreen = [NSScreen screensHaveSeparateSpaces];
7129 #endif
7130       /* Hide dock and menubar if we are on the primary screen.  */
7131       if (onFirstScreen)
7132         {
7133 #ifdef NS_IMPL_COCOA
7134           NSApplicationPresentationOptions options
7135             = NSApplicationPresentationAutoHideDock
7136             | NSApplicationPresentationAutoHideMenuBar;
7138           [NSApp setPresentationOptions: options];
7139 #else
7140           [NSMenu setMenuBarVisible:NO];
7141 #endif
7142         }
7144       fw = [[EmacsFSWindow alloc]
7145                        initWithContentRect:[w contentRectForFrameRect:wr]
7146                                  styleMask:NSBorderlessWindowMask
7147                                    backing:NSBackingStoreBuffered
7148                                      defer:YES
7149                                     screen:screen];
7151       [fw setContentView:[w contentView]];
7152       [fw setTitle:[w title]];
7153       [fw setDelegate:self];
7154       [fw setAcceptsMouseMovedEvents: YES];
7155 #if !defined (NS_IMPL_COCOA) || \
7156   MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_9
7157       [fw useOptimizedDrawing: YES];
7158 #endif
7159       [fw setBackgroundColor: col];
7160       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7161         [fw setOpaque: NO];
7163       f->border_width = 0;
7164       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
7165       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
7166       FRAME_TOOLBAR_HEIGHT (f) = 0;
7168       nonfs_window = w;
7170       [self windowWillEnterFullScreen];
7171       [fw makeKeyAndOrderFront:NSApp];
7172       [fw makeFirstResponder:self];
7173       [w orderOut:self];
7174       r = [fw frameRectForContentRect:[screen frame]];
7175       [fw setFrame: r display:YES animate:ns_use_fullscreen_animation];
7176       [self windowDidEnterFullScreen];
7177       [fw display];
7178     }
7179   else
7180     {
7181       fw = w;
7182       w = nonfs_window;
7183       nonfs_window = nil;
7185       if (onFirstScreen)
7186         {
7187 #ifdef NS_IMPL_COCOA
7188           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
7189 #else
7190           [NSMenu setMenuBarVisible:YES];
7191 #endif
7192         }
7194       [w setContentView:[fw contentView]];
7195       [w setBackgroundColor: col];
7196       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
7197         [w setOpaque: NO];
7199       f->border_width = bwidth;
7200       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
7201       if (FRAME_EXTERNAL_TOOL_BAR (f))
7202         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
7204       // to do: consider using [NSNotificationCenter postNotificationName:] to send notifications.
7206       [self windowWillExitFullScreen];
7207       [fw setFrame: [w frame] display:YES animate:ns_use_fullscreen_animation];
7208       [fw close];
7209       [w makeKeyAndOrderFront:NSApp];
7210       [self windowDidExitFullScreen];
7211       [self updateFrameSize:YES];
7212     }
7215 - (void)handleFS
7217   NSTRACE ("[EmacsView handleFS]");
7219   if (fs_state != emacsframe->want_fullscreen)
7220     {
7221       if (fs_state == FULLSCREEN_BOTH)
7222         {
7223           NSTRACE_MSG ("fs_state == FULLSCREEN_BOTH");
7224           [self toggleFullScreen:self];
7225         }
7227       switch (emacsframe->want_fullscreen)
7228         {
7229         case FULLSCREEN_BOTH:
7230           NSTRACE_MSG ("FULLSCREEN_BOTH");
7231           [self toggleFullScreen:self];
7232           break;
7233         case FULLSCREEN_WIDTH:
7234           NSTRACE_MSG ("FULLSCREEN_WIDTH");
7235           next_maximized = FULLSCREEN_WIDTH;
7236           if (fs_state != FULLSCREEN_BOTH)
7237             [[self window] performZoom:self];
7238           break;
7239         case FULLSCREEN_HEIGHT:
7240           NSTRACE_MSG ("FULLSCREEN_HEIGHT");
7241           next_maximized = FULLSCREEN_HEIGHT;
7242           if (fs_state != FULLSCREEN_BOTH)
7243             [[self window] performZoom:self];
7244           break;
7245         case FULLSCREEN_MAXIMIZED:
7246           NSTRACE_MSG ("FULLSCREEN_MAXIMIZED");
7247           next_maximized = FULLSCREEN_MAXIMIZED;
7248           if (fs_state != FULLSCREEN_BOTH)
7249             [[self window] performZoom:self];
7250           break;
7251         case FULLSCREEN_NONE:
7252           NSTRACE_MSG ("FULLSCREEN_NONE");
7253           if (fs_state != FULLSCREEN_BOTH)
7254             {
7255               next_maximized = FULLSCREEN_NONE;
7256               [[self window] performZoom:self];
7257             }
7258           break;
7259         }
7261       emacsframe->want_fullscreen = FULLSCREEN_NONE;
7262     }
7266 - (void) setFSValue: (int)value
7268   NSTRACE ("[EmacsView setFSValue:" NSTRACE_FMT_FSTYPE "]",
7269            NSTRACE_ARG_FSTYPE(value));
7271   Lisp_Object lval = Qnil;
7272   switch (value)
7273     {
7274     case FULLSCREEN_BOTH:
7275       lval = Qfullboth;
7276       break;
7277     case FULLSCREEN_WIDTH:
7278       lval = Qfullwidth;
7279       break;
7280     case FULLSCREEN_HEIGHT:
7281       lval = Qfullheight;
7282       break;
7283     case FULLSCREEN_MAXIMIZED:
7284       lval = Qmaximized;
7285       break;
7286     }
7287   store_frame_param (emacsframe, Qfullscreen, lval);
7288   fs_state = value;
7291 - (void)mouseEntered: (NSEvent *)theEvent
7293   NSTRACE ("[EmacsView mouseEntered:]");
7294   if (emacsframe)
7295     FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7296       = EV_TIMESTAMP (theEvent);
7300 - (void)mouseExited: (NSEvent *)theEvent
7302   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
7304   NSTRACE ("[EmacsView mouseExited:]");
7306   if (!hlinfo)
7307     return;
7309   FRAME_DISPLAY_INFO (emacsframe)->last_mouse_movement_time
7310     = EV_TIMESTAMP (theEvent);
7312   if (emacsframe == hlinfo->mouse_face_mouse_frame)
7313     {
7314       clear_mouse_face (hlinfo);
7315       hlinfo->mouse_face_mouse_frame = 0;
7316     }
7320 - menuDown: sender
7322   NSTRACE ("[EmacsView menuDown:]");
7323   if (context_menu_value == -1)
7324     context_menu_value = [sender tag];
7325   else
7326     {
7327       NSInteger tag = [sender tag];
7328       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
7329                                     emacsframe->menu_bar_vector,
7330                                     (void *)tag);
7331     }
7333   ns_send_appdefined (-1);
7334   return self;
7338 - (EmacsToolbar *)toolbar
7340   return toolbar;
7344 /* this gets called on toolbar button click */
7345 - toolbarClicked: (id)item
7347   NSEvent *theEvent;
7348   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
7350   NSTRACE ("[EmacsView toolbarClicked:]");
7352   if (!emacs_event)
7353     return self;
7355   /* send first event (for some reason two needed) */
7356   theEvent = [[self window] currentEvent];
7357   emacs_event->kind = TOOL_BAR_EVENT;
7358   XSETFRAME (emacs_event->arg, emacsframe);
7359   EV_TRAILER (theEvent);
7361   emacs_event->kind = TOOL_BAR_EVENT;
7362 /*   XSETINT (emacs_event->code, 0); */
7363   emacs_event->arg = AREF (emacsframe->tool_bar_items,
7364                            idx + TOOL_BAR_ITEM_KEY);
7365   emacs_event->modifiers = EV_MODIFIERS (theEvent);
7366   EV_TRAILER (theEvent);
7367   return self;
7371 - toggleToolbar: (id)sender
7373   NSTRACE ("[EmacsView toggleToolbar:]");
7375   if (!emacs_event)
7376     return self;
7378   emacs_event->kind = NS_NONKEY_EVENT;
7379   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
7380   EV_TRAILER ((id)nil);
7381   return self;
7385 - (void)drawRect: (NSRect)rect
7387   int x = NSMinX (rect), y = NSMinY (rect);
7388   int width = NSWidth (rect), height = NSHeight (rect);
7390   NSTRACE ("[EmacsView drawRect:" NSTRACE_FMT_RECT "]",
7391            NSTRACE_ARG_RECT(rect));
7393   if (!emacsframe || !emacsframe->output_data.ns)
7394     return;
7396   ns_clear_frame_area (emacsframe, x, y, width, height);
7397   block_input ();
7398   expose_frame (emacsframe, x, y, width, height);
7399   unblock_input ();
7401   /*
7402     drawRect: may be called (at least in OS X 10.5) for invisible
7403     views as well for some reason.  Thus, do not infer visibility
7404     here.
7406     emacsframe->async_visible = 1;
7407     emacsframe->async_iconified = 0;
7408   */
7412 /* NSDraggingDestination protocol methods.  Actually this is not really a
7413    protocol, but a category of Object.  O well...  */
7415 -(NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender
7417   NSTRACE ("[EmacsView draggingEntered:]");
7418   return NSDragOperationGeneric;
7422 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
7424   return YES;
7428 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
7430   id pb;
7431   int x, y;
7432   NSString *type;
7433   NSEvent *theEvent = [[self window] currentEvent];
7434   NSPoint position;
7435   NSDragOperation op = [sender draggingSourceOperationMask];
7436   int modifiers = 0;
7438   NSTRACE ("[EmacsView performDragOperation:]");
7440   if (!emacs_event)
7441     return NO;
7443   position = [self convertPoint: [sender draggingLocation] fromView: nil];
7444   x = lrint (position.x);  y = lrint (position.y);
7446   pb = [sender draggingPasteboard];
7447   type = [pb availableTypeFromArray: ns_drag_types];
7449   if (! (op & (NSDragOperationMove|NSDragOperationDelete)) &&
7450       // URL drags contain all operations (0xf), don't allow all to be set.
7451       (op & 0xf) != 0xf)
7452     {
7453       if (op & NSDragOperationLink)
7454         modifiers |= NSControlKeyMask;
7455       if (op & NSDragOperationCopy)
7456         modifiers |= NSAlternateKeyMask;
7457       if (op & NSDragOperationGeneric)
7458         modifiers |= NSCommandKeyMask;
7459     }
7461   modifiers = EV_MODIFIERS2 (modifiers);
7462   if (type == 0)
7463     {
7464       return NO;
7465     }
7466   else if ([type isEqualToString: NSFilenamesPboardType])
7467     {
7468       NSArray *files;
7469       NSEnumerator *fenum;
7470       NSString *file;
7472       if (!(files = [pb propertyListForType: type]))
7473         return NO;
7475       fenum = [files objectEnumerator];
7476       while ( (file = [fenum nextObject]) )
7477         {
7478           emacs_event->kind = DRAG_N_DROP_EVENT;
7479           XSETINT (emacs_event->x, x);
7480           XSETINT (emacs_event->y, y);
7481           ns_input_file = append2 (ns_input_file,
7482                                    build_string ([file UTF8String]));
7483           emacs_event->modifiers = modifiers;
7484           emacs_event->arg =  list2 (Qfile, build_string ([file UTF8String]));
7485           EV_TRAILER (theEvent);
7486         }
7487       return YES;
7488     }
7489   else if ([type isEqualToString: NSURLPboardType])
7490     {
7491       NSURL *url = [NSURL URLFromPasteboard: pb];
7492       if (url == nil) return NO;
7494       emacs_event->kind = DRAG_N_DROP_EVENT;
7495       XSETINT (emacs_event->x, x);
7496       XSETINT (emacs_event->y, y);
7497       emacs_event->modifiers = modifiers;
7498       emacs_event->arg =  list2 (Qurl,
7499                                  build_string ([[url absoluteString]
7500                                                  UTF8String]));
7501       EV_TRAILER (theEvent);
7503       if ([url isFileURL] != NO)
7504         {
7505           NSString *file = [url path];
7506           ns_input_file = append2 (ns_input_file,
7507                                    build_string ([file UTF8String]));
7508         }
7509       return YES;
7510     }
7511   else if ([type isEqualToString: NSStringPboardType]
7512            || [type isEqualToString: NSTabularTextPboardType])
7513     {
7514       NSString *data;
7516       if (! (data = [pb stringForType: type]))
7517         return NO;
7519       emacs_event->kind = DRAG_N_DROP_EVENT;
7520       XSETINT (emacs_event->x, x);
7521       XSETINT (emacs_event->y, y);
7522       emacs_event->modifiers = modifiers;
7523       emacs_event->arg =  list2 (Qnil, build_string ([data UTF8String]));
7524       EV_TRAILER (theEvent);
7525       return YES;
7526     }
7527   else
7528     {
7529       fprintf (stderr, "Invalid data type in dragging pasteboard");
7530       return NO;
7531     }
7535 - (id) validRequestorForSendType: (NSString *)typeSent
7536                       returnType: (NSString *)typeReturned
7538   NSTRACE ("[EmacsView validRequestorForSendType:returnType:]");
7539   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
7540       && typeReturned == nil)
7541     {
7542       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
7543         return self;
7544     }
7546   return [super validRequestorForSendType: typeSent
7547                                returnType: typeReturned];
7551 /* The next two methods are part of NSServicesRequests informal protocol,
7552    supposedly called when a services menu item is chosen from this app.
7553    But this should not happen because we override the services menu with our
7554    own entries which call ns-perform-service.
7555    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
7556    So let's at least stub them out until further investigation can be done. */
7558 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
7560   /* we could call ns_string_from_pasteboard(pboard) here but then it should
7561      be written into the buffer in place of the existing selection..
7562      ordinary service calls go through functions defined in ns-win.el */
7563   return NO;
7566 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
7568   NSArray *typesDeclared;
7569   Lisp_Object val;
7571   NSTRACE ("[EmacsView writeSelectionToPasteboard:types:]");
7573   /* We only support NSStringPboardType */
7574   if ([types containsObject:NSStringPboardType] == NO) {
7575     return NO;
7576   }
7578   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7579   if (CONSP (val) && SYMBOLP (XCAR (val)))
7580     {
7581       val = XCDR (val);
7582       if (CONSP (val) && NILP (XCDR (val)))
7583         val = XCAR (val);
7584     }
7585   if (! STRINGP (val))
7586     return NO;
7588   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
7589   [pb declareTypes:typesDeclared owner:nil];
7590   ns_string_to_pasteboard (pb, val);
7591   return YES;
7595 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
7596    (gives a miniaturized version of the window); currently we use the latter for
7597    frames whose active buffer doesn't correspond to any file
7598    (e.g., '*scratch*') */
7599 - setMiniwindowImage: (BOOL) setMini
7601   id image = [[self window] miniwindowImage];
7602   NSTRACE ("[EmacsView setMiniwindowImage:%d]", setMini);
7604   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
7605      about "AppleDockIconEnabled" notwithstanding, however the set message
7606      below has its effect nonetheless. */
7607   if (image != emacsframe->output_data.ns->miniimage)
7608     {
7609       if (image && [image isKindOfClass: [EmacsImage class]])
7610         [image release];
7611       [[self window] setMiniwindowImage:
7612                        setMini ? emacsframe->output_data.ns->miniimage : nil];
7613     }
7615   return self;
7619 - (void) setRows: (int) r andColumns: (int) c
7621   NSTRACE ("[EmacsView setRows:%d andColumns:%d]", r, c);
7622   rows = r;
7623   cols = c;
7626 - (int) fullscreenState
7628   return fs_state;
7631 @end  /* EmacsView */
7635 /* ==========================================================================
7637     EmacsWindow implementation
7639    ========================================================================== */
7641 @implementation EmacsWindow
7643 #ifdef NS_IMPL_COCOA
7644 - (id)accessibilityAttributeValue:(NSString *)attribute
7646   Lisp_Object str = Qnil;
7647   struct frame *f = SELECTED_FRAME ();
7648   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
7650   NSTRACE ("[EmacsWindow accessibilityAttributeValue:]");
7652   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
7653     return NSAccessibilityTextFieldRole;
7655   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
7656       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
7657     {
7658       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7659     }
7660   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
7661     {
7662       if (! NILP (BVAR (curbuf, mark_active)))
7663           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
7665       if (NILP (str))
7666         {
7667           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
7668           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
7669           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
7671           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
7672             str = make_uninit_multibyte_string (range, byte_range);
7673           else
7674             str = make_uninit_string (range);
7675           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
7676              Is this a problem?  */
7677           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
7678         }
7679     }
7682   if (! NILP (str))
7683     {
7684       if (CONSP (str) && SYMBOLP (XCAR (str)))
7685         {
7686           str = XCDR (str);
7687           if (CONSP (str) && NILP (XCDR (str)))
7688             str = XCAR (str);
7689         }
7690       if (STRINGP (str))
7691         {
7692           const char *utfStr = SSDATA (str);
7693           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
7694           return nsStr;
7695         }
7696     }
7698   return [super accessibilityAttributeValue:attribute];
7700 #endif /* NS_IMPL_COCOA */
7702 /* Constrain size and placement of a frame.
7704    By returning the original "frameRect", the frame is not
7705    constrained. This can lead to unwanted situations where, for
7706    example, the menu bar covers the frame.
7708    The default implementation (accessed using "super") constrains the
7709    frame to the visible area of SCREEN, minus the menu bar (if
7710    present) and the Dock.  Note that default implementation also calls
7711    windowWillResize, with the frame it thinks should have.  (This can
7712    make the frame exit maximized mode.)
7714    Note that this should work in situations where multiple monitors
7715    are present.  Common configurations are side-by-side monitors and a
7716    monitor on top of another (e.g. when a laptop is placed under a
7717    large screen). */
7718 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
7720   NSTRACE ("[EmacsWindow constrainFrameRect:" NSTRACE_FMT_RECT " toScreen:]",
7721              NSTRACE_ARG_RECT (frameRect));
7723 #ifdef NS_IMPL_COCOA
7724 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9
7725   // If separate spaces is on, it is like each screen is independent.  There is
7726   // no spanning of frames across screens.
7727   if ([NSScreen screensHaveSeparateSpaces])
7728     {
7729       NSTRACE_MSG ("Screens have separate spaces");
7730       frameRect = [super constrainFrameRect:frameRect toScreen:screen];
7731       NSTRACE_RETURN_RECT (frameRect);
7732       return frameRect;
7733     }
7734 #endif
7735 #endif
7737   return constrain_frame_rect(frameRect);
7741 - (void)performZoom:(id)sender
7743   NSTRACE ("[EmacsWindow performZoom:]");
7745   return [super performZoom:sender];
7748 - (void)zoom:(id)sender
7750   struct frame * f = SELECTED_FRAME ();
7752   NSTRACE ("[EmacsWindow zoom:]");
7754   ns_update_auto_hide_menu_bar();
7756   // Below are three zoom implementations.  In the final commit, the
7757   // idea is that the last should be included.
7759 #if 0
7760   // Native zoom done using the standard zoom animation.  Size of the
7761   // resulting frame reduced to accommodate the Dock and, if present,
7762   // the menu-bar.
7763   [super zoom:sender];
7765 #elsif 0
7766   // Native zoom done using the standard zoom animation, plus an
7767   // explicit resize to cover the full screen.
7768   [super zoom:sender];
7770   // After the native zoom, resize the resulting frame to fill the
7771   // entire screen, except the menu-bar.
7772   //
7773   // This works for all practical purposes.  (The only minor oddity is
7774   // when transiting from full-height frame to a maximized, the
7775   // animation reduces the height of the frame slightly (to the 4
7776   // pixels needed to accommodate the Doc) before it snaps back into
7777   // full height.  The user would need a very trained eye to spot
7778   // this.)
7779   NSScreen * screen = [self screen];
7780   if (screen != nil)
7781     {
7782       int fs_state = [(EmacsView *)[self delegate] fullscreenState];
7784       NSTRACE_FSTYPE ("fullscreenState", fs_state);
7786       NSRect sr = [screen frame];
7787       NSRect wr = [self frame];
7788       NSTRACE_RECT ("Rect after zoom", wr);
7790       NSRect newWr = wr;
7792       if (fs_state == FULLSCREEN_MAXIMIZED
7793           || fs_state == FULLSCREEN_HEIGHT)
7794         {
7795           newWr.origin.x = 0;
7796           newWr.size.height = sr.size.height - ns_menu_bar_height(screen);
7797         }
7799       if (fs_state == FULLSCREEN_MAXIMIZED
7800           || fs_state == FULLSCREEN_WIDTH)
7801         {
7802           newWr.origin.y = 0;
7803           newWr.size.width = sr.size.width;
7804         }
7806       if (newWr.size.width     != wr.size.width
7807           || newWr.size.height != wr.size.height
7808           || newWr.origin.x    != wr.origin.x
7809           || newWr.origin.y    != wr.origin.y)
7810         {
7811           NSTRACE_MSG ("New frame different");
7812           [self setFrame: newWr display: NO];
7813         }
7814     }
7815 #else
7816   // Non-native zoom which is done instantaneously.  The resulting frame
7817   // covers the entire screen, except the menu-bar, if present.
7818   NSScreen * screen = [self screen];
7819   if (screen != nil)
7820     {
7821       NSRect sr = [screen frame];
7822       sr.size.height -= ns_menu_bar_height (screen);
7824       sr = [[self delegate] windowWillUseStandardFrame:self
7825                                           defaultFrame:sr];
7826       [self setFrame: sr display: NO];
7827     }
7828 #endif
7831 - (void)setFrame:(NSRect)windowFrame
7832          display:(BOOL)displayViews
7834   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT " display:%d]",
7835            NSTRACE_ARG_RECT (windowFrame), displayViews);
7837   [super setFrame:windowFrame display:displayViews];
7840 - (void)setFrame:(NSRect)windowFrame
7841          display:(BOOL)displayViews
7842          animate:(BOOL)performAnimation
7844   NSTRACE ("[EmacsWindow setFrame:" NSTRACE_FMT_RECT
7845            " display:%d performAnimation:%d]",
7846            NSTRACE_ARG_RECT (windowFrame), displayViews, performAnimation);
7848   [super setFrame:windowFrame display:displayViews animate:performAnimation];
7851 - (void)setFrameTopLeftPoint:(NSPoint)point
7853   NSTRACE ("[EmacsWindow setFrameTopLeftPoint:" NSTRACE_FMT_POINT "]",
7854            NSTRACE_ARG_POINT (point));
7856   [super setFrameTopLeftPoint:point];
7858 @end /* EmacsWindow */
7861 @implementation EmacsFSWindow
7863 - (BOOL)canBecomeKeyWindow
7865   return YES;
7868 - (BOOL)canBecomeMainWindow
7870   return YES;
7873 @end
7875 /* ==========================================================================
7877     EmacsScroller implementation
7879    ========================================================================== */
7882 @implementation EmacsScroller
7884 /* for repeat button push */
7885 #define SCROLL_BAR_FIRST_DELAY 0.5
7886 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
7888 + (CGFloat) scrollerWidth
7890   /* TODO: if we want to allow variable widths, this is the place to do it,
7891            however neither GNUstep nor Cocoa support it very well */
7892   CGFloat r;
7893 #if !defined (NS_IMPL_COCOA) || \
7894   MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
7895   r = [NSScroller scrollerWidth];
7896 #else
7897   r = [NSScroller scrollerWidthForControlSize: NSRegularControlSize
7898                                 scrollerStyle: NSScrollerStyleLegacy];
7899 #endif
7900   return r;
7904 - initFrame: (NSRect )r window: (Lisp_Object)nwin
7906   NSTRACE ("[EmacsScroller initFrame: window:]");
7908   r.size.width = [EmacsScroller scrollerWidth];
7909   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
7910   [self setContinuous: YES];
7911   [self setEnabled: YES];
7913   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
7914      locked against the top and bottom edges, and right edge on OS X, where
7915      scrollers are on right. */
7916 #ifdef NS_IMPL_GNUSTEP
7917   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
7918 #else
7919   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
7920 #endif
7922   window = XWINDOW (nwin);
7923   condemned = NO;
7924   pixel_height = NSHeight (r);
7925   if (pixel_height == 0) pixel_height = 1;
7926   min_portion = 20 / pixel_height;
7928   frame = XFRAME (window->frame);
7929   if (FRAME_LIVE_P (frame))
7930     {
7931       int i;
7932       EmacsView *view = FRAME_NS_VIEW (frame);
7933       NSView *sview = [[view window] contentView];
7934       NSArray *subs = [sview subviews];
7936       /* disable optimization stopping redraw of other scrollbars */
7937       view->scrollbarsNeedingUpdate = 0;
7938       for (i =[subs count]-1; i >= 0; i--)
7939         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
7940           view->scrollbarsNeedingUpdate++;
7941       [sview addSubview: self];
7942     }
7944 /*  [self setFrame: r]; */
7946   return self;
7950 - (void)setFrame: (NSRect)newRect
7952   NSTRACE ("[EmacsScroller setFrame:]");
7954 /*  block_input (); */
7955   pixel_height = NSHeight (newRect);
7956   if (pixel_height == 0) pixel_height = 1;
7957   min_portion = 20 / pixel_height;
7958   [super setFrame: newRect];
7959 /*  unblock_input (); */
7963 - (void)dealloc
7965   NSTRACE ("[EmacsScroller dealloc]");
7966   if (window)
7967     wset_vertical_scroll_bar (window, Qnil);
7968   window = 0;
7969   [super dealloc];
7973 - condemn
7975   NSTRACE ("[EmacsScroller condemn]");
7976   condemned =YES;
7977   return self;
7981 - reprieve
7983   NSTRACE ("[EmacsScroller reprieve]");
7984   condemned =NO;
7985   return self;
7989 -(bool)judge
7991   NSTRACE ("[EmacsScroller judge]");
7992   bool ret = condemned;
7993   if (condemned)
7994     {
7995       EmacsView *view;
7996       block_input ();
7997       /* ensure other scrollbar updates after deletion */
7998       view = (EmacsView *)FRAME_NS_VIEW (frame);
7999       if (view != nil)
8000         view->scrollbarsNeedingUpdate++;
8001       if (window)
8002         wset_vertical_scroll_bar (window, Qnil);
8003       window = 0;
8004       [self removeFromSuperview];
8005       [self release];
8006       unblock_input ();
8007     }
8008   return ret;
8012 - (void)resetCursorRects
8014   NSRect visible = [self visibleRect];
8015   NSTRACE ("[EmacsScroller resetCursorRects]");
8017   if (!NSIsEmptyRect (visible))
8018     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
8019   [[NSCursor arrowCursor] setOnMouseEntered: YES];
8023 - (int) checkSamePosition: (int) position portion: (int) portion
8024                     whole: (int) whole
8026   return em_position ==position && em_portion ==portion && em_whole ==whole
8027     && portion != whole; /* needed for resize empty buf */
8031 - setPosition: (int)position portion: (int)portion whole: (int)whole
8033   NSTRACE ("[EmacsScroller setPosition:portion:whole:]");
8035   em_position = position;
8036   em_portion = portion;
8037   em_whole = whole;
8039   if (portion >= whole)
8040     {
8041 #ifdef NS_IMPL_COCOA
8042       [self setKnobProportion: 1.0];
8043       [self setDoubleValue: 1.0];
8044 #else
8045       [self setFloatValue: 0.0 knobProportion: 1.0];
8046 #endif
8047     }
8048   else
8049     {
8050       float pos;
8051       CGFloat por;
8052       portion = max ((float)whole*min_portion/pixel_height, portion);
8053       pos = (float)position / (whole - portion);
8054       por = (CGFloat)portion/whole;
8055 #ifdef NS_IMPL_COCOA
8056       [self setKnobProportion: por];
8057       [self setDoubleValue: pos];
8058 #else
8059       [self setFloatValue: pos knobProportion: por];
8060 #endif
8061     }
8063   return self;
8066 /* set up emacs_event */
8067 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
8069   Lisp_Object win;
8071   NSTRACE ("[EmacsScroller sendScrollEventAtLoc:fromEvent:]");
8073   if (!emacs_event)
8074     return;
8076   emacs_event->part = last_hit_part;
8077   emacs_event->code = 0;
8078   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
8079   XSETWINDOW (win, window);
8080   emacs_event->frame_or_window = win;
8081   emacs_event->timestamp = EV_TIMESTAMP (e);
8082   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
8083   emacs_event->arg = Qnil;
8084   XSETINT (emacs_event->x, loc * pixel_height);
8085   XSETINT (emacs_event->y, pixel_height-20);
8087   if (q_event_ptr)
8088     {
8089       n_emacs_events_pending++;
8090       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
8091     }
8092   else
8093     hold_event (emacs_event);
8094   EVENT_INIT (*emacs_event);
8095   ns_send_appdefined (-1);
8099 /* called manually thru timer to implement repeated button action w/hold-down */
8100 - repeatScroll: (NSTimer *)scrollEntry
8102   NSEvent *e = [[self window] currentEvent];
8103   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
8104   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
8106   NSTRACE ("[EmacsScroller repeatScroll:]");
8108   /* clear timer if need be */
8109   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
8110     {
8111         [scroll_repeat_entry invalidate];
8112         [scroll_repeat_entry release];
8113         scroll_repeat_entry = nil;
8115         if (inKnob)
8116           return self;
8118         scroll_repeat_entry
8119           = [[NSTimer scheduledTimerWithTimeInterval:
8120                         SCROLL_BAR_CONTINUOUS_DELAY
8121                                             target: self
8122                                           selector: @selector (repeatScroll:)
8123                                           userInfo: 0
8124                                            repeats: YES]
8125               retain];
8126     }
8128   [self sendScrollEventAtLoc: 0 fromEvent: e];
8129   return self;
8133 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
8134    mouseDragged events without going into a modal loop. */
8135 - (void)mouseDown: (NSEvent *)e
8137   NSRect sr, kr;
8138   /* hitPart is only updated AFTER event is passed on */
8139   NSScrollerPart part = [self testPart: [e locationInWindow]];
8140   CGFloat inc = 0.0, loc, kloc, pos;
8141   int edge = 0;
8143   NSTRACE ("[EmacsScroller mouseDown:]");
8145   switch (part)
8146     {
8147     case NSScrollerDecrementPage:
8148         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
8149     case NSScrollerIncrementPage:
8150         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
8151     case NSScrollerDecrementLine:
8152       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
8153     case NSScrollerIncrementLine:
8154       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
8155     case NSScrollerKnob:
8156       last_hit_part = scroll_bar_handle; break;
8157     case NSScrollerKnobSlot:  /* GNUstep-only */
8158       last_hit_part = scroll_bar_move_ratio; break;
8159     default:  /* NSScrollerNoPart? */
8160       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
8161                (long) part);
8162       return;
8163     }
8165   if (inc != 0.0)
8166     {
8167       pos = 0;      /* ignored */
8169       /* set a timer to repeat, as we can't let superclass do this modally */
8170       scroll_repeat_entry
8171         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
8172                                             target: self
8173                                           selector: @selector (repeatScroll:)
8174                                           userInfo: 0
8175                                            repeats: YES]
8176             retain];
8177     }
8178   else
8179     {
8180       /* handle, or on GNUstep possibly slot */
8181       NSEvent *fake_event;
8183       /* compute float loc in slot and mouse offset on knob */
8184       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8185                       toView: nil];
8186       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8187       if (loc <= 0.0)
8188         {
8189           loc = 0.0;
8190           edge = -1;
8191         }
8192       else if (loc >= NSHeight (sr))
8193         {
8194           loc = NSHeight (sr);
8195           edge = 1;
8196         }
8198       if (edge)
8199         kloc = 0.5 * edge;
8200       else
8201         {
8202           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
8203                           toView: nil];
8204           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
8205         }
8206       last_mouse_offset = kloc;
8208       /* if knob, tell emacs a location offset by knob pos
8209          (to indicate top of handle) */
8210       if (part == NSScrollerKnob)
8211           pos = (loc - last_mouse_offset) / NSHeight (sr);
8212       else
8213         /* else this is a slot click on GNUstep: go straight there */
8214         pos = loc / NSHeight (sr);
8216       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
8217       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
8218                                       location: [e locationInWindow]
8219                                  modifierFlags: [e modifierFlags]
8220                                      timestamp: [e timestamp]
8221                                   windowNumber: [e windowNumber]
8222                                        context: [e context]
8223                                    eventNumber: [e eventNumber]
8224                                     clickCount: [e clickCount]
8225                                       pressure: [e pressure]];
8226       [super mouseUp: fake_event];
8227     }
8229   if (part != NSScrollerKnob)
8230     [self sendScrollEventAtLoc: pos fromEvent: e];
8234 /* Called as we manually track scroller drags, rather than superclass. */
8235 - (void)mouseDragged: (NSEvent *)e
8237     NSRect sr;
8238     double loc, pos;
8240     NSTRACE ("[EmacsScroller mouseDragged:]");
8242       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
8243                       toView: nil];
8244       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
8246       if (loc <= 0.0)
8247         {
8248           loc = 0.0;
8249         }
8250       else if (loc >= NSHeight (sr) + last_mouse_offset)
8251         {
8252           loc = NSHeight (sr) + last_mouse_offset;
8253         }
8255       pos = (loc - last_mouse_offset) / NSHeight (sr);
8256       [self sendScrollEventAtLoc: pos fromEvent: e];
8260 - (void)mouseUp: (NSEvent *)e
8262   NSTRACE ("[EmacsScroller mouseUp:]");
8264   if (scroll_repeat_entry)
8265     {
8266       [scroll_repeat_entry invalidate];
8267       [scroll_repeat_entry release];
8268       scroll_repeat_entry = nil;
8269     }
8270   last_hit_part = scroll_bar_above_handle;
8274 /* treat scrollwheel events in the bar as though they were in the main window */
8275 - (void) scrollWheel: (NSEvent *)theEvent
8277   NSTRACE ("[EmacsScroller scrollWheel:]");
8279   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
8280   [view mouseDown: theEvent];
8283 @end  /* EmacsScroller */
8286 #ifdef NS_IMPL_GNUSTEP
8287 /* Dummy class to get rid of startup warnings.  */
8288 @implementation EmacsDocument
8290 @end
8291 #endif
8294 /* ==========================================================================
8296    Font-related functions; these used to be in nsfaces.m
8298    ========================================================================== */
8301 Lisp_Object
8302 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
8304   struct font *font = XFONT_OBJECT (font_object);
8305   EmacsView *view = FRAME_NS_VIEW (f);
8306   int font_ascent, font_descent;
8308   if (fontset < 0)
8309     fontset = fontset_from_font (font_object);
8310   FRAME_FONTSET (f) = fontset;
8312   if (FRAME_FONT (f) == font)
8313     /* This font is already set in frame F.  There's nothing more to
8314        do.  */
8315     return font_object;
8317   FRAME_FONT (f) = font;
8319   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
8320   FRAME_COLUMN_WIDTH (f) = font->average_width;
8321   get_font_ascent_descent (font, &font_ascent, &font_descent);
8322   FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
8324   /* Compute the scroll bar width in character columns.  */
8325   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
8326     {
8327       int wid = FRAME_COLUMN_WIDTH (f);
8328       FRAME_CONFIG_SCROLL_BAR_COLS (f)
8329         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
8330     }
8331   else
8332     {
8333       int wid = FRAME_COLUMN_WIDTH (f);
8334       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
8335     }
8337   /* Compute the scroll bar height in character lines.  */
8338   if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
8339     {
8340       int height = FRAME_LINE_HEIGHT (f);
8341       FRAME_CONFIG_SCROLL_BAR_LINES (f)
8342         = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
8343     }
8344   else
8345     {
8346       int height = FRAME_LINE_HEIGHT (f);
8347       FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
8348     }
8350   /* Now make the frame display the given font.  */
8351   if (FRAME_NS_WINDOW (f) != 0 && ! [view isFullscreen])
8352     adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
8353                        FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
8354                        false, Qfont);
8356   return font_object;
8360 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
8361 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
8362          in 1.43. */
8364 const char *
8365 ns_xlfd_to_fontname (const char *xlfd)
8366 /* --------------------------------------------------------------------------
8367     Convert an X font name (XLFD) to an NS font name.
8368     Only family is used.
8369     The string returned is temporarily allocated.
8370    -------------------------------------------------------------------------- */
8372   char *name = xmalloc (180);
8373   int i, len;
8374   const char *ret;
8376   if (!strncmp (xlfd, "--", 2))
8377     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
8378   else
8379     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
8381   /* stopgap for malformed XLFD input */
8382   if (strlen (name) == 0)
8383     strcpy (name, "Monaco");
8385   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
8386      also uppercase after '-' or ' ' */
8387   name[0] = c_toupper (name[0]);
8388   for (len =strlen (name), i =0; i<len; i++)
8389     {
8390       if (name[i] == '$')
8391         {
8392           name[i] = '-';
8393           if (i+1<len)
8394             name[i+1] = c_toupper (name[i+1]);
8395         }
8396       else if (name[i] == '_')
8397         {
8398           name[i] = ' ';
8399           if (i+1<len)
8400             name[i+1] = c_toupper (name[i+1]);
8401         }
8402     }
8403 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
8404   ret = [[NSString stringWithUTF8String: name] UTF8String];
8405   xfree (name);
8406   return ret;
8410 void
8411 syms_of_nsterm (void)
8413   NSTRACE ("syms_of_nsterm");
8415   ns_antialias_threshold = 10.0;
8417   /* from 23+ we need to tell emacs what modifiers there are.. */
8418   DEFSYM (Qmodifier_value, "modifier-value");
8419   DEFSYM (Qalt, "alt");
8420   DEFSYM (Qhyper, "hyper");
8421   DEFSYM (Qmeta, "meta");
8422   DEFSYM (Qsuper, "super");
8423   DEFSYM (Qcontrol, "control");
8424   DEFSYM (QUTF8_STRING, "UTF8_STRING");
8426   DEFSYM (Qfile, "file");
8427   DEFSYM (Qurl, "url");
8429   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
8430   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
8431   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
8432   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
8433   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
8435   DEFVAR_LISP ("ns-input-file", ns_input_file,
8436               "The file specified in the last NS event.");
8437   ns_input_file =Qnil;
8439   DEFVAR_LISP ("ns-working-text", ns_working_text,
8440               "String for visualizing working composition sequence.");
8441   ns_working_text =Qnil;
8443   DEFVAR_LISP ("ns-input-font", ns_input_font,
8444               "The font specified in the last NS event.");
8445   ns_input_font =Qnil;
8447   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
8448               "The fontsize specified in the last NS event.");
8449   ns_input_fontsize =Qnil;
8451   DEFVAR_LISP ("ns-input-line", ns_input_line,
8452                "The line specified in the last NS event.");
8453   ns_input_line =Qnil;
8455   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
8456                "The service name specified in the last NS event.");
8457   ns_input_spi_name =Qnil;
8459   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
8460                "The service argument specified in the last NS event.");
8461   ns_input_spi_arg =Qnil;
8463   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
8464                "This variable describes the behavior of the alternate or option key.\n\
8465 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8466 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8467 at all, allowing it to be used at a lower level for accented character entry.");
8468   ns_alternate_modifier = Qmeta;
8470   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
8471                "This variable describes the behavior of the right alternate or option key.\n\
8472 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8473 Set to left means be the same key as `ns-alternate-modifier'.\n\
8474 Set to none means that the alternate / option key is not interpreted by Emacs\n\
8475 at all, allowing it to be used at a lower level for accented character entry.");
8476   ns_right_alternate_modifier = Qleft;
8478   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
8479                "This variable describes the behavior of the command key.\n\
8480 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8481   ns_command_modifier = Qsuper;
8483   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
8484                "This variable describes the behavior of the right command key.\n\
8485 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8486 Set to left means be the same key as `ns-command-modifier'.\n\
8487 Set to none means that the command / option key is not interpreted by Emacs\n\
8488 at all, allowing it to be used at a lower level for accented character entry.");
8489   ns_right_command_modifier = Qleft;
8491   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
8492                "This variable describes the behavior of the control key.\n\
8493 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
8494   ns_control_modifier = Qcontrol;
8496   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
8497                "This variable describes the behavior of the right control key.\n\
8498 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8499 Set to left means be the same key as `ns-control-modifier'.\n\
8500 Set to none means that the control / option key is not interpreted by Emacs\n\
8501 at all, allowing it to be used at a lower level for accented character entry.");
8502   ns_right_control_modifier = Qleft;
8504   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
8505                "This variable describes the behavior of the function key (on laptops).\n\
8506 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
8507 Set to none means that the function key is not interpreted by Emacs at all,\n\
8508 allowing it to be used at a lower level for accented character entry.");
8509   ns_function_modifier = Qnone;
8511   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
8512                "Non-nil (the default) means to render text antialiased.");
8513   ns_antialias_text = Qt;
8515   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
8516                "Whether to confirm application quit using dialog.");
8517   ns_confirm_quit = Qnil;
8519   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
8520                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
8521 Only works on OSX 10.6 or later.  */);
8522   ns_auto_hide_menu_bar = Qnil;
8524   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
8525      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
8526 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
8527 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
8528 Default is t for OSX >= 10.7, nil otherwise.  */);
8529 #ifdef HAVE_NATIVE_FS
8530   ns_use_native_fullscreen = YES;
8531 #else
8532   ns_use_native_fullscreen = NO;
8533 #endif
8534   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
8536   DEFVAR_BOOL ("ns-use-fullscreen-animation", ns_use_fullscreen_animation,
8537      doc: /*Non-nil means use animation on non-native fullscreen.
8538 For native fullscreen, this does nothing.
8539 Default is nil.  */);
8540   ns_use_fullscreen_animation = NO;
8542   DEFVAR_BOOL ("ns-use-srgb-colorspace", ns_use_srgb_colorspace,
8543      doc: /*Non-nil means to use sRGB colorspace on OSX >= 10.7.
8544 Note that this does not apply to images.
8545 This variable is ignored on OSX < 10.7 and GNUstep.  */);
8546   ns_use_srgb_colorspace = YES;
8548   /* TODO: move to common code */
8549   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
8550                doc: /* Which toolkit scroll bars Emacs uses, if any.
8551 A value of nil means Emacs doesn't use toolkit scroll bars.
8552 With the X Window system, the value is a symbol describing the
8553 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
8554 With MS Windows or Nextstep, the value is t.  */);
8555   Vx_toolkit_scroll_bars = Qt;
8557   DEFVAR_BOOL ("x-use-underline-position-properties",
8558                x_use_underline_position_properties,
8559      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
8560 A value of nil means ignore them.  If you encounter fonts with bogus
8561 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
8562 to 4.1, set this to nil. */);
8563   x_use_underline_position_properties = 0;
8565   DEFVAR_BOOL ("x-underline-at-descent-line",
8566                x_underline_at_descent_line,
8567      doc: /* Non-nil means to draw the underline at the same place as the descent line.
8568 A value of nil means to draw the underline according to the value of the
8569 variable `x-use-underline-position-properties', which is usually at the
8570 baseline level.  The default value is nil.  */);
8571   x_underline_at_descent_line = 0;
8573   /* Tell Emacs about this window system.  */
8574   Fprovide (Qns, Qnil);
8576   DEFSYM (Qcocoa, "cocoa");
8577   DEFSYM (Qgnustep, "gnustep");
8579 #ifdef NS_IMPL_COCOA
8580   Fprovide (Qcocoa, Qnil);
8581   syms_of_macfont ();
8582 #else
8583   Fprovide (Qgnustep, Qnil);
8584   syms_of_nsfont ();
8585 #endif