The experimental url syntax for remote file names is withdrawn.
[emacs.git] / src / nsterm.m
blob31053ca7a0d3ef5fee5708a5640b272de356f1c5
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2013 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"
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 /* call tracing */
68 #if 0
69 int term_trace_num = 0;
70 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
71                                 __FILE__, __LINE__, ++term_trace_num)
72 #else
73 #define NSTRACE(x)
74 #endif
76 extern NSString *NSMenuDidBeginTrackingNotification;
78 /* ==========================================================================
80     Local declarations
82    ========================================================================== */
84 /* Convert a symbol indexed with an NSxxx value to a value as defined
85    in keyboard.c (lispy_function_key). I hope this is a correct way
86    of doing things... */
87 static unsigned convert_ns_to_X_keysym[] =
89   NSHomeFunctionKey,            0x50,
90   NSLeftArrowFunctionKey,       0x51,
91   NSUpArrowFunctionKey,         0x52,
92   NSRightArrowFunctionKey,      0x53,
93   NSDownArrowFunctionKey,       0x54,
94   NSPageUpFunctionKey,          0x55,
95   NSPageDownFunctionKey,        0x56,
96   NSEndFunctionKey,             0x57,
97   NSBeginFunctionKey,           0x58,
98   NSSelectFunctionKey,          0x60,
99   NSPrintFunctionKey,           0x61,
100   NSClearLineFunctionKey,       0x0B,
101   NSExecuteFunctionKey,         0x62,
102   NSInsertFunctionKey,          0x63,
103   NSUndoFunctionKey,            0x65,
104   NSRedoFunctionKey,            0x66,
105   NSMenuFunctionKey,            0x67,
106   NSFindFunctionKey,            0x68,
107   NSHelpFunctionKey,            0x6A,
108   NSBreakFunctionKey,           0x6B,
110   NSF1FunctionKey,              0xBE,
111   NSF2FunctionKey,              0xBF,
112   NSF3FunctionKey,              0xC0,
113   NSF4FunctionKey,              0xC1,
114   NSF5FunctionKey,              0xC2,
115   NSF6FunctionKey,              0xC3,
116   NSF7FunctionKey,              0xC4,
117   NSF8FunctionKey,              0xC5,
118   NSF9FunctionKey,              0xC6,
119   NSF10FunctionKey,             0xC7,
120   NSF11FunctionKey,             0xC8,
121   NSF12FunctionKey,             0xC9,
122   NSF13FunctionKey,             0xCA,
123   NSF14FunctionKey,             0xCB,
124   NSF15FunctionKey,             0xCC,
125   NSF16FunctionKey,             0xCD,
126   NSF17FunctionKey,             0xCE,
127   NSF18FunctionKey,             0xCF,
128   NSF19FunctionKey,             0xD0,
129   NSF20FunctionKey,             0xD1,
130   NSF21FunctionKey,             0xD2,
131   NSF22FunctionKey,             0xD3,
132   NSF23FunctionKey,             0xD4,
133   NSF24FunctionKey,             0xD5,
135   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
136   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
137   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
139   NSTabCharacter,               0x09,
140   0x19,                         0x09,  /* left tab->regular since pass shift */
141   NSCarriageReturnCharacter,    0x0D,
142   NSNewlineCharacter,           0x0D,
143   NSEnterCharacter,             0x8D,
145   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
146   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
147   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
148   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
149   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
150   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
151   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
152   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
153   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
154   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
155   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
156   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
157   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
158   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
159   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
160   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
162   0x1B,                         0x1B   /* escape */
165 static Lisp_Object Qmodifier_value;
166 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
167 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
169 static Lisp_Object QUTF8_STRING;
171 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
172    the maximum font size to NOT antialias.  On GNUstep there is currently
173    no way to control this behavior. */
174 float ns_antialias_threshold;
176 /* Used to pick up AppleHighlightColor on OS X */
177 NSString *ns_selection_color;
179 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
180 NSString *ns_app_name = @"Emacs";  /* default changed later */
182 /* Display variables */
183 struct ns_display_info *x_display_list; /* Chain of existing displays */
184 Lisp_Object ns_display_name_list;
185 long context_menu_value = 0;
187 /* display update */
188 NSPoint last_mouse_motion_position;
189 static NSRect last_mouse_glyph;
190 static Time last_mouse_movement_time = 0;
191 static Lisp_Object last_mouse_motion_frame;
192 static EmacsScroller *last_mouse_scroll_bar = nil;
193 static struct frame *ns_updating_frame;
194 static NSView *focus_view = NULL;
195 static int ns_window_num = 0;
196 #ifdef NS_IMPL_GNUSTEP
197 static NSRect uRect;
198 #endif
199 static BOOL gsaved = NO;
200 static BOOL ns_fake_keydown = NO;
201 int ns_tmp_flags; /* FIXME */
202 struct nsfont_info *ns_tmp_font; /* FIXME */
203 #ifdef NS_IMPL_COCOA
204 static BOOL ns_menu_bar_is_hidden = NO;
205 #endif
206 /*static int debug_lock = 0; */
208 /* event loop */
209 static BOOL send_appdefined = YES;
210 #define NO_APPDEFINED_DATA (-8)
211 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
212 static NSTimer *timed_entry = 0;
213 static NSTimer *scroll_repeat_entry = nil;
214 static fd_set select_readfds, select_writefds;
215 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
216 static int select_nfds = 0, select_valid = 0;
217 static struct timespec select_timeout = { 0, 0 };
218 static int selfds[2] = { -1, -1 };
219 static pthread_mutex_t select_mutex;
220 static int apploopnr = 0;
221 static NSAutoreleasePool *outerpool;
222 static struct input_event *emacs_event = NULL;
223 static struct input_event *q_event_ptr = NULL;
224 static int n_emacs_events_pending = 0;
225 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
226   *ns_pending_service_args;
227 static BOOL ns_do_open_file = NO;
228 static BOOL ns_last_use_native_fullscreen;
230 static struct {
231   struct input_event *q;
232   int nr, cap;
233 } hold_event_q = {
234   NULL, 0, 0
237 #ifdef NS_IMPL_COCOA
239  * State for pending menu activation:
240  * MENU_NONE     Normal state
241  * MENU_PENDING  A menu has been clicked on, but has been canceled so we can
242  *               run lisp to update the menu.
243  * MENU_OPENING  Menu is up to date, and the click event is redone so the menu
244  *               will open.
245  */
246 #define MENU_NONE 0
247 #define MENU_PENDING 1
248 #define MENU_OPENING 2
249 static int menu_will_open_state = MENU_NONE;
251 /* Saved position for menu click.  */
252 static CGPoint menu_mouse_point;
253 #endif
255 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
256 #define NS_FUNCTION_KEY_MASK 0x800000
257 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
258 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
259 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
260 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
261 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
262 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
263 #define EV_MODIFIERS(e)                               \
264     ((([e modifierFlags] & NSHelpKeyMask) ?           \
265            hyper_modifier : 0)                        \
266      | (!EQ (ns_right_alternate_modifier, Qleft) && \
267         (([e modifierFlags] & NSRightAlternateKeyMask) \
268          == NSRightAlternateKeyMask) ? \
269            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
270      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
271            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
272      | (([e modifierFlags] & NSShiftKeyMask) ?     \
273            shift_modifier : 0)                        \
274      | (!EQ (ns_right_control_modifier, Qleft) && \
275         (([e modifierFlags] & NSRightControlKeyMask) \
276          == NSRightControlKeyMask) ? \
277            parse_solitary_modifier (ns_right_control_modifier) : 0) \
278      | (([e modifierFlags] & NSControlKeyMask) ?      \
279            parse_solitary_modifier (ns_control_modifier) : 0)     \
280      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
281            parse_solitary_modifier (ns_function_modifier) : 0)    \
282      | (!EQ (ns_right_command_modifier, Qleft) && \
283         (([e modifierFlags] & NSRightCommandKeyMask) \
284          == NSRightCommandKeyMask) ? \
285            parse_solitary_modifier (ns_right_command_modifier) : 0) \
286      | (([e modifierFlags] & NSCommandKeyMask) ?      \
287            parse_solitary_modifier (ns_command_modifier):0))
289 #define EV_UDMODIFIERS(e)                                      \
290     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
291      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
292      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
293      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
294      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
295      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
296      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
297      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
298      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
300 #define EV_BUTTON(e)                                                         \
301     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
302       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
303      [e buttonNumber] - 1)
305 /* Convert the time field to a timestamp in milliseconds. */
306 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
308 /* This is a piece of code which is common to all the event handling
309    methods.  Maybe it should even be a function.  */
310 #define EV_TRAILER(e)                                                   \
311   {                                                                     \
312     XSETFRAME (emacs_event->frame_or_window, emacsframe);               \
313     EV_TRAILER2 (e);                                                    \
314   }
316 #define EV_TRAILER2(e)                                                  \
317   {                                                                     \
318       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
319       if (q_event_ptr)                                                  \
320         {                                                               \
321           n_emacs_events_pending++;                                     \
322           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
323         }                                                               \
324       else                                                              \
325         hold_event (emacs_event);                                       \
326       EVENT_INIT (*emacs_event);                                        \
327       ns_send_appdefined (-1);                                          \
328     }
330 /* TODO: get rid of need for these forward declarations */
331 static void ns_condemn_scroll_bars (struct frame *f);
332 static void ns_judge_scroll_bars (struct frame *f);
333 void x_set_frame_alpha (struct frame *f);
336 /* ==========================================================================
338     Utilities
340    ========================================================================== */
342 static void
343 hold_event (struct input_event *event)
345   if (hold_event_q.nr == hold_event_q.cap)
346     {
347       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
348       else hold_event_q.cap *= 2;
349       hold_event_q.q =
350         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof *hold_event_q.q);
351     }
353   hold_event_q.q[hold_event_q.nr++] = *event;
354   /* Make sure ns_read_socket is called, i.e. we have input.  */
355   raise (SIGIO);
356   send_appdefined = YES;
359 static Lisp_Object
360 append2 (Lisp_Object list, Lisp_Object item)
361 /* --------------------------------------------------------------------------
362    Utility to append to a list
363    -------------------------------------------------------------------------- */
365   Lisp_Object array[2];
366   array[0] = list;
367   array[1] = list1 (item);
368   return Fnconc (2, &array[0]);
372 const char *
373 ns_etc_directory (void)
374 /* If running as a self-contained app bundle, return as a string the
375    filename of the etc directory, if present; else nil.  */
377   NSBundle *bundle = [NSBundle mainBundle];
378   NSString *resourceDir = [bundle resourcePath];
379   NSString *resourcePath;
380   NSFileManager *fileManager = [NSFileManager defaultManager];
381   BOOL isDir;
383   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
384   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
385     {
386       if (isDir) return [resourcePath UTF8String];
387     }
388   return NULL;
392 const char *
393 ns_exec_path (void)
394 /* If running as a self-contained app bundle, return as a path string
395    the filenames of the libexec and bin directories, ie libexec:bin.
396    Otherwise, return nil.
397    Normally, Emacs does not add its own bin/ directory to the PATH.
398    However, a self-contained NS build has a different layout, with
399    bin/ and libexec/ subdirectories in the directory that contains
400    Emacs.app itself.
401    We put libexec first, because init_callproc_1 uses the first
402    element to initialize exec-directory.  An alternative would be
403    for init_callproc to check for invocation-directory/libexec.
406   NSBundle *bundle = [NSBundle mainBundle];
407   NSString *resourceDir = [bundle resourcePath];
408   NSString *binDir = [bundle bundlePath];
409   NSString *resourcePath, *resourcePaths;
410   NSRange range;
411   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
412   NSFileManager *fileManager = [NSFileManager defaultManager];
413   NSArray *paths;
414   NSEnumerator *pathEnum;
415   BOOL isDir;
417   range = [resourceDir rangeOfString: @"Contents"];
418   if (range.location != NSNotFound)
419     {
420       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
421 #ifdef NS_IMPL_COCOA
422       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
423 #endif
424     }
426   paths = [binDir stringsByAppendingPaths:
427                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
428   pathEnum = [paths objectEnumerator];
429   resourcePaths = @"";
431   while ((resourcePath = [pathEnum nextObject]))
432     {
433       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
434         if (isDir)
435           {
436             if ([resourcePaths length] > 0)
437               resourcePaths
438                 = [resourcePaths stringByAppendingString: pathSeparator];
439             resourcePaths
440               = [resourcePaths stringByAppendingString: resourcePath];
441           }
442     }
443   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
445   return NULL;
449 const char *
450 ns_load_path (void)
451 /* If running as a self-contained app bundle, return as a path string
452    the filenames of the site-lisp, lisp and leim directories.
453    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
455   NSBundle *bundle = [NSBundle mainBundle];
456   NSString *resourceDir = [bundle resourcePath];
457   NSString *resourcePath, *resourcePaths;
458   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
459   NSFileManager *fileManager = [NSFileManager defaultManager];
460   BOOL isDir;
461   NSArray *paths = [resourceDir stringsByAppendingPaths:
462                               [NSArray arrayWithObjects:
463                                          @"site-lisp", @"lisp", @"leim", nil]];
464   NSEnumerator *pathEnum = [paths objectEnumerator];
465   resourcePaths = @"";
467   /* Hack to skip site-lisp.  */
468   if (no_site_lisp) resourcePath = [pathEnum nextObject];
470   while ((resourcePath = [pathEnum nextObject]))
471     {
472       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
473         if (isDir)
474           {
475             if ([resourcePaths length] > 0)
476               resourcePaths
477                 = [resourcePaths stringByAppendingString: pathSeparator];
478             resourcePaths
479               = [resourcePaths stringByAppendingString: resourcePath];
480           }
481     }
482   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
484   return NULL;
487 static void
488 ns_timeout (int usecs)
489 /* --------------------------------------------------------------------------
490      Blocking timer utility used by ns_ring_bell
491    -------------------------------------------------------------------------- */
493   struct timespec wakeup = timespec_add (current_timespec (),
494                                          make_timespec (0, usecs * 1000));
496   /* Keep waiting until past the time wakeup.  */
497   while (1)
498     {
499       struct timespec timeout, now = current_timespec ();
500       if (timespec_cmp (wakeup, now) <= 0)
501         break;
502       timeout = timespec_sub (wakeup, now);
504       /* Try to wait that long--but we might wake up sooner.  */
505       pselect (0, NULL, NULL, NULL, &timeout, NULL);
506     }
510 void
511 ns_release_object (void *obj)
512 /* --------------------------------------------------------------------------
513     Release an object (callable from C)
514    -------------------------------------------------------------------------- */
516     [(id)obj release];
520 void
521 ns_retain_object (void *obj)
522 /* --------------------------------------------------------------------------
523     Retain an object (callable from C)
524    -------------------------------------------------------------------------- */
526     [(id)obj retain];
530 void *
531 ns_alloc_autorelease_pool (void)
532 /* --------------------------------------------------------------------------
533      Allocate a pool for temporary objects (callable from C)
534    -------------------------------------------------------------------------- */
536   return [[NSAutoreleasePool alloc] init];
540 void
541 ns_release_autorelease_pool (void *pool)
542 /* --------------------------------------------------------------------------
543      Free a pool and temporary objects it refers to (callable from C)
544    -------------------------------------------------------------------------- */
546   ns_release_object (pool);
551 /* ==========================================================================
553     Focus (clipping) and screen update
555    ========================================================================== */
558 // Window constraining
559 // -------------------
561 // To ensure that the windows are not placed under the menu bar, they
562 // are typically moved by the call-back constrainFrameRect. However,
563 // by overriding it, it's possible to inhibit this, leaving the window
564 // in it's original position.
566 // It's possible to hide the menu bar. However, technically, it's only
567 // possible to hide it when the application is active. To ensure that
568 // this work properly, the menu bar and window constraining are
569 // deferred until the application becomes active.
571 // Even though it's not possible to manually move a window above the
572 // top of the screen, it is allowed if it's done programmatically,
573 // when the menu is hidden. This allows the editable area to cover the
574 // full screen height.
576 // Test cases
577 // ----------
579 // Use the following extra files:
581 //    init.el:
582 //       ;; Hide menu and place frame slightly above the top of the screen.
583 //       (setq ns-auto-hide-menu-bar t)
584 //       (set-frame-position (selected-frame) 0 -20)
586 // Test 1:
588 //    emacs -Q -l init.el
590 //    Result: No menu bar, and the title bar should be above the screen.
592 // Test 2:
594 //    emacs -Q
596 //    Result: Menu bar visible, frame placed immediately below the menu.
599 static void
600 ns_constrain_all_frames (void)
602   Lisp_Object tail, frame;
604   FOR_EACH_FRAME (tail, frame)
605     {
606       struct frame *f = XFRAME (frame);
607       if (FRAME_NS_P (f))
608         {
609           NSView *view = FRAME_NS_VIEW (f);
610           /* This no-op will trigger the default window placing
611            * constraint system. */
612           f->output_data.ns->dont_constrain = 0;
613           [[view window] setFrameOrigin:[[view window] frame].origin];
614         }
615     }
619 /* True, if the menu bar should be hidden.  */
621 static BOOL
622 ns_menu_bar_should_be_hidden (void)
624   return !NILP (ns_auto_hide_menu_bar)
625     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
629 /* Show or hide the menu bar, based on user setting.  */
631 static void
632 ns_update_auto_hide_menu_bar (void)
634 #ifdef NS_IMPL_COCOA
635 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
636   block_input ();
638   NSTRACE (ns_update_auto_hide_menu_bar);
640   if (NSApp != nil
641       && [NSApp isActive]
642       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
643     {
644       // Note, "setPresentationOptions" triggers an error unless the
645       // application is active.
646       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
648       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
649         {
650           NSApplicationPresentationOptions options
651             = NSApplicationPresentationAutoHideDock;
653           if (menu_bar_should_be_hidden)
654             options |= NSApplicationPresentationAutoHideMenuBar;
656           [NSApp setPresentationOptions: options];
658           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
660           if (!ns_menu_bar_is_hidden)
661             {
662               ns_constrain_all_frames ();
663             }
664         }
665     }
667   unblock_input ();
668 #endif
669 #endif
673 static void
674 ns_update_begin (struct frame *f)
675 /* --------------------------------------------------------------------------
676    Prepare for a grouped sequence of drawing calls
677    external (RIF) call; whole frame, called before update_window_begin
678    -------------------------------------------------------------------------- */
680   NSView *view = FRAME_NS_VIEW (f);
681   NSTRACE (ns_update_begin);
683   ns_update_auto_hide_menu_bar ();
685   ns_updating_frame = f;
686   [view lockFocus];
688   /* drawRect may have been called for say the minibuffer, and then clip path
689      is for the minibuffer.  But the display engine may draw more because
690      we have set the frame as garbaged.  So reset clip path to the whole
691      view.  */
692 #ifdef NS_IMPL_COCOA
693   {
694     NSBezierPath *bp;
695     NSRect r = [view frame];
696     NSRect cr = [[view window] frame];
697     /* If a large frame size is set, r may be larger than the window frame
698        before constrained.  In that case don't change the clip path, as we
699        will clear in to the tool bar and title bar.  */
700     if (r.size.height
701         + FRAME_NS_TITLEBAR_HEIGHT (f)
702         + FRAME_TOOLBAR_HEIGHT (f) <= cr.size.height)
703       {
704         bp = [[NSBezierPath bezierPathWithRect: r] retain];
705         [bp setClip];
706         [bp release];
707       }
708   }
709 #endif
711 #ifdef NS_IMPL_GNUSTEP
712   uRect = NSMakeRect (0, 0, 0, 0);
713 #endif
717 static void
718 ns_update_window_begin (struct window *w)
719 /* --------------------------------------------------------------------------
720    Prepare for a grouped sequence of drawing calls
721    external (RIF) call; for one window, called after update_begin
722    -------------------------------------------------------------------------- */
724   struct frame *f = XFRAME (WINDOW_FRAME (w));
725   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
727   NSTRACE (ns_update_window_begin);
728   w->output_cursor = w->cursor;
730   block_input ();
732   if (f == hlinfo->mouse_face_mouse_frame)
733     {
734       /* Don't do highlighting for mouse motion during the update.  */
735       hlinfo->mouse_face_defer = 1;
737         /* If the frame needs to be redrawn,
738            simply forget about any prior mouse highlighting.  */
739       if (FRAME_GARBAGED_P (f))
740         hlinfo->mouse_face_window = Qnil;
742       /* (further code for mouse faces ifdef'd out in other terms elided) */
743     }
745   unblock_input ();
749 static void
750 ns_update_window_end (struct window *w, bool cursor_on_p,
751                       bool mouse_face_overwritten_p)
752 /* --------------------------------------------------------------------------
753    Finished a grouped sequence of drawing calls
754    external (RIF) call; for one window called before update_end
755    -------------------------------------------------------------------------- */
757   /* note: this fn is nearly identical in all terms */
758   if (!w->pseudo_window_p)
759     {
760       block_input ();
762       if (cursor_on_p)
763         display_and_set_cursor (w, 1,
764                                 w->output_cursor.hpos, w->output_cursor.vpos,
765                                 w->output_cursor.x, w->output_cursor.y);
767       if (draw_window_fringes (w, 1))
768         x_draw_vertical_border (w);
770       unblock_input ();
771     }
773   /* If a row with mouse-face was overwritten, arrange for
774      frame_up_to_date to redisplay the mouse highlight.  */
775   if (mouse_face_overwritten_p)
776     reset_mouse_highlight (MOUSE_HL_INFO (XFRAME (w->frame)));
778   NSTRACE (update_window_end);
782 static void
783 ns_update_end (struct frame *f)
784 /* --------------------------------------------------------------------------
785    Finished a grouped sequence of drawing calls
786    external (RIF) call; for whole frame, called after update_window_end
787    -------------------------------------------------------------------------- */
789   EmacsView *view = FRAME_NS_VIEW (f);
791 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
792   MOUSE_HL_INFO (f)->mouse_face_defer = 0;
794   block_input ();
796   [view unlockFocus];
797   [[view window] flushWindow];
799   unblock_input ();
800   ns_updating_frame = NULL;
801   NSTRACE (ns_update_end);
805 static void
806 ns_flush (struct frame *f)
807 /* --------------------------------------------------------------------------
808    external (RIF) call
809    NS impl is no-op since currently we flush in ns_update_end and elsewhere
810    -------------------------------------------------------------------------- */
812     NSTRACE (ns_flush);
816 static void
817 ns_focus (struct frame *f, NSRect *r, int n)
818 /* --------------------------------------------------------------------------
819    Internal: Focus on given frame.  During small local updates this is used to
820      draw, however during large updates, ns_update_begin and ns_update_end are
821      called to wrap the whole thing, in which case these calls are stubbed out.
822      Except, on GNUstep, we accumulate the rectangle being drawn into, because
823      the back end won't do this automatically, and will just end up flushing
824      the entire window.
825    -------------------------------------------------------------------------- */
827 //  NSTRACE (ns_focus);
828 /* static int c =0;
829    fprintf (stderr, "focus: %d", c++);
830    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
831    fprintf (stderr, "\n"); */
833   if (f != ns_updating_frame)
834     {
835       NSView *view = FRAME_NS_VIEW (f);
836       if (view != focus_view)
837         {
838           if (focus_view != NULL)
839             {
840               [focus_view unlockFocus];
841               [[focus_view window] flushWindow];
842 /*debug_lock--; */
843             }
845           if (view)
846             [view lockFocus];
847           focus_view = view;
848 /*if (view) debug_lock++; */
849         }
850     }
852   /* clipping */
853   if (r)
854     {
855       [[NSGraphicsContext currentContext] saveGraphicsState];
856       if (n == 2)
857         NSRectClipList (r, 2);
858       else
859         NSRectClip (*r);
860       gsaved = YES;
861     }
865 static void
866 ns_unfocus (struct frame *f)
867 /* --------------------------------------------------------------------------
868      Internal: Remove focus on given frame
869    -------------------------------------------------------------------------- */
871 //  NSTRACE (ns_unfocus);
873   if (gsaved)
874     {
875       [[NSGraphicsContext currentContext] restoreGraphicsState];
876       gsaved = NO;
877     }
879   if (f != ns_updating_frame)
880     {
881       if (focus_view != NULL)
882         {
883           [focus_view unlockFocus];
884           [[focus_view window] flushWindow];
885           focus_view = NULL;
886 /*debug_lock--; */
887         }
888     }
892 static void
893 ns_clip_to_row (struct window *w, struct glyph_row *row,
894                 enum glyph_row_area area, BOOL gc)
895 /* --------------------------------------------------------------------------
896      Internal (but parallels other terms): Focus drawing on given row
897    -------------------------------------------------------------------------- */
899   struct frame *f = XFRAME (WINDOW_FRAME (w));
900   NSRect clip_rect;
901   int window_x, window_y, window_width;
903   window_box (w, area, &window_x, &window_y, &window_width, 0);
905   clip_rect.origin.x = window_x;
906   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
907   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
908   clip_rect.size.width = window_width;
909   clip_rect.size.height = row->visible_height;
911   ns_focus (f, &clip_rect, 1);
915 static void
916 ns_ring_bell (struct frame *f)
917 /* --------------------------------------------------------------------------
918      "Beep" routine
919    -------------------------------------------------------------------------- */
921   NSTRACE (ns_ring_bell);
922   if (visible_bell)
923     {
924       NSAutoreleasePool *pool;
925       struct frame *frame = SELECTED_FRAME ();
926       NSView *view;
928       block_input ();
929       pool = [[NSAutoreleasePool alloc] init];
931       view = FRAME_NS_VIEW (frame);
932       if (view != nil)
933         {
934           NSRect r, surr;
935           NSPoint dim = NSMakePoint (128, 128);
937           r = [view bounds];
938           r.origin.x += (r.size.width - dim.x) / 2;
939           r.origin.y += (r.size.height - dim.y) / 2;
940           r.size.width = dim.x;
941           r.size.height = dim.y;
942           surr = NSInsetRect (r, -2, -2);
943           ns_focus (frame, &surr, 1);
944           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
945           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
946                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
947           NSRectFill (r);
948           [[view window] flushWindow];
949           ns_timeout (150000);
950           [[view window] restoreCachedImage];
951           [[view window] flushWindow];
952           ns_unfocus (frame);
953         }
954       [pool release];
955       unblock_input ();
956     }
957   else
958     {
959       NSBeep ();
960     }
963 /* ==========================================================================
965     Frame / window manager related functions
967    ========================================================================== */
970 static void
971 ns_raise_frame (struct frame *f)
972 /* --------------------------------------------------------------------------
973      Bring window to foreground and make it active
974    -------------------------------------------------------------------------- */
976   NSView *view;
977   check_window_system (f);
978   view = FRAME_NS_VIEW (f);
979   block_input ();
980   if (FRAME_VISIBLE_P (f))
981     [[view window] makeKeyAndOrderFront: NSApp];
982   unblock_input ();
986 static void
987 ns_lower_frame (struct frame *f)
988 /* --------------------------------------------------------------------------
989      Send window to back
990    -------------------------------------------------------------------------- */
992   NSView *view;
993   check_window_system (f);
994   view = FRAME_NS_VIEW (f);
995   block_input ();
996   [[view window] orderBack: NSApp];
997   unblock_input ();
1001 static void
1002 ns_frame_raise_lower (struct frame *f, int raise)
1003 /* --------------------------------------------------------------------------
1004      External (hook)
1005    -------------------------------------------------------------------------- */
1007   NSTRACE (ns_frame_raise_lower);
1009   if (raise)
1010     ns_raise_frame (f);
1011   else
1012     ns_lower_frame (f);
1016 static void
1017 ns_frame_rehighlight (struct frame *frame)
1018 /* --------------------------------------------------------------------------
1019      External (hook): called on things like window switching within frame
1020    -------------------------------------------------------------------------- */
1022   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1023   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1025   NSTRACE (ns_frame_rehighlight);
1026   if (dpyinfo->x_focus_frame)
1027     {
1028       dpyinfo->x_highlight_frame
1029         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1030            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1031            : dpyinfo->x_focus_frame);
1032       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1033         {
1034           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1035           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1036         }
1037     }
1038   else
1039       dpyinfo->x_highlight_frame = 0;
1041   if (dpyinfo->x_highlight_frame &&
1042          dpyinfo->x_highlight_frame != old_highlight)
1043     {
1044       if (old_highlight)
1045         {
1046           x_update_cursor (old_highlight, 1);
1047           x_set_frame_alpha (old_highlight);
1048         }
1049       if (dpyinfo->x_highlight_frame)
1050         {
1051           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1052           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1053         }
1054     }
1058 void
1059 x_make_frame_visible (struct frame *f)
1060 /* --------------------------------------------------------------------------
1061      External: Show the window (X11 semantics)
1062    -------------------------------------------------------------------------- */
1064   NSTRACE (x_make_frame_visible);
1065   /* XXX: at some points in past this was not needed, as the only place that
1066      called this (frame.c:Fraise_frame ()) also called raise_lower;
1067      if this ends up the case again, comment this out again. */
1068   if (!FRAME_VISIBLE_P (f))
1069     {
1070       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1072       SET_FRAME_VISIBLE (f, 1);
1073       ns_raise_frame (f);
1075       /* Making a new frame from a fullscreen frame will make the new frame
1076          fullscreen also.  So skip handleFS as this will print an error.  */
1077       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1078           && [view isFullscreen])
1079         return;
1081       if (f->want_fullscreen != FULLSCREEN_NONE)
1082         {
1083           block_input ();
1084           [view handleFS];
1085           unblock_input ();
1086         }
1087     }
1091 void
1092 x_make_frame_invisible (struct frame *f)
1093 /* --------------------------------------------------------------------------
1094      External: Hide the window (X11 semantics)
1095    -------------------------------------------------------------------------- */
1097   NSView *view;
1098   NSTRACE (x_make_frame_invisible);
1099   check_window_system (f);
1100   view = FRAME_NS_VIEW (f);
1101   [[view window] orderOut: NSApp];
1102   SET_FRAME_VISIBLE (f, 0);
1103   SET_FRAME_ICONIFIED (f, 0);
1107 void
1108 x_iconify_frame (struct frame *f)
1109 /* --------------------------------------------------------------------------
1110      External: Iconify window
1111    -------------------------------------------------------------------------- */
1113   NSView *view;
1114   struct ns_display_info *dpyinfo;
1116   NSTRACE (x_iconify_frame);
1117   check_window_system (f);
1118   view = FRAME_NS_VIEW (f);
1119   dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1121   if (dpyinfo->x_highlight_frame == f)
1122     dpyinfo->x_highlight_frame = 0;
1124   if ([[view window] windowNumber] <= 0)
1125     {
1126       /* the window is still deferred.  Make it very small, bring it
1127          on screen and order it out. */
1128       NSRect s = { { 100, 100}, {0, 0} };
1129       NSRect t;
1130       t = [[view window] frame];
1131       [[view window] setFrame: s display: NO];
1132       [[view window] orderBack: NSApp];
1133       [[view window] orderOut: NSApp];
1134       [[view window] setFrame: t display: NO];
1135     }
1136   [[view window] miniaturize: NSApp];
1139 /* Free X resources of frame F.  */
1141 void
1142 x_free_frame_resources (struct frame *f)
1144   NSView *view;
1145   struct ns_display_info *dpyinfo;
1146   Mouse_HLInfo *hlinfo;
1148   NSTRACE (x_free_frame_resources);
1149   check_window_system (f);
1150   view = FRAME_NS_VIEW (f);
1151   dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1152   hlinfo = MOUSE_HL_INFO (f);
1154   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1156   block_input ();
1158   free_frame_menubar (f);
1160   if (FRAME_FACE_CACHE (f))
1161     free_frame_faces (f);
1163   if (f == dpyinfo->x_focus_frame)
1164     dpyinfo->x_focus_frame = 0;
1165   if (f == dpyinfo->x_highlight_frame)
1166     dpyinfo->x_highlight_frame = 0;
1167   if (f == hlinfo->mouse_face_mouse_frame)
1168     reset_mouse_highlight (hlinfo);
1170   if (f->output_data.ns->miniimage != nil)
1171     [f->output_data.ns->miniimage release];
1173   [[view window] close];
1174   [view release];
1176   xfree (f->output_data.ns);
1178   unblock_input ();
1181 void
1182 x_destroy_window (struct frame *f)
1183 /* --------------------------------------------------------------------------
1184      External: Delete the window
1185    -------------------------------------------------------------------------- */
1187   NSTRACE (x_destroy_window);
1188   check_window_system (f);
1189   x_free_frame_resources (f);
1190   ns_window_num--;
1194 void
1195 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1196 /* --------------------------------------------------------------------------
1197      External: Position the window
1198    -------------------------------------------------------------------------- */
1200   NSView *view = FRAME_NS_VIEW (f);
1201   NSArray *screens = [NSScreen screens];
1202   NSScreen *fscreen = [screens objectAtIndex: 0];
1203   NSScreen *screen = [[view window] screen];
1205   NSTRACE (x_set_offset);
1207   block_input ();
1209   f->left_pos = xoff;
1210   f->top_pos = yoff;
1212   if (view != nil && screen && fscreen)
1213     {
1214       f->left_pos = f->size_hint_flags & XNegative
1215         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1216         : f->left_pos;
1217       /* We use visibleFrame here to take menu bar into account.
1218          Ideally we should also adjust left/top with visibleFrame.origin.  */
1220       f->top_pos = f->size_hint_flags & YNegative
1221         ? ([screen visibleFrame].size.height + f->top_pos
1222            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1223            - FRAME_TOOLBAR_HEIGHT (f))
1224         : f->top_pos;
1225 #ifdef NS_IMPL_GNUSTEP
1226       if (f->left_pos < 100)
1227         f->left_pos = 100;  /* don't overlap menu */
1228 #endif
1229       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1230          menu bar.  */
1231       f->output_data.ns->dont_constrain = 0;
1232       [[view window] setFrameTopLeftPoint:
1233                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1234                                     SCREENMAXBOUND ([fscreen frame].size.height
1235                                                     - NS_TOP_POS (f)))];
1236       f->size_hint_flags &= ~(XNegative|YNegative);
1237     }
1239   unblock_input ();
1243 void
1244 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1245 /* --------------------------------------------------------------------------
1246      Adjust window pixel size based on given character grid size
1247      Impl is a bit more complex than other terms, need to do some
1248      internal clipping.
1249    -------------------------------------------------------------------------- */
1251   EmacsView *view = FRAME_NS_VIEW (f);
1252   NSWindow *window = [view window];
1253   NSRect wr = [window frame];
1254   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1255   int pixelwidth, pixelheight;
1257   NSTRACE (x_set_window_size);
1259   if (view == nil)
1260     return;
1262 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1264   block_input ();
1266   check_frame_size (f, &rows, &cols);
1268   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1269   compute_fringe_widths (f, 0);
1271   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1272   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1274   /* If we have a toolbar, take its height into account. */
1275   if (tb && ! [view isFullscreen])
1276     {
1277     /* NOTE: previously this would generate wrong result if toolbar not
1278              yet displayed and fixing toolbar_height=32 helped, but
1279              now (200903) seems no longer needed */
1280     FRAME_TOOLBAR_HEIGHT (f) =
1281       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1282         - FRAME_NS_TITLEBAR_HEIGHT (f);
1283 #ifdef NS_IMPL_GNUSTEP
1284       FRAME_TOOLBAR_HEIGHT (f) -= 3;
1285 #endif
1286     }
1287   else
1288     FRAME_TOOLBAR_HEIGHT (f) = 0;
1290   wr.size.width = pixelwidth + f->border_width;
1291   wr.size.height = pixelheight;
1292   if (! [view isFullscreen])
1293     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1294       + FRAME_TOOLBAR_HEIGHT (f);
1296   /* Do not try to constrain to this screen.  We may have multiple
1297      screens, and want Emacs to span those.  Constraining to screen
1298      prevents that, and that is not nice to the user.  */
1299  if (f->output_data.ns->zooming)
1300    f->output_data.ns->zooming = 0;
1301  else
1302    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1304   [view setRows: rows andColumns: cols];
1305   [window setFrame: wr display: YES];
1307 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1309   /* This is a trick to compensate for Emacs' managing the scrollbar area
1310      as a fixed number of standard character columns.  Instead of leaving
1311      blank space for the extra, we chopped it off above.  Now for
1312      left-hand scrollbars, we shift all rendering to the left by the
1313      difference between the real width and Emacs' imagined one.  For
1314      right-hand bars, don't worry about it since the extra is never used.
1315      (Obviously doesn't work for vertically split windows tho..) */
1316   {
1317     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1318       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1319                      - NS_SCROLL_BAR_WIDTH (f), 0)
1320       : NSMakePoint (0, 0);
1321     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1322     [view setBoundsOrigin: origin];
1323   }
1325   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1326   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1327   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1328 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1330   mark_window_cursors_off (XWINDOW (f->root_window));
1331   cancel_mouse_face (f);
1333   unblock_input ();
1337 static void
1338 ns_fullscreen_hook (struct frame *f)
1340   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1342   if (!FRAME_VISIBLE_P (f))
1343     return;
1345    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1346     {
1347       /* Old style fs don't initiate correctly if created from
1348          init/default-frame alist, so use a timer (not nice...).
1349       */
1350       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1351                                      selector: @selector (handleFS)
1352                                      userInfo: nil repeats: NO];
1353       return;
1354     }
1356   block_input ();
1357   [view handleFS];
1358   unblock_input ();
1361 /* ==========================================================================
1363     Color management
1365    ========================================================================== */
1368 NSColor *
1369 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1371   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1372   if (idx < 1 || idx >= color_table->avail)
1373     return nil;
1374   return color_table->colors[idx];
1378 unsigned long
1379 ns_index_color (NSColor *color, struct frame *f)
1381   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1382   ptrdiff_t idx;
1383   ptrdiff_t i;
1385   if (!color_table->colors)
1386     {
1387       color_table->size = NS_COLOR_CAPACITY;
1388       color_table->avail = 1; /* skip idx=0 as marker */
1389       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1390       color_table->colors[0] = nil;
1391       color_table->empty_indices = [[NSMutableSet alloc] init];
1392     }
1394   /* do we already have this color ? */
1395   for (i = 1; i < color_table->avail; i++)
1396     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1397       return i;
1399   if ([color_table->empty_indices count] > 0)
1400     {
1401       NSNumber *index = [color_table->empty_indices anyObject];
1402       [color_table->empty_indices removeObject: index];
1403       idx = [index unsignedLongValue];
1404     }
1405   else
1406     {
1407       if (color_table->avail == color_table->size)
1408         color_table->colors =
1409           xpalloc (color_table->colors, &color_table->size, 1,
1410                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1411       idx = color_table->avail++;
1412     }
1414   color_table->colors[idx] = color;
1415   [color retain];
1416 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1417   return idx;
1421 void
1422 ns_free_indexed_color (unsigned long idx, struct frame *f)
1424   struct ns_color_table *color_table;
1425   NSColor *color;
1426   NSNumber *index;
1428   if (!f)
1429     return;
1431   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1433   if (idx <= 0 || idx >= color_table->size) {
1434     message1 ("ns_free_indexed_color: Color index out of range.\n");
1435     return;
1436   }
1438   index = [NSNumber numberWithUnsignedInt: idx];
1439   if ([color_table->empty_indices containsObject: index]) {
1440     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1441     return;
1442   }
1444   color = color_table->colors[idx];
1445   [color release];
1446   color_table->colors[idx] = nil;
1447   [color_table->empty_indices addObject: index];
1448 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1452 static int
1453 ns_get_color (const char *name, NSColor **col)
1454 /* --------------------------------------------------------------------------
1455      Parse a color name
1456    -------------------------------------------------------------------------- */
1457 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1458    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1459    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1461   NSColor *new = nil;
1462   static char hex[20];
1463   int scaling;
1464   float r = -1.0, g, b;
1465   NSString *nsname = [NSString stringWithUTF8String: name];
1467 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1468   block_input ();
1470   if ([nsname isEqualToString: @"ns_selection_color"])
1471     {
1472       nsname = ns_selection_color;
1473       name = [ns_selection_color UTF8String];
1474     }
1476   /* First, check for some sort of numeric specification. */
1477   hex[0] = '\0';
1479   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1480     {
1481       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1482       [scanner scanFloat: &r];
1483       [scanner scanFloat: &g];
1484       [scanner scanFloat: &b];
1485     }
1486   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1487     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1488   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1489     {
1490       int len = (strlen(name) - 1);
1491       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1492       int i;
1493       scaling = strlen(name+start) / 3;
1494       for (i = 0; i < 3; i++)
1495         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1496                  name + start + i * scaling);
1497       hex[3 * (scaling + 1) - 1] = '\0';
1498     }
1500   if (hex[0])
1501     {
1502       int rr, gg, bb;
1503       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1504       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1505         {
1506           r = rr / fscale;
1507           g = gg / fscale;
1508           b = bb / fscale;
1509         }
1510     }
1512   if (r >= 0.0F)
1513     {
1514       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1515       unblock_input ();
1516       return 0;
1517     }
1519   /* Otherwise, color is expected to be from a list */
1520   {
1521     NSEnumerator *lenum, *cenum;
1522     NSString *name;
1523     NSColorList *clist;
1525 #ifdef NS_IMPL_GNUSTEP
1526     /* XXX: who is wrong, the requestor or the implementation? */
1527     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1528         == NSOrderedSame)
1529       nsname = @"highlightColor";
1530 #endif
1532     lenum = [[NSColorList availableColorLists] objectEnumerator];
1533     while ( (clist = [lenum nextObject]) && new == nil)
1534       {
1535         cenum = [[clist allKeys] objectEnumerator];
1536         while ( (name = [cenum nextObject]) && new == nil )
1537           {
1538             if ([name compare: nsname
1539                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1540               new = [clist colorWithKey: name];
1541           }
1542       }
1543   }
1545   if (new)
1546     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1547   unblock_input ();
1548   return new ? 0 : 1;
1553 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1554 /* --------------------------------------------------------------------------
1555      Convert a Lisp string object to a NS color
1556    -------------------------------------------------------------------------- */
1558   NSTRACE (ns_lisp_to_color);
1559   if (STRINGP (color))
1560     return ns_get_color (SSDATA (color), col);
1561   else if (SYMBOLP (color))
1562     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1563   return 1;
1567 Lisp_Object
1568 ns_color_to_lisp (NSColor *col)
1569 /* --------------------------------------------------------------------------
1570      Convert a color to a lisp string with the RGB equivalent
1571    -------------------------------------------------------------------------- */
1573   EmacsCGFloat red, green, blue, alpha, gray;
1574   char buf[1024];
1575   const char *str;
1576   NSTRACE (ns_color_to_lisp);
1578   block_input ();
1579   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1581       if ((str =[[col colorNameComponent] UTF8String]))
1582         {
1583           unblock_input ();
1584           return build_string ((char *)str);
1585         }
1587     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1588         getRed: &red green: &green blue: &blue alpha: &alpha];
1589   if (red ==green && red ==blue)
1590     {
1591       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1592             getWhite: &gray alpha: &alpha];
1593       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1594                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1595       unblock_input ();
1596       return build_string (buf);
1597     }
1599   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1600             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1602   unblock_input ();
1603   return build_string (buf);
1607 void
1608 ns_query_color(void *col, XColor *color_def, int setPixel)
1609 /* --------------------------------------------------------------------------
1610          Get ARGB values out of NSColor col and put them into color_def.
1611          If setPixel, set the pixel to a concatenated version.
1612          and set color_def pixel to the resulting index.
1613    -------------------------------------------------------------------------- */
1615   EmacsCGFloat r, g, b, a;
1617   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1618   color_def->red   = r * 65535;
1619   color_def->green = g * 65535;
1620   color_def->blue  = b * 65535;
1622   if (setPixel == YES)
1623     color_def->pixel
1624       = ARGB_TO_ULONG((int)(a*255),
1625                       (int)(r*255), (int)(g*255), (int)(b*255));
1629 bool
1630 ns_defined_color (struct frame *f,
1631                   const char *name,
1632                   XColor *color_def,
1633                   bool alloc,
1634                   bool makeIndex)
1635 /* --------------------------------------------------------------------------
1636          Return true if named color found, and set color_def rgb accordingly.
1637          If makeIndex and alloc are nonzero put the color in the color_table,
1638          and set color_def pixel to the resulting index.
1639          If makeIndex is zero, set color_def pixel to ARGB.
1640          Return false if not found
1641    -------------------------------------------------------------------------- */
1643   NSColor *col;
1644   NSTRACE (ns_defined_color);
1646   block_input ();
1647   if (ns_get_color (name, &col) != 0) /* Color not found  */
1648     {
1649       unblock_input ();
1650       return 0;
1651     }
1652   if (makeIndex && alloc)
1653     color_def->pixel = ns_index_color (col, f);
1654   ns_query_color (col, color_def, !makeIndex);
1655   unblock_input ();
1656   return 1;
1660 void
1661 x_set_frame_alpha (struct frame *f)
1662 /* --------------------------------------------------------------------------
1663      change the entire-frame transparency
1664    -------------------------------------------------------------------------- */
1666   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1667   double alpha = 1.0;
1668   double alpha_min = 1.0;
1670   if (dpyinfo->x_highlight_frame == f)
1671     alpha = f->alpha[0];
1672   else
1673     alpha = f->alpha[1];
1675   if (FLOATP (Vframe_alpha_lower_limit))
1676     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1677   else if (INTEGERP (Vframe_alpha_lower_limit))
1678     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1680   if (alpha < 0.0)
1681     return;
1682   else if (1.0 < alpha)
1683     alpha = 1.0;
1684   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1685     alpha = alpha_min;
1687 #ifdef NS_IMPL_COCOA
1688   {
1689     EmacsView *view = FRAME_NS_VIEW (f);
1690   [[view window] setAlphaValue: alpha];
1691   }
1692 #endif
1696 /* ==========================================================================
1698     Mouse handling
1700    ========================================================================== */
1703 void
1704 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1705 /* --------------------------------------------------------------------------
1706      Programmatically reposition mouse pointer in pixel coordinates
1707    -------------------------------------------------------------------------- */
1709   NSTRACE (x_set_mouse_pixel_position);
1710   ns_raise_frame (f);
1711 #if 0
1712   /* FIXME: this does not work, and what about GNUstep? */
1713 #ifdef NS_IMPL_COCOA
1714   [FRAME_NS_VIEW (f) lockFocus];
1715   PSsetmouse ((float)pix_x, (float)pix_y);
1716   [FRAME_NS_VIEW (f) unlockFocus];
1717 #endif
1718 #endif
1722 void
1723 x_set_mouse_position (struct frame *f, int h, int v)
1724 /* --------------------------------------------------------------------------
1725      Programmatically reposition mouse pointer in character coordinates
1726    -------------------------------------------------------------------------- */
1728   int pix_x, pix_y;
1730   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1731   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1733   if (pix_x < 0) pix_x = 0;
1734   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1736   if (pix_y < 0) pix_y = 0;
1737   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1739   x_set_mouse_pixel_position (f, pix_x, pix_y);
1743 static int
1744 note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y)
1745 /*   ------------------------------------------------------------------------
1746      Called by EmacsView on mouseMovement events.  Passes on
1747      to emacs mainstream code if we moved off of a rect of interest
1748      known as last_mouse_glyph.
1749      ------------------------------------------------------------------------ */
1751 //  NSTRACE (note_mouse_movement);
1753   XSETFRAME (last_mouse_motion_frame, frame);
1755   /* Note, this doesn't get called for enter/leave, since we don't have a
1756      position.  Those are taken care of in the corresponding NSView methods. */
1758   /* has movement gone beyond last rect we were tracking? */
1759   if (x < last_mouse_glyph.origin.x ||
1760       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1761       y < last_mouse_glyph.origin.y ||
1762       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1763     {
1764       ns_update_begin(frame);
1765       frame->mouse_moved = 1;
1766       note_mouse_highlight (frame, x, y);
1767       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1768       ns_update_end(frame);
1769       return 1;
1770     }
1772   return 0;
1776 static void
1777 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1778                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1779                    Time *time)
1780 /* --------------------------------------------------------------------------
1781     External (hook): inform emacs about mouse position and hit parts.
1782     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1783     x & y should be position in the scrollbar (the whole bar, not the handle)
1784     and length of scrollbar respectively
1785    -------------------------------------------------------------------------- */
1787   id view;
1788   NSPoint position;
1789   Lisp_Object frame, tail;
1790   struct frame *f;
1791   struct ns_display_info *dpyinfo;
1793   NSTRACE (ns_mouse_position);
1795   if (*fp == NULL)
1796     {
1797       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1798       return;
1799     }
1801   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1803   block_input ();
1805   if (last_mouse_scroll_bar != nil && insist == 0)
1806     {
1807       /* TODO: we do not use this path at the moment because drag events will
1808            go directly to the EmacsScroller.  Leaving code in for now. */
1809       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1810                                               x: x y: y];
1811       if (time) *time = last_mouse_movement_time;
1812       last_mouse_scroll_bar = nil;
1813     }
1814   else
1815     {
1816       /* Clear the mouse-moved flag for every frame on this display.  */
1817       FOR_EACH_FRAME (tail, frame)
1818         if (FRAME_NS_P (XFRAME (frame))
1819             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1820           XFRAME (frame)->mouse_moved = 0;
1822       last_mouse_scroll_bar = nil;
1823       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1824         f = last_mouse_frame;
1825       else
1826         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1827                                     : SELECTED_FRAME ();
1829       if (f && FRAME_NS_P (f))
1830         {
1831           view = FRAME_NS_VIEW (*fp);
1833           position = [[view window] mouseLocationOutsideOfEventStream];
1834           position = [view convertPoint: position fromView: nil];
1835           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1836 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1838           if (bar_window) *bar_window = Qnil;
1839           if (part) *part = 0; /*scroll_bar_handle; */
1841           if (x) XSETINT (*x, lrint (position.x));
1842           if (y) XSETINT (*y, lrint (position.y));
1843           if (time) *time = last_mouse_movement_time;
1844           *fp = f;
1845         }
1846     }
1848   unblock_input ();
1852 static void
1853 ns_frame_up_to_date (struct frame *f)
1854 /* --------------------------------------------------------------------------
1855     External (hook): Fix up mouse highlighting right after a full update.
1856     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1857    -------------------------------------------------------------------------- */
1859   NSTRACE (ns_frame_up_to_date);
1861   if (FRAME_NS_P (f))
1862     {
1863       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1864       if (f == hlinfo->mouse_face_mouse_frame)
1865         {
1866           block_input ();
1867           ns_update_begin(f);
1868           note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1869                                 hlinfo->mouse_face_mouse_x,
1870                                 hlinfo->mouse_face_mouse_y);
1871           ns_update_end(f);
1872           unblock_input ();
1873         }
1874     }
1878 static void
1879 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1880 /* --------------------------------------------------------------------------
1881     External (RIF): set frame mouse pointer type.
1882    -------------------------------------------------------------------------- */
1884   NSTRACE (ns_define_frame_cursor);
1885   if (FRAME_POINTER_TYPE (f) != cursor)
1886     {
1887       EmacsView *view = FRAME_NS_VIEW (f);
1888       FRAME_POINTER_TYPE (f) = cursor;
1889       [[view window] invalidateCursorRectsForView: view];
1890       /* Redisplay assumes this function also draws the changed frame
1891          cursor, but this function doesn't, so do it explicitly.  */
1892       x_update_cursor (f, 1);
1893     }
1898 /* ==========================================================================
1900     Keyboard handling
1902    ========================================================================== */
1905 static unsigned
1906 ns_convert_key (unsigned code)
1907 /* --------------------------------------------------------------------------
1908     Internal call used by NSView-keyDown.
1909    -------------------------------------------------------------------------- */
1911   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1912                                 / sizeof (convert_ns_to_X_keysym[0]));
1913   unsigned keysym;
1914   /* An array would be faster, but less easy to read. */
1915   for (keysym = 0; keysym < last_keysym; keysym += 2)
1916     if (code == convert_ns_to_X_keysym[keysym])
1917       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1918   return 0;
1919 /* if decide to use keyCode and Carbon table, use this line:
1920      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1924 char *
1925 x_get_keysym_name (int keysym)
1926 /* --------------------------------------------------------------------------
1927     Called by keyboard.c.  Not sure if the return val is important, except
1928     that it be unique.
1929    -------------------------------------------------------------------------- */
1931   static char value[16];
1932   NSTRACE (x_get_keysym_name);
1933   sprintf (value, "%d", keysym);
1934   return value;
1939 /* ==========================================================================
1941     Block drawing operations
1943    ========================================================================== */
1946 static void
1947 ns_redraw_scroll_bars (struct frame *f)
1949   int i;
1950   id view;
1951   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1952   NSTRACE (ns_redraw_scroll_bars);
1953   for (i =[subviews count]-1; i >= 0; i--)
1954     {
1955       view = [subviews objectAtIndex: i];
1956       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1957       [view display];
1958     }
1962 void
1963 ns_clear_frame (struct frame *f)
1964 /* --------------------------------------------------------------------------
1965       External (hook): Erase the entire frame
1966    -------------------------------------------------------------------------- */
1968   NSView *view = FRAME_NS_VIEW (f);
1969   NSRect r;
1971   NSTRACE (ns_clear_frame);
1973  /* comes on initial frame because we have
1974     after-make-frame-functions = select-frame */
1975  if (!FRAME_DEFAULT_FACE (f))
1976    return;
1978   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1980   r = [view bounds];
1982   block_input ();
1983   ns_focus (f, &r, 1);
1984   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
1985   NSRectFill (r);
1986   ns_unfocus (f);
1988   /* as of 2006/11 or so this is now needed */
1989   ns_redraw_scroll_bars (f);
1990   unblock_input ();
1994 static void
1995 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
1996 /* --------------------------------------------------------------------------
1997     External (RIF):  Clear section of frame
1998    -------------------------------------------------------------------------- */
2000   NSRect r = NSMakeRect (x, y, width, height);
2001   NSView *view = FRAME_NS_VIEW (f);
2002   struct face *face = FRAME_DEFAULT_FACE (f);
2004   if (!view || !face)
2005     return;
2007   NSTRACE (ns_clear_frame_area);
2009   r = NSIntersectionRect (r, [view frame]);
2010   ns_focus (f, &r, 1);
2011   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2013   NSRectFill (r);
2015   ns_unfocus (f);
2016   return;
2020 static void
2021 ns_scroll_run (struct window *w, struct run *run)
2022 /* --------------------------------------------------------------------------
2023     External (RIF):  Insert or delete n lines at line vpos
2024    -------------------------------------------------------------------------- */
2026   struct frame *f = XFRAME (w->frame);
2027   int x, y, width, height, from_y, to_y, bottom_y;
2029   NSTRACE (ns_scroll_run);
2031   /* begin copy from other terms */
2032   /* Get frame-relative bounding box of the text display area of W,
2033      without mode lines.  Include in this box the left and right
2034      fringe of W.  */
2035   window_box (w, ANY_AREA, &x, &y, &width, &height);
2037   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2038   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2039   bottom_y = y + height;
2041   if (to_y < from_y)
2042     {
2043       /* Scrolling up.  Make sure we don't copy part of the mode
2044          line at the bottom.  */
2045       if (from_y + run->height > bottom_y)
2046         height = bottom_y - from_y;
2047       else
2048         height = run->height;
2049     }
2050   else
2051     {
2052       /* Scrolling down.  Make sure we don't copy over the mode line.
2053          at the bottom.  */
2054       if (to_y + run->height > bottom_y)
2055         height = bottom_y - to_y;
2056       else
2057         height = run->height;
2058     }
2059   /* end copy from other terms */
2061   if (height == 0)
2062       return;
2064   block_input ();
2066   x_clear_cursor (w);
2068   {
2069     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2070     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2071     NSPoint dstOrigin = NSMakePoint (x, to_y);
2073     ns_focus (f, &dstRect, 1);
2074     NSCopyBits (0, srcRect , dstOrigin);
2075     ns_unfocus (f);
2076   }
2078   unblock_input ();
2082 static void
2083 ns_after_update_window_line (struct window *w, struct glyph_row *desired_row)
2084 /* --------------------------------------------------------------------------
2085     External (RIF): preparatory to fringe update after text was updated
2086    -------------------------------------------------------------------------- */
2088   struct frame *f;
2089   int width, height;
2091   NSTRACE (ns_after_update_window_line);
2093   /* begin copy from other terms */
2094   eassert (w);
2096   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2097     desired_row->redraw_fringe_bitmaps_p = 1;
2099   /* When a window has disappeared, make sure that no rest of
2100      full-width rows stays visible in the internal border.  */
2101   if (windows_or_buffers_changed
2102       && desired_row->full_width_p
2103       && (f = XFRAME (w->frame),
2104           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2105           width != 0)
2106       && (height = desired_row->visible_height,
2107           height > 0))
2108     {
2109       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2111       block_input ();
2112       ns_clear_frame_area (f, 0, y, width, height);
2113       ns_clear_frame_area (f,
2114                            FRAME_PIXEL_WIDTH (f) - width,
2115                            y, width, height);
2116       unblock_input ();
2117     }
2121 static void
2122 ns_shift_glyphs_for_insert (struct frame *f,
2123                            int x, int y, int width, int height,
2124                            int shift_by)
2125 /* --------------------------------------------------------------------------
2126     External (RIF): copy an area horizontally, don't worry about clearing src
2127    -------------------------------------------------------------------------- */
2129   NSRect srcRect = NSMakeRect (x, y, width, height);
2130   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2131   NSPoint dstOrigin = dstRect.origin;
2133   NSTRACE (ns_shift_glyphs_for_insert);
2135   ns_focus (f, &dstRect, 1);
2136   NSCopyBits (0, srcRect, dstOrigin);
2137   ns_unfocus (f);
2142 /* ==========================================================================
2144     Character encoding and metrics
2146    ========================================================================== */
2149 static void
2150 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2151 /* --------------------------------------------------------------------------
2152      External (RIF); compute left/right overhang of whole string and set in s
2153    -------------------------------------------------------------------------- */
2155   struct font *font = s->font;
2157   if (s->char2b)
2158     {
2159       struct font_metrics metrics;
2160       unsigned int codes[2];
2161       codes[0] = *(s->char2b);
2162       codes[1] = *(s->char2b + s->nchars - 1);
2164       font->driver->text_extents (font, codes, 2, &metrics);
2165       s->left_overhang = -metrics.lbearing;
2166       s->right_overhang
2167         = metrics.rbearing > metrics.width
2168         ? metrics.rbearing - metrics.width : 0;
2169     }
2170   else
2171     {
2172       s->left_overhang = 0;
2173       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2174         FONT_HEIGHT (font) * 0.2 : 0;
2175     }
2180 /* ==========================================================================
2182     Fringe and cursor drawing
2184    ========================================================================== */
2187 extern int max_used_fringe_bitmap;
2188 static void
2189 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2190                       struct draw_fringe_bitmap_params *p)
2191 /* --------------------------------------------------------------------------
2192     External (RIF); fringe-related
2193    -------------------------------------------------------------------------- */
2195   struct frame *f = XFRAME (WINDOW_FRAME (w));
2196   struct face *face = p->face;
2197   static EmacsImage **bimgs = NULL;
2198   static int nBimgs = 0;
2200   /* grow bimgs if needed */
2201   if (nBimgs < max_used_fringe_bitmap)
2202     {
2203       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2204       memset (bimgs + nBimgs, 0,
2205               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2206       nBimgs = max_used_fringe_bitmap;
2207     }
2209   /* Must clip because of partially visible lines.  */
2210   ns_clip_to_row (w, row, ANY_AREA, YES);
2212   if (!p->overlay_p)
2213     {
2214       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2216       /* If the fringe is adjacent to the left (right) scroll bar of a
2217          leftmost (rightmost, respectively) window, then extend its
2218          background to the gap between the fringe and the bar.  */
2219       if ((WINDOW_LEFTMOST_P (w)
2220            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2221           || (WINDOW_RIGHTMOST_P (w)
2222               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2223         {
2224           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2226           if (sb_width > 0)
2227             {
2228               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2229               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2230                                     * FRAME_COLUMN_WIDTH (f));
2232               if (bx < 0)
2233                 {
2234                   /* Bitmap fills the fringe.  */
2235                   if (bar_area_x + bar_area_width == p->x)
2236                     bx = bar_area_x + sb_width;
2237                   else if (p->x + p->wd == bar_area_x)
2238                     bx = bar_area_x;
2239                   if (bx >= 0)
2240                     {
2241                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2243                       nx = bar_area_width - sb_width;
2244                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2245                                                             row->y));
2246                       ny = row->visible_height;
2247                     }
2248                 }
2249               else
2250                 {
2251                   if (bar_area_x + bar_area_width == bx)
2252                     {
2253                       bx = bar_area_x + sb_width;
2254                       nx += bar_area_width - sb_width;
2255                     }
2256                   else if (bx + nx == bar_area_x)
2257                     nx += bar_area_width - sb_width;
2258                 }
2259             }
2260         }
2262       if (bx >= 0 && nx > 0)
2263         {
2264           NSRect r = NSMakeRect (bx, by, nx, ny);
2265           NSRectClip (r);
2266           [ns_lookup_indexed_color (face->background, f) set];
2267           NSRectFill (r);
2268         }
2269     }
2271   if (p->which)
2272     {
2273       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2274       EmacsImage *img = bimgs[p->which - 1];
2276       if (!img)
2277         {
2278           unsigned short *bits = p->bits + p->dh;
2279           int len = p->h;
2280           int i;
2281           unsigned char *cbits = xmalloc (len);
2283           for (i = 0; i < len; i++)
2284             cbits[i] = ~(bits[i] & 0xff);
2285           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2286                                            flip: NO];
2287           bimgs[p->which - 1] = img;
2288           xfree (cbits);
2289         }
2291       NSRectClip (r);
2292       /* Since we composite the bitmap instead of just blitting it, we need
2293          to erase the whole background. */
2294       [ns_lookup_indexed_color(face->background, f) set];
2295       NSRectFill (r);
2296       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2297 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2298       [img drawInRect: r
2299               fromRect: NSZeroRect
2300              operation: NSCompositeSourceOver
2301               fraction: 1.0
2302            respectFlipped: YES
2303                 hints: nil];
2304 #else
2305       {
2306         NSPoint pt = r.origin;
2307         pt.y += p->h;
2308         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2309       }
2310 #endif
2311     }
2312   ns_unfocus (f);
2316 static void
2317 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2318                        int x, int y, enum text_cursor_kinds cursor_type,
2319                        int cursor_width, bool on_p, bool active_p)
2320 /* --------------------------------------------------------------------------
2321      External call (RIF): draw cursor.
2322      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2323    -------------------------------------------------------------------------- */
2325   NSRect r, s;
2326   int fx, fy, h, cursor_height;
2327   struct frame *f = WINDOW_XFRAME (w);
2328   struct glyph *phys_cursor_glyph;
2329   struct glyph *cursor_glyph;
2330   struct face *face;
2331   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2333   /* If cursor is out of bounds, don't draw garbage.  This can happen
2334      in mini-buffer windows when switching between echo area glyphs
2335      and mini-buffer.  */
2337   NSTRACE (dumpcursor);
2339   if (!on_p)
2340     return;
2342   w->phys_cursor_type = cursor_type;
2343   w->phys_cursor_on_p = on_p;
2345   if (cursor_type == NO_CURSOR)
2346     {
2347       w->phys_cursor_width = 0;
2348       return;
2349     }
2351   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2352     {
2353       if (glyph_row->exact_window_width_line_p
2354           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2355         {
2356           glyph_row->cursor_in_fringe_p = 1;
2357           draw_fringe_bitmap (w, glyph_row, 0);
2358         }
2359       return;
2360     }
2362   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2363      (other terminals do it the other way round).  We must set
2364      w->phys_cursor_width to the cursor width.  For bar cursors, that
2365      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2366   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2368   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2369      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2370   if (cursor_type == BAR_CURSOR)
2371     {
2372       if (cursor_width < 1)
2373         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2374       w->phys_cursor_width = cursor_width;
2375     }
2376   /* If we have an HBAR, "cursor_width" MAY specify height. */
2377   else if (cursor_type == HBAR_CURSOR)
2378     {
2379       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2380       fy += h - cursor_height;
2381       h = cursor_height;
2382     }
2384   r.origin.x = fx, r.origin.y = fy;
2385   r.size.height = h;
2386   r.size.width = w->phys_cursor_width;
2388   /* TODO: only needed in rare cases with last-resort font in HELLO..
2389      should we do this more efficiently? */
2390   ns_clip_to_row (w, glyph_row, ANY_AREA, NO); /* do ns_focus(f, &r, 1); if remove */
2393   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2394   if (face && NS_FACE_BACKGROUND (face)
2395       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2396     {
2397       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2398       hollow_color = FRAME_CURSOR_COLOR (f);
2399     }
2400   else
2401     [FRAME_CURSOR_COLOR (f) set];
2403 #ifdef NS_IMPL_COCOA
2404   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2405            atomic.  Cleaner ways of doing this should be investigated.
2406            One way would be to set a global variable DRAWING_CURSOR
2407            when making the call to draw_phys..(), don't focus in that
2408            case, then move the ns_unfocus() here after that call. */
2409   NSDisableScreenUpdates ();
2410 #endif
2412   switch (cursor_type)
2413     {
2414     case NO_CURSOR:
2415       break;
2416     case FILLED_BOX_CURSOR:
2417       NSRectFill (r);
2418       break;
2419     case HOLLOW_BOX_CURSOR:
2420       NSRectFill (r);
2421       [hollow_color set];
2422       NSRectFill (NSInsetRect (r, 1, 1));
2423       [FRAME_CURSOR_COLOR (f) set];
2424       break;
2425     case HBAR_CURSOR:
2426       NSRectFill (r);
2427       break;
2428     case BAR_CURSOR:
2429       s = r;
2430       /* If the character under cursor is R2L, draw the bar cursor
2431          on the right of its glyph, rather than on the left.  */
2432       cursor_glyph = get_phys_cursor_glyph (w);
2433       if ((cursor_glyph->resolved_level & 1) != 0)
2434         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2436       NSRectFill (s);
2437       break;
2438     }
2439   ns_unfocus (f);
2441   /* draw the character under the cursor */
2442   if (cursor_type != NO_CURSOR)
2443     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2445 #ifdef NS_IMPL_COCOA
2446   NSEnableScreenUpdates ();
2447 #endif
2452 static void
2453 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2454 /* --------------------------------------------------------------------------
2455      External (RIF): Draw a vertical line.
2456    -------------------------------------------------------------------------- */
2458   struct frame *f = XFRAME (WINDOW_FRAME (w));
2459   struct face *face;
2460   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2462   NSTRACE (ns_draw_vertical_window_border);
2464   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2465   if (face)
2466       [ns_lookup_indexed_color(face->foreground, f) set];
2468   ns_focus (f, &r, 1);
2469   NSRectFill(r);
2470   ns_unfocus (f);
2474 void
2475 show_hourglass (struct atimer *timer)
2477   if (hourglass_shown_p)
2478     return;
2480   block_input ();
2482   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2484   hourglass_shown_p = 1;
2485   unblock_input ();
2489 void
2490 hide_hourglass (void)
2492   if (!hourglass_shown_p)
2493     return;
2495   block_input ();
2497   /* TODO: remove NSProgressIndicator from all frames */
2499   hourglass_shown_p = 0;
2500   unblock_input ();
2505 /* ==========================================================================
2507     Glyph drawing operations
2509    ========================================================================== */
2511 static int
2512 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2513 /* --------------------------------------------------------------------------
2514     Wrapper utility to account for internal border width on full-width lines,
2515     and allow top full-width rows to hit the frame top.  nr should be pointer
2516     to two successive NSRects.  Number of rects actually used is returned.
2517    -------------------------------------------------------------------------- */
2519   int n = get_glyph_string_clip_rects (s, nr, 2);
2520   return n;
2523 /* --------------------------------------------------------------------
2524    Draw a wavy line under glyph string s. The wave fills wave_height
2525    pixels from y.
2527                     x          wave_length = 2
2528                                  --
2529                 y    *   *   *   *   *
2530                      |* * * * * * * * *
2531     wave_height = 3  | *   *   *   *
2532   --------------------------------------------------------------------- */
2534 static void
2535 ns_draw_underwave (struct glyph_string *s, EmacsCGFloat width, EmacsCGFloat x)
2537   int wave_height = 3, wave_length = 2;
2538   int y, dx, dy, odd, xmax;
2539   NSPoint a, b;
2540   NSRect waveClip;
2542   dx = wave_length;
2543   dy = wave_height - 1;
2544   y =  s->ybase - wave_height + 3;
2545   xmax = x + width;
2547   /* Find and set clipping rectangle */
2548   waveClip = NSMakeRect (x, y, width, wave_height);
2549   [[NSGraphicsContext currentContext] saveGraphicsState];
2550   NSRectClip (waveClip);
2552   /* Draw the waves */
2553   a.x = x - ((int)(x) % dx) + (EmacsCGFloat) 0.5;
2554   b.x = a.x + dx;
2555   odd = (int)(a.x/dx) % 2;
2556   a.y = b.y = y + 0.5;
2558   if (odd)
2559     a.y += dy;
2560   else
2561     b.y += dy;
2563   while (a.x <= xmax)
2564     {
2565       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2566       a.x = b.x, a.y = b.y;
2567       b.x += dx, b.y = y + 0.5 + odd*dy;
2568       odd = !odd;
2569     }
2571   /* Restore previous clipping rectangle(s) */
2572   [[NSGraphicsContext currentContext] restoreGraphicsState];
2577 void
2578 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2579                          NSColor *defaultCol, CGFloat width, CGFloat x)
2580 /* --------------------------------------------------------------------------
2581    Draw underline, overline, and strike-through on glyph string s.
2582    -------------------------------------------------------------------------- */
2584   if (s->for_overlaps)
2585     return;
2587   /* Do underline. */
2588   if (face->underline_p)
2589     {
2590       if (s->face->underline_type == FACE_UNDER_WAVE)
2591         {
2592           if (face->underline_defaulted_p)
2593             [defaultCol set];
2594           else
2595             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2597           ns_draw_underwave (s, width, x);
2598         }
2599       else if (s->face->underline_type == FACE_UNDER_LINE)
2600         {
2602           NSRect r;
2603           unsigned long thickness, position;
2605           /* If the prev was underlined, match its appearance. */
2606           if (s->prev && s->prev->face->underline_p
2607               && s->prev->face->underline_type == FACE_UNDER_LINE
2608               && s->prev->underline_thickness > 0)
2609             {
2610               thickness = s->prev->underline_thickness;
2611               position = s->prev->underline_position;
2612             }
2613           else
2614             {
2615               struct font *font;
2616               unsigned long descent;
2618               font=s->font;
2619               descent = s->y + s->height - s->ybase;
2621               /* Use underline thickness of font, defaulting to 1. */
2622               thickness = (font && font->underline_thickness > 0)
2623                 ? font->underline_thickness : 1;
2625               /* Determine the offset of underlining from the baseline. */
2626               if (x_underline_at_descent_line)
2627                 position = descent - thickness;
2628               else if (x_use_underline_position_properties
2629                        && font && font->underline_position >= 0)
2630                 position = font->underline_position;
2631               else if (font)
2632                 position = lround (font->descent / 2);
2633               else
2634                 position = underline_minimum_offset;
2636               position = max (position, underline_minimum_offset);
2638               /* Ensure underlining is not cropped. */
2639               if (descent <= position)
2640                 {
2641                   position = descent - 1;
2642                   thickness = 1;
2643                 }
2644               else if (descent < position + thickness)
2645                 thickness = 1;
2646             }
2648           s->underline_thickness = thickness;
2649           s->underline_position = position;
2651           r = NSMakeRect (x, s->ybase + position, width, thickness);
2653           if (face->underline_defaulted_p)
2654             [defaultCol set];
2655           else
2656             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2657           NSRectFill (r);
2658         }
2659     }
2660   /* Do overline. We follow other terms in using a thickness of 1
2661      and ignoring overline_margin. */
2662   if (face->overline_p)
2663     {
2664       NSRect r;
2665       r = NSMakeRect (x, s->y, width, 1);
2667       if (face->overline_color_defaulted_p)
2668         [defaultCol set];
2669       else
2670         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2671       NSRectFill (r);
2672     }
2674   /* Do strike-through.  We follow other terms for thickness and
2675      vertical position.*/
2676   if (face->strike_through_p)
2677     {
2678       NSRect r;
2679       unsigned long dy;
2681       dy = lrint ((s->height - 1) / 2);
2682       r = NSMakeRect (x, s->y + dy, width, 1);
2684       if (face->strike_through_color_defaulted_p)
2685         [defaultCol set];
2686       else
2687         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2688       NSRectFill (r);
2689     }
2692 static void
2693 ns_draw_box (NSRect r, CGFloat thickness, NSColor *col,
2694              char left_p, char right_p)
2695 /* --------------------------------------------------------------------------
2696     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2697     Note we can't just use an NSDrawRect command, because of the possibility
2698     of some sides not being drawn, and because the rect will be filled.
2699    -------------------------------------------------------------------------- */
2701   NSRect s = r;
2702   [col set];
2704   /* top, bottom */
2705   s.size.height = thickness;
2706   NSRectFill (s);
2707   s.origin.y += r.size.height - thickness;
2708   NSRectFill (s);
2710   s.size.height = r.size.height;
2711   s.origin.y = r.origin.y;
2713   /* left, right (optional) */
2714   s.size.width = thickness;
2715   if (left_p)
2716     NSRectFill (s);
2717   if (right_p)
2718     {
2719       s.origin.x += r.size.width - thickness;
2720       NSRectFill (s);
2721     }
2725 static void
2726 ns_draw_relief (NSRect r, int thickness, char raised_p,
2727                char top_p, char bottom_p, char left_p, char right_p,
2728                struct glyph_string *s)
2729 /* --------------------------------------------------------------------------
2730     Draw a relief rect inside r, optionally leaving some sides open.
2731     Note we can't just use an NSDrawBezel command, because of the possibility
2732     of some sides not being drawn, and because the rect will be filled.
2733    -------------------------------------------------------------------------- */
2735   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2736   NSColor *newBaseCol = nil;
2737   NSRect sr = r;
2739   NSTRACE (ns_draw_relief);
2741   /* set up colors */
2743   if (s->face->use_box_color_for_shadows_p)
2744     {
2745       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2746     }
2747 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2748            && s->img->pixmap
2749            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2750        {
2751          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2752        } */
2753   else
2754     {
2755       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2756     }
2758   if (newBaseCol == nil)
2759     newBaseCol = [NSColor grayColor];
2761   if (newBaseCol != baseCol)  /* TODO: better check */
2762     {
2763       [baseCol release];
2764       baseCol = [newBaseCol retain];
2765       [lightCol release];
2766       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2767       [darkCol release];
2768       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2769     }
2771   [(raised_p ? lightCol : darkCol) set];
2773   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2775   /* top */
2776   sr.size.height = thickness;
2777   if (top_p) NSRectFill (sr);
2779   /* left */
2780   sr.size.height = r.size.height;
2781   sr.size.width = thickness;
2782   if (left_p) NSRectFill (sr);
2784   [(raised_p ? darkCol : lightCol) set];
2786   /* bottom */
2787   sr.size.width = r.size.width;
2788   sr.size.height = thickness;
2789   sr.origin.y += r.size.height - thickness;
2790   if (bottom_p) NSRectFill (sr);
2792   /* right */
2793   sr.size.height = r.size.height;
2794   sr.origin.y = r.origin.y;
2795   sr.size.width = thickness;
2796   sr.origin.x += r.size.width - thickness;
2797   if (right_p) NSRectFill (sr);
2801 static void
2802 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2803 /* --------------------------------------------------------------------------
2804       Function modeled after x_draw_glyph_string_box ().
2805       Sets up parameters for drawing.
2806    -------------------------------------------------------------------------- */
2808   int right_x, last_x;
2809   char left_p, right_p;
2810   struct glyph *last_glyph;
2811   NSRect r;
2812   int thickness;
2813   struct face *face;
2815   if (s->hl == DRAW_MOUSE_FACE)
2816     {
2817       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2818       if (!face)
2819         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2820     }
2821   else
2822     face = s->face;
2824   thickness = face->box_line_width;
2826   NSTRACE (ns_dumpglyphs_box_or_relief);
2828   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2829             ? WINDOW_RIGHT_EDGE_X (s->w)
2830             : window_box_right (s->w, s->area));
2831   last_glyph = (s->cmp || s->img
2832                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2834   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2835               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2837   left_p = (s->first_glyph->left_box_line_p
2838             || (s->hl == DRAW_MOUSE_FACE
2839                 && (s->prev == NULL || s->prev->hl != s->hl)));
2840   right_p = (last_glyph->right_box_line_p
2841              || (s->hl == DRAW_MOUSE_FACE
2842                  && (s->next == NULL || s->next->hl != s->hl)));
2844   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2846   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2847   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2848     {
2849       ns_draw_box (r, abs (thickness),
2850                    ns_lookup_indexed_color (face->box_color, s->f),
2851                   left_p, right_p);
2852     }
2853   else
2854     {
2855       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2856                      1, 1, left_p, right_p, s);
2857     }
2861 static void
2862 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2863 /* --------------------------------------------------------------------------
2864       Modeled after x_draw_glyph_string_background, which draws BG in
2865       certain cases.  Others are left to the text rendering routine.
2866    -------------------------------------------------------------------------- */
2868   NSTRACE (ns_maybe_dumpglyphs_background);
2870   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2871     {
2872       int box_line_width = max (s->face->box_line_width, 0);
2873       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2874           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2875         {
2876           struct face *face;
2877           if (s->hl == DRAW_MOUSE_FACE)
2878             {
2879               face = FACE_FROM_ID (s->f,
2880                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2881               if (!face)
2882                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2883             }
2884           else
2885             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2886           if (!face->stipple)
2887             [(NS_FACE_BACKGROUND (face) != 0
2888               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2889               : FRAME_BACKGROUND_COLOR (s->f)) set];
2890           else
2891             {
2892               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2893               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2894             }
2896           if (s->hl != DRAW_CURSOR)
2897             {
2898               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2899                                     s->background_width,
2900                                     s->height-2*box_line_width);
2901               NSRectFill (r);
2902             }
2904           s->background_filled_p = 1;
2905         }
2906     }
2910 static void
2911 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2912 /* --------------------------------------------------------------------------
2913       Renders an image and associated borders.
2914    -------------------------------------------------------------------------- */
2916   EmacsImage *img = s->img->pixmap;
2917   int box_line_vwidth = max (s->face->box_line_width, 0);
2918   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2919   int bg_x, bg_y, bg_height;
2920   int th;
2921   char raised_p;
2922   NSRect br;
2923   struct face *face;
2924   NSColor *tdCol;
2926   NSTRACE (ns_dumpglyphs_image);
2928   if (s->face->box != FACE_NO_BOX
2929       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2930     x += abs (s->face->box_line_width);
2932   bg_x = x;
2933   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2934   bg_height = s->height;
2935   /* other terms have this, but was causing problems w/tabbar mode */
2936   /* - 2 * box_line_vwidth; */
2938   if (s->slice.x == 0) x += s->img->hmargin;
2939   if (s->slice.y == 0) y += s->img->vmargin;
2941   /* Draw BG: if we need larger area than image itself cleared, do that,
2942      otherwise, since we composite the image under NS (instead of mucking
2943      with its background color), we must clear just the image area. */
2944   if (s->hl == DRAW_MOUSE_FACE)
2945     {
2946       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2947       if (!face)
2948        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2949     }
2950   else
2951     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2953   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2955   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2956       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2957     {
2958       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2959       s->background_filled_p = 1;
2960     }
2961   else
2962     {
2963       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2964     }
2966   NSRectFill (br);
2968   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2969   if (img != nil)
2970     {
2971 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2972       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
2973       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
2974                               s->slice.width, s->slice.height);
2975       [img drawInRect: dr
2976              fromRect: ir
2977              operation: NSCompositeSourceOver
2978               fraction: 1.0
2979            respectFlipped: YES
2980                 hints: nil];
2981 #else
2982       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
2983                   operation: NSCompositeSourceOver];
2984 #endif
2985     }
2987   if (s->hl == DRAW_CURSOR)
2988     {
2989     [FRAME_CURSOR_COLOR (s->f) set];
2990     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
2991       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
2992     else
2993       /* Currently on NS img->mask is always 0. Since
2994          get_window_cursor_type specifies a hollow box cursor when on
2995          a non-masked image we never reach this clause. But we put it
2996          in in anticipation of better support for image masks on
2997          NS. */
2998       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
2999     }
3000   else
3001     {
3002       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3003     }
3005   /* Draw underline, overline, strike-through. */
3006   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3008   /* Draw relief, if requested */
3009   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3010     {
3011       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3012         {
3013           th = tool_bar_button_relief >= 0 ?
3014             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3015           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3016         }
3017       else
3018         {
3019           th = abs (s->img->relief);
3020           raised_p = (s->img->relief > 0);
3021         }
3023       r.origin.x = x - th;
3024       r.origin.y = y - th;
3025       r.size.width = s->slice.width + 2*th-1;
3026       r.size.height = s->slice.height + 2*th-1;
3027       ns_draw_relief (r, th, raised_p,
3028                       s->slice.y == 0,
3029                       s->slice.y + s->slice.height == s->img->height,
3030                       s->slice.x == 0,
3031                       s->slice.x + s->slice.width == s->img->width, s);
3032     }
3034   /* If there is no mask, the background won't be seen,
3035      so draw a rectangle on the image for the cursor.
3036      Do this for all images, getting transparency right is not reliable.  */
3037   if (s->hl == DRAW_CURSOR)
3038     {
3039       int thickness = abs (s->img->relief);
3040       if (thickness == 0) thickness = 1;
3041       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3042     }
3046 static void
3047 ns_dumpglyphs_stretch (struct glyph_string *s)
3049   NSRect r[2];
3050   int n, i;
3051   struct face *face;
3052   NSColor *fgCol, *bgCol;
3054   if (!s->background_filled_p)
3055     {
3056       n = ns_get_glyph_string_clip_rect (s, r);
3057       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3059       ns_focus (s->f, r, n);
3061       if (s->hl == DRAW_MOUSE_FACE)
3062        {
3063          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3064          if (!face)
3065            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3066        }
3067       else
3068        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3070       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3071       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3073       for (i = 0; i < n; ++i)
3074         {
3075           if (!s->row->full_width_p)
3076             {
3077               int overrun, leftoverrun;
3079               /* truncate to avoid overwriting fringe and/or scrollbar */
3080               overrun = max (0, (s->x + s->background_width)
3081                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3082                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3083               r[i].size.width -= overrun;
3085               /* truncate to avoid overwriting to left of the window box */
3086               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3087                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3089               if (leftoverrun > 0)
3090                 {
3091                   r[i].origin.x += leftoverrun;
3092                   r[i].size.width -= leftoverrun;
3093                 }
3095               /* XXX: Try to work between problem where a stretch glyph on
3096                  a partially-visible bottom row will clear part of the
3097                  modeline, and another where list-buffers headers and similar
3098                  rows erroneously have visible_height set to 0.  Not sure
3099                  where this is coming from as other terms seem not to show. */
3100               r[i].size.height = min (s->height, s->row->visible_height);
3101             }
3103           [bgCol set];
3105           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3106              overwriting cursor (usually when cursor on a tab) */
3107           if (s->hl == DRAW_CURSOR)
3108             {
3109               CGFloat x, width;
3111               x = r[i].origin.x;
3112               width = s->w->phys_cursor_width;
3113               r[i].size.width -= width;
3114               r[i].origin.x += width;
3116               NSRectFill (r[i]);
3118               /* Draw overlining, etc. on the cursor. */
3119               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3120                 ns_draw_text_decoration (s, face, bgCol, width, x);
3121               else
3122                 ns_draw_text_decoration (s, face, fgCol, width, x);
3123             }
3124           else
3125             {
3126               NSRectFill (r[i]);
3127             }
3129           /* Draw overlining, etc. on the stretch glyph (or the part
3130              of the stretch glyph after the cursor). */
3131           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3132                                    r[i].origin.x);
3133         }
3134       ns_unfocus (s->f);
3135       s->background_filled_p = 1;
3136     }
3140 static void
3141 ns_draw_glyph_string (struct glyph_string *s)
3142 /* --------------------------------------------------------------------------
3143       External (RIF): Main draw-text call.
3144    -------------------------------------------------------------------------- */
3146   /* TODO (optimize): focus for box and contents draw */
3147   NSRect r[2];
3148   int n;
3149   char box_drawn_p = 0;
3151   NSTRACE (ns_draw_glyph_string);
3153   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3154     {
3155       int width;
3156       struct glyph_string *next;
3158       for (width = 0, next = s->next;
3159            next && width < s->right_overhang;
3160            width += next->width, next = next->next)
3161         if (next->first_glyph->type != IMAGE_GLYPH)
3162           {
3163             if (next->first_glyph->type != STRETCH_GLYPH)
3164               {
3165                 n = ns_get_glyph_string_clip_rect (s->next, r);
3166                 ns_focus (s->f, r, n);
3167                 ns_maybe_dumpglyphs_background (s->next, 1);
3168                 ns_unfocus (s->f);
3169               }
3170             else
3171               {
3172                 ns_dumpglyphs_stretch (s->next);
3173               }
3174             next->num_clips = 0;
3175           }
3176     }
3178   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3179         && (s->first_glyph->type == CHAR_GLYPH
3180             || s->first_glyph->type == COMPOSITE_GLYPH))
3181     {
3182       n = ns_get_glyph_string_clip_rect (s, r);
3183       ns_focus (s->f, r, n);
3184       ns_maybe_dumpglyphs_background (s, 1);
3185       ns_dumpglyphs_box_or_relief (s);
3186       ns_unfocus (s->f);
3187       box_drawn_p = 1;
3188     }
3190   switch (s->first_glyph->type)
3191     {
3193     case IMAGE_GLYPH:
3194       n = ns_get_glyph_string_clip_rect (s, r);
3195       ns_focus (s->f, r, n);
3196       ns_dumpglyphs_image (s, r[0]);
3197       ns_unfocus (s->f);
3198       break;
3200     case STRETCH_GLYPH:
3201       ns_dumpglyphs_stretch (s);
3202       break;
3204     case CHAR_GLYPH:
3205     case COMPOSITE_GLYPH:
3206       n = ns_get_glyph_string_clip_rect (s, r);
3207       ns_focus (s->f, r, n);
3209       if (s->for_overlaps || (s->cmp_from > 0
3210                               && ! s->first_glyph->u.cmp.automatic))
3211         s->background_filled_p = 1;
3212       else
3213         ns_maybe_dumpglyphs_background
3214           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3216       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3217                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3218                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3219                       NS_DUMPGLYPH_NORMAL));
3220       ns_tmp_font = (struct nsfont_info *)s->face->font;
3221       if (ns_tmp_font == NULL)
3222           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3224       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3225         {
3226           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3227           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3228           NS_FACE_FOREGROUND (s->face) = tmp;
3229         }
3231       ns_tmp_font->font.driver->draw
3232         (s, 0, s->nchars, s->x, s->y,
3233          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3234          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3236       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3237         {
3238           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3239           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3240           NS_FACE_FOREGROUND (s->face) = tmp;
3241         }
3243       ns_unfocus (s->f);
3244       break;
3246     case GLYPHLESS_GLYPH:
3247       n = ns_get_glyph_string_clip_rect (s, r);
3248       ns_focus (s->f, r, n);
3250       if (s->for_overlaps || (s->cmp_from > 0
3251                               && ! s->first_glyph->u.cmp.automatic))
3252         s->background_filled_p = 1;
3253       else
3254         ns_maybe_dumpglyphs_background
3255           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3256       /* ... */
3257       /* Not yet implemented.  */
3258       /* ... */
3259       ns_unfocus (s->f);
3260       break;
3262     default:
3263       emacs_abort ();
3264     }
3266   /* Draw box if not done already. */
3267   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3268     {
3269       n = ns_get_glyph_string_clip_rect (s, r);
3270       ns_focus (s->f, r, n);
3271       ns_dumpglyphs_box_or_relief (s);
3272       ns_unfocus (s->f);
3273     }
3275   s->num_clips = 0;
3280 /* ==========================================================================
3282     Event loop
3284    ========================================================================== */
3287 static void
3288 ns_send_appdefined (int value)
3289 /* --------------------------------------------------------------------------
3290     Internal: post an appdefined event which EmacsApp-sendEvent will
3291               recognize and take as a command to halt the event loop.
3292    -------------------------------------------------------------------------- */
3294   /*NSTRACE (ns_send_appdefined); */
3296 #ifdef NS_IMPL_GNUSTEP
3297   // GNUStep needs postEvent to happen on the main thread.
3298   if (! [[NSThread currentThread] isMainThread])
3299     {
3300       EmacsApp *app = (EmacsApp *)NSApp;
3301       app->nextappdefined = value;
3302       [app performSelectorOnMainThread:@selector (sendFromMainThread:)
3303                             withObject:nil
3304                          waitUntilDone:YES];
3305       return;
3306     }
3307 #endif
3309   /* Only post this event if we haven't already posted one.  This will end
3310        the [NXApp run] main loop after having processed all events queued at
3311        this moment.  */
3312   if (send_appdefined)
3313     {
3314       NSEvent *nxev;
3316       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3317       send_appdefined = NO;
3319       /* Don't need wakeup timer any more */
3320       if (timed_entry)
3321         {
3322           [timed_entry invalidate];
3323           [timed_entry release];
3324           timed_entry = nil;
3325         }
3327       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3328                                 location: NSMakePoint (0, 0)
3329                            modifierFlags: 0
3330                                timestamp: 0
3331                             windowNumber: [[NSApp mainWindow] windowNumber]
3332                                  context: [NSApp context]
3333                                  subtype: 0
3334                                    data1: value
3335                                    data2: 0];
3337       /* Post an application defined event on the event queue.  When this is
3338          received the [NXApp run] will return, thus having processed all
3339          events which are currently queued.  */
3340       [NSApp postEvent: nxev atStart: NO];
3341     }
3344 #ifdef HAVE_NATIVE_FS
3345 static void
3346 check_native_fs ()
3348   Lisp_Object frame, tail;
3350   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3351     return;
3353   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3355   /* Clear the mouse-moved flag for every frame on this display.  */
3356   FOR_EACH_FRAME (tail, frame)
3357     {
3358       struct frame *f = XFRAME (frame);
3359       if (FRAME_NS_P (f))
3360         {
3361           EmacsView *view = FRAME_NS_VIEW (f);
3362           [view updateCollectionBehaviour];
3363         }
3364     }
3366 #endif
3368 /* GNUStep and OSX <= 10.4 does not have cancelTracking.  */
3369 #if defined (NS_IMPL_COCOA) && \
3370   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
3371 /* Check if menu open should be cancelled or continued as normal.  */
3372 void
3373 ns_check_menu_open (NSMenu *menu)
3375   /* Click in menu bar? */
3376   NSArray *a = [[NSApp mainMenu] itemArray];
3377   int i;
3378   BOOL found = NO;
3380   if (menu == nil) // Menu tracking ended.
3381     {
3382       if (menu_will_open_state == MENU_OPENING)
3383         menu_will_open_state = MENU_NONE;
3384       return;
3385     }
3387   for (i = 0; ! found && i < [a count]; i++)
3388     found = menu == [[a objectAtIndex:i] submenu];
3389   if (found)
3390     {
3391       if (menu_will_open_state == MENU_NONE && emacs_event)
3392         {
3393           NSEvent *theEvent = [NSApp currentEvent];
3394           struct frame *emacsframe = SELECTED_FRAME ();
3396           [menu cancelTracking];
3397           menu_will_open_state = MENU_PENDING;
3398           emacs_event->kind = MENU_BAR_ACTIVATE_EVENT;
3399           EV_TRAILER (theEvent);
3401           CGEventRef ourEvent = CGEventCreate (NULL);
3402           menu_mouse_point = CGEventGetLocation (ourEvent);
3403           CFRelease (ourEvent);
3404         }
3405       else if (menu_will_open_state == MENU_OPENING)
3406         {
3407           menu_will_open_state = MENU_NONE;
3408         }
3409     }
3412 /* Redo saved menu click if state is MENU_PENDING.  */
3413 void
3414 ns_check_pending_open_menu ()
3416   if (menu_will_open_state == MENU_PENDING)
3417     {
3418       CGEventSourceRef source
3419         = CGEventSourceCreate (kCGEventSourceStateHIDSystemState);
3421       CGEventRef event = CGEventCreateMouseEvent (source,
3422                                                   kCGEventLeftMouseDown,
3423                                                   menu_mouse_point,
3424                                                   kCGMouseButtonLeft);
3425       CGEventSetType (event, kCGEventLeftMouseDown);
3426       CGEventPost (kCGHIDEventTap, event);
3427       CFRelease (event);
3428       CFRelease (source);
3430       menu_will_open_state = MENU_OPENING;
3431     }
3433 #endif /* NS_IMPL_COCOA) && >= MAC_OS_X_VERSION_10_5 */
3435 static int
3436 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3437 /* --------------------------------------------------------------------------
3438      External (hook): Post an event to ourself and keep reading events until
3439      we read it back again.  In effect process all events which were waiting.
3440      From 21+ we have to manage the event buffer ourselves.
3441    -------------------------------------------------------------------------- */
3443   struct input_event ev;
3444   int nevents;
3446 /* NSTRACE (ns_read_socket); */
3448 #ifdef HAVE_NATIVE_FS
3449   check_native_fs ();
3450 #endif
3452   if ([NSApp modalWindow] != nil)
3453     return -1;
3455   if (hold_event_q.nr > 0)
3456     {
3457       int i;
3458       for (i = 0; i < hold_event_q.nr; ++i)
3459         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3460       hold_event_q.nr = 0;
3461       return i;
3462     }
3464   block_input ();
3465   n_emacs_events_pending = 0;
3466   EVENT_INIT (ev);
3467   emacs_event = &ev;
3468   q_event_ptr = hold_quit;
3470   /* we manage autorelease pools by allocate/reallocate each time around
3471      the loop; strict nesting is occasionally violated but seems not to
3472      matter.. earlier methods using full nesting caused major memory leaks */
3473   [outerpool release];
3474   outerpool = [[NSAutoreleasePool alloc] init];
3476   /* If have pending open-file requests, attend to the next one of those. */
3477   if (ns_pending_files && [ns_pending_files count] != 0
3478       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3479     {
3480       [ns_pending_files removeObjectAtIndex: 0];
3481     }
3482   /* Deal with pending service requests. */
3483   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3484     && [(EmacsApp *)
3485          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3486                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3487     {
3488       [ns_pending_service_names removeObjectAtIndex: 0];
3489       [ns_pending_service_args removeObjectAtIndex: 0];
3490     }
3491   else
3492     {
3493       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3494          to ourself, otherwise [NXApp run] will never exit.  */
3495       send_appdefined = YES;
3496       ns_send_appdefined (-1);
3498       if (++apploopnr != 1)
3499         {
3500           emacs_abort ();
3501         }
3502       [NSApp run];
3503       --apploopnr;
3504     }
3506   nevents = n_emacs_events_pending;
3507   n_emacs_events_pending = 0;
3508   emacs_event = q_event_ptr = NULL;
3509   unblock_input ();
3511   return nevents;
3516 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3517            fd_set *exceptfds, struct timespec const *timeout,
3518            sigset_t const *sigmask)
3519 /* --------------------------------------------------------------------------
3520      Replacement for select, checking for events
3521    -------------------------------------------------------------------------- */
3523   int result;
3524   int t, k, nr = 0;
3525   struct input_event event;
3526   char c;
3528 /*  NSTRACE (ns_select); */
3530 #ifdef HAVE_NATIVE_FS
3531   check_native_fs ();
3532 #endif
3534   if (hold_event_q.nr > 0)
3535     {
3536       /* We already have events pending. */
3537       raise (SIGIO);
3538       errno = EINTR;
3539       return -1;
3540     }
3542   for (k = 0; k < nfds+1; k++)
3543     {
3544       if (readfds && FD_ISSET(k, readfds)) ++nr;
3545       if (writefds && FD_ISSET(k, writefds)) ++nr;
3546     }
3548   if (NSApp == nil
3549       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3550     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3552   [outerpool release];
3553   outerpool = [[NSAutoreleasePool alloc] init];
3556   send_appdefined = YES;
3557   if (nr > 0)
3558     {
3559       pthread_mutex_lock (&select_mutex);
3560       select_nfds = nfds;
3561       select_valid = 0;
3562       if (readfds)
3563         {
3564           select_readfds = *readfds;
3565           select_valid += SELECT_HAVE_READ;
3566         }
3567       if (writefds)
3568         {
3569           select_writefds = *writefds;
3570           select_valid += SELECT_HAVE_WRITE;
3571         }
3573       if (timeout)
3574         {
3575           select_timeout = *timeout;
3576           select_valid += SELECT_HAVE_TMO;
3577         }
3579       pthread_mutex_unlock (&select_mutex);
3581       /* Inform fd_handler that select should be called */
3582       c = 'g';
3583       emacs_write_sig (selfds[1], &c, 1);
3584     }
3585   else if (nr == 0 && timeout)
3586     {
3587       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3588       double time = timespectod (*timeout);
3589       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3590                                                       target: NSApp
3591                                                     selector:
3592                                   @selector (timeout_handler:)
3593                                                     userInfo: 0
3594                                                      repeats: NO]
3595                       retain];
3596     }
3597   else /* No timeout and no file descriptors, can this happen?  */
3598     {
3599       /* Send appdefined so we exit from the loop */
3600       ns_send_appdefined (-1);
3601     }
3603   EVENT_INIT (event);
3604   block_input ();
3605   emacs_event = &event;
3606   if (++apploopnr != 1)
3607     {
3608       emacs_abort ();
3609     }
3610   [NSApp run];
3611   --apploopnr;
3612   emacs_event = NULL;
3613   if (nr > 0 && readfds)
3614     {
3615       c = 's';
3616       emacs_write_sig (selfds[1], &c, 1);
3617     }
3618   unblock_input ();
3620   t = last_appdefined_event_data;
3622   if (t != NO_APPDEFINED_DATA)
3623     {
3624       last_appdefined_event_data = NO_APPDEFINED_DATA;
3626       if (t == -2)
3627         {
3628           /* The NX_APPDEFINED event we received was a timeout. */
3629           result = 0;
3630         }
3631       else if (t == -1)
3632         {
3633           /* The NX_APPDEFINED event we received was the result of
3634              at least one real input event arriving.  */
3635           errno = EINTR;
3636           result = -1;
3637         }
3638       else
3639         {
3640           /* Received back from select () in fd_handler; copy the results */
3641           pthread_mutex_lock (&select_mutex);
3642           if (readfds) *readfds = select_readfds;
3643           if (writefds) *writefds = select_writefds;
3644           pthread_mutex_unlock (&select_mutex);
3645           result = t;
3646         }
3647     }
3648   else
3649     {
3650       errno = EINTR;
3651       result = -1;
3652     }
3654   return result;
3659 /* ==========================================================================
3661     Scrollbar handling
3663    ========================================================================== */
3666 static void
3667 ns_set_vertical_scroll_bar (struct window *window,
3668                            int portion, int whole, int position)
3669 /* --------------------------------------------------------------------------
3670       External (hook): Update or add scrollbar
3671    -------------------------------------------------------------------------- */
3673   Lisp_Object win;
3674   NSRect r, v;
3675   struct frame *f = XFRAME (WINDOW_FRAME (window));
3676   EmacsView *view = FRAME_NS_VIEW (f);
3677   int window_y, window_height;
3678   int top, left, height, width, sb_width, sb_left;
3679   EmacsScroller *bar;
3680   BOOL fringe_extended_p;
3682   /* optimization; display engine sends WAY too many of these.. */
3683   if (!NILP (window->vertical_scroll_bar))
3684     {
3685       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3686       if ([bar checkSamePosition: position portion: portion whole: whole])
3687         {
3688           if (view->scrollbarsNeedingUpdate == 0)
3689             {
3690               if (!windows_or_buffers_changed)
3691                   return;
3692             }
3693           else
3694             view->scrollbarsNeedingUpdate--;
3695         }
3696     }
3698   NSTRACE (ns_set_vertical_scroll_bar);
3700   /* Get dimensions.  */
3701   window_box (window, ANY_AREA, 0, &window_y, 0, &window_height);
3702   top = window_y;
3703   height = window_height;
3704   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3705   left = WINDOW_SCROLL_BAR_AREA_X (window);
3707   /* allow for displaying a skinnier scrollbar than char area allotted */
3708   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3709     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3710   sb_left = left;
3712   r = NSMakeRect (sb_left, top, sb_width, height);
3713   /* the parent view is flipped, so we need to flip y value */
3714   v = [view frame];
3715   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3717   fringe_extended_p = WINDOW_FRINGE_EXTENDED_P (window);
3719   XSETWINDOW (win, window);
3720   block_input ();
3722   /* we want at least 5 lines to display a scrollbar */
3723   if (WINDOW_TOTAL_LINES (window) < 5)
3724     {
3725       if (!NILP (window->vertical_scroll_bar))
3726         {
3727           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3728           [bar removeFromSuperview];
3729           wset_vertical_scroll_bar (window, Qnil);
3730         }
3731       ns_clear_frame_area (f, sb_left, top, width, height);
3732       unblock_input ();
3733       return;
3734     }
3736   if (NILP (window->vertical_scroll_bar))
3737     {
3738       if (width > 0 && height > 0)
3739         {
3740           if (fringe_extended_p)
3741             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3742           else
3743             ns_clear_frame_area (f, left, top, width, height);
3744         }
3746       bar = [[EmacsScroller alloc] initFrame: r window: win];
3747       wset_vertical_scroll_bar (window, make_save_ptr (bar));
3748     }
3749   else
3750     {
3751       NSRect oldRect;
3752       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3753       oldRect = [bar frame];
3754       r.size.width = oldRect.size.width;
3755       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3756         {
3757           if (oldRect.origin.x != r.origin.x)
3758               ns_clear_frame_area (f, sb_left, top, width, height);
3759           [bar setFrame: r];
3760         }
3761     }
3763   [bar setPosition: position portion: portion whole: whole];
3764   unblock_input ();
3768 static void
3769 ns_condemn_scroll_bars (struct frame *f)
3770 /* --------------------------------------------------------------------------
3771      External (hook): arrange for all frame's scrollbars to be removed
3772      at next call to judge_scroll_bars, except for those redeemed.
3773    -------------------------------------------------------------------------- */
3775   int i;
3776   id view;
3777   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3779   NSTRACE (ns_condemn_scroll_bars);
3781   for (i =[subviews count]-1; i >= 0; i--)
3782     {
3783       view = [subviews objectAtIndex: i];
3784       if ([view isKindOfClass: [EmacsScroller class]])
3785         [view condemn];
3786     }
3790 static void
3791 ns_redeem_scroll_bar (struct window *window)
3792 /* --------------------------------------------------------------------------
3793      External (hook): arrange to spare this window's scrollbar
3794      at next call to judge_scroll_bars.
3795    -------------------------------------------------------------------------- */
3797   id bar;
3798   NSTRACE (ns_redeem_scroll_bar);
3799   if (!NILP (window->vertical_scroll_bar))
3800     {
3801       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3802       [bar reprieve];
3803     }
3807 static void
3808 ns_judge_scroll_bars (struct frame *f)
3809 /* --------------------------------------------------------------------------
3810      External (hook): destroy all scrollbars on frame that weren't
3811      redeemed after call to condemn_scroll_bars.
3812    -------------------------------------------------------------------------- */
3814   int i;
3815   id view;
3816   EmacsView *eview = FRAME_NS_VIEW (f);
3817   NSArray *subviews = [[eview superview] subviews];
3818   BOOL removed = NO;
3820   NSTRACE (ns_judge_scroll_bars);
3821   for (i = [subviews count]-1; i >= 0; --i)
3822     {
3823       view = [subviews objectAtIndex: i];
3824       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3825       [view judge];
3826       removed = YES;
3827     }
3829   if (removed)
3830     [eview updateFrameSize: NO];
3833 /* ==========================================================================
3835     Initialization
3837    ========================================================================== */
3840 x_display_pixel_height (struct ns_display_info *dpyinfo)
3842   NSArray *screens = [NSScreen screens];
3843   NSEnumerator *enumerator = [screens objectEnumerator];
3844   NSScreen *screen;
3845   NSRect frame;
3847   frame = NSZeroRect;
3848   while ((screen = [enumerator nextObject]) != nil)
3849     frame = NSUnionRect (frame, [screen frame]);
3851   return NSHeight (frame);
3855 x_display_pixel_width (struct ns_display_info *dpyinfo)
3857   NSArray *screens = [NSScreen screens];
3858   NSEnumerator *enumerator = [screens objectEnumerator];
3859   NSScreen *screen;
3860   NSRect frame;
3862   frame = NSZeroRect;
3863   while ((screen = [enumerator nextObject]) != nil)
3864     frame = NSUnionRect (frame, [screen frame]);
3866   return NSWidth (frame);
3870 static Lisp_Object ns_string_to_lispmod (const char *s)
3871 /* --------------------------------------------------------------------------
3872      Convert modifier name to lisp symbol
3873    -------------------------------------------------------------------------- */
3875   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3876     return Qmeta;
3877   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3878     return Qsuper;
3879   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3880     return Qcontrol;
3881   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3882     return Qalt;
3883   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3884     return Qhyper;
3885   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3886     return Qnone;
3887   else
3888     return Qnil;
3892 static void
3893 ns_default (const char *parameter, Lisp_Object *result,
3894            Lisp_Object yesval, Lisp_Object noval,
3895            BOOL is_float, BOOL is_modstring)
3896 /* --------------------------------------------------------------------------
3897       Check a parameter value in user's preferences
3898    -------------------------------------------------------------------------- */
3900   const char *value = ns_get_defaults_value (parameter);
3902   if (value)
3903     {
3904       double f;
3905       char *pos;
3906       if (c_strcasecmp (value, "YES") == 0)
3907         *result = yesval;
3908       else if (c_strcasecmp (value, "NO") == 0)
3909         *result = noval;
3910       else if (is_float && (f = strtod (value, &pos), pos != value))
3911         *result = make_float (f);
3912       else if (is_modstring && value)
3913         *result = ns_string_to_lispmod (value);
3914       else fprintf (stderr,
3915                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3916     }
3920 static void
3921 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3922 /* --------------------------------------------------------------------------
3923       Initialize global info and storage for display.
3924    -------------------------------------------------------------------------- */
3926     NSScreen *screen = [NSScreen mainScreen];
3927     NSWindowDepth depth = [screen depth];
3929     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3930     dpyinfo->resy = 72.27;
3931     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3932                                                   NSColorSpaceFromDepth (depth)]
3933                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3934                                                  NSColorSpaceFromDepth (depth)];
3935     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3936     dpyinfo->image_cache = make_image_cache ();
3937     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3938     dpyinfo->color_table->colors = NULL;
3939     dpyinfo->root_window = 42; /* a placeholder.. */
3940     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3941     dpyinfo->n_fonts = 0;
3942     dpyinfo->smallest_font_height = 1;
3943     dpyinfo->smallest_char_width = 1;
3945     reset_mouse_highlight (&dpyinfo->mouse_highlight);
3949 /* This and next define (many of the) public functions in this file. */
3950 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3951          with using despite presence in the "system dependent" redisplay
3952          interface.  In addition, many of the ns_ methods have code that is
3953          shared with all terms, indicating need for further refactoring. */
3954 extern frame_parm_handler ns_frame_parm_handlers[];
3955 static struct redisplay_interface ns_redisplay_interface =
3957   ns_frame_parm_handlers,
3958   x_produce_glyphs,
3959   x_write_glyphs,
3960   x_insert_glyphs,
3961   x_clear_end_of_line,
3962   ns_scroll_run,
3963   ns_after_update_window_line,
3964   ns_update_window_begin,
3965   ns_update_window_end,
3966   ns_flush,
3967   0, /* flush_display_optional */
3968   x_clear_window_mouse_face,
3969   x_get_glyph_overhangs,
3970   x_fix_overlapping_area,
3971   ns_draw_fringe_bitmap,
3972   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3973   0, /* destroy_fringe_bitmap */
3974   ns_compute_glyph_string_overhangs,
3975   ns_draw_glyph_string, /* interface to nsfont.m */
3976   ns_define_frame_cursor,
3977   ns_clear_frame_area,
3978   ns_draw_window_cursor,
3979   ns_draw_vertical_window_border,
3980   ns_shift_glyphs_for_insert
3984 static void
3985 ns_delete_display (struct ns_display_info *dpyinfo)
3987   /* TODO... */
3991 /* This function is called when the last frame on a display is deleted. */
3992 static void
3993 ns_delete_terminal (struct terminal *terminal)
3995   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3997   /* Protect against recursive calls.  delete_frame in
3998      delete_terminal calls us back when it deletes our last frame.  */
3999   if (!terminal->name)
4000     return;
4002   block_input ();
4004   x_destroy_all_bitmaps (dpyinfo);
4005   ns_delete_display (dpyinfo);
4006   unblock_input ();
4010 static struct terminal *
4011 ns_create_terminal (struct ns_display_info *dpyinfo)
4012 /* --------------------------------------------------------------------------
4013       Set up use of NS before we make the first connection.
4014    -------------------------------------------------------------------------- */
4016   struct terminal *terminal;
4018   NSTRACE (ns_create_terminal);
4020   terminal = create_terminal ();
4022   terminal->type = output_ns;
4023   terminal->display_info.ns = dpyinfo;
4024   dpyinfo->terminal = terminal;
4026   terminal->rif = &ns_redisplay_interface;
4028   terminal->clear_frame_hook = ns_clear_frame;
4029   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4030   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4031   terminal->ring_bell_hook = ns_ring_bell;
4032   terminal->reset_terminal_modes_hook = NULL;
4033   terminal->set_terminal_modes_hook = NULL;
4034   terminal->update_begin_hook = ns_update_begin;
4035   terminal->update_end_hook = ns_update_end;
4036   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4037   terminal->read_socket_hook = ns_read_socket;
4038   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4039   terminal->mouse_position_hook = ns_mouse_position;
4040   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4041   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4043   terminal->fullscreen_hook = ns_fullscreen_hook;
4045   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4046   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4047   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4048   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4050   terminal->delete_frame_hook = x_destroy_window;
4051   terminal->delete_terminal_hook = ns_delete_terminal;
4053   terminal->scroll_region_ok = 1;
4054   terminal->char_ins_del_ok = 1;
4055   terminal->line_ins_del_ok = 1;
4056   terminal->fast_clear_end_of_line = 1;
4057   terminal->memory_below_frame = 0;
4059   return terminal;
4063 struct ns_display_info *
4064 ns_term_init (Lisp_Object display_name)
4065 /* --------------------------------------------------------------------------
4066      Start the Application and get things rolling.
4067    -------------------------------------------------------------------------- */
4069   struct terminal *terminal;
4070   struct ns_display_info *dpyinfo;
4071   static int ns_initialized = 0;
4072   Lisp_Object tmp;
4074   if (ns_initialized) return x_display_list;
4075   ns_initialized = 1;
4077   NSTRACE (ns_term_init);
4079   [outerpool release];
4080   outerpool = [[NSAutoreleasePool alloc] init];
4082   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4083   /*GSDebugAllocationActive (YES); */
4084   block_input ();
4086   baud_rate = 38400;
4087   Fset_input_interrupt_mode (Qnil);
4089   if (selfds[0] == -1)
4090     {
4091       if (emacs_pipe (selfds) != 0)
4092         {
4093           fprintf (stderr, "Failed to create pipe: %s\n",
4094                    emacs_strerror (errno));
4095           emacs_abort ();
4096         }
4098       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4099       FD_ZERO (&select_readfds);
4100       FD_ZERO (&select_writefds);
4101       pthread_mutex_init (&select_mutex, NULL);
4102     }
4104   ns_pending_files = [[NSMutableArray alloc] init];
4105   ns_pending_service_names = [[NSMutableArray alloc] init];
4106   ns_pending_service_args = [[NSMutableArray alloc] init];
4108 /* Start app and create the main menu, window, view.
4109      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4110      The view will then ask the NSApp to stop and return to Emacs. */
4111   [EmacsApp sharedApplication];
4112   if (NSApp == nil)
4113     return NULL;
4114   [NSApp setDelegate: NSApp];
4116   /* Start the select thread.  */
4117   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4118                            toTarget:NSApp
4119                          withObject:nil];
4121   /* debugging: log all notifications */
4122   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4123                                          selector: @selector (logNotification:)
4124                                              name: nil object: nil]; */
4126   dpyinfo = xzalloc (sizeof *dpyinfo);
4128   ns_initialize_display_info (dpyinfo);
4129   terminal = ns_create_terminal (dpyinfo);
4131   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4132   init_kboard (terminal->kboard);
4133   kset_window_system (terminal->kboard, Qns);
4134   terminal->kboard->next_kboard = all_kboards;
4135   all_kboards = terminal->kboard;
4136   /* Don't let the initial kboard remain current longer than necessary.
4137      That would cause problems if a file loaded on startup tries to
4138      prompt in the mini-buffer.  */
4139   if (current_kboard == initial_kboard)
4140     current_kboard = terminal->kboard;
4141   terminal->kboard->reference_count++;
4143   dpyinfo->next = x_display_list;
4144   x_display_list = dpyinfo;
4146   /* Put it on ns_display_name_list */
4147   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4148                                 ns_display_name_list);
4149   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4151   terminal->name = xstrdup (SSDATA (display_name));
4153   unblock_input ();
4155   if (!inhibit_x_resources)
4156     {
4157       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4158                  Qt, Qnil, NO, NO);
4159       tmp = Qnil;
4160       /* this is a standard variable */
4161       ns_default ("AppleAntiAliasingThreshold", &tmp,
4162                  make_float (10.0), make_float (6.0), YES, NO);
4163       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4164     }
4166   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4167                          stringForKey: @"AppleHighlightColor"];
4168   if (ns_selection_color == nil)
4169     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4171   {
4172     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4174     if ( cl == nil )
4175       {
4176         Lisp_Object color_file, color_map, color;
4177         unsigned long c;
4178         char *name;
4180         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4181                          Fsymbol_value (intern ("data-directory")));
4183         color_map = Fx_load_color_file (color_file);
4184         if (NILP (color_map))
4185           fatal ("Could not read %s.\n", SDATA (color_file));
4187         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4188         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4189           {
4190             color = XCAR (color_map);
4191             name = SSDATA (XCAR (color));
4192             c = XINT (XCDR (color));
4193             [cl setColor:
4194                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4195                                             green: GREEN_FROM_ULONG (c) / 255.0
4196                                              blue: BLUE_FROM_ULONG (c) / 255.0
4197                                             alpha: 1.0]
4198                   forKey: [NSString stringWithUTF8String: name]];
4199           }
4200         [cl writeToFile: nil];
4201       }
4202   }
4204   {
4205 #ifdef NS_IMPL_GNUSTEP
4206     Vwindow_system_version = build_string (gnustep_base_version);
4207 #else
4208     /*PSnextrelease (128, c); */
4209     char c[DBL_BUFSIZE_BOUND];
4210     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4211     Vwindow_system_version = make_unibyte_string (c, len);
4212 #endif
4213   }
4215   delete_keyboard_wait_descriptor (0);
4217   ns_app_name = [[NSProcessInfo processInfo] processName];
4219 /* Set up OS X app menu */
4220 #ifdef NS_IMPL_COCOA
4221   {
4222     NSMenu *appMenu;
4223     NSMenuItem *item;
4224     /* set up the application menu */
4225     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4226     [svcsMenu setAutoenablesItems: NO];
4227     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4228     [appMenu setAutoenablesItems: NO];
4229     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4230     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4232     [appMenu insertItemWithTitle: @"About Emacs"
4233                           action: @selector (orderFrontStandardAboutPanel:)
4234                    keyEquivalent: @""
4235                          atIndex: 0];
4236     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4237     [appMenu insertItemWithTitle: @"Preferences..."
4238                           action: @selector (showPreferencesWindow:)
4239                    keyEquivalent: @","
4240                          atIndex: 2];
4241     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4242     item = [appMenu insertItemWithTitle: @"Services"
4243                                  action: @selector (menuDown:)
4244                           keyEquivalent: @""
4245                                 atIndex: 4];
4246     [appMenu setSubmenu: svcsMenu forItem: item];
4247     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4248     [appMenu insertItemWithTitle: @"Hide Emacs"
4249                           action: @selector (hide:)
4250                    keyEquivalent: @"h"
4251                          atIndex: 6];
4252     item =  [appMenu insertItemWithTitle: @"Hide Others"
4253                           action: @selector (hideOtherApplications:)
4254                    keyEquivalent: @"h"
4255                          atIndex: 7];
4256     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4257     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4258     [appMenu insertItemWithTitle: @"Quit Emacs"
4259                           action: @selector (terminate:)
4260                    keyEquivalent: @"q"
4261                          atIndex: 9];
4263     item = [mainMenu insertItemWithTitle: ns_app_name
4264                                   action: @selector (menuDown:)
4265                            keyEquivalent: @""
4266                                  atIndex: 0];
4267     [mainMenu setSubmenu: appMenu forItem: item];
4268     [dockMenu insertItemWithTitle: @"New Frame"
4269                            action: @selector (newFrame:)
4270                     keyEquivalent: @""
4271                           atIndex: 0];
4273     [NSApp setMainMenu: mainMenu];
4274     [NSApp setAppleMenu: appMenu];
4275     [NSApp setServicesMenu: svcsMenu];
4276     /* Needed at least on Cocoa, to get dock menu to show windows */
4277     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4279     [[NSNotificationCenter defaultCenter]
4280       addObserver: mainMenu
4281          selector: @selector (trackingNotification:)
4282              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4283     [[NSNotificationCenter defaultCenter]
4284       addObserver: mainMenu
4285          selector: @selector (trackingNotification:)
4286              name: NSMenuDidEndTrackingNotification object: mainMenu];
4287   }
4288 #endif /* MAC OS X menu setup */
4290   /* Register our external input/output types, used for determining
4291      applicable services and also drag/drop eligibility. */
4292   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4293   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4294                       retain];
4295   ns_drag_types = [[NSArray arrayWithObjects:
4296                             NSStringPboardType,
4297                             NSTabularTextPboardType,
4298                             NSFilenamesPboardType,
4299                             NSURLPboardType,
4300                             NSColorPboardType,
4301                             NSFontPboardType, nil] retain];
4303   /* If fullscreen is in init/default-frame-alist, focus isn't set
4304      right for fullscreen windows, so set this.  */
4305   [NSApp activateIgnoringOtherApps:YES];
4307   [NSApp run];
4308   ns_do_open_file = YES;
4310 #ifdef NS_IMPL_GNUSTEP
4311   /* GNUstep steals SIGCHLD for use in NSTask, but we don't use NSTask.
4312      We must re-catch it so subprocess works.  */
4313   catch_child_signal ();
4314 #endif
4315   return dpyinfo;
4319 void
4320 ns_term_shutdown (int sig)
4322   [[NSUserDefaults standardUserDefaults] synchronize];
4324   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4325   if (STRINGP (Vauto_save_list_file_name))
4326     unlink (SSDATA (Vauto_save_list_file_name));
4328   if (sig == 0 || sig == SIGTERM)
4329     {
4330       [NSApp terminate: NSApp];
4331     }
4332   else // force a stack trace to happen
4333     {
4334       emacs_abort ();
4335     }
4339 /* ==========================================================================
4341     EmacsApp implementation
4343    ========================================================================== */
4346 @implementation EmacsApp
4348 - (void)logNotification: (NSNotification *)notification
4350   const char *name = [[notification name] UTF8String];
4351   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4352       && !strstr (name, "WindowNumber"))
4353     NSLog (@"notification: '%@'", [notification name]);
4357 - (void)sendEvent: (NSEvent *)theEvent
4358 /* --------------------------------------------------------------------------
4359      Called when NSApp is running for each event received.  Used to stop
4360      the loop when we choose, since there's no way to just run one iteration.
4361    -------------------------------------------------------------------------- */
4363   int type = [theEvent type];
4364   NSWindow *window = [theEvent window];
4366 /*  NSTRACE (sendEvent); */
4367 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4369 #ifdef NS_IMPL_GNUSTEP
4370   // Keyboard events aren't propagated to file dialogs for some reason.
4371   if ([NSApp modalWindow] != nil &&
4372       (type == NSKeyDown || type == NSKeyUp || type == NSFlagsChanged))
4373     {
4374       [[NSApp modalWindow] sendEvent: theEvent];
4375       return;
4376     }
4377 #endif
4379   if (type == NSApplicationDefined)
4380     {
4381       switch ([theEvent data2])
4382         {
4383 #ifdef NS_IMPL_COCOA
4384         case NSAPP_DATA2_RUNASSCRIPT:
4385           ns_run_ascript ();
4386           [self stop: self];
4387           return;
4388 #endif
4389         case NSAPP_DATA2_RUNFILEDIALOG:
4390           ns_run_file_dialog ();
4391           [self stop: self];
4392           return;
4393         }
4394     }
4396   if (type == NSCursorUpdate && window == nil)
4397     {
4398       fprintf (stderr, "Dropping external cursor update event.\n");
4399       return;
4400     }
4402   if (type == NSApplicationDefined)
4403     {
4404       /* Events posted by ns_send_appdefined interrupt the run loop here.
4405          But, if a modal window is up, an appdefined can still come through,
4406          (e.g., from a makeKeyWindow event) but stopping self also stops the
4407          modal loop. Just defer it until later. */
4408       if ([NSApp modalWindow] == nil)
4409         {
4410           last_appdefined_event_data = [theEvent data1];
4411           [self stop: self];
4412         }
4413       else
4414         {
4415           send_appdefined = YES;
4416         }
4417     }
4420 #ifdef NS_IMPL_COCOA
4421   /* If no dialog and none of our frames have focus and it is a move, skip it.
4422      It is a mouse move in an auxiliary menu, i.e. on the top right on OSX,
4423      such as Wifi, sound, date or similar.
4424      This prevents "spooky" highlighting in the frame under the menu.  */
4425   if (type == NSMouseMoved && [NSApp modalWindow] == nil)
4426     {
4427       struct ns_display_info *di;
4428       BOOL has_focus = NO;
4429       for (di = x_display_list; ! has_focus && di; di = di->next)
4430         has_focus = di->x_focus_frame != 0;
4431       if (! has_focus)
4432         return;
4433     }
4434 #endif
4436   [super sendEvent: theEvent];
4440 - (void)showPreferencesWindow: (id)sender
4442   struct frame *emacsframe = SELECTED_FRAME ();
4443   NSEvent *theEvent = [NSApp currentEvent];
4445   if (!emacs_event)
4446     return;
4447   emacs_event->kind = NS_NONKEY_EVENT;
4448   emacs_event->code = KEY_NS_SHOW_PREFS;
4449   emacs_event->modifiers = 0;
4450   EV_TRAILER (theEvent);
4454 - (void)newFrame: (id)sender
4456   struct frame *emacsframe = SELECTED_FRAME ();
4457   NSEvent *theEvent = [NSApp currentEvent];
4459   if (!emacs_event)
4460     return;
4461   emacs_event->kind = NS_NONKEY_EVENT;
4462   emacs_event->code = KEY_NS_NEW_FRAME;
4463   emacs_event->modifiers = 0;
4464   EV_TRAILER (theEvent);
4468 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4469 - (BOOL) openFile: (NSString *)fileName
4471   struct frame *emacsframe = SELECTED_FRAME ();
4472   NSEvent *theEvent = [NSApp currentEvent];
4474   if (!emacs_event)
4475     return NO;
4477   emacs_event->kind = NS_NONKEY_EVENT;
4478   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4479   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4480   ns_input_line = Qnil; /* can be start or cons start,end */
4481   emacs_event->modifiers =0;
4482   EV_TRAILER (theEvent);
4484   return YES;
4488 /* **************************************************************************
4490       EmacsApp delegate implementation
4492    ************************************************************************** */
4494 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4495 /* --------------------------------------------------------------------------
4496      When application is loaded, terminate event loop in ns_term_init
4497    -------------------------------------------------------------------------- */
4499   NSTRACE (applicationDidFinishLaunching);
4500   [NSApp setServicesProvider: NSApp];
4501   ns_send_appdefined (-2);
4505 /* Termination sequences:
4506     C-x C-c:
4507     Cmd-Q:
4508     MenuBar | File | Exit:
4509     Select Quit from App menubar:
4510         -terminate
4511         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4512         ns_term_shutdown()
4514     Select Quit from Dock menu:
4515     Logout attempt:
4516         -appShouldTerminate
4517           Cancel -> Nothing else
4518           Accept ->
4520           -terminate
4521           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4522           ns_term_shutdown()
4526 - (void) terminate: (id)sender
4528   struct frame *emacsframe = SELECTED_FRAME ();
4530   if (!emacs_event)
4531     return;
4533   emacs_event->kind = NS_NONKEY_EVENT;
4534   emacs_event->code = KEY_NS_POWER_OFF;
4535   emacs_event->arg = Qt; /* mark as non-key event */
4536   EV_TRAILER ((id)nil);
4540 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4542   int ret;
4544   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4545     return NSTerminateNow;
4547     ret = NSRunAlertPanel(ns_app_name,
4548                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4549                           @"Save Buffers and Exit", @"Cancel", nil);
4551     if (ret == NSAlertDefaultReturn)
4552         return NSTerminateNow;
4553     else if (ret == NSAlertAlternateReturn)
4554         return NSTerminateCancel;
4555     return NSTerminateNow;  /* just in case */
4558 static int
4559 not_in_argv (NSString *arg)
4561   int k;
4562   const char *a = [arg UTF8String];
4563   for (k = 1; k < initial_argc; ++k)
4564     if (strcmp (a, initial_argv[k]) == 0) return 0;
4565   return 1;
4568 /*   Notification from the Workspace to open a file */
4569 - (BOOL)application: sender openFile: (NSString *)file
4571   if (ns_do_open_file || not_in_argv (file))
4572     [ns_pending_files addObject: file];
4573   return YES;
4577 /*   Open a file as a temporary file */
4578 - (BOOL)application: sender openTempFile: (NSString *)file
4580   if (ns_do_open_file || not_in_argv (file))
4581     [ns_pending_files addObject: file];
4582   return YES;
4586 /*   Notification from the Workspace to open a file noninteractively (?) */
4587 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4589   if (ns_do_open_file || not_in_argv (file))
4590     [ns_pending_files addObject: file];
4591   return YES;
4594 /*   Notification from the Workspace to open multiple files */
4595 - (void)application: sender openFiles: (NSArray *)fileList
4597   NSEnumerator *files = [fileList objectEnumerator];
4598   NSString *file;
4599   /* Don't open files from the command line unconditionally,
4600      Cocoa parses the command line wrong, --option value tries to open value
4601      if --option is the last option.  */
4602   while ((file = [files nextObject]) != nil)
4603     if (ns_do_open_file || not_in_argv (file))
4604       [ns_pending_files addObject: file];
4606   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4611 /* Handle dock menu requests.  */
4612 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4614   return dockMenu;
4618 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4619 - (void)applicationWillBecomeActive: (NSNotification *)notification
4621   //ns_app_active=YES;
4623 - (void)applicationDidBecomeActive: (NSNotification *)notification
4625   NSTRACE (applicationDidBecomeActive);
4627   //ns_app_active=YES;
4629   ns_update_auto_hide_menu_bar ();
4630   // No constraining takes place when the application is not active.
4631   ns_constrain_all_frames ();
4633 - (void)applicationDidResignActive: (NSNotification *)notification
4635   //ns_app_active=NO;
4636   ns_send_appdefined (-1);
4641 /* ==========================================================================
4643     EmacsApp aux handlers for managing event loop
4645    ========================================================================== */
4648 - (void)timeout_handler: (NSTimer *)timedEntry
4649 /* --------------------------------------------------------------------------
4650      The timeout specified to ns_select has passed.
4651    -------------------------------------------------------------------------- */
4653   /*NSTRACE (timeout_handler); */
4654   ns_send_appdefined (-2);
4657 #ifdef NS_IMPL_GNUSTEP
4658 - (void)sendFromMainThread:(id)unused
4660   ns_send_appdefined (nextappdefined);
4662 #endif
4664 - (void)fd_handler:(id)unused
4665 /* --------------------------------------------------------------------------
4666      Check data waiting on file descriptors and terminate if so
4667    -------------------------------------------------------------------------- */
4669   int result;
4670   int waiting = 1, nfds;
4671   char c;
4673   fd_set readfds, writefds, *wfds;
4674   struct timespec timeout, *tmo;
4675   NSAutoreleasePool *pool = nil;
4677   /* NSTRACE (fd_handler); */
4679   for (;;)
4680     {
4681       [pool release];
4682       pool = [[NSAutoreleasePool alloc] init];
4684       if (waiting)
4685         {
4686           fd_set fds;
4687           FD_ZERO (&fds);
4688           FD_SET (selfds[0], &fds);
4689           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4690           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4691             waiting = 0;
4692         }
4693       else
4694         {
4695           pthread_mutex_lock (&select_mutex);
4696           nfds = select_nfds;
4698           if (select_valid & SELECT_HAVE_READ)
4699             readfds = select_readfds;
4700           else
4701             FD_ZERO (&readfds);
4703           if (select_valid & SELECT_HAVE_WRITE)
4704             {
4705               writefds = select_writefds;
4706               wfds = &writefds;
4707             }
4708           else
4709             wfds = NULL;
4710           if (select_valid & SELECT_HAVE_TMO)
4711             {
4712               timeout = select_timeout;
4713               tmo = &timeout;
4714             }
4715           else
4716             tmo = NULL;
4718           pthread_mutex_unlock (&select_mutex);
4720           FD_SET (selfds[0], &readfds);
4721           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4723           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4725           if (result == 0)
4726             ns_send_appdefined (-2);
4727           else if (result > 0)
4728             {
4729               if (FD_ISSET (selfds[0], &readfds))
4730                 {
4731                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4732                     waiting = 1;
4733                 }
4734               else
4735                 {
4736                   pthread_mutex_lock (&select_mutex);
4737                   if (select_valid & SELECT_HAVE_READ)
4738                     select_readfds = readfds;
4739                   if (select_valid & SELECT_HAVE_WRITE)
4740                     select_writefds = writefds;
4741                   if (select_valid & SELECT_HAVE_TMO)
4742                     select_timeout = timeout;
4743                   pthread_mutex_unlock (&select_mutex);
4745                   ns_send_appdefined (result);
4746                 }
4747             }
4748           waiting = 1;
4749         }
4750     }
4755 /* ==========================================================================
4757     Service provision
4759    ========================================================================== */
4761 /* called from system: queue for next pass through event loop */
4762 - (void)requestService: (NSPasteboard *)pboard
4763               userData: (NSString *)userData
4764                  error: (NSString **)error
4766   [ns_pending_service_names addObject: userData];
4767   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4768       SSDATA (ns_string_from_pasteboard (pboard))]];
4772 /* called from ns_read_socket to clear queue */
4773 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4775   struct frame *emacsframe = SELECTED_FRAME ();
4776   NSEvent *theEvent = [NSApp currentEvent];
4778   if (!emacs_event)
4779     return NO;
4781   emacs_event->kind = NS_NONKEY_EVENT;
4782   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4783   ns_input_spi_name = build_string ([name UTF8String]);
4784   ns_input_spi_arg = build_string ([arg UTF8String]);
4785   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4786   EV_TRAILER (theEvent);
4788   return YES;
4792 @end  /* EmacsApp */
4796 /* ==========================================================================
4798     EmacsView implementation
4800    ========================================================================== */
4803 @implementation EmacsView
4805 /* needed to inform when window closed from LISP */
4806 - (void) setWindowClosing: (BOOL)closing
4808   windowClosing = closing;
4812 - (void)dealloc
4814   NSTRACE (EmacsView_dealloc);
4815   [toolbar release];
4816   if (fs_state == FULLSCREEN_BOTH)
4817     [nonfs_window release];
4818   [super dealloc];
4822 /* called on font panel selection */
4823 - (void)changeFont: (id)sender
4825   NSEvent *e =[[self window] currentEvent];
4826   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4827   id newFont;
4828   CGFloat size;
4830   NSTRACE (changeFont);
4831   if (!emacs_event)
4832     return;
4834   if ((newFont = [sender convertFont:
4835                            ((struct nsfont_info *)face->font)->nsfont]))
4836     {
4837       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4839       emacs_event->kind = NS_NONKEY_EVENT;
4840       emacs_event->modifiers = 0;
4841       emacs_event->code = KEY_NS_CHANGE_FONT;
4843       size = [newFont pointSize];
4844       ns_input_fontsize = make_number (lrint (size));
4845       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4846       EV_TRAILER (e);
4847     }
4851 - (BOOL)acceptsFirstResponder
4853   NSTRACE (acceptsFirstResponder);
4854   return YES;
4858 - (void)resetCursorRects
4860   NSRect visible = [self visibleRect];
4861   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4862   NSTRACE (resetCursorRects);
4864   if (currentCursor == nil)
4865     currentCursor = [NSCursor arrowCursor];
4867   if (!NSIsEmptyRect (visible))
4868     [self addCursorRect: visible cursor: currentCursor];
4869   [currentCursor setOnMouseEntered: YES];
4874 /*****************************************************************************/
4875 /* Keyboard handling. */
4876 #define NS_KEYLOG 0
4878 - (void)keyDown: (NSEvent *)theEvent
4880   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4881   int code;
4882   unsigned fnKeysym = 0;
4883   static NSMutableArray *nsEvArray;
4884 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4885   static BOOL firstTime = YES;
4886 #endif
4887   int left_is_none;
4888   unsigned int flags = [theEvent modifierFlags];
4890   NSTRACE (keyDown);
4892   /* Rhapsody and OS X give up and down events for the arrow keys */
4893   if (ns_fake_keydown == YES)
4894     ns_fake_keydown = NO;
4895   else if ([theEvent type] != NSKeyDown)
4896     return;
4898   if (!emacs_event)
4899     return;
4901  if (![[self window] isKeyWindow]
4902      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4903      /* we must avoid an infinite loop here. */
4904      && (EmacsView *)[[theEvent window] delegate] != self)
4905    {
4906      /* XXX: There is an occasional condition in which, when Emacs display
4907          updates a different frame from the current one, and temporarily
4908          selects it, then processes some interrupt-driven input
4909          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4910          for some reason that window has its first responder set to the NSView
4911          most recently updated (I guess), which is not the correct one. */
4912      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4913      return;
4914    }
4916   if (nsEvArray == nil)
4917     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4919   [NSCursor setHiddenUntilMouseMoves: YES];
4921   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4922     {
4923       clear_mouse_face (hlinfo);
4924       hlinfo->mouse_face_hidden = 1;
4925     }
4927   if (!processingCompose)
4928     {
4929       /* When using screen sharing, no left or right information is sent,
4930          so use Left key in those cases.  */
4931       int is_left_key, is_right_key;
4933       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4934         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4936       /* (Carbon way: [theEvent keyCode]) */
4938       /* is it a "function key"? */
4939       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4940         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4941         : ns_convert_key (code);
4943       if (fnKeysym)
4944         {
4945           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4946              because Emacs treats Delete and KP-Delete same (in simple.el). */
4947           if ((fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4948 #ifdef NS_IMPL_GNUSTEP
4949               /*  GNUstep uses incompatible keycodes, even for those that are
4950                   supposed to be hardware independent.  Just check for delete.
4951                   Keypad delete does not have keysym 0xFFFF.
4952                   See http://savannah.gnu.org/bugs/?25395
4953               */
4954               || (fnKeysym == 0xFFFF && code == 127)
4955 #endif
4956             )
4957             code = 0xFF08; /* backspace */
4958           else
4959             code = fnKeysym;
4960         }
4962       /* are there modifiers? */
4963       emacs_event->modifiers = 0;
4965       if (flags & NSHelpKeyMask)
4966           emacs_event->modifiers |= hyper_modifier;
4968       if (flags & NSShiftKeyMask)
4969         emacs_event->modifiers |= shift_modifier;
4971       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4972       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4973         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4975       if (is_right_key)
4976         emacs_event->modifiers |= parse_solitary_modifier
4977           (EQ (ns_right_command_modifier, Qleft)
4978            ? ns_command_modifier
4979            : ns_right_command_modifier);
4981       if (is_left_key)
4982         {
4983           emacs_event->modifiers |= parse_solitary_modifier
4984             (ns_command_modifier);
4986           /* if super (default), take input manager's word so things like
4987              dvorak / qwerty layout work */
4988           if (EQ (ns_command_modifier, Qsuper)
4989               && !fnKeysym
4990               && [[theEvent characters] length] != 0)
4991             {
4992               /* XXX: the code we get will be unshifted, so if we have
4993                  a shift modifier, must convert ourselves */
4994               if (!(flags & NSShiftKeyMask))
4995                 code = [[theEvent characters] characterAtIndex: 0];
4996 #if 0
4997               /* this is ugly and also requires linking w/Carbon framework
4998                  (for LMGetKbdType) so for now leave this rare (?) case
4999                  undealt with.. in future look into CGEvent methods */
5000               else
5001                 {
5002                   long smv = GetScriptManagerVariable (smKeyScript);
5003                   Handle uchrHandle = GetResource
5004                     ('uchr', GetScriptVariable (smv, smScriptKeys));
5005                   UInt32 dummy = 0;
5006                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
5007                                  [[theEvent characters] characterAtIndex: 0],
5008                                  kUCKeyActionDisplay,
5009                                  (flags & ~NSCommandKeyMask) >> 8,
5010                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
5011                                  &dummy, 1, &dummy, &code);
5012                   code &= 0xFF;
5013                 }
5014 #endif
5015             }
5016         }
5018       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
5019       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
5020         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
5022       if (is_right_key)
5023           emacs_event->modifiers |= parse_solitary_modifier
5024               (EQ (ns_right_control_modifier, Qleft)
5025                ? ns_control_modifier
5026                : ns_right_control_modifier);
5028       if (is_left_key)
5029         emacs_event->modifiers |= parse_solitary_modifier
5030           (ns_control_modifier);
5032       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
5033           emacs_event->modifiers |=
5034             parse_solitary_modifier (ns_function_modifier);
5036       left_is_none = NILP (ns_alternate_modifier)
5037         || EQ (ns_alternate_modifier, Qnone);
5039       is_right_key = (flags & NSRightAlternateKeyMask)
5040         == NSRightAlternateKeyMask;
5041       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
5042         || (! is_right_key
5043             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
5045       if (is_right_key)
5046         {
5047           if ((NILP (ns_right_alternate_modifier)
5048                || EQ (ns_right_alternate_modifier, Qnone)
5049                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
5050               && !fnKeysym)
5051             {   /* accept pre-interp alt comb */
5052               if ([[theEvent characters] length] > 0)
5053                 code = [[theEvent characters] characterAtIndex: 0];
5054               /*HACK: clear lone shift modifier to stop next if from firing */
5055               if (emacs_event->modifiers == shift_modifier)
5056                 emacs_event->modifiers = 0;
5057             }
5058           else
5059             emacs_event->modifiers |= parse_solitary_modifier
5060               (EQ (ns_right_alternate_modifier, Qleft)
5061                ? ns_alternate_modifier
5062                : ns_right_alternate_modifier);
5063         }
5065       if (is_left_key) /* default = meta */
5066         {
5067           if (left_is_none && !fnKeysym)
5068             {   /* accept pre-interp alt comb */
5069               if ([[theEvent characters] length] > 0)
5070                 code = [[theEvent characters] characterAtIndex: 0];
5071               /*HACK: clear lone shift modifier to stop next if from firing */
5072               if (emacs_event->modifiers == shift_modifier)
5073                 emacs_event->modifiers = 0;
5074             }
5075           else
5076               emacs_event->modifiers |=
5077                 parse_solitary_modifier (ns_alternate_modifier);
5078         }
5080   if (NS_KEYLOG)
5081     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
5082              code, fnKeysym, flags, emacs_event->modifiers);
5084       /* if it was a function key or had modifiers, pass it directly to emacs */
5085       if (fnKeysym || (emacs_event->modifiers
5086                        && (emacs_event->modifiers != shift_modifier)
5087                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5088 /*[[theEvent characters] length] */
5089         {
5090           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5091           if (code < 0x20)
5092             code |= (1<<28)|(3<<16);
5093           else if (code == 0x7f)
5094             code |= (1<<28)|(3<<16);
5095           else if (!fnKeysym)
5096             emacs_event->kind = code > 0xFF
5097               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5099           emacs_event->code = code;
5100           EV_TRAILER (theEvent);
5101           processingCompose = NO;
5102           return;
5103         }
5104     }
5107 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5108   /* if we get here we should send the key for input manager processing */
5109   /* Disable warning, there is nothing a user can do about it anyway, and
5110      it does not seem to matter.  */
5111 #if 0
5112   if (firstTime && [[NSInputManager currentInputManager]
5113                      wantsToDelayTextChangeNotifications] == NO)
5114     fprintf (stderr,
5115           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5116 #endif
5117   firstTime = NO;
5118 #endif
5119   if (NS_KEYLOG && !processingCompose)
5120     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5122   processingCompose = YES;
5123   [nsEvArray addObject: theEvent];
5124   [self interpretKeyEvents: nsEvArray];
5125   [nsEvArray removeObject: theEvent];
5129 #ifdef NS_IMPL_COCOA
5130 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5131    decided not to send key-down for.
5132    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5133    This only applies on Tiger and earlier.
5134    If it matches one of these, send it on to keyDown. */
5135 -(void)keyUp: (NSEvent *)theEvent
5137   int flags = [theEvent modifierFlags];
5138   int code = [theEvent keyCode];
5139   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5140       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5141     {
5142       if (NS_KEYLOG)
5143         fprintf (stderr, "keyUp: passed test");
5144       ns_fake_keydown = YES;
5145       [self keyDown: theEvent];
5146     }
5148 #endif
5151 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5154 /* <NSTextInput>: called when done composing;
5155    NOTE: also called when we delete over working text, followed immed.
5156          by doCommandBySelector: deleteBackward: */
5157 - (void)insertText: (id)aString
5159   int code;
5160   int len = [(NSString *)aString length];
5161   int i;
5163   if (NS_KEYLOG)
5164     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5165   processingCompose = NO;
5167   if (!emacs_event)
5168     return;
5170   /* first, clear any working text */
5171   if (workingText != nil)
5172     [self deleteWorkingText];
5174   /* now insert the string as keystrokes */
5175   for (i =0; i<len; i++)
5176     {
5177       code = [aString characterAtIndex: i];
5178       /* TODO: still need this? */
5179       if (code == 0x2DC)
5180         code = '~'; /* 0x7E */
5181       if (code != 32) /* Space */
5182         emacs_event->modifiers = 0;
5183       emacs_event->kind
5184         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5185       emacs_event->code = code;
5186       EV_TRAILER ((id)nil);
5187     }
5191 /* <NSTextInput>: inserts display of composing characters */
5192 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5194   NSString *str = [aString respondsToSelector: @selector (string)] ?
5195     [aString string] : aString;
5196   if (NS_KEYLOG)
5197     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5198            selRange.length, selRange.location);
5200   if (workingText != nil)
5201     [self deleteWorkingText];
5202   if ([str length] == 0)
5203     return;
5205   if (!emacs_event)
5206     return;
5208   processingCompose = YES;
5209   workingText = [str copy];
5210   ns_working_text = build_string ([workingText UTF8String]);
5212   emacs_event->kind = NS_TEXT_EVENT;
5213   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5214   EV_TRAILER ((id)nil);
5218 /* delete display of composing characters [not in <NSTextInput>] */
5219 - (void)deleteWorkingText
5221   if (workingText == nil)
5222     return;
5223   if (NS_KEYLOG)
5224     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5225   [workingText release];
5226   workingText = nil;
5227   processingCompose = NO;
5229   if (!emacs_event)
5230     return;
5232   emacs_event->kind = NS_TEXT_EVENT;
5233   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5234   EV_TRAILER ((id)nil);
5238 - (BOOL)hasMarkedText
5240   return workingText != nil;
5244 - (NSRange)markedRange
5246   NSRange rng = workingText != nil
5247     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5248   if (NS_KEYLOG)
5249     NSLog (@"markedRange request");
5250   return rng;
5254 - (void)unmarkText
5256   if (NS_KEYLOG)
5257     NSLog (@"unmark (accept) text");
5258   [self deleteWorkingText];
5259   processingCompose = NO;
5263 /* used to position char selection windows, etc. */
5264 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5266   NSRect rect;
5267   NSPoint pt;
5268   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5269   if (NS_KEYLOG)
5270     NSLog (@"firstRectForCharRange request");
5272   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5273   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5274   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5275   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5276                                        +FRAME_LINE_HEIGHT (emacsframe));
5278   pt = [self convertPoint: pt toView: nil];
5279   pt = [[self window] convertBaseToScreen: pt];
5280   rect.origin = pt;
5281   return rect;
5285 - (NSInteger)conversationIdentifier
5287   return (NSInteger)self;
5291 - (void)doCommandBySelector: (SEL)aSelector
5293   if (NS_KEYLOG)
5294     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5296   processingCompose = NO;
5297   if (aSelector == @selector (deleteBackward:))
5298     {
5299       /* happens when user backspaces over an ongoing composition:
5300          throw a 'delete' into the event queue */
5301       if (!emacs_event)
5302         return;
5303       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5304       emacs_event->code = 0xFF08;
5305       EV_TRAILER ((id)nil);
5306     }
5309 - (NSArray *)validAttributesForMarkedText
5311   static NSArray *arr = nil;
5312   if (arr == nil) arr = [NSArray new];
5313  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5314   return arr;
5317 - (NSRange)selectedRange
5319   if (NS_KEYLOG)
5320     NSLog (@"selectedRange request");
5321   return NSMakeRange (NSNotFound, 0);
5324 #if defined (NS_IMPL_COCOA) || GNUSTEP_GUI_MAJOR_VERSION > 0 || \
5325     GNUSTEP_GUI_MINOR_VERSION > 22
5326 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5327 #else
5328 - (unsigned int)characterIndexForPoint: (NSPoint)thePoint
5329 #endif
5331   if (NS_KEYLOG)
5332     NSLog (@"characterIndexForPoint request");
5333   return 0;
5336 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5338   static NSAttributedString *str = nil;
5339   if (str == nil) str = [NSAttributedString new];
5340   if (NS_KEYLOG)
5341     NSLog (@"attributedSubstringFromRange request");
5342   return str;
5345 /* End <NSTextInput> impl. */
5346 /*****************************************************************************/
5349 /* This is what happens when the user presses a mouse button.  */
5350 - (void)mouseDown: (NSEvent *)theEvent
5352   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5354   NSTRACE (mouseDown);
5356   [self deleteWorkingText];
5358   if (!emacs_event)
5359     return;
5361   last_mouse_frame = emacsframe;
5362   /* appears to be needed to prevent spurious movement events generated on
5363      button clicks */
5364   last_mouse_frame->mouse_moved = 0;
5366   if ([theEvent type] == NSScrollWheel)
5367     {
5368       CGFloat delta = [theEvent deltaY];
5369       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5370       if (delta == 0)
5371         return;
5372       emacs_event->kind = WHEEL_EVENT;
5373       emacs_event->code = 0;
5374       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5375         ((delta > 0) ? up_modifier : down_modifier);
5376     }
5377   else
5378     {
5379       emacs_event->kind = MOUSE_CLICK_EVENT;
5380       emacs_event->code = EV_BUTTON (theEvent);
5381       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5382                              | EV_UDMODIFIERS (theEvent);
5383     }
5384   XSETINT (emacs_event->x, lrint (p.x));
5385   XSETINT (emacs_event->y, lrint (p.y));
5386   EV_TRAILER (theEvent);
5390 - (void)rightMouseDown: (NSEvent *)theEvent
5392   NSTRACE (rightMouseDown);
5393   [self mouseDown: theEvent];
5397 - (void)otherMouseDown: (NSEvent *)theEvent
5399   NSTRACE (otherMouseDown);
5400   [self mouseDown: theEvent];
5404 - (void)mouseUp: (NSEvent *)theEvent
5406   NSTRACE (mouseUp);
5407   [self mouseDown: theEvent];
5411 - (void)rightMouseUp: (NSEvent *)theEvent
5413   NSTRACE (rightMouseUp);
5414   [self mouseDown: theEvent];
5418 - (void)otherMouseUp: (NSEvent *)theEvent
5420   NSTRACE (otherMouseUp);
5421   [self mouseDown: theEvent];
5425 - (void) scrollWheel: (NSEvent *)theEvent
5427   NSTRACE (scrollWheel);
5428   [self mouseDown: theEvent];
5432 /* Tell emacs the mouse has moved. */
5433 - (void)mouseMoved: (NSEvent *)e
5435   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5436   Lisp_Object frame;
5438 //  NSTRACE (mouseMoved);
5440   last_mouse_movement_time = EV_TIMESTAMP (e);
5441   last_mouse_motion_position
5442     = [self convertPoint: [e locationInWindow] fromView: nil];
5444   /* update any mouse face */
5445   if (hlinfo->mouse_face_hidden)
5446     {
5447       hlinfo->mouse_face_hidden = 0;
5448       clear_mouse_face (hlinfo);
5449     }
5451   /* tooltip handling */
5452   previous_help_echo_string = help_echo_string;
5453   help_echo_string = Qnil;
5455   if (!NILP (Vmouse_autoselect_window))
5456     {
5457       NSTRACE (mouse_autoselect_window);
5458       static Lisp_Object last_mouse_window;
5459       Lisp_Object window = window_from_coordinates
5460         (emacsframe, last_mouse_motion_position.x,
5461          last_mouse_motion_position.y, 0, 0);
5463       if (WINDOWP (window)
5464           && !EQ (window, last_mouse_window)
5465           && !EQ (window, selected_window)
5466           && (focus_follows_mouse
5467               || (EQ (XWINDOW (window)->frame,
5468                       XWINDOW (selected_window)->frame))))
5469         {
5470           NSTRACE (in_window);
5471           emacs_event->kind = SELECT_WINDOW_EVENT;
5472           emacs_event->frame_or_window = window;
5473           EV_TRAILER2 (e);
5474         }
5475       /* Remember the last window where we saw the mouse.  */
5476       last_mouse_window = window;
5477     }
5479   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5480                             last_mouse_motion_position.y))
5481     help_echo_string = previous_help_echo_string;
5483   XSETFRAME (frame, emacsframe);
5484   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5485     {
5486       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5487          (note_mouse_highlight), which is called through the
5488          note_mouse_movement () call above */
5489       gen_help_event (help_echo_string, frame, help_echo_window,
5490                       help_echo_object, help_echo_pos);
5491     }
5492   else
5493     {
5494       help_echo_string = Qnil;
5495       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5496     }
5498   if (emacsframe->mouse_moved && send_appdefined)
5499     ns_send_appdefined (-1);
5503 - (void)mouseDragged: (NSEvent *)e
5505   NSTRACE (mouseDragged);
5506   [self mouseMoved: e];
5510 - (void)rightMouseDragged: (NSEvent *)e
5512   NSTRACE (rightMouseDragged);
5513   [self mouseMoved: e];
5517 - (void)otherMouseDragged: (NSEvent *)e
5519   NSTRACE (otherMouseDragged);
5520   [self mouseMoved: e];
5524 - (BOOL)windowShouldClose: (id)sender
5526   NSEvent *e =[[self window] currentEvent];
5528   NSTRACE (windowShouldClose);
5529   windowClosing = YES;
5530   if (!emacs_event)
5531     return NO;
5532   emacs_event->kind = DELETE_WINDOW_EVENT;
5533   emacs_event->modifiers = 0;
5534   emacs_event->code = 0;
5535   EV_TRAILER (e);
5536   /* Don't close this window, let this be done from lisp code.  */
5537   return NO;
5540 - (void) updateFrameSize: (BOOL) delay;
5542   NSWindow *window = [self window];
5543   NSRect wr = [window frame];
5544   int extra = 0;
5545   int gsextra = 0;
5546 #ifdef NS_IMPL_GNUSTEP
5547   gsextra = 3;
5548 #endif
5550   int oldc = cols, oldr = rows;
5551   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5552     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5553   int neww, newh;
5555   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5557   if (cols < MINWIDTH)
5558     cols = MINWIDTH;
5560   if (! [self isFullscreen])
5561     {
5562       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5563         + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5564     }
5566   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5568   if (rows < MINHEIGHT)
5569     rows = MINHEIGHT;
5571   neww = (int)wr.size.width - emacsframe->border_width;
5572   newh = (int)wr.size.height - extra;
5574   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5575     {
5576       NSView *view = FRAME_NS_VIEW (emacsframe);
5577       NSWindow *win = [view window];
5578       NSSize sz = [win resizeIncrements];
5580       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5581       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5582       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5583       SET_FRAME_GARBAGED (emacsframe);
5584       cancel_mouse_face (emacsframe);
5586       // Did resize increments change because of a font change?
5587       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5588           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5589         {
5590           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5591           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5592           [win setResizeIncrements: sz];
5593         }
5595       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5596       [self windowDidMove:nil];   // Update top/left.
5597     }
5600 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5601 /* normalize frame to gridded text size */
5603   int extra = 0;
5604   int gsextra = 0;
5605 #ifdef NS_IMPL_GNUSTEP
5606   gsextra = 3;
5607 #endif
5609   NSTRACE (windowWillResize);
5610 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5612   if (fs_state == FULLSCREEN_MAXIMIZED
5613       && (maximized_width != (int)frameSize.width
5614           || maximized_height != (int)frameSize.height))
5615     [self setFSValue: FULLSCREEN_NONE];
5616   else if (fs_state == FULLSCREEN_WIDTH
5617            && maximized_width != (int)frameSize.width)
5618     [self setFSValue: FULLSCREEN_NONE];
5619   else if (fs_state == FULLSCREEN_HEIGHT
5620            && maximized_height != (int)frameSize.height)
5621     [self setFSValue: FULLSCREEN_NONE];
5622   if (fs_state == FULLSCREEN_NONE)
5623     maximized_width = maximized_height = -1;
5625   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5626                                          frameSize.width + gsextra);
5627   if (cols < MINWIDTH)
5628     cols = MINWIDTH;
5630   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5631                                            frameSize.height - extra);
5632   if (rows < MINHEIGHT)
5633     rows = MINHEIGHT;
5634 #ifdef NS_IMPL_COCOA
5635   {
5636     /* this sets window title to have size in it; the wm does this under GS */
5637     NSRect r = [[self window] frame];
5638     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5639       {
5640         if (old_title != 0)
5641           {
5642             xfree (old_title);
5643             old_title = 0;
5644           }
5645       }
5646     else if (fs_state == FULLSCREEN_NONE && ! maximizing_resize)
5647       {
5648         char *size_title;
5649         NSWindow *window = [self window];
5650         if (old_title == 0)
5651           {
5652             char *t = strdup ([[[self window] title] UTF8String]);
5653             char *pos = strstr (t, "  â€”  ");
5654             if (pos)
5655               *pos = '\0';
5656             old_title = t;
5657           }
5658         size_title = xmalloc (strlen (old_title) + 40);
5659         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5660         [window setTitle: [NSString stringWithUTF8String: size_title]];
5661         [window display];
5662         xfree (size_title);
5663       }
5664   }
5665 #endif /* NS_IMPL_COCOA */
5666 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5668   return frameSize;
5672 - (void)windowDidResize: (NSNotification *)notification
5674   if (! [self fsIsNative])
5675     {
5676       NSWindow *theWindow = [notification object];
5677       /* We can get notification on the non-FS window when in
5678          fullscreen mode.  */
5679       if ([self window] != theWindow) return;
5680     }
5682 #ifdef NS_IMPL_GNUSTEP
5683   NSWindow *theWindow = [notification object];
5685    /* In GNUstep, at least currently, it's possible to get a didResize
5686       without getting a willResize.. therefore we need to act as if we got
5687       the willResize now */
5688   NSSize sz = [theWindow frame].size;
5689   sz = [self windowWillResize: theWindow toSize: sz];
5690 #endif /* NS_IMPL_GNUSTEP */
5692   NSTRACE (windowDidResize);
5693 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5695 if (cols > 0 && rows > 0)
5696     {
5697       [self updateFrameSize: YES];
5698     }
5700   ns_send_appdefined (-1);
5703 #ifdef NS_IMPL_COCOA
5704 - (void)viewDidEndLiveResize
5706   [super viewDidEndLiveResize];
5707   if (old_title != 0)
5708     {
5709       [[self window] setTitle: [NSString stringWithUTF8String: old_title]];
5710       xfree (old_title);
5711       old_title = 0;
5712     }
5713   maximizing_resize = NO;
5715 #endif /* NS_IMPL_COCOA */
5718 - (void)windowDidBecomeKey: (NSNotification *)notification
5719 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5721   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5722   struct frame *old_focus = dpyinfo->x_focus_frame;
5724   NSTRACE (windowDidBecomeKey);
5726   if (emacsframe != old_focus)
5727     dpyinfo->x_focus_frame = emacsframe;
5729   ns_frame_rehighlight (emacsframe);
5731   if (emacs_event)
5732     {
5733       emacs_event->kind = FOCUS_IN_EVENT;
5734       EV_TRAILER ((id)nil);
5735     }
5739 - (void)windowDidResignKey: (NSNotification *)notification
5740 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5742   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5743   BOOL is_focus_frame = dpyinfo->x_focus_frame == emacsframe;
5744   NSTRACE (windowDidResignKey);
5746   if (is_focus_frame)
5747     dpyinfo->x_focus_frame = 0;
5749   ns_frame_rehighlight (emacsframe);
5751   /* FIXME: for some reason needed on second and subsequent clicks away
5752             from sole-frame Emacs to get hollow box to show */
5753   if (!windowClosing && [[self window] isVisible] == YES)
5754     {
5755       x_update_cursor (emacsframe, 1);
5756       x_set_frame_alpha (emacsframe);
5757     }
5759   if (emacs_event && is_focus_frame)
5760     {
5761       [self deleteWorkingText];
5762       emacs_event->kind = FOCUS_OUT_EVENT;
5763       EV_TRAILER ((id)nil);
5764     }
5768 - (void)windowWillMiniaturize: sender
5770   NSTRACE (windowWillMiniaturize);
5774 - (BOOL)isFlipped
5776   return YES;
5780 - (BOOL)isOpaque
5782   return NO;
5786 - initFrameFromEmacs: (struct frame *)f
5788   NSRect r, wr;
5789   Lisp_Object tem;
5790   NSWindow *win;
5791   NSSize sz;
5792   NSColor *col;
5793   NSString *name;
5795   NSTRACE (initFrameFromEmacs);
5797   windowClosing = NO;
5798   processingCompose = NO;
5799   scrollbarsNeedingUpdate = 0;
5800   fs_state = FULLSCREEN_NONE;
5801   fs_before_fs = next_maximized = -1;
5802 #ifdef HAVE_NATIVE_FS
5803   fs_is_native = ns_use_native_fullscreen;
5804 #else
5805   fs_is_native = NO;
5806 #endif
5807   maximized_width = maximized_height = -1;
5808   nonfs_window = nil;
5810 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5812   ns_userRect = NSMakeRect (0, 0, 0, 0);
5813   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5814                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5815   [self initWithFrame: r];
5816   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5818   FRAME_NS_VIEW (f) = self;
5819   emacsframe = f;
5820 #ifdef NS_IMPL_COCOA
5821   old_title = 0;
5822   maximizing_resize = NO;
5823 #endif
5825   win = [[EmacsWindow alloc]
5826             initWithContentRect: r
5827                       styleMask: (NSResizableWindowMask |
5828 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5829                                   NSTitledWindowMask |
5830 #endif
5831                                   NSMiniaturizableWindowMask |
5832                                   NSClosableWindowMask)
5833                         backing: NSBackingStoreBuffered
5834                           defer: YES];
5836 #ifdef HAVE_NATIVE_FS
5837     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5838 #endif
5840   wr = [win frame];
5841   bwidth = f->border_width = wr.size.width - r.size.width;
5842   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5844   [win setAcceptsMouseMovedEvents: YES];
5845   [win setDelegate: self];
5846   [win useOptimizedDrawing: YES];
5848   sz.width = FRAME_COLUMN_WIDTH (f);
5849   sz.height = FRAME_LINE_HEIGHT (f);
5850   [win setResizeIncrements: sz];
5852   [[win contentView] addSubview: self];
5854   if (ns_drag_types)
5855     [self registerForDraggedTypes: ns_drag_types];
5857   tem = f->name;
5858   name = [NSString stringWithUTF8String:
5859                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5860   [win setTitle: name];
5862   /* toolbar support */
5863   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5864                          [NSString stringWithFormat: @"Emacs Frame %d",
5865                                    ns_window_num]];
5866   [win setToolbar: toolbar];
5867   [toolbar setVisible: NO];
5868 #ifdef NS_IMPL_COCOA
5869   {
5870     NSButton *toggleButton;
5871   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5872   [toggleButton setTarget: self];
5873   [toggleButton setAction: @selector (toggleToolbar: )];
5874   }
5875 #endif
5876   FRAME_TOOLBAR_HEIGHT (f) = 0;
5878   tem = f->icon_name;
5879   if (!NILP (tem))
5880     [win setMiniwindowTitle:
5881            [NSString stringWithUTF8String: SSDATA (tem)]];
5883   {
5884     NSScreen *screen = [win screen];
5886     if (screen != 0)
5887       [win setFrameTopLeftPoint: NSMakePoint
5888            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5889             IN_BOUND (-SCREENMAX,
5890                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5891   }
5893   [win makeFirstResponder: self];
5895   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5896                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5897   [win setBackgroundColor: col];
5898   if ([col alphaComponent] != (EmacsCGFloat) 1.0)
5899     [win setOpaque: NO];
5901   [self allocateGState];
5903   [NSApp registerServicesMenuSendTypes: ns_send_types
5904                            returnTypes: nil];
5906   ns_window_num++;
5907   return self;
5911 - (void)windowDidMove: sender
5913   NSWindow *win = [self window];
5914   NSRect r = [win frame];
5915   NSArray *screens = [NSScreen screens];
5916   NSScreen *screen = [screens objectAtIndex: 0];
5918   NSTRACE (windowDidMove);
5920   if (!emacsframe->output_data.ns)
5921     return;
5922   if (screen != nil)
5923     {
5924       emacsframe->left_pos = r.origin.x;
5925       emacsframe->top_pos =
5926         [screen frame].size.height - (r.origin.y + r.size.height);
5927     }
5931 /* Called AFTER method below, but before our windowWillResize call there leads
5932    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5933    location so set_window_size moves the frame. */
5934 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5936   emacsframe->output_data.ns->zooming = 1;
5937   return YES;
5941 /* Override to do something slightly nonstandard, but nice.  First click on
5942    zoom button will zoom vertically.  Second will zoom completely.  Third
5943    returns to original. */
5944 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5945                         defaultFrame:(NSRect)defaultFrame
5947   NSRect result = [sender frame];
5949   NSTRACE (windowWillUseStandardFrame);
5951   if (fs_before_fs != -1) /* Entering fullscreen */
5952       {
5953         result = defaultFrame;
5954       }
5955   else if (next_maximized == FULLSCREEN_HEIGHT
5956       || (next_maximized == -1
5957           && abs (defaultFrame.size.height - result.size.height)
5958           > FRAME_LINE_HEIGHT (emacsframe)))
5959     {
5960       /* first click */
5961       ns_userRect = result;
5962       maximized_height = result.size.height = defaultFrame.size.height;
5963       maximized_width = -1;
5964       result.origin.y = defaultFrame.origin.y;
5965       [self setFSValue: FULLSCREEN_HEIGHT];
5966 #ifdef NS_IMPL_COCOA
5967       maximizing_resize = YES;
5968 #endif
5969     }
5970   else if (next_maximized == FULLSCREEN_WIDTH)
5971     {
5972       ns_userRect = result;
5973       maximized_width = result.size.width = defaultFrame.size.width;
5974       maximized_height = -1;
5975       result.origin.x = defaultFrame.origin.x;
5976       [self setFSValue: FULLSCREEN_WIDTH];
5977     }
5978   else if (next_maximized == FULLSCREEN_MAXIMIZED
5979            || (next_maximized == -1
5980                && abs (defaultFrame.size.width - result.size.width)
5981                > FRAME_COLUMN_WIDTH (emacsframe)))
5982     {
5983       result = defaultFrame;  /* second click */
5984       maximized_width = result.size.width;
5985       maximized_height = result.size.height;
5986       [self setFSValue: FULLSCREEN_MAXIMIZED];
5987 #ifdef NS_IMPL_COCOA
5988       maximizing_resize = YES;
5989 #endif
5990     }
5991   else
5992     {
5993       /* restore */
5994       result = ns_userRect.size.height ? ns_userRect : result;
5995       ns_userRect = NSMakeRect (0, 0, 0, 0);
5996 #ifdef NS_IMPL_COCOA
5997       maximizing_resize = fs_state != FULLSCREEN_NONE;
5998 #endif
5999       [self setFSValue: FULLSCREEN_NONE];
6000       maximized_width = maximized_height = -1;
6001     }
6003   if (fs_before_fs == -1) next_maximized = -1;
6004   [self windowWillResize: sender toSize: result.size];
6005   return result;
6009 - (void)windowDidDeminiaturize: sender
6011   NSTRACE (windowDidDeminiaturize);
6012   if (!emacsframe->output_data.ns)
6013     return;
6015   SET_FRAME_ICONIFIED (emacsframe, 0);
6016   SET_FRAME_VISIBLE (emacsframe, 1);
6017   windows_or_buffers_changed++;
6019   if (emacs_event)
6020     {
6021       emacs_event->kind = DEICONIFY_EVENT;
6022       EV_TRAILER ((id)nil);
6023     }
6027 - (void)windowDidExpose: sender
6029   NSTRACE (windowDidExpose);
6030   if (!emacsframe->output_data.ns)
6031     return;
6033   SET_FRAME_VISIBLE (emacsframe, 1);
6034   SET_FRAME_GARBAGED (emacsframe);
6036   if (send_appdefined)
6037     ns_send_appdefined (-1);
6041 - (void)windowDidMiniaturize: sender
6043   NSTRACE (windowDidMiniaturize);
6044   if (!emacsframe->output_data.ns)
6045     return;
6047   SET_FRAME_ICONIFIED (emacsframe, 1);
6048   SET_FRAME_VISIBLE (emacsframe, 0);
6050   if (emacs_event)
6051     {
6052       emacs_event->kind = ICONIFY_EVENT;
6053       EV_TRAILER ((id)nil);
6054     }
6057 #ifdef HAVE_NATIVE_FS
6058 - (NSApplicationPresentationOptions)window:(NSWindow *)window
6059       willUseFullScreenPresentationOptions:
6060   (NSApplicationPresentationOptions)proposedOptions
6062   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
6064 #endif
6066 - (void)windowWillEnterFullScreen:(NSNotification *)notification
6068   fs_before_fs = fs_state;
6071 - (void)windowDidEnterFullScreen:(NSNotification *)notification
6073   [self setFSValue: FULLSCREEN_BOTH];
6074   if (! [self fsIsNative])
6075     {
6076       [self windowDidBecomeKey:notification];
6077       [nonfs_window orderOut:self];
6078     }
6079   else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6080     [toolbar setVisible:NO];
6083 - (void)windowWillExitFullScreen:(NSNotification *)notification
6085   if (next_maximized != -1)
6086     fs_before_fs = next_maximized;
6089 - (void)windowDidExitFullScreen:(NSNotification *)notification
6091   [self setFSValue: fs_before_fs];
6092   fs_before_fs = -1;
6093 #ifdef NS_IMPL_COCOA
6094   [self updateCollectionBehaviour];
6095 #endif
6096   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
6097     {
6098       [toolbar setVisible:YES];
6099       update_frame_tool_bar (emacsframe);
6100       [self updateFrameSize:YES];
6101       [[self window] display];
6102     }
6103   else
6104     [toolbar setVisible:NO];
6106   if (next_maximized != -1)
6107     [[self window] performZoom:self];
6110 - (BOOL)fsIsNative
6112   return fs_is_native;
6115 - (BOOL)isFullscreen
6117   if (! fs_is_native) return nonfs_window != nil;
6118 #ifdef HAVE_NATIVE_FS
6119   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
6120 #else
6121   return NO;
6122 #endif
6125 #ifdef HAVE_NATIVE_FS
6126 - (void)updateCollectionBehaviour
6128   if (! [self isFullscreen])
6129     {
6130       NSWindow *win = [self window];
6131       NSWindowCollectionBehavior b = [win collectionBehavior];
6132       if (ns_use_native_fullscreen)
6133         b |= NSWindowCollectionBehaviorFullScreenPrimary;
6134       else
6135         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
6137       [win setCollectionBehavior: b];
6138       fs_is_native = ns_use_native_fullscreen;
6139     }
6141 #endif
6143 - (void)toggleFullScreen: (id)sender
6145   NSWindow *w, *fw;
6146   BOOL onFirstScreen;
6147   struct frame *f;
6148   NSSize sz;
6149   NSRect r, wr;
6150   NSColor *col;
6152   if (fs_is_native)
6153     {
6154 #ifdef NS_IMPL_COCOA
6155       [[self window] toggleFullScreen:sender];
6156 #endif
6157       return;
6158     }
6160   w = [self window];
6161   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6162   f = emacsframe;
6163   wr = [w frame];
6164   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6165                                  (FRAME_DEFAULT_FACE (f)),
6166                                  f);
6168   sz.width = FRAME_COLUMN_WIDTH (f);
6169   sz.height = FRAME_LINE_HEIGHT (f);
6171   if (fs_state != FULLSCREEN_BOTH)
6172     {
6173       /* Hide dock and menubar if we are on the primary screen.  */
6174       if (onFirstScreen)
6175         {
6176 #if defined (NS_IMPL_COCOA) && \
6177   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6178           NSApplicationPresentationOptions options
6179             = NSApplicationPresentationAutoHideDock
6180             | NSApplicationPresentationAutoHideMenuBar;
6182           [NSApp setPresentationOptions: options];
6183 #else
6184           [NSMenu setMenuBarVisible:NO];
6185 #endif
6186         }
6188       fw = [[EmacsFSWindow alloc]
6189                        initWithContentRect:[w contentRectForFrameRect:wr]
6190                                  styleMask:NSBorderlessWindowMask
6191                                    backing:NSBackingStoreBuffered
6192                                      defer:YES
6193                                     screen:[w screen]];
6195       [fw setContentView:[w contentView]];
6196       [fw setTitle:[w title]];
6197       [fw setDelegate:self];
6198       [fw setAcceptsMouseMovedEvents: YES];
6199       [fw useOptimizedDrawing: YES];
6200       [fw setResizeIncrements: sz];
6201       [fw setBackgroundColor: col];
6202       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6203         [fw setOpaque: NO];
6205       f->border_width = 0;
6206       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6207       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6208       FRAME_TOOLBAR_HEIGHT (f) = 0;
6210       nonfs_window = w;
6212       [self windowWillEnterFullScreen:nil];
6213       [fw makeKeyAndOrderFront:NSApp];
6214       [fw makeFirstResponder:self];
6215       [w orderOut:self];
6216       r = [fw frameRectForContentRect:[[fw screen] frame]];
6217       [fw setFrame: r display:YES animate:YES];
6218       [self windowDidEnterFullScreen:nil];
6219       [fw display];
6220     }
6221   else
6222     {
6223       fw = w;
6224       w = nonfs_window;
6225       nonfs_window = nil;
6227       if (onFirstScreen)
6228         {
6229 #if defined (NS_IMPL_COCOA) && \
6230   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6231           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6232 #else
6233           [NSMenu setMenuBarVisible:YES];
6234 #endif
6235         }
6237       [w setContentView:[fw contentView]];
6238       [w setResizeIncrements: sz];
6239       [w setBackgroundColor: col];
6240       if ([col alphaComponent] != (EmacsCGFloat) 1.0)
6241         [w setOpaque: NO];
6243       f->border_width = bwidth;
6244       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6245       if (FRAME_EXTERNAL_TOOL_BAR (f))
6246         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6248       [self windowWillExitFullScreen:nil];
6249       [fw setFrame: [w frame] display:YES animate:YES];
6250       [fw close];
6251       [w makeKeyAndOrderFront:NSApp];
6252       [self windowDidExitFullScreen:nil];
6253       [self updateFrameSize:YES];
6254     }
6257 - (void)handleFS
6259   if (fs_state != emacsframe->want_fullscreen)
6260     {
6261       if (fs_state == FULLSCREEN_BOTH)
6262         {
6263           [self toggleFullScreen:self];
6264         }
6266       switch (emacsframe->want_fullscreen)
6267         {
6268         case FULLSCREEN_BOTH:
6269           [self toggleFullScreen:self];
6270           break;
6271         case FULLSCREEN_WIDTH:
6272           next_maximized = FULLSCREEN_WIDTH;
6273           if (fs_state != FULLSCREEN_BOTH)
6274             [[self window] performZoom:self];
6275           break;
6276         case FULLSCREEN_HEIGHT:
6277           next_maximized = FULLSCREEN_HEIGHT;
6278           if (fs_state != FULLSCREEN_BOTH)
6279             [[self window] performZoom:self];
6280           break;
6281         case FULLSCREEN_MAXIMIZED:
6282           next_maximized = FULLSCREEN_MAXIMIZED;
6283           if (fs_state != FULLSCREEN_BOTH)
6284             [[self window] performZoom:self];
6285           break;
6286         case FULLSCREEN_NONE:
6287           if (fs_state != FULLSCREEN_BOTH)
6288             {
6289               next_maximized = FULLSCREEN_NONE;
6290               [[self window] performZoom:self];
6291             }
6292           break;
6293         }
6295       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6296     }
6300 - (void) setFSValue: (int)value
6302   Lisp_Object lval = Qnil;
6303   switch (value)
6304     {
6305     case FULLSCREEN_BOTH:
6306       lval = Qfullboth;
6307       break;
6308     case FULLSCREEN_WIDTH:
6309       lval = Qfullwidth;
6310       break;
6311     case FULLSCREEN_HEIGHT:
6312       lval = Qfullheight;
6313       break;
6314     case FULLSCREEN_MAXIMIZED:
6315       lval = Qmaximized;
6316       break;
6317     }
6318   store_frame_param (emacsframe, Qfullscreen, lval);
6319   fs_state = value;
6322 - (void)mouseEntered: (NSEvent *)theEvent
6324   NSTRACE (mouseEntered);
6325   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6329 - (void)mouseExited: (NSEvent *)theEvent
6331   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6333   NSTRACE (mouseExited);
6335   if (!hlinfo)
6336     return;
6338   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6340   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6341     {
6342       clear_mouse_face (hlinfo);
6343       hlinfo->mouse_face_mouse_frame = 0;
6344     }
6348 - menuDown: sender
6350   NSTRACE (menuDown);
6351   if (context_menu_value == -1)
6352     context_menu_value = [sender tag];
6353   else
6354     {
6355       NSInteger tag = [sender tag];
6356       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6357                                     emacsframe->menu_bar_vector,
6358                                     (void *)tag);
6359     }
6361   ns_send_appdefined (-1);
6362   return self;
6366 - (EmacsToolbar *)toolbar
6368   return toolbar;
6372 /* this gets called on toolbar button click */
6373 - toolbarClicked: (id)item
6375   NSEvent *theEvent;
6376   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6378   NSTRACE (toolbarClicked);
6380   if (!emacs_event)
6381     return self;
6383   /* send first event (for some reason two needed) */
6384   theEvent = [[self window] currentEvent];
6385   emacs_event->kind = TOOL_BAR_EVENT;
6386   XSETFRAME (emacs_event->arg, emacsframe);
6387   EV_TRAILER (theEvent);
6389   emacs_event->kind = TOOL_BAR_EVENT;
6390 /*   XSETINT (emacs_event->code, 0); */
6391   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6392                            idx + TOOL_BAR_ITEM_KEY);
6393   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6394   EV_TRAILER (theEvent);
6395   return self;
6399 - toggleToolbar: (id)sender
6401   if (!emacs_event)
6402     return self;
6404   emacs_event->kind = NS_NONKEY_EVENT;
6405   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6406   EV_TRAILER ((id)nil);
6407   return self;
6411 - (void)drawRect: (NSRect)rect
6413   int x = NSMinX (rect), y = NSMinY (rect);
6414   int width = NSWidth (rect), height = NSHeight (rect);
6416   NSTRACE (drawRect);
6418   if (!emacsframe || !emacsframe->output_data.ns)
6419     return;
6421   ns_clear_frame_area (emacsframe, x, y, width, height);
6422   expose_frame (emacsframe, x, y, width, height);
6424   /*
6425     drawRect: may be called (at least in OS X 10.5) for invisible
6426     views as well for some reason.  Thus, do not infer visibility
6427     here.
6429     emacsframe->async_visible = 1;
6430     emacsframe->async_iconified = 0;
6431   */
6435 /* NSDraggingDestination protocol methods.  Actually this is not really a
6436    protocol, but a category of Object.  O well...  */
6438 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6440   NSTRACE (draggingEntered);
6441   return NSDragOperationGeneric;
6445 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6447   return YES;
6451 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6453   id pb;
6454   int x, y;
6455   NSString *type;
6456   NSEvent *theEvent = [[self window] currentEvent];
6457   NSPoint position;
6459   NSTRACE (performDragOperation);
6461   if (!emacs_event)
6462     return NO;
6464   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6465   x = lrint (position.x);  y = lrint (position.y);
6467   pb = [sender draggingPasteboard];
6468   type = [pb availableTypeFromArray: ns_drag_types];
6469   if (type == 0)
6470     {
6471       return NO;
6472     }
6473   else if ([type isEqualToString: NSFilenamesPboardType])
6474     {
6475       NSArray *files;
6476       NSEnumerator *fenum;
6477       NSString *file;
6479       if (!(files = [pb propertyListForType: type]))
6480         return NO;
6482       fenum = [files objectEnumerator];
6483       while ( (file = [fenum nextObject]) )
6484         {
6485           emacs_event->kind = NS_NONKEY_EVENT;
6486           emacs_event->code = KEY_NS_DRAG_FILE;
6487           XSETINT (emacs_event->x, x);
6488           XSETINT (emacs_event->y, y);
6489           ns_input_file = append2 (ns_input_file,
6490                                    build_string ([file UTF8String]));
6491           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6492           EV_TRAILER (theEvent);
6493         }
6494       return YES;
6495     }
6496   else if ([type isEqualToString: NSURLPboardType])
6497     {
6498       NSString *file;
6499       NSURL *fileURL;
6501       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6502           [fileURL isFileURL] == NO)
6503         return NO;
6505       file = [fileURL path];
6506       emacs_event->kind = NS_NONKEY_EVENT;
6507       emacs_event->code = KEY_NS_DRAG_FILE;
6508       XSETINT (emacs_event->x, x);
6509       XSETINT (emacs_event->y, y);
6510       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6511       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6512       EV_TRAILER (theEvent);
6513       return YES;
6514     }
6515   else if ([type isEqualToString: NSStringPboardType]
6516            || [type isEqualToString: NSTabularTextPboardType])
6517     {
6518       NSString *data;
6520       if (! (data = [pb stringForType: type]))
6521         return NO;
6523       emacs_event->kind = NS_NONKEY_EVENT;
6524       emacs_event->code = KEY_NS_DRAG_TEXT;
6525       XSETINT (emacs_event->x, x);
6526       XSETINT (emacs_event->y, y);
6527       ns_input_text = build_string ([data UTF8String]);
6528       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6529       EV_TRAILER (theEvent);
6530       return YES;
6531     }
6532   else if ([type isEqualToString: NSColorPboardType])
6533     {
6534       NSColor *c = [NSColor colorFromPasteboard: pb];
6535       emacs_event->kind = NS_NONKEY_EVENT;
6536       emacs_event->code = KEY_NS_DRAG_COLOR;
6537       XSETINT (emacs_event->x, x);
6538       XSETINT (emacs_event->y, y);
6539       ns_input_color = ns_color_to_lisp (c);
6540       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6541       EV_TRAILER (theEvent);
6542       return YES;
6543     }
6544   else if ([type isEqualToString: NSFontPboardType])
6545     {
6546       /* impl based on GNUstep NSTextView.m */
6547       NSData *data = [pb dataForType: NSFontPboardType];
6548       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6549       NSFont *font = [dict objectForKey: NSFontAttributeName];
6550       char fontSize[10];
6552       if (font == nil)
6553         return NO;
6555       emacs_event->kind = NS_NONKEY_EVENT;
6556       emacs_event->code = KEY_NS_CHANGE_FONT;
6557       XSETINT (emacs_event->x, x);
6558       XSETINT (emacs_event->y, y);
6559       ns_input_font = build_string ([[font fontName] UTF8String]);
6560       snprintf (fontSize, 10, "%f", [font pointSize]);
6561       ns_input_fontsize = build_string (fontSize);
6562       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6563       EV_TRAILER (theEvent);
6564       return YES;
6565     }
6566   else
6567     {
6568       error ("Invalid data type in dragging pasteboard.");
6569       return NO;
6570     }
6574 - (id) validRequestorForSendType: (NSString *)typeSent
6575                       returnType: (NSString *)typeReturned
6577   NSTRACE (validRequestorForSendType);
6578   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6579       && typeReturned == nil)
6580     {
6581       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6582         return self;
6583     }
6585   return [super validRequestorForSendType: typeSent
6586                                returnType: typeReturned];
6590 /* The next two methods are part of NSServicesRequests informal protocol,
6591    supposedly called when a services menu item is chosen from this app.
6592    But this should not happen because we override the services menu with our
6593    own entries which call ns-perform-service.
6594    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6595    So let's at least stub them out until further investigation can be done. */
6597 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6599   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6600      be written into the buffer in place of the existing selection..
6601      ordinary service calls go through functions defined in ns-win.el */
6602   return NO;
6605 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6607   NSArray *typesDeclared;
6608   Lisp_Object val;
6610   /* We only support NSStringPboardType */
6611   if ([types containsObject:NSStringPboardType] == NO) {
6612     return NO;
6613   }
6615   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6616   if (CONSP (val) && SYMBOLP (XCAR (val)))
6617     {
6618       val = XCDR (val);
6619       if (CONSP (val) && NILP (XCDR (val)))
6620         val = XCAR (val);
6621     }
6622   if (! STRINGP (val))
6623     return NO;
6625   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6626   [pb declareTypes:typesDeclared owner:nil];
6627   ns_string_to_pasteboard (pb, val);
6628   return YES;
6632 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6633    (gives a miniaturized version of the window); currently we use the latter for
6634    frames whose active buffer doesn't correspond to any file
6635    (e.g., '*scratch*') */
6636 - setMiniwindowImage: (BOOL) setMini
6638   id image = [[self window] miniwindowImage];
6639   NSTRACE (setMiniwindowImage);
6641   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6642      about "AppleDockIconEnabled" notwithstanding, however the set message
6643      below has its effect nonetheless. */
6644   if (image != emacsframe->output_data.ns->miniimage)
6645     {
6646       if (image && [image isKindOfClass: [EmacsImage class]])
6647         [image release];
6648       [[self window] setMiniwindowImage:
6649                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6650     }
6652   return self;
6656 - (void) setRows: (int) r andColumns: (int) c
6658   rows = r;
6659   cols = c;
6662 @end  /* EmacsView */
6666 /* ==========================================================================
6668     EmacsWindow implementation
6670    ========================================================================== */
6672 @implementation EmacsWindow
6674 #ifdef NS_IMPL_COCOA
6675 - (id)accessibilityAttributeValue:(NSString *)attribute
6677   Lisp_Object str = Qnil;
6678   struct frame *f = SELECTED_FRAME ();
6679   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->contents);
6681   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6682     return NSAccessibilityTextFieldRole;
6684   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6685       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6686     {
6687       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6688     }
6689   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6690     {
6691       if (! NILP (BVAR (curbuf, mark_active)))
6692           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6694       if (NILP (str))
6695         {
6696           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6697           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6698           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6700           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6701             str = make_uninit_multibyte_string (range, byte_range);
6702           else
6703             str = make_uninit_string (range);
6704           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6705              Is this a problem?  */
6706           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6707         }
6708     }
6711   if (! NILP (str))
6712     {
6713       if (CONSP (str) && SYMBOLP (XCAR (str)))
6714         {
6715           str = XCDR (str);
6716           if (CONSP (str) && NILP (XCDR (str)))
6717             str = XCAR (str);
6718         }
6719       if (STRINGP (str))
6720         {
6721           const char *utfStr = SSDATA (str);
6722           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6723           return nsStr;
6724         }
6725     }
6727   return [super accessibilityAttributeValue:attribute];
6729 #endif /* NS_IMPL_COCOA */
6731 /* If we have multiple monitors, one above the other, we don't want to
6732    restrict the height to just one monitor.  So we override this.  */
6733 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6735   /* When making the frame visible for the first time or if there is just
6736      one screen, we want to constrain.  Other times not.  */
6737   NSUInteger nr_screens = [[NSScreen screens] count];
6738   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6739   NSTRACE (constrainFrameRect);
6741   if (nr_screens == 1)
6742     {
6743       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6744       return r;
6745     }
6747   if (f->output_data.ns->dont_constrain
6748       || ns_menu_bar_should_be_hidden ())
6749     return frameRect;
6751   f->output_data.ns->dont_constrain = 1;
6752   return [super constrainFrameRect:frameRect toScreen:screen];
6755 @end /* EmacsWindow */
6758 @implementation EmacsFSWindow
6760 - (BOOL)canBecomeKeyWindow
6762   return YES;
6765 - (BOOL)canBecomeMainWindow
6767   return YES;
6770 @end
6772 /* ==========================================================================
6774     EmacsScroller implementation
6776    ========================================================================== */
6779 @implementation EmacsScroller
6781 /* for repeat button push */
6782 #define SCROLL_BAR_FIRST_DELAY 0.5
6783 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6785 + (CGFloat) scrollerWidth
6787   /* TODO: if we want to allow variable widths, this is the place to do it,
6788            however neither GNUstep nor Cocoa support it very well */
6789   return [NSScroller scrollerWidth];
6793 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6795   NSTRACE (EmacsScroller_initFrame);
6797   r.size.width = [EmacsScroller scrollerWidth];
6798   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6799   [self setContinuous: YES];
6800   [self setEnabled: YES];
6802   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6803      locked against the top and bottom edges, and right edge on OS X, where
6804      scrollers are on right. */
6805 #ifdef NS_IMPL_GNUSTEP
6806   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6807 #else
6808   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6809 #endif
6811   win = nwin;
6812   condemned = NO;
6813   pixel_height = NSHeight (r);
6814   if (pixel_height == 0) pixel_height = 1;
6815   min_portion = 20 / pixel_height;
6817   frame = XFRAME (XWINDOW (win)->frame);
6818   if (FRAME_LIVE_P (frame))
6819     {
6820       int i;
6821       EmacsView *view = FRAME_NS_VIEW (frame);
6822       NSView *sview = [[view window] contentView];
6823       NSArray *subs = [sview subviews];
6825       /* disable optimization stopping redraw of other scrollbars */
6826       view->scrollbarsNeedingUpdate = 0;
6827       for (i =[subs count]-1; i >= 0; i--)
6828         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6829           view->scrollbarsNeedingUpdate++;
6830       [sview addSubview: self];
6831     }
6833 /*  [self setFrame: r]; */
6835   return self;
6839 - (void)setFrame: (NSRect)newRect
6841   NSTRACE (EmacsScroller_setFrame);
6842 /*  block_input (); */
6843   pixel_height = NSHeight (newRect);
6844   if (pixel_height == 0) pixel_height = 1;
6845   min_portion = 20 / pixel_height;
6846   [super setFrame: newRect];
6847   [self display];
6848 /*  unblock_input (); */
6852 - (void)dealloc
6854   NSTRACE (EmacsScroller_dealloc);
6855   if (!NILP (win))
6856     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6857   [super dealloc];
6861 - condemn
6863   NSTRACE (condemn);
6864   condemned =YES;
6865   return self;
6869 - reprieve
6871   NSTRACE (reprieve);
6872   condemned =NO;
6873   return self;
6877 - judge
6879   NSTRACE (judge);
6880   if (condemned)
6881     {
6882       EmacsView *view;
6883       block_input ();
6884       /* ensure other scrollbar updates after deletion */
6885       view = (EmacsView *)FRAME_NS_VIEW (frame);
6886       if (view != nil)
6887         view->scrollbarsNeedingUpdate++;
6888       [self removeFromSuperview];
6889       [self release];
6890       unblock_input ();
6891     }
6892   return self;
6896 - (void)resetCursorRects
6898   NSRect visible = [self visibleRect];
6899   NSTRACE (resetCursorRects);
6901   if (!NSIsEmptyRect (visible))
6902     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6903   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6907 - (int) checkSamePosition: (int) position portion: (int) portion
6908                     whole: (int) whole
6910   return em_position ==position && em_portion ==portion && em_whole ==whole
6911     && portion != whole; /* needed for resize empty buf */
6915 - setPosition: (int)position portion: (int)portion whole: (int)whole
6917   NSTRACE (setPosition);
6919   em_position = position;
6920   em_portion = portion;
6921   em_whole = whole;
6923   if (portion >= whole)
6924     {
6925 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6926       [self setKnobProportion: 1.0];
6927       [self setDoubleValue: 1.0];
6928 #else
6929       [self setFloatValue: 0.0 knobProportion: 1.0];
6930 #endif
6931     }
6932   else
6933     {
6934       float pos;
6935       CGFloat por;
6936       portion = max ((float)whole*min_portion/pixel_height, portion);
6937       pos = (float)position / (whole - portion);
6938       por = (CGFloat)portion/whole;
6939 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6940       [self setKnobProportion: por];
6941       [self setDoubleValue: pos];
6942 #else
6943       [self setFloatValue: pos knobProportion: por];
6944 #endif
6945     }
6947   /* Events may come here even if the event loop is not running.
6948      If we don't enter the event loop, the scroll bar will not update.
6949      So send SIGIO to ourselves.  */
6950   if (apploopnr == 0) raise (SIGIO);
6952   return self;
6955 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6956      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6957 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6958                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6960   *part = last_hit_part;
6961   *window = win;
6962   XSETINT (*y, pixel_height);
6963   if ([self floatValue] > 0.999F)
6964     XSETINT (*x, pixel_height);
6965   else
6966     XSETINT (*x, pixel_height * [self floatValue]);
6970 /* set up emacs_event */
6971 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6973   if (!emacs_event)
6974     return;
6976   emacs_event->part = last_hit_part;
6977   emacs_event->code = 0;
6978   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6979   emacs_event->frame_or_window = win;
6980   emacs_event->timestamp = EV_TIMESTAMP (e);
6981   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6982   emacs_event->arg = Qnil;
6983   XSETINT (emacs_event->x, loc * pixel_height);
6984   XSETINT (emacs_event->y, pixel_height-20);
6986   if (q_event_ptr)
6987     {
6988       n_emacs_events_pending++;
6989       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6990     }
6991   else
6992     hold_event (emacs_event);
6993   EVENT_INIT (*emacs_event);
6994   ns_send_appdefined (-1);
6998 /* called manually thru timer to implement repeated button action w/hold-down */
6999 - repeatScroll: (NSTimer *)scrollEntry
7001   NSEvent *e = [[self window] currentEvent];
7002   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
7003   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
7005   /* clear timer if need be */
7006   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
7007     {
7008         [scroll_repeat_entry invalidate];
7009         [scroll_repeat_entry release];
7010         scroll_repeat_entry = nil;
7012         if (inKnob)
7013           return self;
7015         scroll_repeat_entry
7016           = [[NSTimer scheduledTimerWithTimeInterval:
7017                         SCROLL_BAR_CONTINUOUS_DELAY
7018                                             target: self
7019                                           selector: @selector (repeatScroll:)
7020                                           userInfo: 0
7021                                            repeats: YES]
7022               retain];
7023     }
7025   [self sendScrollEventAtLoc: 0 fromEvent: e];
7026   return self;
7030 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
7031    mouseDragged events without going into a modal loop. */
7032 - (void)mouseDown: (NSEvent *)e
7034   NSRect sr, kr;
7035   /* hitPart is only updated AFTER event is passed on */
7036   NSScrollerPart part = [self testPart: [e locationInWindow]];
7037   CGFloat inc = 0.0, loc, kloc, pos;
7038   int edge = 0;
7040   NSTRACE (EmacsScroller_mouseDown);
7042   switch (part)
7043     {
7044     case NSScrollerDecrementPage:
7045         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
7046     case NSScrollerIncrementPage:
7047         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
7048     case NSScrollerDecrementLine:
7049       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
7050     case NSScrollerIncrementLine:
7051       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
7052     case NSScrollerKnob:
7053       last_hit_part = scroll_bar_handle; break;
7054     case NSScrollerKnobSlot:  /* GNUstep-only */
7055       last_hit_part = scroll_bar_move_ratio; break;
7056     default:  /* NSScrollerNoPart? */
7057       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
7058                (long) part);
7059       return;
7060     }
7062   if (inc != 0.0)
7063     {
7064       pos = 0;      /* ignored */
7066       /* set a timer to repeat, as we can't let superclass do this modally */
7067       scroll_repeat_entry
7068         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
7069                                             target: self
7070                                           selector: @selector (repeatScroll:)
7071                                           userInfo: 0
7072                                            repeats: YES]
7073             retain];
7074     }
7075   else
7076     {
7077       /* handle, or on GNUstep possibly slot */
7078       NSEvent *fake_event;
7080       /* compute float loc in slot and mouse offset on knob */
7081       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7082                       toView: nil];
7083       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7084       if (loc <= 0.0)
7085         {
7086           loc = 0.0;
7087           edge = -1;
7088         }
7089       else if (loc >= NSHeight (sr))
7090         {
7091           loc = NSHeight (sr);
7092           edge = 1;
7093         }
7095       if (edge)
7096         kloc = 0.5 * edge;
7097       else
7098         {
7099           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
7100                           toView: nil];
7101           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
7102         }
7103       last_mouse_offset = kloc;
7105       /* if knob, tell emacs a location offset by knob pos
7106          (to indicate top of handle) */
7107       if (part == NSScrollerKnob)
7108           pos = (loc - last_mouse_offset) / NSHeight (sr);
7109       else
7110         /* else this is a slot click on GNUstep: go straight there */
7111         pos = loc / NSHeight (sr);
7113       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
7114       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
7115                                       location: [e locationInWindow]
7116                                  modifierFlags: [e modifierFlags]
7117                                      timestamp: [e timestamp]
7118                                   windowNumber: [e windowNumber]
7119                                        context: [e context]
7120                                    eventNumber: [e eventNumber]
7121                                     clickCount: [e clickCount]
7122                                       pressure: [e pressure]];
7123       [super mouseUp: fake_event];
7124     }
7126   if (part != NSScrollerKnob)
7127     [self sendScrollEventAtLoc: pos fromEvent: e];
7131 /* Called as we manually track scroller drags, rather than superclass. */
7132 - (void)mouseDragged: (NSEvent *)e
7134     NSRect sr;
7135     double loc, pos;
7137     NSTRACE (EmacsScroller_mouseDragged);
7139       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
7140                       toView: nil];
7141       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
7143       if (loc <= 0.0)
7144         {
7145           loc = 0.0;
7146         }
7147       else if (loc >= NSHeight (sr) + last_mouse_offset)
7148         {
7149           loc = NSHeight (sr) + last_mouse_offset;
7150         }
7152       pos = (loc - last_mouse_offset) / NSHeight (sr);
7153       [self sendScrollEventAtLoc: pos fromEvent: e];
7157 - (void)mouseUp: (NSEvent *)e
7159   if (scroll_repeat_entry)
7160     {
7161       [scroll_repeat_entry invalidate];
7162       [scroll_repeat_entry release];
7163       scroll_repeat_entry = nil;
7164     }
7165   last_hit_part = 0;
7169 /* treat scrollwheel events in the bar as though they were in the main window */
7170 - (void) scrollWheel: (NSEvent *)theEvent
7172   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7173   [view mouseDown: theEvent];
7176 @end  /* EmacsScroller */
7179 #ifdef NS_IMPL_GNUSTEP
7180 /* Dummy class to get rid of startup warnings.  */
7181 @implementation EmacsDocument
7183 @end
7184 #endif
7187 /* ==========================================================================
7189    Font-related functions; these used to be in nsfaces.m
7191    ========================================================================== */
7194 Lisp_Object
7195 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7197   struct font *font = XFONT_OBJECT (font_object);
7199   if (fontset < 0)
7200     fontset = fontset_from_font (font_object);
7201   FRAME_FONTSET (f) = fontset;
7203   if (FRAME_FONT (f) == font)
7204     /* This font is already set in frame F.  There's nothing more to
7205        do.  */
7206     return font_object;
7208   FRAME_FONT (f) = font;
7210   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7211   FRAME_COLUMN_WIDTH (f) = font->average_width;
7212   FRAME_LINE_HEIGHT (f) = font->height;
7214   compute_fringe_widths (f, 1);
7216   /* Compute the scroll bar width in character columns.  */
7217   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7218     {
7219       int wid = FRAME_COLUMN_WIDTH (f);
7220       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7221         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7222     }
7223   else
7224     {
7225       int wid = FRAME_COLUMN_WIDTH (f);
7226       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7227     }
7229   /* Now make the frame display the given font.  */
7230   if (FRAME_NS_WINDOW (f) != 0)
7231         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7233   return font_object;
7237 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7238 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7239          in 1.43. */
7241 const char *
7242 ns_xlfd_to_fontname (const char *xlfd)
7243 /* --------------------------------------------------------------------------
7244     Convert an X font name (XLFD) to an NS font name.
7245     Only family is used.
7246     The string returned is temporarily allocated.
7247    -------------------------------------------------------------------------- */
7249   char *name = xmalloc (180);
7250   int i, len;
7251   const char *ret;
7253   if (!strncmp (xlfd, "--", 2))
7254     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7255   else
7256     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7258   /* stopgap for malformed XLFD input */
7259   if (strlen (name) == 0)
7260     strcpy (name, "Monaco");
7262   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7263      also uppercase after '-' or ' ' */
7264   name[0] = c_toupper (name[0]);
7265   for (len =strlen (name), i =0; i<len; i++)
7266     {
7267       if (name[i] == '$')
7268         {
7269           name[i] = '-';
7270           if (i+1<len)
7271             name[i+1] = c_toupper (name[i+1]);
7272         }
7273       else if (name[i] == '_')
7274         {
7275           name[i] = ' ';
7276           if (i+1<len)
7277             name[i+1] = c_toupper (name[i+1]);
7278         }
7279     }
7280 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7281   ret = [[NSString stringWithUTF8String: name] UTF8String];
7282   xfree (name);
7283   return ret;
7287 void
7288 syms_of_nsterm (void)
7290   NSTRACE (syms_of_nsterm);
7292   ns_antialias_threshold = 10.0;
7294   /* from 23+ we need to tell emacs what modifiers there are.. */
7295   DEFSYM (Qmodifier_value, "modifier-value");
7296   DEFSYM (Qalt, "alt");
7297   DEFSYM (Qhyper, "hyper");
7298   DEFSYM (Qmeta, "meta");
7299   DEFSYM (Qsuper, "super");
7300   DEFSYM (Qcontrol, "control");
7301   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7303   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7304   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7305   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7306   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7307   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7309   DEFVAR_LISP ("ns-input-file", ns_input_file,
7310               "The file specified in the last NS event.");
7311   ns_input_file =Qnil;
7313   DEFVAR_LISP ("ns-input-text", ns_input_text,
7314               "The data received in the last NS text drag event.");
7315   ns_input_text =Qnil;
7317   DEFVAR_LISP ("ns-working-text", ns_working_text,
7318               "String for visualizing working composition sequence.");
7319   ns_working_text =Qnil;
7321   DEFVAR_LISP ("ns-input-font", ns_input_font,
7322               "The font specified in the last NS event.");
7323   ns_input_font =Qnil;
7325   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7326               "The fontsize specified in the last NS event.");
7327   ns_input_fontsize =Qnil;
7329   DEFVAR_LISP ("ns-input-line", ns_input_line,
7330                "The line specified in the last NS event.");
7331   ns_input_line =Qnil;
7333   DEFVAR_LISP ("ns-input-color", ns_input_color,
7334                "The color specified in the last NS event.");
7335   ns_input_color =Qnil;
7337   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7338                "The service name specified in the last NS event.");
7339   ns_input_spi_name =Qnil;
7341   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7342                "The service argument specified in the last NS event.");
7343   ns_input_spi_arg =Qnil;
7345   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7346                "This variable describes the behavior of the alternate or option key.\n\
7347 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7348 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7349 at all, allowing it to be used at a lower level for accented character entry.");
7350   ns_alternate_modifier = Qmeta;
7352   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7353                "This variable describes the behavior of the right alternate or option key.\n\
7354 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7355 Set to left means be the same key as `ns-alternate-modifier'.\n\
7356 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7357 at all, allowing it to be used at a lower level for accented character entry.");
7358   ns_right_alternate_modifier = Qleft;
7360   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7361                "This variable describes the behavior of the command key.\n\
7362 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7363   ns_command_modifier = Qsuper;
7365   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7366                "This variable describes the behavior of the right command key.\n\
7367 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7368 Set to left means be the same key as `ns-command-modifier'.\n\
7369 Set to none means that the command / option key is not interpreted by Emacs\n\
7370 at all, allowing it to be used at a lower level for accented character entry.");
7371   ns_right_command_modifier = Qleft;
7373   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7374                "This variable describes the behavior of the control key.\n\
7375 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7376   ns_control_modifier = Qcontrol;
7378   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7379                "This variable describes the behavior of the right control key.\n\
7380 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7381 Set to left means be the same key as `ns-control-modifier'.\n\
7382 Set to none means that the control / option key is not interpreted by Emacs\n\
7383 at all, allowing it to be used at a lower level for accented character entry.");
7384   ns_right_control_modifier = Qleft;
7386   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7387                "This variable describes the behavior of the function key (on laptops).\n\
7388 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7389 Set to none means that the function key is not interpreted by Emacs at all,\n\
7390 allowing it to be used at a lower level for accented character entry.");
7391   ns_function_modifier = Qnone;
7393   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7394                "Non-nil (the default) means to render text antialiased.");
7395   ns_antialias_text = Qt;
7397   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7398                "Whether to confirm application quit using dialog.");
7399   ns_confirm_quit = Qnil;
7401   staticpro (&ns_display_name_list);
7402   ns_display_name_list = Qnil;
7404   staticpro (&last_mouse_motion_frame);
7405   last_mouse_motion_frame = Qnil;
7407   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7408                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7409 Only works on OSX 10.6 or later.  */);
7410   ns_auto_hide_menu_bar = Qnil;
7412   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7413      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7414 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7415 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7416 Default is t for OSX >= 10.7, nil otherwise. */);
7417 #ifdef HAVE_NATIVE_FS
7418   ns_use_native_fullscreen = YES;
7419 #else
7420   ns_use_native_fullscreen = NO;
7421 #endif
7422   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7424   /* TODO: move to common code */
7425   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7426                doc: /* Which toolkit scroll bars Emacs uses, if any.
7427 A value of nil means Emacs doesn't use toolkit scroll bars.
7428 With the X Window system, the value is a symbol describing the
7429 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7430 With MS Windows or Nextstep, the value is t.  */);
7431   Vx_toolkit_scroll_bars = Qt;
7433   DEFVAR_BOOL ("x-use-underline-position-properties",
7434                x_use_underline_position_properties,
7435      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7436 A value of nil means ignore them.  If you encounter fonts with bogus
7437 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7438 to 4.1, set this to nil. */);
7439   x_use_underline_position_properties = 0;
7441   DEFVAR_BOOL ("x-underline-at-descent-line",
7442                x_underline_at_descent_line,
7443      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7444 A value of nil means to draw the underline according to the value of the
7445 variable `x-use-underline-position-properties', which is usually at the
7446 baseline level.  The default value is nil.  */);
7447   x_underline_at_descent_line = 0;
7449   /* Tell emacs about this window system. */
7450   Fprovide (intern ("ns"), Qnil);