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