* notes/unicode: ja-dic.el is now UTF-8.
[emacs.git] / src / nsterm.m
blob40e506eab2787fe3d9596598d50a69782b455573
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 /* call tracing */
64 #if 0
65 int term_trace_num = 0;
66 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
67                                 __FILE__, __LINE__, ++term_trace_num)
68 #else
69 #define NSTRACE(x)
70 #endif
72 extern NSString *NSMenuDidBeginTrackingNotification;
74 /* ==========================================================================
76     Local declarations
78    ========================================================================== */
80 /* Convert a symbol indexed with an NSxxx value to a value as defined
81    in keyboard.c (lispy_function_key). I hope this is a correct way
82    of doing things... */
83 static unsigned convert_ns_to_X_keysym[] =
85   NSHomeFunctionKey,            0x50,
86   NSLeftArrowFunctionKey,       0x51,
87   NSUpArrowFunctionKey,         0x52,
88   NSRightArrowFunctionKey,      0x53,
89   NSDownArrowFunctionKey,       0x54,
90   NSPageUpFunctionKey,          0x55,
91   NSPageDownFunctionKey,        0x56,
92   NSEndFunctionKey,             0x57,
93   NSBeginFunctionKey,           0x58,
94   NSSelectFunctionKey,          0x60,
95   NSPrintFunctionKey,           0x61,
96   NSClearLineFunctionKey,       0x0B,
97   NSExecuteFunctionKey,         0x62,
98   NSInsertFunctionKey,          0x63,
99   NSUndoFunctionKey,            0x65,
100   NSRedoFunctionKey,            0x66,
101   NSMenuFunctionKey,            0x67,
102   NSFindFunctionKey,            0x68,
103   NSHelpFunctionKey,            0x6A,
104   NSBreakFunctionKey,           0x6B,
106   NSF1FunctionKey,              0xBE,
107   NSF2FunctionKey,              0xBF,
108   NSF3FunctionKey,              0xC0,
109   NSF4FunctionKey,              0xC1,
110   NSF5FunctionKey,              0xC2,
111   NSF6FunctionKey,              0xC3,
112   NSF7FunctionKey,              0xC4,
113   NSF8FunctionKey,              0xC5,
114   NSF9FunctionKey,              0xC6,
115   NSF10FunctionKey,             0xC7,
116   NSF11FunctionKey,             0xC8,
117   NSF12FunctionKey,             0xC9,
118   NSF13FunctionKey,             0xCA,
119   NSF14FunctionKey,             0xCB,
120   NSF15FunctionKey,             0xCC,
121   NSF16FunctionKey,             0xCD,
122   NSF17FunctionKey,             0xCE,
123   NSF18FunctionKey,             0xCF,
124   NSF19FunctionKey,             0xD0,
125   NSF20FunctionKey,             0xD1,
126   NSF21FunctionKey,             0xD2,
127   NSF22FunctionKey,             0xD3,
128   NSF23FunctionKey,             0xD4,
129   NSF24FunctionKey,             0xD5,
131   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
132   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
133   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
135   NSTabCharacter,               0x09,
136   0x19,                         0x09,  /* left tab->regular since pass shift */
137   NSCarriageReturnCharacter,    0x0D,
138   NSNewlineCharacter,           0x0D,
139   NSEnterCharacter,             0x8D,
141   0x41|NSNumericPadKeyMask,     0xAE,  /* KP_Decimal */
142   0x43|NSNumericPadKeyMask,     0xAA,  /* KP_Multiply */
143   0x45|NSNumericPadKeyMask,     0xAB,  /* KP_Add */
144   0x4B|NSNumericPadKeyMask,     0xAF,  /* KP_Divide */
145   0x4E|NSNumericPadKeyMask,     0xAD,  /* KP_Subtract */
146   0x51|NSNumericPadKeyMask,     0xBD,  /* KP_Equal */
147   0x52|NSNumericPadKeyMask,     0xB0,  /* KP_0 */
148   0x53|NSNumericPadKeyMask,     0xB1,  /* KP_1 */
149   0x54|NSNumericPadKeyMask,     0xB2,  /* KP_2 */
150   0x55|NSNumericPadKeyMask,     0xB3,  /* KP_3 */
151   0x56|NSNumericPadKeyMask,     0xB4,  /* KP_4 */
152   0x57|NSNumericPadKeyMask,     0xB5,  /* KP_5 */
153   0x58|NSNumericPadKeyMask,     0xB6,  /* KP_6 */
154   0x59|NSNumericPadKeyMask,     0xB7,  /* KP_7 */
155   0x5B|NSNumericPadKeyMask,     0xB8,  /* KP_8 */
156   0x5C|NSNumericPadKeyMask,     0xB9,  /* KP_9 */
158   0x1B,                         0x1B   /* escape */
161 static Lisp_Object Qmodifier_value;
162 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
163 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
165 static Lisp_Object QUTF8_STRING;
167 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
168    the maximum font size to NOT antialias.  On GNUstep there is currently
169    no way to control this behavior. */
170 float ns_antialias_threshold;
172 /* Used to pick up AppleHighlightColor on OS X */
173 NSString *ns_selection_color;
175 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
176 NSString *ns_app_name = @"Emacs";  /* default changed later */
178 /* Display variables */
179 struct ns_display_info *x_display_list; /* Chain of existing displays */
180 Lisp_Object ns_display_name_list;
181 long context_menu_value = 0;
183 /* display update */
184 NSPoint last_mouse_motion_position;
185 static NSRect last_mouse_glyph;
186 static Time last_mouse_movement_time = 0;
187 static Lisp_Object last_mouse_motion_frame;
188 static EmacsScroller *last_mouse_scroll_bar = nil;
189 static struct frame *ns_updating_frame;
190 static NSView *focus_view = NULL;
191 static int ns_window_num = 0;
192 #ifdef NS_IMPL_GNUSTEP
193 static NSRect uRect;
194 #endif
195 static BOOL gsaved = NO;
196 static BOOL ns_fake_keydown = NO;
197 int ns_tmp_flags; /* FIXME */
198 struct nsfont_info *ns_tmp_font; /* FIXME */
199 static BOOL ns_menu_bar_is_hidden = NO;
200 /*static int debug_lock = 0; */
202 /* event loop */
203 static BOOL send_appdefined = YES;
204 #define NO_APPDEFINED_DATA (-8)
205 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
206 static NSTimer *timed_entry = 0;
207 static NSTimer *scroll_repeat_entry = nil;
208 static fd_set select_readfds, select_writefds;
209 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
210 static int select_nfds = 0, select_valid = 0;
211 static EMACS_TIME select_timeout = { 0, 0 };
212 static int selfds[2] = { -1, -1 };
213 static pthread_mutex_t select_mutex;
214 static int apploopnr = 0;
215 static NSAutoreleasePool *outerpool;
216 static struct input_event *emacs_event = NULL;
217 static struct input_event *q_event_ptr = NULL;
218 static int n_emacs_events_pending = 0;
219 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
220   *ns_pending_service_args;
221 static BOOL ns_do_open_file = NO;
222 static BOOL ns_last_use_native_fullscreen;
224 static struct {
225   struct input_event *q;
226   int nr, cap;
227 } hold_event_q = {
228   NULL, 0, 0
231 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
232 #define NS_FUNCTION_KEY_MASK 0x800000
233 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
234 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
235 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
236 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
237 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
238 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
239 #define EV_MODIFIERS(e)                               \
240     ((([e modifierFlags] & NSHelpKeyMask) ?           \
241            hyper_modifier : 0)                        \
242      | (!EQ (ns_right_alternate_modifier, Qleft) && \
243         (([e modifierFlags] & NSRightAlternateKeyMask) \
244          == NSRightAlternateKeyMask) ? \
245            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
246      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
247            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
248      | (([e modifierFlags] & NSShiftKeyMask) ?     \
249            shift_modifier : 0)                        \
250      | (!EQ (ns_right_control_modifier, Qleft) && \
251         (([e modifierFlags] & NSRightControlKeyMask) \
252          == NSRightControlKeyMask) ? \
253            parse_solitary_modifier (ns_right_control_modifier) : 0) \
254      | (([e modifierFlags] & NSControlKeyMask) ?      \
255            parse_solitary_modifier (ns_control_modifier) : 0)     \
256      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
257            parse_solitary_modifier (ns_function_modifier) : 0)    \
258      | (!EQ (ns_right_command_modifier, Qleft) && \
259         (([e modifierFlags] & NSRightCommandKeyMask) \
260          == NSRightCommandKeyMask) ? \
261            parse_solitary_modifier (ns_right_command_modifier) : 0) \
262      | (([e modifierFlags] & NSCommandKeyMask) ?      \
263            parse_solitary_modifier (ns_command_modifier):0))
265 #define EV_UDMODIFIERS(e)                                      \
266     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
267      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
268      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
269      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
270      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
271      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
272      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
273      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
274      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
276 #define EV_BUTTON(e)                                                         \
277     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
278       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
279      [e buttonNumber] - 1)
281 /* Convert the time field to a timestamp in milliseconds. */
282 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
284 /* This is a piece of code which is common to all the event handling
285    methods.  Maybe it should even be a function.  */
286 #define EV_TRAILER(e)                                                   \
287     {                                                                   \
288       XSETFRAME (emacs_event->frame_or_window, emacsframe);             \
289       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
290       if (q_event_ptr)                                                  \
291         {                                                               \
292           n_emacs_events_pending++;                                     \
293           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
294         }                                                               \
295       else                                                              \
296         hold_event (emacs_event);                                       \
297       EVENT_INIT (*emacs_event);                                        \
298       ns_send_appdefined (-1);                                          \
299     }
301 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
303 /* TODO: get rid of need for these forward declarations */
304 static void ns_condemn_scroll_bars (struct frame *f);
305 static void ns_judge_scroll_bars (struct frame *f);
306 void x_set_frame_alpha (struct frame *f);
309 /* ==========================================================================
311     Utilities
313    ========================================================================== */
315 static void
316 hold_event (struct input_event *event)
318   if (hold_event_q.nr == hold_event_q.cap)
319     {
320       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
321       else hold_event_q.cap *= 2;
322       hold_event_q.q = (struct input_event *)
323         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof (*hold_event_q.q));
324     }
326   hold_event_q.q[hold_event_q.nr++] = *event;
327   /* Make sure ns_read_socket is called, i.e. we have input.  */
328   raise (SIGIO);
329   send_appdefined = YES;
332 static Lisp_Object
333 append2 (Lisp_Object list, Lisp_Object item)
334 /* --------------------------------------------------------------------------
335    Utility to append to a list
336    -------------------------------------------------------------------------- */
338   Lisp_Object array[2];
339   array[0] = list;
340   array[1] = Fcons (item, Qnil);
341   return Fnconc (2, &array[0]);
345 const char *
346 ns_etc_directory (void)
347 /* If running as a self-contained app bundle, return as a string the
348    filename of the etc directory, if present; else nil.  */
350   NSBundle *bundle = [NSBundle mainBundle];
351   NSString *resourceDir = [bundle resourcePath];
352   NSString *resourcePath;
353   NSFileManager *fileManager = [NSFileManager defaultManager];
354   BOOL isDir;
356   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
357   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
358     {
359       if (isDir) return [resourcePath UTF8String];
360     }
361   return NULL;
365 const char *
366 ns_exec_path (void)
367 /* If running as a self-contained app bundle, return as a path string
368    the filenames of the libexec and bin directories, ie libexec:bin.
369    Otherwise, return nil.
370    Normally, Emacs does not add its own bin/ directory to the PATH.
371    However, a self-contained NS build has a different layout, with
372    bin/ and libexec/ subdirectories in the directory that contains
373    Emacs.app itself.
374    We put libexec first, because init_callproc_1 uses the first
375    element to initialize exec-directory.  An alternative would be
376    for init_callproc to check for invocation-directory/libexec.
379   NSBundle *bundle = [NSBundle mainBundle];
380   NSString *resourceDir = [bundle resourcePath];
381   NSString *binDir = [bundle bundlePath];
382   NSString *resourcePath, *resourcePaths;
383   NSRange range;
384   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
385   NSFileManager *fileManager = [NSFileManager defaultManager];
386   NSArray *paths;
387   NSEnumerator *pathEnum;
388   BOOL isDir;
390   range = [resourceDir rangeOfString: @"Contents"];
391   if (range.location != NSNotFound)
392     {
393       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
394 #ifdef NS_IMPL_COCOA
395       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
396 #endif
397     }
399   paths = [binDir stringsByAppendingPaths:
400                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
401   pathEnum = [paths objectEnumerator];
402   resourcePaths = @"";
404   while ((resourcePath = [pathEnum nextObject]))
405     {
406       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
407         if (isDir)
408           {
409             if ([resourcePaths length] > 0)
410               resourcePaths
411                 = [resourcePaths stringByAppendingString: pathSeparator];
412             resourcePaths
413               = [resourcePaths stringByAppendingString: resourcePath];
414           }
415     }
416   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
418   return NULL;
422 const char *
423 ns_load_path (void)
424 /* If running as a self-contained app bundle, return as a path string
425    the filenames of the site-lisp, lisp and leim directories.
426    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
428   NSBundle *bundle = [NSBundle mainBundle];
429   NSString *resourceDir = [bundle resourcePath];
430   NSString *resourcePath, *resourcePaths;
431   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
432   NSFileManager *fileManager = [NSFileManager defaultManager];
433   BOOL isDir;
434   NSArray *paths = [resourceDir stringsByAppendingPaths:
435                               [NSArray arrayWithObjects:
436                                          @"site-lisp", @"lisp", @"leim", nil]];
437   NSEnumerator *pathEnum = [paths objectEnumerator];
438   resourcePaths = @"";
440   /* Hack to skip site-lisp.  */
441   if (no_site_lisp) resourcePath = [pathEnum nextObject];
443   while ((resourcePath = [pathEnum nextObject]))
444     {
445       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
446         if (isDir)
447           {
448             if ([resourcePaths length] > 0)
449               resourcePaths
450                 = [resourcePaths stringByAppendingString: pathSeparator];
451             resourcePaths
452               = [resourcePaths stringByAppendingString: resourcePath];
453           }
454     }
455   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
457   return NULL;
460 static void
461 ns_timeout (int usecs)
462 /* --------------------------------------------------------------------------
463      Blocking timer utility used by ns_ring_bell
464    -------------------------------------------------------------------------- */
466   EMACS_TIME wakeup = add_emacs_time (current_emacs_time (),
467                                       make_emacs_time (0, usecs * 1000));
469   /* Keep waiting until past the time wakeup.  */
470   while (1)
471     {
472       EMACS_TIME timeout, now = current_emacs_time ();
473       if (EMACS_TIME_LE (wakeup, now))
474         break;
475       timeout = sub_emacs_time (wakeup, now);
477       /* Try to wait that long--but we might wake up sooner.  */
478       pselect (0, NULL, NULL, NULL, &timeout, NULL);
479     }
483 void
484 ns_release_object (void *obj)
485 /* --------------------------------------------------------------------------
486     Release an object (callable from C)
487    -------------------------------------------------------------------------- */
489     [(id)obj release];
493 void
494 ns_retain_object (void *obj)
495 /* --------------------------------------------------------------------------
496     Retain an object (callable from C)
497    -------------------------------------------------------------------------- */
499     [(id)obj retain];
503 void *
504 ns_alloc_autorelease_pool (void)
505 /* --------------------------------------------------------------------------
506      Allocate a pool for temporary objects (callable from C)
507    -------------------------------------------------------------------------- */
509   return [[NSAutoreleasePool alloc] init];
513 void
514 ns_release_autorelease_pool (void *pool)
515 /* --------------------------------------------------------------------------
516      Free a pool and temporary objects it refers to (callable from C)
517    -------------------------------------------------------------------------- */
519   ns_release_object (pool);
524 /* ==========================================================================
526     Focus (clipping) and screen update
528    ========================================================================== */
531 // Window constraining
532 // -------------------
534 // To ensure that the windows are not placed under the menu bar, they
535 // are typically moved by the call-back constrainFrameRect. However,
536 // by overriding it, it's possible to inhibit this, leaving the window
537 // in it's original position.
539 // It's possible to hide the menu bar. However, technically, it's only
540 // possible to hide it when the application is active. To ensure that
541 // this work properly, the menu bar and window constraining are
542 // deferred until the application becomes active.
544 // Even though it's not possible to manually move a window above the
545 // top of the screen, it is allowed if it's done programmatically,
546 // when the menu is hidden. This allows the editable area to cover the
547 // full screen height.
549 // Test cases
550 // ----------
552 // Use the following extra files:
554 //    init.el:
555 //       ;; Hide menu and place frame slightly above the top of the screen.
556 //       (setq ns-auto-hide-menu-bar t)
557 //       (set-frame-position (selected-frame) 0 -20)
559 // Test 1:
561 //    emacs -Q -l init.el
563 //    Result: No menu bar, and the title bar should be above the screen.
565 // Test 2:
567 //    emacs -Q
569 //    Result: Menu bar visible, frame placed immediately below the menu.
572 static void
573 ns_constrain_all_frames (void)
575   Lisp_Object tail, frame;
577   FOR_EACH_FRAME (tail, frame)
578     {
579       struct frame *f = XFRAME (frame);
580       if (FRAME_NS_P (f))
581         {
582           NSView *view = FRAME_NS_VIEW (f);
583           /* This no-op will trigger the default window placing
584            * constraint system. */
585           f->output_data.ns->dont_constrain = 0;
586           [[view window] setFrameOrigin:[[view window] frame].origin];
587         }
588     }
592 /* True, if the menu bar should be hidden.  */
594 static BOOL
595 ns_menu_bar_should_be_hidden (void)
597   return !NILP (ns_auto_hide_menu_bar)
598     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
602 /* Show or hide the menu bar, based on user setting.  */
604 static void
605 ns_update_auto_hide_menu_bar (void)
607 #ifdef NS_IMPL_COCOA
608 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
609   block_input ();
611   NSTRACE (ns_update_auto_hide_menu_bar);
613   if (NSApp != nil
614       && [NSApp isActive]
615       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
616     {
617       // Note, "setPresentationOptions" triggers an error unless the
618       // application is active.
619       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
621       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
622         {
623           NSApplicationPresentationOptions options
624             = NSApplicationPresentationAutoHideDock;
626           if (menu_bar_should_be_hidden)
627             options |= NSApplicationPresentationAutoHideMenuBar;
629           [NSApp setPresentationOptions: options];
631           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
633           if (!ns_menu_bar_is_hidden)
634             {
635               ns_constrain_all_frames ();
636             }
637         }
638     }
640   unblock_input ();
641 #endif
642 #endif
646 static void
647 ns_update_begin (struct frame *f)
648 /* --------------------------------------------------------------------------
649    Prepare for a grouped sequence of drawing calls
650    external (RIF) call; whole frame, called before update_window_begin
651    -------------------------------------------------------------------------- */
653   NSView *view = FRAME_NS_VIEW (f);
654   NSRect r = [view frame];
655   NSBezierPath *bp;
656   NSTRACE (ns_update_begin);
658   ns_update_auto_hide_menu_bar ();
660   ns_updating_frame = f;
661   [view lockFocus];
663   /* drawRect may have been called for say the minibuffer, and then clip path
664      is for the minibuffer.  But the display engine may draw more because
665      we have set the frame as garbaged.  So reset clip path to the whole
666      view.  */
667   bp = [[NSBezierPath bezierPathWithRect: r] retain];
668   [bp setClip];
669   [bp release];
671 #ifdef NS_IMPL_GNUSTEP
672   uRect = NSMakeRect (0, 0, 0, 0);
673 #endif
677 static void
678 ns_update_window_begin (struct window *w)
679 /* --------------------------------------------------------------------------
680    Prepare for a grouped sequence of drawing calls
681    external (RIF) call; for one window, called after update_begin
682    -------------------------------------------------------------------------- */
684   struct frame *f = XFRAME (WINDOW_FRAME (w));
685  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
686   NSTRACE (ns_update_window_begin);
687   updated_window = w;
688   set_output_cursor (&w->cursor);
690   block_input ();
692   if (f == hlinfo->mouse_face_mouse_frame)
693     {
694       /* Don't do highlighting for mouse motion during the update.  */
695       hlinfo->mouse_face_defer = 1;
697         /* If the frame needs to be redrawn,
698            simply forget about any prior mouse highlighting.  */
699       if (FRAME_GARBAGED_P (f))
700         hlinfo->mouse_face_window = Qnil;
702       /* (further code for mouse faces ifdef'd out in other terms elided) */
703     }
705   unblock_input ();
709 static void
710 ns_update_window_end (struct window *w, int cursor_on_p,
711                       int mouse_face_overwritten_p)
712 /* --------------------------------------------------------------------------
713    Finished a grouped sequence of drawing calls
714    external (RIF) call; for one window called before update_end
715    -------------------------------------------------------------------------- */
717   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
719   /* note: this fn is nearly identical in all terms */
720   if (!w->pseudo_window_p)
721     {
722       block_input ();
724       if (cursor_on_p)
725         display_and_set_cursor (w, 1,
726                                 output_cursor.hpos, output_cursor.vpos,
727                                 output_cursor.x, output_cursor.y);
729       if (draw_window_fringes (w, 1))
730         x_draw_vertical_border (w);
732       unblock_input ();
733     }
735   /* If a row with mouse-face was overwritten, arrange for
736      frame_up_to_date to redisplay the mouse highlight.  */
737   if (mouse_face_overwritten_p)
738     {
739       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
740       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
741       hlinfo->mouse_face_window = Qnil;
742     }
744   updated_window = NULL;
745   NSTRACE (update_window_end);
749 static void
750 ns_update_end (struct frame *f)
751 /* --------------------------------------------------------------------------
752    Finished a grouped sequence of drawing calls
753    external (RIF) call; for whole frame, called after update_window_end
754    -------------------------------------------------------------------------- */
756   NSView *view = FRAME_NS_VIEW (f);
758 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
759     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
761     block_input ();
763 #ifdef NS_IMPL_GNUSTEP
764   /* trigger flush only in the rectangle we tracked as being drawn */
765   [view unlockFocusNeedsFlush: NO];
766 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
767   [view lockFocusInRect: uRect];
768 #endif
770   [view unlockFocus];
771   [[view window] flushWindow];
773   unblock_input ();
774   ns_updating_frame = NULL;
775   NSTRACE (ns_update_end);
779 static void
780 ns_flush (struct frame *f)
781 /* --------------------------------------------------------------------------
782    external (RIF) call
783    NS impl is no-op since currently we flush in ns_update_end and elsewhere
784    -------------------------------------------------------------------------- */
786     NSTRACE (ns_flush);
790 static void
791 ns_focus (struct frame *f, NSRect *r, int n)
792 /* --------------------------------------------------------------------------
793    Internal: Focus on given frame.  During small local updates this is used to
794      draw, however during large updates, ns_update_begin and ns_update_end are
795      called to wrap the whole thing, in which case these calls are stubbed out.
796      Except, on GNUstep, we accumulate the rectangle being drawn into, because
797      the back end won't do this automatically, and will just end up flushing
798      the entire window.
799    -------------------------------------------------------------------------- */
801 //  NSTRACE (ns_focus);
802 #ifdef NS_IMPL_GNUSTEP
803   NSRect u;
804     if (n == 2)
805       u = NSUnionRect (r[0], r[1]);
806     else if (r)
807       u = *r;
808 #endif
809 /* static int c =0;
810    fprintf (stderr, "focus: %d", c++);
811    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
812    fprintf (stderr, "\n"); */
814   if (f != ns_updating_frame)
815     {
816       NSView *view = FRAME_NS_VIEW (f);
817       if (view != focus_view)
818         {
819           if (focus_view != NULL)
820             {
821               [focus_view unlockFocus];
822               [[focus_view window] flushWindow];
823 /*debug_lock--; */
824             }
826           if (view)
827 #ifdef NS_IMPL_GNUSTEP
828             r ? [view lockFocusInRect: u] : [view lockFocus];
829 #else
830             [view lockFocus];
831 #endif
832           focus_view = view;
833 /*if (view) debug_lock++; */
834         }
835 #ifdef NS_IMPL_GNUSTEP
836       else
837         {
838           /* more than one rect being drawn into */
839           if (view && r)
840             {
841               [view unlockFocus]; /* add prev rect to redraw list */
842               [view lockFocusInRect: u]; /* focus for draw in new rect */
843             }
844         }
845 #endif
846     }
847 #ifdef NS_IMPL_GNUSTEP
848   else
849     {
850       /* in batch mode, but in GNUstep must still track rectangles explicitly */
851       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
852     }
853 #endif
855   /* clipping */
856   if (r)
857     {
858       [[NSGraphicsContext currentContext] saveGraphicsState];
859       if (n == 2)
860         NSRectClipList (r, 2);
861       else
862         NSRectClip (*r);
863       gsaved = YES;
864     }
868 static void
869 ns_unfocus (struct frame *f)
870 /* --------------------------------------------------------------------------
871      Internal: Remove focus on given frame
872    -------------------------------------------------------------------------- */
874 //  NSTRACE (ns_unfocus);
876   if (gsaved)
877     {
878       [[NSGraphicsContext currentContext] restoreGraphicsState];
879       gsaved = NO;
880     }
882   if (f != ns_updating_frame)
883     {
884       if (focus_view != NULL)
885         {
886           [focus_view unlockFocus];
887           [[focus_view window] flushWindow];
888           focus_view = NULL;
889 /*debug_lock--; */
890         }
891     }
895 static void
896 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
897 /* --------------------------------------------------------------------------
898      Internal (but parallels other terms): Focus drawing on given row
899    -------------------------------------------------------------------------- */
901   struct frame *f = XFRAME (WINDOW_FRAME (w));
902   NSRect clip_rect;
903   int window_x, window_y, window_width;
905   window_box (w, area, &window_x, &window_y, &window_width, 0);
907   clip_rect.origin.x = window_x;
908   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
909   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
910   clip_rect.size.width = window_width;
911   clip_rect.size.height = row->visible_height;
913   ns_focus (f, &clip_rect, 1);
917 static void
918 ns_ring_bell (struct frame *f)
919 /* --------------------------------------------------------------------------
920      "Beep" routine
921    -------------------------------------------------------------------------- */
923   NSTRACE (ns_ring_bell);
924   if (visible_bell)
925     {
926       NSAutoreleasePool *pool;
927       struct frame *frame = SELECTED_FRAME ();
928       NSView *view;
930       block_input ();
931       pool = [[NSAutoreleasePool alloc] init];
933       view = FRAME_NS_VIEW (frame);
934       if (view != nil)
935         {
936           NSRect r, surr;
937           NSPoint dim = NSMakePoint (128, 128);
939           r = [view bounds];
940           r.origin.x += (r.size.width - dim.x) / 2;
941           r.origin.y += (r.size.height - dim.y) / 2;
942           r.size.width = dim.x;
943           r.size.height = dim.y;
944           surr = NSInsetRect (r, -2, -2);
945           ns_focus (frame, &surr, 1);
946           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
947           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
948                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
949           NSRectFill (r);
950           [[view window] flushWindow];
951           ns_timeout (150000);
952           [[view window] restoreCachedImage];
953           [[view window] flushWindow];
954           ns_unfocus (frame);
955         }
956       [pool release];
957       unblock_input ();
958     }
959   else
960     {
961       NSBeep ();
962     }
966 static void
967 ns_reset_terminal_modes (struct terminal *terminal)
968 /*  Externally called as hook */
970   NSTRACE (ns_reset_terminal_modes);
974 static void
975 ns_set_terminal_modes (struct terminal *terminal)
976 /*  Externally called as hook */
978   NSTRACE (ns_set_terminal_modes);
983 /* ==========================================================================
985     Frame / window manager related functions
987    ========================================================================== */
990 static void
991 ns_raise_frame (struct frame *f)
992 /* --------------------------------------------------------------------------
993      Bring window to foreground and make it active
994    -------------------------------------------------------------------------- */
996   NSView *view = FRAME_NS_VIEW (f);
997   check_ns ();
998   block_input ();
999   if (FRAME_VISIBLE_P (f))
1000     [[view window] makeKeyAndOrderFront: NSApp];
1001   unblock_input ();
1005 static void
1006 ns_lower_frame (struct frame *f)
1007 /* --------------------------------------------------------------------------
1008      Send window to back
1009    -------------------------------------------------------------------------- */
1011   NSView *view = FRAME_NS_VIEW (f);
1012   check_ns ();
1013   block_input ();
1014   [[view window] orderBack: NSApp];
1015   unblock_input ();
1019 static void
1020 ns_frame_raise_lower (struct frame *f, int raise)
1021 /* --------------------------------------------------------------------------
1022      External (hook)
1023    -------------------------------------------------------------------------- */
1025   NSTRACE (ns_frame_raise_lower);
1027   if (raise)
1028     ns_raise_frame (f);
1029   else
1030     ns_lower_frame (f);
1034 static void
1035 ns_frame_rehighlight (struct frame *frame)
1036 /* --------------------------------------------------------------------------
1037      External (hook): called on things like window switching within frame
1038    -------------------------------------------------------------------------- */
1040   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1041   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1043   NSTRACE (ns_frame_rehighlight);
1044   if (dpyinfo->x_focus_frame)
1045     {
1046       dpyinfo->x_highlight_frame
1047         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1048            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1049            : dpyinfo->x_focus_frame);
1050       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1051         {
1052           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1053           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1054         }
1055     }
1056   else
1057       dpyinfo->x_highlight_frame = 0;
1059   if (dpyinfo->x_highlight_frame &&
1060          dpyinfo->x_highlight_frame != old_highlight)
1061     {
1062       if (old_highlight)
1063         {
1064           x_update_cursor (old_highlight, 1);
1065           x_set_frame_alpha (old_highlight);
1066         }
1067       if (dpyinfo->x_highlight_frame)
1068         {
1069           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1070           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1071         }
1072     }
1076 void
1077 x_make_frame_visible (struct frame *f)
1078 /* --------------------------------------------------------------------------
1079      External: Show the window (X11 semantics)
1080    -------------------------------------------------------------------------- */
1082   NSTRACE (x_make_frame_visible);
1083   /* XXX: at some points in past this was not needed, as the only place that
1084      called this (frame.c:Fraise_frame ()) also called raise_lower;
1085      if this ends up the case again, comment this out again. */
1086   if (!FRAME_VISIBLE_P (f))
1087     {
1088       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1090       SET_FRAME_VISIBLE (f, 1);
1091       ns_raise_frame (f);
1093       /* Making a new frame from a fullscreen frame will make the new frame
1094          fullscreen also.  So skip handleFS as this will print an error.  */
1095       if ([view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH
1096           && [view isFullscreen])
1097         return;
1099       if (f->want_fullscreen != FULLSCREEN_NONE)
1100         {
1101           block_input ();
1102           [view handleFS];
1103           unblock_input ();
1104         }
1105     }
1109 void
1110 x_make_frame_invisible (struct frame *f)
1111 /* --------------------------------------------------------------------------
1112      External: Hide the window (X11 semantics)
1113    -------------------------------------------------------------------------- */
1115   NSView * view = FRAME_NS_VIEW (f);
1116   NSTRACE (x_make_frame_invisible);
1117   check_ns ();
1118   [[view window] orderOut: NSApp];
1119   SET_FRAME_VISIBLE (f, 0);
1120   SET_FRAME_ICONIFIED (f, 0);
1124 void
1125 x_iconify_frame (struct frame *f)
1126 /* --------------------------------------------------------------------------
1127      External: Iconify window
1128    -------------------------------------------------------------------------- */
1130   NSView * view = FRAME_NS_VIEW (f);
1131   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1132   NSTRACE (x_iconify_frame);
1133   check_ns ();
1135   if (dpyinfo->x_highlight_frame == f)
1136     dpyinfo->x_highlight_frame = 0;
1138   if ([[view window] windowNumber] <= 0)
1139     {
1140       /* the window is still deferred.  Make it very small, bring it
1141          on screen and order it out. */
1142       NSRect s = { { 100, 100}, {0, 0} };
1143       NSRect t;
1144       t = [[view window] frame];
1145       [[view window] setFrame: s display: NO];
1146       [[view window] orderBack: NSApp];
1147       [[view window] orderOut: NSApp];
1148       [[view window] setFrame: t display: NO];
1149     }
1150   [[view window] miniaturize: NSApp];
1153 /* Free X resources of frame F.  */
1155 void
1156 x_free_frame_resources (struct frame *f)
1158   NSView *view = FRAME_NS_VIEW (f);
1159   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1160   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1161   NSTRACE (x_free_frame_resources);
1162   check_ns ();
1164   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1166   block_input ();
1168   free_frame_menubar (f);
1170   if (FRAME_FACE_CACHE (f))
1171     free_frame_faces (f);
1173   if (f == dpyinfo->x_focus_frame)
1174     dpyinfo->x_focus_frame = 0;
1175   if (f == dpyinfo->x_highlight_frame)
1176     dpyinfo->x_highlight_frame = 0;
1177   if (f == hlinfo->mouse_face_mouse_frame)
1178     {
1179       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1180       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1181       hlinfo->mouse_face_window = Qnil;
1182       hlinfo->mouse_face_mouse_frame = 0;
1183     }
1185   if (f->output_data.ns->miniimage != nil)
1186     [f->output_data.ns->miniimage release];
1188   [[view window] close];
1189   [view release];
1191   xfree (f->output_data.ns);
1193   unblock_input ();
1196 void
1197 x_destroy_window (struct frame *f)
1198 /* --------------------------------------------------------------------------
1199      External: Delete the window
1200    -------------------------------------------------------------------------- */
1202   NSTRACE (x_destroy_window);
1203   check_ns ();
1204   x_free_frame_resources (f);
1205   ns_window_num--;
1209 void
1210 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1211 /* --------------------------------------------------------------------------
1212      External: Position the window
1213    -------------------------------------------------------------------------- */
1215   NSView *view = FRAME_NS_VIEW (f);
1216   NSArray *screens = [NSScreen screens];
1217   NSScreen *fscreen = [screens objectAtIndex: 0];
1218   NSScreen *screen = [[view window] screen];
1220   NSTRACE (x_set_offset);
1222   block_input ();
1224   f->left_pos = xoff;
1225   f->top_pos = yoff;
1227   if (view != nil && screen && fscreen)
1228     {
1229       f->left_pos = f->size_hint_flags & XNegative
1230         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1231         : f->left_pos;
1232       /* We use visibleFrame here to take menu bar into account.
1233          Ideally we should also adjust left/top with visibleFrame.origin.  */
1235       f->top_pos = f->size_hint_flags & YNegative
1236         ? ([screen visibleFrame].size.height + f->top_pos
1237            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1238            - FRAME_TOOLBAR_HEIGHT (f))
1239         : f->top_pos;
1240 #ifdef NS_IMPL_GNUSTEP
1241       if (f->left_pos < 100)
1242         f->left_pos = 100;  /* don't overlap menu */
1243 #endif
1244       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1245          menu bar.  */
1246       f->output_data.ns->dont_constrain = 0;
1247       [[view window] setFrameTopLeftPoint:
1248                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1249                                     SCREENMAXBOUND ([fscreen frame].size.height
1250                                                     - NS_TOP_POS (f)))];
1251       f->size_hint_flags &= ~(XNegative|YNegative);
1252     }
1254   unblock_input ();
1258 void
1259 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1260 /* --------------------------------------------------------------------------
1261      Adjust window pixel size based on given character grid size
1262      Impl is a bit more complex than other terms, need to do some
1263      internal clipping.
1264    -------------------------------------------------------------------------- */
1266   EmacsView *view = FRAME_NS_VIEW (f);
1267   NSWindow *window = [view window];
1268   NSRect wr = [window frame];
1269   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1270   int pixelwidth, pixelheight;
1272   NSTRACE (x_set_window_size);
1274   if (view == nil)
1275     return;
1277 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1279   block_input ();
1281   check_frame_size (f, &rows, &cols);
1283   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1284   compute_fringe_widths (f, 0);
1286   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1287   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1289   /* If we have a toolbar, take its height into account. */
1290   if (tb && ! [view isFullscreen])
1291     /* NOTE: previously this would generate wrong result if toolbar not
1292              yet displayed and fixing toolbar_height=32 helped, but
1293              now (200903) seems no longer needed */
1294     FRAME_TOOLBAR_HEIGHT (f) =
1295       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1296         - FRAME_NS_TITLEBAR_HEIGHT (f);
1297   else
1298     FRAME_TOOLBAR_HEIGHT (f) = 0;
1300   wr.size.width = pixelwidth + f->border_width;
1301   wr.size.height = pixelheight;
1302   if (! [view isFullscreen])
1303     wr.size.height += FRAME_NS_TITLEBAR_HEIGHT (f)
1304       + FRAME_TOOLBAR_HEIGHT (f);
1306   /* Do not try to constrain to this screen.  We may have multiple
1307      screens, and want Emacs to span those.  Constraining to screen
1308      prevents that, and that is not nice to the user.  */
1309  if (f->output_data.ns->zooming)
1310    f->output_data.ns->zooming = 0;
1311  else
1312    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1314   [view setRows: rows andColumns: cols];
1315   [window setFrame: wr display: YES];
1317 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1319   /* This is a trick to compensate for Emacs' managing the scrollbar area
1320      as a fixed number of standard character columns.  Instead of leaving
1321      blank space for the extra, we chopped it off above.  Now for
1322      left-hand scrollbars, we shift all rendering to the left by the
1323      difference between the real width and Emacs' imagined one.  For
1324      right-hand bars, don't worry about it since the extra is never used.
1325      (Obviously doesn't work for vertically split windows tho..) */
1326   {
1327     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1328       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1329                      - NS_SCROLL_BAR_WIDTH (f), 0)
1330       : NSMakePoint (0, 0);
1331     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1332     [view setBoundsOrigin: origin];
1333   }
1335   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1336   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1337   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1338 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1340   mark_window_cursors_off (XWINDOW (f->root_window));
1341   cancel_mouse_face (f);
1343   unblock_input ();
1347 static void
1348 ns_fullscreen_hook (FRAME_PTR f)
1350   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1352   if (!FRAME_VISIBLE_P (f))
1353     return;
1355    if (! [view fsIsNative] && f->want_fullscreen == FULLSCREEN_BOTH)
1356     {
1357       /* Old style fs don't initiate correctly if created from
1358          init/default-frame alist, so use a timer (not nice...).
1359       */
1360       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1361                                      selector: @selector (handleFS)
1362                                      userInfo: nil repeats: NO];
1363       return;
1364     }
1366   block_input ();
1367   [view handleFS];
1368   unblock_input ();
1371 /* ==========================================================================
1373     Color management
1375    ========================================================================== */
1378 NSColor *
1379 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1381   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1382   if (idx < 1 || idx >= color_table->avail)
1383     return nil;
1384   return color_table->colors[idx];
1388 unsigned long
1389 ns_index_color (NSColor *color, struct frame *f)
1391   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1392   ptrdiff_t idx;
1393   ptrdiff_t i;
1395   if (!color_table->colors)
1396     {
1397       color_table->size = NS_COLOR_CAPACITY;
1398       color_table->avail = 1; /* skip idx=0 as marker */
1399       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1400       color_table->colors[0] = nil;
1401       color_table->empty_indices = [[NSMutableSet alloc] init];
1402     }
1404   /* do we already have this color ? */
1405   for (i = 1; i < color_table->avail; i++)
1406     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1407       return i;
1409   if ([color_table->empty_indices count] > 0)
1410     {
1411       NSNumber *index = [color_table->empty_indices anyObject];
1412       [color_table->empty_indices removeObject: index];
1413       idx = [index unsignedLongValue];
1414     }
1415   else
1416     {
1417       if (color_table->avail == color_table->size)
1418         color_table->colors =
1419           xpalloc (color_table->colors, &color_table->size, 1,
1420                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1421       idx = color_table->avail++;
1422     }
1424   color_table->colors[idx] = color;
1425   [color retain];
1426 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1427   return idx;
1431 void
1432 ns_free_indexed_color (unsigned long idx, struct frame *f)
1434   struct ns_color_table *color_table;
1435   NSColor *color;
1436   NSNumber *index;
1438   if (!f)
1439     return;
1441   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1443   if (idx <= 0 || idx >= color_table->size) {
1444     message1 ("ns_free_indexed_color: Color index out of range.\n");
1445     return;
1446   }
1448   index = [NSNumber numberWithUnsignedInt: idx];
1449   if ([color_table->empty_indices containsObject: index]) {
1450     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1451     return;
1452   }
1454   color = color_table->colors[idx];
1455   [color release];
1456   color_table->colors[idx] = nil;
1457   [color_table->empty_indices addObject: index];
1458 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1462 static int
1463 ns_get_color (const char *name, NSColor **col)
1464 /* --------------------------------------------------------------------------
1465      Parse a color name
1466    -------------------------------------------------------------------------- */
1467 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1468    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1469    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1471   NSColor *new = nil;
1472   static char hex[20];
1473   int scaling;
1474   float r = -1.0, g, b;
1475   NSString *nsname = [NSString stringWithUTF8String: name];
1477 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1478   block_input ();
1480   if ([nsname isEqualToString: @"ns_selection_color"])
1481     {
1482       nsname = ns_selection_color;
1483       name = [ns_selection_color UTF8String];
1484     }
1486   /* First, check for some sort of numeric specification. */
1487   hex[0] = '\0';
1489   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1490     {
1491       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1492       [scanner scanFloat: &r];
1493       [scanner scanFloat: &g];
1494       [scanner scanFloat: &b];
1495     }
1496   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1497     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1498   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1499     {
1500       int len = (strlen(name) - 1);
1501       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1502       int i;
1503       scaling = strlen(name+start) / 3;
1504       for (i = 0; i < 3; i++)
1505         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1506                  name + start + i * scaling);
1507       hex[3 * (scaling + 1) - 1] = '\0';
1508     }
1510   if (hex[0])
1511     {
1512       int rr, gg, bb;
1513       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1514       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1515         {
1516           r = rr / fscale;
1517           g = gg / fscale;
1518           b = bb / fscale;
1519         }
1520     }
1522   if (r >= 0.0)
1523     {
1524       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1525       unblock_input ();
1526       return 0;
1527     }
1529   /* Otherwise, color is expected to be from a list */
1530   {
1531     NSEnumerator *lenum, *cenum;
1532     NSString *name;
1533     NSColorList *clist;
1535 #ifdef NS_IMPL_GNUSTEP
1536     /* XXX: who is wrong, the requestor or the implementation? */
1537     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1538         == NSOrderedSame)
1539       nsname = @"highlightColor";
1540 #endif
1542     lenum = [[NSColorList availableColorLists] objectEnumerator];
1543     while ( (clist = [lenum nextObject]) && new == nil)
1544       {
1545         cenum = [[clist allKeys] objectEnumerator];
1546         while ( (name = [cenum nextObject]) && new == nil )
1547           {
1548             if ([name compare: nsname
1549                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1550               new = [clist colorWithKey: name];
1551           }
1552       }
1553   }
1555   if (new)
1556     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1557   unblock_input ();
1558   return new ? 0 : 1;
1563 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1564 /* --------------------------------------------------------------------------
1565      Convert a Lisp string object to a NS color
1566    -------------------------------------------------------------------------- */
1568   NSTRACE (ns_lisp_to_color);
1569   if (STRINGP (color))
1570     return ns_get_color (SSDATA (color), col);
1571   else if (SYMBOLP (color))
1572     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1573   return 1;
1577 Lisp_Object
1578 ns_color_to_lisp (NSColor *col)
1579 /* --------------------------------------------------------------------------
1580      Convert a color to a lisp string with the RGB equivalent
1581    -------------------------------------------------------------------------- */
1583   CGFloat red, green, blue, alpha, gray;
1584   char buf[1024];
1585   const char *str;
1586   NSTRACE (ns_color_to_lisp);
1588   block_input ();
1589   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1591       if ((str =[[col colorNameComponent] UTF8String]))
1592         {
1593           unblock_input ();
1594           return build_string ((char *)str);
1595         }
1597     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1598         getRed: &red green: &green blue: &blue alpha: &alpha];
1599   if (red ==green && red ==blue)
1600     {
1601       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1602             getWhite: &gray alpha: &alpha];
1603       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1604                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1605       unblock_input ();
1606       return build_string (buf);
1607     }
1609   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1610             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1612   unblock_input ();
1613   return build_string (buf);
1617 void
1618 ns_query_color(void *col, XColor *color_def, int setPixel)
1619 /* --------------------------------------------------------------------------
1620          Get ARGB values out of NSColor col and put them into color_def.
1621          If setPixel, set the pixel to a concatenated version.
1622          and set color_def pixel to the resulting index.
1623    -------------------------------------------------------------------------- */
1625   CGFloat r, g, b, a;
1627   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1628   color_def->red   = r * 65535;
1629   color_def->green = g * 65535;
1630   color_def->blue  = b * 65535;
1632   if (setPixel == YES)
1633     color_def->pixel
1634       = ARGB_TO_ULONG((int)(a*255),
1635                       (int)(r*255), (int)(g*255), (int)(b*255));
1639 bool
1640 ns_defined_color (struct frame *f,
1641                   const char *name,
1642                   XColor *color_def,
1643                   bool alloc,
1644                   bool makeIndex)
1645 /* --------------------------------------------------------------------------
1646          Return true if named color found, and set color_def rgb accordingly.
1647          If makeIndex and alloc are nonzero put the color in the color_table,
1648          and set color_def pixel to the resulting index.
1649          If makeIndex is zero, set color_def pixel to ARGB.
1650          Return false if not found
1651    -------------------------------------------------------------------------- */
1653   NSColor *col;
1654   NSTRACE (ns_defined_color);
1656   block_input ();
1657   if (ns_get_color (name, &col) != 0) /* Color not found  */
1658     {
1659       unblock_input ();
1660       return 0;
1661     }
1662   if (makeIndex && alloc)
1663     color_def->pixel = ns_index_color (col, f);
1664   ns_query_color (col, color_def, !makeIndex);
1665   unblock_input ();
1666   return 1;
1670 unsigned long
1671 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1672 /* --------------------------------------------------------------------------
1673     return an autoreleased RGB color
1674    -------------------------------------------------------------------------- */
1676 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1677   if (r < 0.0) r = 0.0;
1678   else if (r > 1.0) r = 1.0;
1679   if (g < 0.0) g = 0.0;
1680   else if (g > 1.0) g = 1.0;
1681   if (b < 0.0) b = 0.0;
1682   else if (b > 1.0) b = 1.0;
1683   if (a < 0.0) a = 0.0;
1684   else if (a > 1.0) a = 1.0;
1685   return (unsigned long) ns_index_color(
1686     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1690 void
1691 x_set_frame_alpha (struct frame *f)
1692 /* --------------------------------------------------------------------------
1693      change the entire-frame transparency
1694    -------------------------------------------------------------------------- */
1696   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1697   EmacsView *view = FRAME_NS_VIEW (f);
1698   double alpha = 1.0;
1699   double alpha_min = 1.0;
1701   if (dpyinfo->x_highlight_frame == f)
1702     alpha = f->alpha[0];
1703   else
1704     alpha = f->alpha[1];
1706   if (FLOATP (Vframe_alpha_lower_limit))
1707     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1708   else if (INTEGERP (Vframe_alpha_lower_limit))
1709     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1711   if (alpha < 0.0)
1712     return;
1713   else if (1.0 < alpha)
1714     alpha = 1.0;
1715   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1716     alpha = alpha_min;
1718 #ifdef NS_IMPL_COCOA
1719   [[view window] setAlphaValue: alpha];
1720 #endif
1724 /* ==========================================================================
1726     Mouse handling
1728    ========================================================================== */
1731 void
1732 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1733 /* --------------------------------------------------------------------------
1734      Programmatically reposition mouse pointer in pixel coordinates
1735    -------------------------------------------------------------------------- */
1737   NSTRACE (x_set_mouse_pixel_position);
1738   ns_raise_frame (f);
1739 #if 0
1740   /* FIXME: this does not work, and what about GNUstep? */
1741 #ifdef NS_IMPL_COCOA
1742   [FRAME_NS_VIEW (f) lockFocus];
1743   PSsetmouse ((float)pix_x, (float)pix_y);
1744   [FRAME_NS_VIEW (f) unlockFocus];
1745 #endif
1746 #endif
1750 void
1751 x_set_mouse_position (struct frame *f, int h, int v)
1752 /* --------------------------------------------------------------------------
1753      Programmatically reposition mouse pointer in character coordinates
1754    -------------------------------------------------------------------------- */
1756   int pix_x, pix_y;
1758   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1759   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1761   if (pix_x < 0) pix_x = 0;
1762   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1764   if (pix_y < 0) pix_y = 0;
1765   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1767   x_set_mouse_pixel_position (f, pix_x, pix_y);
1771 static int
1772 note_mouse_movement (struct frame *frame, float x, float y)
1773 /*   ------------------------------------------------------------------------
1774      Called by EmacsView on mouseMovement events.  Passes on
1775      to emacs mainstream code if we moved off of a rect of interest
1776      known as last_mouse_glyph.
1777      ------------------------------------------------------------------------ */
1779 //  NSTRACE (note_mouse_movement);
1781   XSETFRAME (last_mouse_motion_frame, frame);
1783   /* Note, this doesn't get called for enter/leave, since we don't have a
1784      position.  Those are taken care of in the corresponding NSView methods. */
1786   /* has movement gone beyond last rect we were tracking? */
1787   if (x < last_mouse_glyph.origin.x ||
1788       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1789       y < last_mouse_glyph.origin.y ||
1790       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1791     {
1792       ns_update_begin(frame);
1793       frame->mouse_moved = 1;
1794       note_mouse_highlight (frame, x, y);
1795       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1796       ns_update_end(frame);
1797       return 1;
1798     }
1800   return 0;
1804 static void
1805 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1806                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1807                    Time *time)
1808 /* --------------------------------------------------------------------------
1809     External (hook): inform emacs about mouse position and hit parts.
1810     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1811     x & y should be position in the scrollbar (the whole bar, not the handle)
1812     and length of scrollbar respectively
1813    -------------------------------------------------------------------------- */
1815   id view;
1816   NSPoint position;
1817   Lisp_Object frame, tail;
1818   struct frame *f;
1819   struct ns_display_info *dpyinfo;
1821   NSTRACE (ns_mouse_position);
1823   if (*fp == NULL)
1824     {
1825       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1826       return;
1827     }
1829   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1831   block_input ();
1833   if (last_mouse_scroll_bar != nil && insist == 0)
1834     {
1835       /* TODO: we do not use this path at the moment because drag events will
1836            go directly to the EmacsScroller.  Leaving code in for now. */
1837       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1838                                               x: x y: y];
1839       if (time) *time = last_mouse_movement_time;
1840       last_mouse_scroll_bar = nil;
1841     }
1842   else
1843     {
1844       /* Clear the mouse-moved flag for every frame on this display.  */
1845       FOR_EACH_FRAME (tail, frame)
1846         if (FRAME_NS_P (XFRAME (frame))
1847             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1848           XFRAME (frame)->mouse_moved = 0;
1850       last_mouse_scroll_bar = nil;
1851       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1852         f = last_mouse_frame;
1853       else
1854         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1855                                     : SELECTED_FRAME ();
1857       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1858         {
1859           view = FRAME_NS_VIEW (*fp);
1861           position = [[view window] mouseLocationOutsideOfEventStream];
1862           position = [view convertPoint: position fromView: nil];
1863           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1864 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1866           if (bar_window) *bar_window = Qnil;
1867           if (part) *part = 0; /*scroll_bar_handle; */
1869           if (x) XSETINT (*x, lrint (position.x));
1870           if (y) XSETINT (*y, lrint (position.y));
1871           if (time) *time = last_mouse_movement_time;
1872           *fp = f;
1873         }
1874     }
1876   unblock_input ();
1880 static void
1881 ns_frame_up_to_date (struct frame *f)
1882 /* --------------------------------------------------------------------------
1883     External (hook): Fix up mouse highlighting right after a full update.
1884     Can't use FRAME_MOUSE_UPDATE due to ns_frame_begin and ns_frame_end calls.
1885    -------------------------------------------------------------------------- */
1887   NSTRACE (ns_frame_up_to_date);
1889   if (FRAME_NS_P (f))
1890     {
1891       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1892       if (f == hlinfo->mouse_face_mouse_frame)
1893         {
1894           block_input ();
1895           ns_update_begin(f);
1896           if (hlinfo->mouse_face_mouse_frame)
1897             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1898                                   hlinfo->mouse_face_mouse_x,
1899                                   hlinfo->mouse_face_mouse_y);
1900           ns_update_end(f);
1901           unblock_input ();
1902         }
1903     }
1907 static void
1908 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1909 /* --------------------------------------------------------------------------
1910     External (RIF): set frame mouse pointer type.
1911    -------------------------------------------------------------------------- */
1913   NSTRACE (ns_define_frame_cursor);
1914   if (FRAME_POINTER_TYPE (f) != cursor)
1915     {
1916       EmacsView *view = FRAME_NS_VIEW (f);
1917       FRAME_POINTER_TYPE (f) = cursor;
1918       [[view window] invalidateCursorRectsForView: view];
1919       /* Redisplay assumes this function also draws the changed frame
1920          cursor, but this function doesn't, so do it explicitly.  */
1921       x_update_cursor (f, 1);
1922     }
1927 /* ==========================================================================
1929     Keyboard handling
1931    ========================================================================== */
1934 static unsigned
1935 ns_convert_key (unsigned code)
1936 /* --------------------------------------------------------------------------
1937     Internal call used by NSView-keyDown.
1938    -------------------------------------------------------------------------- */
1940   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1941                                 / sizeof (convert_ns_to_X_keysym[0]));
1942   unsigned keysym;
1943   /* An array would be faster, but less easy to read. */
1944   for (keysym = 0; keysym < last_keysym; keysym += 2)
1945     if (code == convert_ns_to_X_keysym[keysym])
1946       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1947   return 0;
1948 /* if decide to use keyCode and Carbon table, use this line:
1949      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1953 char *
1954 x_get_keysym_name (int keysym)
1955 /* --------------------------------------------------------------------------
1956     Called by keyboard.c.  Not sure if the return val is important, except
1957     that it be unique.
1958    -------------------------------------------------------------------------- */
1960   static char value[16];
1961   NSTRACE (x_get_keysym_name);
1962   sprintf (value, "%d", keysym);
1963   return value;
1968 /* ==========================================================================
1970     Block drawing operations
1972    ========================================================================== */
1975 static void
1976 ns_redraw_scroll_bars (struct frame *f)
1978   int i;
1979   id view;
1980   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1981   NSTRACE (ns_redraw_scroll_bars);
1982   for (i =[subviews count]-1; i >= 0; i--)
1983     {
1984       view = [subviews objectAtIndex: i];
1985       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1986       [view display];
1987     }
1991 void
1992 ns_clear_frame (struct frame *f)
1993 /* --------------------------------------------------------------------------
1994       External (hook): Erase the entire frame
1995    -------------------------------------------------------------------------- */
1997   NSView *view = FRAME_NS_VIEW (f);
1998   NSRect r;
2000   NSTRACE (ns_clear_frame);
2002  /* comes on initial frame because we have
2003     after-make-frame-functions = select-frame */
2004  if (!FRAME_DEFAULT_FACE (f))
2005    return;
2007   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
2009   output_cursor.hpos = output_cursor.vpos = 0;
2010   output_cursor.x = -1;
2012   r = [view bounds];
2014   block_input ();
2015   ns_focus (f, &r, 1);
2016   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2017   NSRectFill (r);
2018   ns_unfocus (f);
2020   /* as of 2006/11 or so this is now needed */
2021   ns_redraw_scroll_bars (f);
2022   unblock_input ();
2026 static void
2027 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2028 /* --------------------------------------------------------------------------
2029     External (RIF):  Clear section of frame
2030    -------------------------------------------------------------------------- */
2032   NSRect r = NSMakeRect (x, y, width, height);
2033   NSView *view = FRAME_NS_VIEW (f);
2034   struct face *face = FRAME_DEFAULT_FACE (f);
2036   if (!view || !face)
2037     return;
2039   NSTRACE (ns_clear_frame_area);
2041   r = NSIntersectionRect (r, [view frame]);
2042   ns_focus (f, &r, 1);
2043   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2045   NSRectFill (r);
2047   ns_unfocus (f);
2048   return;
2052 static void
2053 ns_scroll_run (struct window *w, struct run *run)
2054 /* --------------------------------------------------------------------------
2055     External (RIF):  Insert or delete n lines at line vpos
2056    -------------------------------------------------------------------------- */
2058   struct frame *f = XFRAME (w->frame);
2059   int x, y, width, height, from_y, to_y, bottom_y;
2061   NSTRACE (ns_scroll_run);
2063   /* begin copy from other terms */
2064   /* Get frame-relative bounding box of the text display area of W,
2065      without mode lines.  Include in this box the left and right
2066      fringe of W.  */
2067   window_box (w, -1, &x, &y, &width, &height);
2069   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2070   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2071   bottom_y = y + height;
2073   if (to_y < from_y)
2074     {
2075       /* Scrolling up.  Make sure we don't copy part of the mode
2076          line at the bottom.  */
2077       if (from_y + run->height > bottom_y)
2078         height = bottom_y - from_y;
2079       else
2080         height = run->height;
2081     }
2082   else
2083     {
2084       /* Scrolling down.  Make sure we don't copy over the mode line.
2085          at the bottom.  */
2086       if (to_y + run->height > bottom_y)
2087         height = bottom_y - to_y;
2088       else
2089         height = run->height;
2090     }
2091   /* end copy from other terms */
2093   if (height == 0)
2094       return;
2096   block_input ();
2098   updated_window = w;
2099   x_clear_cursor (w);
2101   {
2102     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2103     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2104     NSPoint dstOrigin = NSMakePoint (x, to_y);
2106     ns_focus (f, &dstRect, 1);
2107     NSCopyBits (0, srcRect , dstOrigin);
2108     ns_unfocus (f);
2109   }
2111   unblock_input ();
2115 static void
2116 ns_after_update_window_line (struct glyph_row *desired_row)
2117 /* --------------------------------------------------------------------------
2118     External (RIF): preparatory to fringe update after text was updated
2119    -------------------------------------------------------------------------- */
2121   struct window *w = updated_window;
2122   struct frame *f;
2123   int width, height;
2125   NSTRACE (ns_after_update_window_line);
2127   /* begin copy from other terms */
2128   eassert (w);
2130   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2131     desired_row->redraw_fringe_bitmaps_p = 1;
2133   /* When a window has disappeared, make sure that no rest of
2134      full-width rows stays visible in the internal border.  */
2135   if (windows_or_buffers_changed
2136       && desired_row->full_width_p
2137       && (f = XFRAME (w->frame),
2138           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2139           width != 0)
2140       && (height = desired_row->visible_height,
2141           height > 0))
2142     {
2143       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2145       block_input ();
2146       ns_clear_frame_area (f, 0, y, width, height);
2147       ns_clear_frame_area (f,
2148                            FRAME_PIXEL_WIDTH (f) - width,
2149                            y, width, height);
2150       unblock_input ();
2151     }
2155 static void
2156 ns_shift_glyphs_for_insert (struct frame *f,
2157                            int x, int y, int width, int height,
2158                            int shift_by)
2159 /* --------------------------------------------------------------------------
2160     External (RIF): copy an area horizontally, don't worry about clearing src
2161    -------------------------------------------------------------------------- */
2163   NSRect srcRect = NSMakeRect (x, y, width, height);
2164   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2165   NSPoint dstOrigin = dstRect.origin;
2167   NSTRACE (ns_shift_glyphs_for_insert);
2169   ns_focus (f, &dstRect, 1);
2170   NSCopyBits (0, srcRect, dstOrigin);
2171   ns_unfocus (f);
2176 /* ==========================================================================
2178     Character encoding and metrics
2180    ========================================================================== */
2183 static void
2184 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2185 /* --------------------------------------------------------------------------
2186      External (RIF); compute left/right overhang of whole string and set in s
2187    -------------------------------------------------------------------------- */
2189   struct font *font = s->font;
2191   if (s->char2b)
2192     {
2193       struct font_metrics metrics;
2194       unsigned int codes[2];
2195       codes[0] = *(s->char2b);
2196       codes[1] = *(s->char2b + s->nchars - 1);
2198       font->driver->text_extents (font, codes, 2, &metrics);
2199       s->left_overhang = -metrics.lbearing;
2200       s->right_overhang
2201         = metrics.rbearing > metrics.width
2202         ? metrics.rbearing - metrics.width : 0;
2203     }
2204   else
2205     {
2206       s->left_overhang = 0;
2207       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2208         FONT_HEIGHT (font) * 0.2 : 0;
2209     }
2214 /* ==========================================================================
2216     Fringe and cursor drawing
2218    ========================================================================== */
2221 extern int max_used_fringe_bitmap;
2222 static void
2223 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2224                       struct draw_fringe_bitmap_params *p)
2225 /* --------------------------------------------------------------------------
2226     External (RIF); fringe-related
2227    -------------------------------------------------------------------------- */
2229   struct frame *f = XFRAME (WINDOW_FRAME (w));
2230   struct face *face = p->face;
2231   int rowY;
2232   static EmacsImage **bimgs = NULL;
2233   static int nBimgs = 0;
2235   /* grow bimgs if needed */
2236   if (nBimgs < max_used_fringe_bitmap)
2237     {
2238       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2239       memset (bimgs + nBimgs, 0,
2240               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2241       nBimgs = max_used_fringe_bitmap;
2242     }
2244   /* Must clip because of partially visible lines.  */
2245   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2246   ns_clip_to_row (w, row, -1, YES);
2248   if (!p->overlay_p)
2249     {
2250       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2252       /* If the fringe is adjacent to the left (right) scroll bar of a
2253          leftmost (rightmost, respectively) window, then extend its
2254          background to the gap between the fringe and the bar.  */
2255       if ((WINDOW_LEFTMOST_P (w)
2256            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2257           || (WINDOW_RIGHTMOST_P (w)
2258               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2259         {
2260           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2262           if (sb_width > 0)
2263             {
2264               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2265               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2266                                     * FRAME_COLUMN_WIDTH (f));
2268               if (bx < 0)
2269                 {
2270                   /* Bitmap fills the fringe.  */
2271                   if (bar_area_x + bar_area_width == p->x)
2272                     bx = bar_area_x + sb_width;
2273                   else if (p->x + p->wd == bar_area_x)
2274                     bx = bar_area_x;
2275                   if (bx >= 0)
2276                     {
2277                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2279                       nx = bar_area_width - sb_width;
2280                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2281                                                             row->y));
2282                       ny = row->visible_height;
2283                     }
2284                 }
2285               else
2286                 {
2287                   if (bar_area_x + bar_area_width == bx)
2288                     {
2289                       bx = bar_area_x + sb_width;
2290                       nx += bar_area_width - sb_width;
2291                     }
2292                   else if (bx + nx == bar_area_x)
2293                     nx += bar_area_width - sb_width;
2294                 }
2295             }
2296         }
2298       if (bx >= 0 && nx > 0)
2299         {
2300           NSRect r = NSMakeRect (bx, by, nx, ny);
2301           NSRectClip (r);
2302           [ns_lookup_indexed_color (face->background, f) set];
2303           NSRectFill (r);
2304         }
2305     }
2307   if (p->which)
2308     {
2309       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2310       EmacsImage *img = bimgs[p->which - 1];
2312       if (!img)
2313         {
2314           unsigned short *bits = p->bits + p->dh;
2315           int len = p->h;
2316           int i;
2317           unsigned char *cbits = xmalloc (len);
2319           for (i = 0; i < len; i++)
2320             cbits[i] = ~(bits[i] & 0xff);
2321           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2322                                            flip: NO];
2323           bimgs[p->which - 1] = img;
2324           xfree (cbits);
2325         }
2327       NSRectClip (r);
2328       /* Since we composite the bitmap instead of just blitting it, we need
2329          to erase the whole background. */
2330       [ns_lookup_indexed_color(face->background, f) set];
2331       NSRectFill (r);
2332       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2333 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2334       [img drawInRect: r
2335               fromRect: NSZeroRect
2336              operation: NSCompositeSourceOver
2337               fraction: 1.0
2338            respectFlipped: YES
2339                 hints: nil];
2340 #else
2341       {
2342         NSPoint pt = r.origin;
2343         pt.y += p->h;
2344         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2345       }
2346 #endif
2347     }
2348   ns_unfocus (f);
2352 static void
2353 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2354                        int x, int y, int cursor_type, int cursor_width,
2355                        int on_p, int active_p)
2356 /* --------------------------------------------------------------------------
2357      External call (RIF): draw cursor.
2358      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2359    -------------------------------------------------------------------------- */
2361   NSRect r, s;
2362   int fx, fy, h, cursor_height;
2363   struct frame *f = WINDOW_XFRAME (w);
2364   struct glyph *phys_cursor_glyph;
2365   int overspill;
2366   struct glyph *cursor_glyph;
2367   struct face *face;
2368   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2370   /* If cursor is out of bounds, don't draw garbage.  This can happen
2371      in mini-buffer windows when switching between echo area glyphs
2372      and mini-buffer.  */
2374   NSTRACE (dumpcursor);
2376   if (!on_p)
2377     return;
2379   w->phys_cursor_type = cursor_type;
2380   w->phys_cursor_on_p = on_p;
2382   if (cursor_type == NO_CURSOR)
2383     {
2384       w->phys_cursor_width = 0;
2385       return;
2386     }
2388   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2389     {
2390       if (glyph_row->exact_window_width_line_p
2391           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2392         {
2393           glyph_row->cursor_in_fringe_p = 1;
2394           draw_fringe_bitmap (w, glyph_row, 0);
2395         }
2396       return;
2397     }
2399   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2400      (other terminals do it the other way round).  We must set
2401      w->phys_cursor_width to the cursor width.  For bar cursors, that
2402      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2403   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2405   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2406      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2407   if (cursor_type == BAR_CURSOR)
2408     {
2409       if (cursor_width < 1)
2410         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2411       w->phys_cursor_width = cursor_width;
2412     }
2413   /* If we have an HBAR, "cursor_width" MAY specify height. */
2414   else if (cursor_type == HBAR_CURSOR)
2415     {
2416       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2417       fy += h - cursor_height;
2418       h = cursor_height;
2419     }
2421   r.origin.x = fx, r.origin.y = fy;
2422   r.size.height = h;
2423   r.size.width = w->phys_cursor_width;
2425   /* TODO: only needed in rare cases with last-resort font in HELLO..
2426      should we do this more efficiently? */
2427   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2430   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2431   if (face && NS_FACE_BACKGROUND (face)
2432       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2433     {
2434       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2435       hollow_color = FRAME_CURSOR_COLOR (f);
2436     }
2437   else
2438     [FRAME_CURSOR_COLOR (f) set];
2440 #ifdef NS_IMPL_COCOA
2441   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2442            atomic.  Cleaner ways of doing this should be investigated.
2443            One way would be to set a global variable DRAWING_CURSOR
2444            when making the call to draw_phys..(), don't focus in that
2445            case, then move the ns_unfocus() here after that call. */
2446   NSDisableScreenUpdates ();
2447 #endif
2449   switch (cursor_type)
2450     {
2451     case NO_CURSOR:
2452       break;
2453     case FILLED_BOX_CURSOR:
2454       NSRectFill (r);
2455       break;
2456     case HOLLOW_BOX_CURSOR:
2457       NSRectFill (r);
2458       [hollow_color set];
2459       NSRectFill (NSInsetRect (r, 1, 1));
2460       [FRAME_CURSOR_COLOR (f) set];
2461       break;
2462     case HBAR_CURSOR:
2463       NSRectFill (r);
2464       break;
2465     case BAR_CURSOR:
2466       s = r;
2467       /* If the character under cursor is R2L, draw the bar cursor
2468          on the right of its glyph, rather than on the left.  */
2469       cursor_glyph = get_phys_cursor_glyph (w);
2470       if ((cursor_glyph->resolved_level & 1) != 0)
2471         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2473       NSRectFill (s);
2474       break;
2475     }
2476   ns_unfocus (f);
2478   /* draw the character under the cursor */
2479   if (cursor_type != NO_CURSOR)
2480     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2482 #ifdef NS_IMPL_COCOA
2483   NSEnableScreenUpdates ();
2484 #endif
2489 static void
2490 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2491 /* --------------------------------------------------------------------------
2492      External (RIF): Draw a vertical line.
2493    -------------------------------------------------------------------------- */
2495   struct frame *f = XFRAME (WINDOW_FRAME (w));
2496   struct face *face;
2497   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2499   NSTRACE (ns_draw_vertical_window_border);
2501   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2502   if (face)
2503       [ns_lookup_indexed_color(face->foreground, f) set];
2505   ns_focus (f, &r, 1);
2506   NSRectFill(r);
2507   ns_unfocus (f);
2511 void
2512 show_hourglass (struct atimer *timer)
2514   if (hourglass_shown_p)
2515     return;
2517   block_input ();
2519   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2521   hourglass_shown_p = 1;
2522   unblock_input ();
2526 void
2527 hide_hourglass (void)
2529   if (!hourglass_shown_p)
2530     return;
2532   block_input ();
2534   /* TODO: remove NSProgressIndicator from all frames */
2536   hourglass_shown_p = 0;
2537   unblock_input ();
2542 /* ==========================================================================
2544     Glyph drawing operations
2546    ========================================================================== */
2548 static int
2549 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2550 /* --------------------------------------------------------------------------
2551     Wrapper utility to account for internal border width on full-width lines,
2552     and allow top full-width rows to hit the frame top.  nr should be pointer
2553     to two successive NSRects.  Number of rects actually used is returned.
2554    -------------------------------------------------------------------------- */
2556   int n = get_glyph_string_clip_rects (s, nr, 2);
2557   return n;
2560 /* --------------------------------------------------------------------
2561    Draw a wavy line under glyph string s. The wave fills wave_height
2562    pixels from y.
2564                     x          wave_length = 2
2565                                  --
2566                 y    *   *   *   *   *
2567                      |* * * * * * * * *
2568     wave_height = 3  | *   *   *   *
2569   --------------------------------------------------------------------- */
2571 static void
2572 ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2574   int wave_height = 3, wave_length = 2;
2575   int y, dx, dy, odd, xmax;
2576   NSPoint a, b;
2577   NSRect waveClip;
2579   dx = wave_length;
2580   dy = wave_height - 1;
2581   y =  s->ybase - wave_height + 3;
2582   xmax = x + width;
2584   /* Find and set clipping rectangle */
2585   waveClip = NSMakeRect (x, y, width, wave_height);
2586   [[NSGraphicsContext currentContext] saveGraphicsState];
2587   NSRectClip (waveClip);
2589   /* Draw the waves */
2590   a.x = x - ((int)(x) % dx) + 0.5;
2591   b.x = a.x + dx;
2592   odd = (int)(a.x/dx) % 2;
2593   a.y = b.y = y + 0.5;
2595   if (odd)
2596     a.y += dy;
2597   else
2598     b.y += dy;
2600   while (a.x <= xmax)
2601     {
2602       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2603       a.x = b.x, a.y = b.y;
2604       b.x += dx, b.y = y + 0.5 + odd*dy;
2605       odd = !odd;
2606     }
2608   /* Restore previous clipping rectangle(s) */
2609   [[NSGraphicsContext currentContext] restoreGraphicsState];
2614 void
2615 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2616                          NSColor *defaultCol, CGFloat width, CGFloat x)
2617 /* --------------------------------------------------------------------------
2618    Draw underline, overline, and strike-through on glyph string s.
2619    -------------------------------------------------------------------------- */
2621   if (s->for_overlaps)
2622     return;
2624   /* Do underline. */
2625   if (face->underline_p)
2626     {
2627       if (s->face->underline_type == FACE_UNDER_WAVE)
2628         {
2629           if (face->underline_defaulted_p)
2630             [defaultCol set];
2631           else
2632             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2634           ns_draw_underwave (s, width, x);
2635         }
2636       else if (s->face->underline_type == FACE_UNDER_LINE)
2637         {
2639           NSRect r;
2640           unsigned long thickness, position;
2642           /* If the prev was underlined, match its appearance. */
2643           if (s->prev && s->prev->face->underline_p
2644               && s->prev->face->underline_type == FACE_UNDER_LINE
2645               && s->prev->underline_thickness > 0)
2646             {
2647               thickness = s->prev->underline_thickness;
2648               position = s->prev->underline_position;
2649             }
2650           else
2651             {
2652               struct font *font;
2653               unsigned long descent;
2655               font=s->font;
2656               descent = s->y + s->height - s->ybase;
2658               /* Use underline thickness of font, defaulting to 1. */
2659               thickness = (font && font->underline_thickness > 0)
2660                 ? font->underline_thickness : 1;
2662               /* Determine the offset of underlining from the baseline. */
2663               if (x_underline_at_descent_line)
2664                 position = descent - thickness;
2665               else if (x_use_underline_position_properties
2666                        && font && font->underline_position >= 0)
2667                 position = font->underline_position;
2668               else if (font)
2669                 position = lround (font->descent / 2);
2670               else
2671                 position = underline_minimum_offset;
2673               position = max (position, underline_minimum_offset);
2675               /* Ensure underlining is not cropped. */
2676               if (descent <= position)
2677                 {
2678                   position = descent - 1;
2679                   thickness = 1;
2680                 }
2681               else if (descent < position + thickness)
2682                 thickness = 1;
2683             }
2685           s->underline_thickness = thickness;
2686           s->underline_position = position;
2688           r = NSMakeRect (x, s->ybase + position, width, thickness);
2690           if (face->underline_defaulted_p)
2691             [defaultCol set];
2692           else
2693             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2694           NSRectFill (r);
2695         }
2696     }
2697   /* Do overline. We follow other terms in using a thickness of 1
2698      and ignoring overline_margin. */
2699   if (face->overline_p)
2700     {
2701       NSRect r;
2702       r = NSMakeRect (x, s->y, width, 1);
2704       if (face->overline_color_defaulted_p)
2705         [defaultCol set];
2706       else
2707         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2708       NSRectFill (r);
2709     }
2711   /* Do strike-through.  We follow other terms for thickness and
2712      vertical position.*/
2713   if (face->strike_through_p)
2714     {
2715       NSRect r;
2716       unsigned long dy;
2718       dy = lrint ((s->height - 1) / 2);
2719       r = NSMakeRect (x, s->y + dy, width, 1);
2721       if (face->strike_through_color_defaulted_p)
2722         [defaultCol set];
2723       else
2724         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2725       NSRectFill (r);
2726     }
2729 static void
2730 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2731 /* --------------------------------------------------------------------------
2732     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2733     Note we can't just use an NSDrawRect command, because of the possibility
2734     of some sides not being drawn, and because the rect will be filled.
2735    -------------------------------------------------------------------------- */
2737   NSRect s = r;
2738   [col set];
2740   /* top, bottom */
2741   s.size.height = thickness;
2742   NSRectFill (s);
2743   s.origin.y += r.size.height - thickness;
2744   NSRectFill (s);
2746   s.size.height = r.size.height;
2747   s.origin.y = r.origin.y;
2749   /* left, right (optional) */
2750   s.size.width = thickness;
2751   if (left_p)
2752     NSRectFill (s);
2753   if (right_p)
2754     {
2755       s.origin.x += r.size.width - thickness;
2756       NSRectFill (s);
2757     }
2761 static void
2762 ns_draw_relief (NSRect r, int thickness, char raised_p,
2763                char top_p, char bottom_p, char left_p, char right_p,
2764                struct glyph_string *s)
2765 /* --------------------------------------------------------------------------
2766     Draw a relief rect inside r, optionally leaving some sides open.
2767     Note we can't just use an NSDrawBezel command, because of the possibility
2768     of some sides not being drawn, and because the rect will be filled.
2769    -------------------------------------------------------------------------- */
2771   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2772   NSColor *newBaseCol = nil;
2773   NSRect sr = r;
2775   NSTRACE (ns_draw_relief);
2777   /* set up colors */
2779   if (s->face->use_box_color_for_shadows_p)
2780     {
2781       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2782     }
2783 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2784            && s->img->pixmap
2785            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2786        {
2787          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2788        } */
2789   else
2790     {
2791       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2792     }
2794   if (newBaseCol == nil)
2795     newBaseCol = [NSColor grayColor];
2797   if (newBaseCol != baseCol)  /* TODO: better check */
2798     {
2799       [baseCol release];
2800       baseCol = [newBaseCol retain];
2801       [lightCol release];
2802       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2803       [darkCol release];
2804       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2805     }
2807   [(raised_p ? lightCol : darkCol) set];
2809   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2811   /* top */
2812   sr.size.height = thickness;
2813   if (top_p) NSRectFill (sr);
2815   /* left */
2816   sr.size.height = r.size.height;
2817   sr.size.width = thickness;
2818   if (left_p) NSRectFill (sr);
2820   [(raised_p ? darkCol : lightCol) set];
2822   /* bottom */
2823   sr.size.width = r.size.width;
2824   sr.size.height = thickness;
2825   sr.origin.y += r.size.height - thickness;
2826   if (bottom_p) NSRectFill (sr);
2828   /* right */
2829   sr.size.height = r.size.height;
2830   sr.origin.y = r.origin.y;
2831   sr.size.width = thickness;
2832   sr.origin.x += r.size.width - thickness;
2833   if (right_p) NSRectFill (sr);
2837 static void
2838 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2839 /* --------------------------------------------------------------------------
2840       Function modeled after x_draw_glyph_string_box ().
2841       Sets up parameters for drawing.
2842    -------------------------------------------------------------------------- */
2844   int right_x, last_x;
2845   char left_p, right_p;
2846   struct glyph *last_glyph;
2847   NSRect r;
2848   int thickness;
2849   struct face *face;
2851   if (s->hl == DRAW_MOUSE_FACE)
2852     {
2853       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2854       if (!face)
2855         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2856     }
2857   else
2858     face = s->face;
2860   thickness = face->box_line_width;
2862   NSTRACE (ns_dumpglyphs_box_or_relief);
2864   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2865             ? WINDOW_RIGHT_EDGE_X (s->w)
2866             : window_box_right (s->w, s->area));
2867   last_glyph = (s->cmp || s->img
2868                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2870   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2871               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2873   left_p = (s->first_glyph->left_box_line_p
2874             || (s->hl == DRAW_MOUSE_FACE
2875                 && (s->prev == NULL || s->prev->hl != s->hl)));
2876   right_p = (last_glyph->right_box_line_p
2877              || (s->hl == DRAW_MOUSE_FACE
2878                  && (s->next == NULL || s->next->hl != s->hl)));
2880   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2882   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2883   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2884     {
2885       ns_draw_box (r, abs (thickness),
2886                    ns_lookup_indexed_color (face->box_color, s->f),
2887                   left_p, right_p);
2888     }
2889   else
2890     {
2891       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2892                      1, 1, left_p, right_p, s);
2893     }
2897 static void
2898 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2899 /* --------------------------------------------------------------------------
2900       Modeled after x_draw_glyph_string_background, which draws BG in
2901       certain cases.  Others are left to the text rendering routine.
2902    -------------------------------------------------------------------------- */
2904   NSTRACE (ns_maybe_dumpglyphs_background);
2906   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2907     {
2908       int box_line_width = max (s->face->box_line_width, 0);
2909       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2910           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2911         {
2912           struct face *face;
2913           if (s->hl == DRAW_MOUSE_FACE)
2914             {
2915               face = FACE_FROM_ID (s->f,
2916                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2917               if (!face)
2918                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2919             }
2920           else
2921             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2922           if (!face->stipple)
2923             [(NS_FACE_BACKGROUND (face) != 0
2924               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2925               : FRAME_BACKGROUND_COLOR (s->f)) set];
2926           else
2927             {
2928               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2929               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2930             }
2932           if (s->hl != DRAW_CURSOR)
2933             {
2934               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2935                                     s->background_width,
2936                                     s->height-2*box_line_width);
2937               NSRectFill (r);
2938             }
2940           s->background_filled_p = 1;
2941         }
2942     }
2946 static void
2947 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2948 /* --------------------------------------------------------------------------
2949       Renders an image and associated borders.
2950    -------------------------------------------------------------------------- */
2952   EmacsImage *img = s->img->pixmap;
2953   int box_line_vwidth = max (s->face->box_line_width, 0);
2954   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2955   int bg_x, bg_y, bg_height;
2956   int th;
2957   char raised_p;
2958   NSRect br;
2959   struct face *face;
2960   NSColor *tdCol;
2962   NSTRACE (ns_dumpglyphs_image);
2964   if (s->face->box != FACE_NO_BOX
2965       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2966     x += abs (s->face->box_line_width);
2968   bg_x = x;
2969   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2970   bg_height = s->height;
2971   /* other terms have this, but was causing problems w/tabbar mode */
2972   /* - 2 * box_line_vwidth; */
2974   if (s->slice.x == 0) x += s->img->hmargin;
2975   if (s->slice.y == 0) y += s->img->vmargin;
2977   /* Draw BG: if we need larger area than image itself cleared, do that,
2978      otherwise, since we composite the image under NS (instead of mucking
2979      with its background color), we must clear just the image area. */
2980   if (s->hl == DRAW_MOUSE_FACE)
2981     {
2982       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2983       if (!face)
2984        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2985     }
2986   else
2987     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2989   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2991   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2992       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2993     {
2994       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2995       s->background_filled_p = 1;
2996     }
2997   else
2998     {
2999       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
3000     }
3002   NSRectFill (br);
3004   /* Draw the image.. do we need to draw placeholder if img ==nil? */
3005   if (img != nil)
3006     {
3007 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
3008       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
3009       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
3010                               s->slice.width, s->slice.height);
3011       [img drawInRect: dr
3012              fromRect: ir
3013              operation: NSCompositeSourceOver
3014               fraction: 1.0
3015            respectFlipped: YES
3016                 hints: nil];
3017 #else
3018       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3019                   operation: NSCompositeSourceOver];
3020 #endif
3021     }
3023   if (s->hl == DRAW_CURSOR)
3024     {
3025     [FRAME_CURSOR_COLOR (s->f) set];
3026     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3027       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3028     else
3029       /* Currently on NS img->mask is always 0. Since
3030          get_window_cursor_type specifies a hollow box cursor when on
3031          a non-masked image we never reach this clause. But we put it
3032          in in anticipation of better support for image masks on
3033          NS. */
3034       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3035     }
3036   else
3037     {
3038       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3039     }
3041   /* Draw underline, overline, strike-through. */
3042   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3044   /* Draw relief, if requested */
3045   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3046     {
3047       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3048         {
3049           th = tool_bar_button_relief >= 0 ?
3050             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3051           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3052         }
3053       else
3054         {
3055           th = abs (s->img->relief);
3056           raised_p = (s->img->relief > 0);
3057         }
3059       r.origin.x = x - th;
3060       r.origin.y = y - th;
3061       r.size.width = s->slice.width + 2*th-1;
3062       r.size.height = s->slice.height + 2*th-1;
3063       ns_draw_relief (r, th, raised_p,
3064                       s->slice.y == 0,
3065                       s->slice.y + s->slice.height == s->img->height,
3066                       s->slice.x == 0,
3067                       s->slice.x + s->slice.width == s->img->width, s);
3068     }
3070   /* If there is no mask, the background won't be seen,
3071      so draw a rectangle on the image for the cursor.
3072      Do this for all images, getting transparency right is not reliable.  */
3073   if (s->hl == DRAW_CURSOR)
3074     {
3075       int thickness = abs (s->img->relief);
3076       if (thickness == 0) thickness = 1;
3077       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3078     }
3082 static void
3083 ns_dumpglyphs_stretch (struct glyph_string *s)
3085   NSRect r[2];
3086   int n, i;
3087   struct face *face;
3088   NSColor *fgCol, *bgCol;
3090   if (!s->background_filled_p)
3091     {
3092       n = ns_get_glyph_string_clip_rect (s, r);
3093       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3095       ns_focus (s->f, r, n);
3097       if (s->hl == DRAW_MOUSE_FACE)
3098        {
3099          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3100          if (!face)
3101            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3102        }
3103       else
3104        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3106       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3107       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3109       for (i = 0; i < n; ++i)
3110         {
3111           if (!s->row->full_width_p)
3112             {
3113               int overrun, leftoverrun;
3115               /* truncate to avoid overwriting fringe and/or scrollbar */
3116               overrun = max (0, (s->x + s->background_width)
3117                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3118                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3119               r[i].size.width -= overrun;
3121               /* truncate to avoid overwriting to left of the window box */
3122               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3123                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3125               if (leftoverrun > 0)
3126                 {
3127                   r[i].origin.x += leftoverrun;
3128                   r[i].size.width -= leftoverrun;
3129                 }
3131               /* XXX: Try to work between problem where a stretch glyph on
3132                  a partially-visible bottom row will clear part of the
3133                  modeline, and another where list-buffers headers and similar
3134                  rows erroneously have visible_height set to 0.  Not sure
3135                  where this is coming from as other terms seem not to show. */
3136               r[i].size.height = min (s->height, s->row->visible_height);
3137             }
3139           [bgCol set];
3141           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3142              overwriting cursor (usually when cursor on a tab) */
3143           if (s->hl == DRAW_CURSOR)
3144             {
3145               CGFloat x, width;
3147               x = r[i].origin.x;
3148               width = s->w->phys_cursor_width;
3149               r[i].size.width -= width;
3150               r[i].origin.x += width;
3152               NSRectFill (r[i]);
3154               /* Draw overlining, etc. on the cursor. */
3155               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3156                 ns_draw_text_decoration (s, face, bgCol, width, x);
3157               else
3158                 ns_draw_text_decoration (s, face, fgCol, width, x);
3159             }
3160           else
3161             {
3162               NSRectFill (r[i]);
3163             }
3165           /* Draw overlining, etc. on the stretch glyph (or the part
3166              of the stretch glyph after the cursor). */
3167           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3168                                    r[i].origin.x);
3169         }
3170       ns_unfocus (s->f);
3171       s->background_filled_p = 1;
3172     }
3176 static void
3177 ns_draw_glyph_string (struct glyph_string *s)
3178 /* --------------------------------------------------------------------------
3179       External (RIF): Main draw-text call.
3180    -------------------------------------------------------------------------- */
3182   /* TODO (optimize): focus for box and contents draw */
3183   NSRect r[2];
3184   int n;
3185   char box_drawn_p = 0;
3187   NSTRACE (ns_draw_glyph_string);
3189   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3190     {
3191       int width;
3192       struct glyph_string *next;
3194       for (width = 0, next = s->next;
3195            next && width < s->right_overhang;
3196            width += next->width, next = next->next)
3197         if (next->first_glyph->type != IMAGE_GLYPH)
3198           {
3199             if (next->first_glyph->type != STRETCH_GLYPH)
3200               {
3201                 n = ns_get_glyph_string_clip_rect (s->next, r);
3202                 ns_focus (s->f, r, n);
3203                 ns_maybe_dumpglyphs_background (s->next, 1);
3204                 ns_unfocus (s->f);
3205               }
3206             else
3207               {
3208                 ns_dumpglyphs_stretch (s->next);
3209               }
3210             next->num_clips = 0;
3211           }
3212     }
3214   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3215         && (s->first_glyph->type == CHAR_GLYPH
3216             || s->first_glyph->type == COMPOSITE_GLYPH))
3217     {
3218       n = ns_get_glyph_string_clip_rect (s, r);
3219       ns_focus (s->f, r, n);
3220       ns_maybe_dumpglyphs_background (s, 1);
3221       ns_dumpglyphs_box_or_relief (s);
3222       ns_unfocus (s->f);
3223       box_drawn_p = 1;
3224     }
3226   switch (s->first_glyph->type)
3227     {
3229     case IMAGE_GLYPH:
3230       n = ns_get_glyph_string_clip_rect (s, r);
3231       ns_focus (s->f, r, n);
3232       ns_dumpglyphs_image (s, r[0]);
3233       ns_unfocus (s->f);
3234       break;
3236     case STRETCH_GLYPH:
3237       ns_dumpglyphs_stretch (s);
3238       break;
3240     case CHAR_GLYPH:
3241     case COMPOSITE_GLYPH:
3242       n = ns_get_glyph_string_clip_rect (s, r);
3243       ns_focus (s->f, r, n);
3245       if (s->for_overlaps || (s->cmp_from > 0
3246                               && ! s->first_glyph->u.cmp.automatic))
3247         s->background_filled_p = 1;
3248       else
3249         ns_maybe_dumpglyphs_background
3250           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3252       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3253                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3254                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3255                       NS_DUMPGLYPH_NORMAL));
3256       ns_tmp_font = (struct nsfont_info *)s->face->font;
3257       if (ns_tmp_font == NULL)
3258           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3260       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3261         {
3262           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3263           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3264           NS_FACE_FOREGROUND (s->face) = tmp;
3265         }
3267       ns_tmp_font->font.driver->draw
3268         (s, 0, s->nchars, s->x, s->y,
3269          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3270          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3272       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3273         {
3274           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3275           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3276           NS_FACE_FOREGROUND (s->face) = tmp;
3277         }
3279       ns_unfocus (s->f);
3280       break;
3282     case GLYPHLESS_GLYPH:
3283       n = ns_get_glyph_string_clip_rect (s, r);
3284       ns_focus (s->f, r, n);
3286       if (s->for_overlaps || (s->cmp_from > 0
3287                               && ! s->first_glyph->u.cmp.automatic))
3288         s->background_filled_p = 1;
3289       else
3290         ns_maybe_dumpglyphs_background
3291           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3292       /* ... */
3293       /* Not yet implemented.  */
3294       /* ... */
3295       ns_unfocus (s->f);
3296       break;
3298     default:
3299       emacs_abort ();
3300     }
3302   /* Draw box if not done already. */
3303   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3304     {
3305       n = ns_get_glyph_string_clip_rect (s, r);
3306       ns_focus (s->f, r, n);
3307       ns_dumpglyphs_box_or_relief (s);
3308       ns_unfocus (s->f);
3309     }
3311   s->num_clips = 0;
3316 /* ==========================================================================
3318     Event loop
3320    ========================================================================== */
3323 static void
3324 ns_send_appdefined (int value)
3325 /* --------------------------------------------------------------------------
3326     Internal: post an appdefined event which EmacsApp-sendEvent will
3327               recognize and take as a command to halt the event loop.
3328    -------------------------------------------------------------------------- */
3330   /*NSTRACE (ns_send_appdefined); */
3332   /* Only post this event if we haven't already posted one.  This will end
3333        the [NXApp run] main loop after having processed all events queued at
3334        this moment.  */
3335   if (send_appdefined)
3336     {
3337       NSEvent *nxev;
3339       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3340       send_appdefined = NO;
3342       /* Don't need wakeup timer any more */
3343       if (timed_entry)
3344         {
3345           [timed_entry invalidate];
3346           [timed_entry release];
3347           timed_entry = nil;
3348         }
3350       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3351                                 location: NSMakePoint (0, 0)
3352                            modifierFlags: 0
3353                                timestamp: 0
3354                             windowNumber: [[NSApp mainWindow] windowNumber]
3355                                  context: [NSApp context]
3356                                  subtype: 0
3357                                    data1: value
3358                                    data2: 0];
3360       /* Post an application defined event on the event queue.  When this is
3361          received the [NXApp run] will return, thus having processed all
3362          events which are currently queued.  */
3363       [NSApp postEvent: nxev atStart: NO];
3364     }
3367 #ifdef HAVE_NATIVE_FS
3368 static void
3369 check_native_fs ()
3371   Lisp_Object frame, tail;
3373   if (ns_last_use_native_fullscreen == ns_use_native_fullscreen)
3374     return;
3376   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
3378   /* Clear the mouse-moved flag for every frame on this display.  */
3379   FOR_EACH_FRAME (tail, frame)
3380     {
3381       struct frame *f = XFRAME (frame);
3382       if (FRAME_NS_P (f))
3383         {
3384           EmacsView *view = FRAME_NS_VIEW (f);
3385           [view updateCollectionBehaviour];
3386         }
3387     }
3389 #endif
3391 static int
3392 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3393 /* --------------------------------------------------------------------------
3394      External (hook): Post an event to ourself and keep reading events until
3395      we read it back again.  In effect process all events which were waiting.
3396      From 21+ we have to manage the event buffer ourselves.
3397    -------------------------------------------------------------------------- */
3399   struct input_event ev;
3400   int nevents;
3402 /* NSTRACE (ns_read_socket); */
3404 #ifdef HAVE_NATIVE_FS
3405   check_native_fs ();
3406 #endif
3408   if ([NSApp modalWindow] != nil)
3409     return -1;
3411   if (hold_event_q.nr > 0)
3412     {
3413       int i;
3414       for (i = 0; i < hold_event_q.nr; ++i)
3415         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3416       hold_event_q.nr = 0;
3417       return i;
3418     }
3420   block_input ();
3421   n_emacs_events_pending = 0;
3422   EVENT_INIT (ev);
3423   emacs_event = &ev;
3424   q_event_ptr = hold_quit;
3426   /* we manage autorelease pools by allocate/reallocate each time around
3427      the loop; strict nesting is occasionally violated but seems not to
3428      matter.. earlier methods using full nesting caused major memory leaks */
3429   [outerpool release];
3430   outerpool = [[NSAutoreleasePool alloc] init];
3432   /* If have pending open-file requests, attend to the next one of those. */
3433   if (ns_pending_files && [ns_pending_files count] != 0
3434       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3435     {
3436       [ns_pending_files removeObjectAtIndex: 0];
3437     }
3438   /* Deal with pending service requests. */
3439   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3440     && [(EmacsApp *)
3441          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3442                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3443     {
3444       [ns_pending_service_names removeObjectAtIndex: 0];
3445       [ns_pending_service_args removeObjectAtIndex: 0];
3446     }
3447   else
3448     {
3449       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3450          to ourself, otherwise [NXApp run] will never exit.  */
3451       send_appdefined = YES;
3452       ns_send_appdefined (-1);
3454       if (++apploopnr != 1)
3455         {
3456           emacs_abort ();
3457         }
3458       [NSApp run];
3459       --apploopnr;
3460     }
3462   nevents = n_emacs_events_pending;
3463   n_emacs_events_pending = 0;
3464   emacs_event = q_event_ptr = NULL;
3465   unblock_input ();
3467   return nevents;
3472 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3473            fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask)
3474 /* --------------------------------------------------------------------------
3475      Replacement for select, checking for events
3476    -------------------------------------------------------------------------- */
3478   int result;
3479   int t, k, nr = 0;
3480   struct input_event event;
3481   char c;
3483 /*  NSTRACE (ns_select); */
3485 #ifdef HAVE_NATIVE_FS
3486   check_native_fs ();
3487 #endif
3489   if (hold_event_q.nr > 0)
3490     {
3491       /* We already have events pending. */
3492       raise (SIGIO);
3493       errno = EINTR;
3494       return -1;
3495     }
3497   for (k = 0; k < nfds+1; k++)
3498     {
3499       if (readfds && FD_ISSET(k, readfds)) ++nr;
3500       if (writefds && FD_ISSET(k, writefds)) ++nr;
3501     }
3503   if (NSApp == nil
3504       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3505     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3507   [outerpool release];
3508   outerpool = [[NSAutoreleasePool alloc] init];
3511   send_appdefined = YES;
3512   if (nr > 0)
3513     {
3514       pthread_mutex_lock (&select_mutex);
3515       select_nfds = nfds;
3516       select_valid = 0;
3517       if (readfds)
3518         {
3519           select_readfds = *readfds;
3520           select_valid += SELECT_HAVE_READ;
3521         }
3522       if (writefds)
3523         {
3524           select_writefds = *writefds;
3525           select_valid += SELECT_HAVE_WRITE;
3526         }
3528       if (timeout)
3529         {
3530           select_timeout = *timeout;
3531           select_valid += SELECT_HAVE_TMO;
3532         }
3534       pthread_mutex_unlock (&select_mutex);
3536       /* Inform fd_handler that select should be called */
3537       c = 'g';
3538       emacs_write (selfds[1], &c, 1);
3539     }
3540   else if (nr == 0 && timeout)
3541     {
3542       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3543       double time = EMACS_TIME_TO_DOUBLE (*timeout);
3544       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3545                                                       target: NSApp
3546                                                     selector:
3547                                   @selector (timeout_handler:)
3548                                                     userInfo: 0
3549                                                      repeats: NO]
3550                       retain];
3551     }
3552   else /* No timeout and no file descriptors, can this happen?  */
3553     {
3554       /* Send appdefined so we exit from the loop */
3555       ns_send_appdefined (-1);
3556     }
3558   EVENT_INIT (event);
3559   block_input ();
3560   emacs_event = &event;
3561   if (++apploopnr != 1)
3562     {
3563       emacs_abort ();
3564     }
3565   [NSApp run];
3566   --apploopnr;
3567   emacs_event = NULL;
3568   if (nr > 0 && readfds)
3569     {
3570       c = 's';
3571       emacs_write (selfds[1], &c, 1);
3572     }
3573   unblock_input ();
3575   t = last_appdefined_event_data;
3577   if (t != NO_APPDEFINED_DATA)
3578     {
3579       last_appdefined_event_data = NO_APPDEFINED_DATA;
3581       if (t == -2)
3582         {
3583           /* The NX_APPDEFINED event we received was a timeout. */
3584           result = 0;
3585         }
3586       else if (t == -1)
3587         {
3588           /* The NX_APPDEFINED event we received was the result of
3589              at least one real input event arriving.  */
3590           errno = EINTR;
3591           result = -1;
3592         }
3593       else
3594         {
3595           /* Received back from select () in fd_handler; copy the results */
3596           pthread_mutex_lock (&select_mutex);
3597           if (readfds) *readfds = select_readfds;
3598           if (writefds) *writefds = select_writefds;
3599           if (timeout) *timeout = select_timeout;
3600           pthread_mutex_unlock (&select_mutex);
3601           result = t;
3602         }
3603     }
3604   else
3605     {
3606       errno = EINTR;
3607       result = -1;
3608     }
3610   return result;
3615 /* ==========================================================================
3617     Scrollbar handling
3619    ========================================================================== */
3622 static void
3623 ns_set_vertical_scroll_bar (struct window *window,
3624                            int portion, int whole, int position)
3625 /* --------------------------------------------------------------------------
3626       External (hook): Update or add scrollbar
3627    -------------------------------------------------------------------------- */
3629   Lisp_Object win;
3630   NSRect r, v;
3631   struct frame *f = XFRAME (WINDOW_FRAME (window));
3632   EmacsView *view = FRAME_NS_VIEW (f);
3633   int window_y, window_height;
3634   int top, left, height, width, sb_width, sb_left;
3635   EmacsScroller *bar;
3636   BOOL fringe_extended_p;
3638   /* optimization; display engine sends WAY too many of these.. */
3639   if (!NILP (window->vertical_scroll_bar))
3640     {
3641       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3642       if ([bar checkSamePosition: position portion: portion whole: whole])
3643         {
3644           if (view->scrollbarsNeedingUpdate == 0)
3645             {
3646               if (!windows_or_buffers_changed)
3647                   return;
3648             }
3649           else
3650             view->scrollbarsNeedingUpdate--;
3651         }
3652     }
3654   NSTRACE (ns_set_vertical_scroll_bar);
3656   /* Get dimensions.  */
3657   window_box (window, -1, 0, &window_y, 0, &window_height);
3658   top = window_y;
3659   height = window_height;
3660   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3661   left = WINDOW_SCROLL_BAR_AREA_X (window);
3663   /* allow for displaying a skinnier scrollbar than char area allotted */
3664   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3665     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3666   sb_left = left;
3668   r = NSMakeRect (sb_left, top, sb_width, height);
3669   /* the parent view is flipped, so we need to flip y value */
3670   v = [view frame];
3671   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3673   if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (window))
3674     fringe_extended_p = (WINDOW_LEFTMOST_P (window)
3675                          && WINDOW_LEFT_FRINGE_WIDTH (window)
3676                          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3677                              || WINDOW_LEFT_MARGIN_COLS (window) == 0));
3678   else
3679     fringe_extended_p = (WINDOW_RIGHTMOST_P (window)
3680                          && WINDOW_RIGHT_FRINGE_WIDTH (window)
3681                          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3682                              || WINDOW_RIGHT_MARGIN_COLS (window) == 0));
3684   XSETWINDOW (win, window);
3685   block_input ();
3687   /* we want at least 5 lines to display a scrollbar */
3688   if (WINDOW_TOTAL_LINES (window) < 5)
3689     {
3690       if (!NILP (window->vertical_scroll_bar))
3691         {
3692           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3693           [bar removeFromSuperview];
3694           wset_vertical_scroll_bar (window, Qnil);
3695         }
3696       ns_clear_frame_area (f, sb_left, top, width, height);
3697       unblock_input ();
3698       return;
3699     }
3701   if (NILP (window->vertical_scroll_bar))
3702     {
3703       if (width > 0 && height > 0)
3704         {
3705           if (fringe_extended_p)
3706             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3707           else
3708             ns_clear_frame_area (f, left, top, width, height);
3709         }
3711       bar = [[EmacsScroller alloc] initFrame: r window: win];
3712       wset_vertical_scroll_bar (window, make_save_pointer (bar));
3713     }
3714   else
3715     {
3716       NSRect oldRect;
3717       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3718       oldRect = [bar frame];
3719       r.size.width = oldRect.size.width;
3720       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3721         {
3722           if (oldRect.origin.x != r.origin.x)
3723               ns_clear_frame_area (f, sb_left, top, width, height);
3724           [bar setFrame: r];
3725         }
3726     }
3728   [bar setPosition: position portion: portion whole: whole];
3729   unblock_input ();
3733 static void
3734 ns_condemn_scroll_bars (struct frame *f)
3735 /* --------------------------------------------------------------------------
3736      External (hook): arrange for all frame's scrollbars to be removed
3737      at next call to judge_scroll_bars, except for those redeemed.
3738    -------------------------------------------------------------------------- */
3740   int i;
3741   id view;
3742   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3744   NSTRACE (ns_condemn_scroll_bars);
3746   for (i =[subviews count]-1; i >= 0; i--)
3747     {
3748       view = [subviews objectAtIndex: i];
3749       if ([view isKindOfClass: [EmacsScroller class]])
3750         [view condemn];
3751     }
3755 static void
3756 ns_redeem_scroll_bar (struct window *window)
3757 /* --------------------------------------------------------------------------
3758      External (hook): arrange to spare this window's scrollbar
3759      at next call to judge_scroll_bars.
3760    -------------------------------------------------------------------------- */
3762   id bar;
3763   NSTRACE (ns_redeem_scroll_bar);
3764   if (!NILP (window->vertical_scroll_bar))
3765     {
3766       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3767       [bar reprieve];
3768     }
3772 static void
3773 ns_judge_scroll_bars (struct frame *f)
3774 /* --------------------------------------------------------------------------
3775      External (hook): destroy all scrollbars on frame that weren't
3776      redeemed after call to condemn_scroll_bars.
3777    -------------------------------------------------------------------------- */
3779   int i;
3780   id view;
3781   EmacsView *eview = FRAME_NS_VIEW (f);
3782   NSArray *subviews = [[eview superview] subviews];
3783   BOOL removed = NO;
3785   NSTRACE (ns_judge_scroll_bars);
3786   for (i = [subviews count]-1; i >= 0; --i)
3787     {
3788       view = [subviews objectAtIndex: i];
3789       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3790       [view judge];
3791       removed = YES;
3792     }
3794   if (removed)
3795     [eview updateFrameSize: NO];
3799 void
3800 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3802   /* XXX irrelevant under NS */
3807 /* ==========================================================================
3809     Initialization
3811    ========================================================================== */
3814 x_display_pixel_height (struct ns_display_info *dpyinfo)
3816   NSScreen *screen = [NSScreen mainScreen];
3817   return [screen frame].size.height;
3821 x_display_pixel_width (struct ns_display_info *dpyinfo)
3823   NSScreen *screen = [NSScreen mainScreen];
3824   return [screen frame].size.width;
3828 static Lisp_Object ns_string_to_lispmod (const char *s)
3829 /* --------------------------------------------------------------------------
3830      Convert modifier name to lisp symbol
3831    -------------------------------------------------------------------------- */
3833   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3834     return Qmeta;
3835   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3836     return Qsuper;
3837   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3838     return Qcontrol;
3839   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3840     return Qalt;
3841   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3842     return Qhyper;
3843   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3844     return Qnone;
3845   else
3846     return Qnil;
3850 static void
3851 ns_default (const char *parameter, Lisp_Object *result,
3852            Lisp_Object yesval, Lisp_Object noval,
3853            BOOL is_float, BOOL is_modstring)
3854 /* --------------------------------------------------------------------------
3855       Check a parameter value in user's preferences
3856    -------------------------------------------------------------------------- */
3858   const char *value = ns_get_defaults_value (parameter);
3860   if (value)
3861     {
3862       double f;
3863       char *pos;
3864       if (c_strcasecmp (value, "YES") == 0)
3865         *result = yesval;
3866       else if (c_strcasecmp (value, "NO") == 0)
3867         *result = noval;
3868       else if (is_float && (f = strtod (value, &pos), pos != value))
3869         *result = make_float (f);
3870       else if (is_modstring && value)
3871         *result = ns_string_to_lispmod (value);
3872       else fprintf (stderr,
3873                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3874     }
3878 static void
3879 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3880 /* --------------------------------------------------------------------------
3881       Initialize global info and storage for display.
3882    -------------------------------------------------------------------------- */
3884     NSScreen *screen = [NSScreen mainScreen];
3885     NSWindowDepth depth = [screen depth];
3886     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3888     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3889     dpyinfo->resy = 72.27;
3890     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3891                                                   NSColorSpaceFromDepth (depth)]
3892                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3893                                                  NSColorSpaceFromDepth (depth)];
3894     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3895     dpyinfo->image_cache = make_image_cache ();
3896     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3897     dpyinfo->color_table->colors = NULL;
3898     dpyinfo->root_window = 42; /* a placeholder.. */
3900     hlinfo->mouse_face_mouse_frame = NULL;
3901     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3902     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3903     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3904     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3905     hlinfo->mouse_face_hidden = 0;
3907     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3908     hlinfo->mouse_face_defer = 0;
3910     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3912     dpyinfo->n_fonts = 0;
3913     dpyinfo->smallest_font_height = 1;
3914     dpyinfo->smallest_char_width = 1;
3918 /* This and next define (many of the) public functions in this file. */
3919 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3920          with using despite presence in the "system dependent" redisplay
3921          interface.  In addition, many of the ns_ methods have code that is
3922          shared with all terms, indicating need for further refactoring. */
3923 extern frame_parm_handler ns_frame_parm_handlers[];
3924 static struct redisplay_interface ns_redisplay_interface =
3926   ns_frame_parm_handlers,
3927   x_produce_glyphs,
3928   x_write_glyphs,
3929   x_insert_glyphs,
3930   x_clear_end_of_line,
3931   ns_scroll_run,
3932   ns_after_update_window_line,
3933   ns_update_window_begin,
3934   ns_update_window_end,
3935   x_cursor_to,
3936   ns_flush,
3937   0, /* flush_display_optional */
3938   x_clear_window_mouse_face,
3939   x_get_glyph_overhangs,
3940   x_fix_overlapping_area,
3941   ns_draw_fringe_bitmap,
3942   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3943   0, /* destroy_fringe_bitmap */
3944   ns_compute_glyph_string_overhangs,
3945   ns_draw_glyph_string, /* interface to nsfont.m */
3946   ns_define_frame_cursor,
3947   ns_clear_frame_area,
3948   ns_draw_window_cursor,
3949   ns_draw_vertical_window_border,
3950   ns_shift_glyphs_for_insert
3954 static void
3955 ns_delete_display (struct ns_display_info *dpyinfo)
3957   /* TODO... */
3961 /* This function is called when the last frame on a display is deleted. */
3962 static void
3963 ns_delete_terminal (struct terminal *terminal)
3965   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3967   /* Protect against recursive calls.  delete_frame in
3968      delete_terminal calls us back when it deletes our last frame.  */
3969   if (!terminal->name)
3970     return;
3972   block_input ();
3974   x_destroy_all_bitmaps (dpyinfo);
3975   ns_delete_display (dpyinfo);
3976   unblock_input ();
3980 static struct terminal *
3981 ns_create_terminal (struct ns_display_info *dpyinfo)
3982 /* --------------------------------------------------------------------------
3983       Set up use of NS before we make the first connection.
3984    -------------------------------------------------------------------------- */
3986   struct terminal *terminal;
3988   NSTRACE (ns_create_terminal);
3990   terminal = create_terminal ();
3992   terminal->type = output_ns;
3993   terminal->display_info.ns = dpyinfo;
3994   dpyinfo->terminal = terminal;
3996   terminal->rif = &ns_redisplay_interface;
3998   terminal->clear_frame_hook = ns_clear_frame;
3999   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
4000   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
4001   terminal->ring_bell_hook = ns_ring_bell;
4002   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
4003   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
4004   terminal->update_begin_hook = ns_update_begin;
4005   terminal->update_end_hook = ns_update_end;
4006   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
4007   terminal->read_socket_hook = ns_read_socket;
4008   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
4009   terminal->mouse_position_hook = ns_mouse_position;
4010   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
4011   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
4013   terminal->fullscreen_hook = ns_fullscreen_hook;
4015   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
4016   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
4017   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
4018   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
4020   terminal->delete_frame_hook = x_destroy_window;
4021   terminal->delete_terminal_hook = ns_delete_terminal;
4023   terminal->scroll_region_ok = 1;
4024   terminal->char_ins_del_ok = 1;
4025   terminal->line_ins_del_ok = 1;
4026   terminal->fast_clear_end_of_line = 1;
4027   terminal->memory_below_frame = 0;
4029   return terminal;
4033 struct ns_display_info *
4034 ns_term_init (Lisp_Object display_name)
4035 /* --------------------------------------------------------------------------
4036      Start the Application and get things rolling.
4037    -------------------------------------------------------------------------- */
4039   struct terminal *terminal;
4040   struct ns_display_info *dpyinfo;
4041   static int ns_initialized = 0;
4042   Lisp_Object tmp;
4044   if (ns_initialized) return x_display_list;
4045   ns_initialized = 1;
4047   NSTRACE (ns_term_init);
4049   [outerpool release];
4050   outerpool = [[NSAutoreleasePool alloc] init];
4052   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
4053   /*GSDebugAllocationActive (YES); */
4054   block_input ();
4056   baud_rate = 38400;
4057   Fset_input_interrupt_mode (Qnil);
4059   if (selfds[0] == -1)
4060     {
4061       if (pipe (selfds) == -1)
4062         {
4063           fprintf (stderr, "Failed to create pipe: %s\n",
4064                    emacs_strerror (errno));
4065           emacs_abort ();
4066         }
4068       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4069       FD_ZERO (&select_readfds);
4070       FD_ZERO (&select_writefds);
4071       pthread_mutex_init (&select_mutex, NULL);
4072     }
4074   ns_pending_files = [[NSMutableArray alloc] init];
4075   ns_pending_service_names = [[NSMutableArray alloc] init];
4076   ns_pending_service_args = [[NSMutableArray alloc] init];
4078 /* Start app and create the main menu, window, view.
4079      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4080      The view will then ask the NSApp to stop and return to Emacs. */
4081   [EmacsApp sharedApplication];
4082   if (NSApp == nil)
4083     return NULL;
4084   [NSApp setDelegate: NSApp];
4086   /* Start the select thread.  */
4087   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4088                            toTarget:NSApp
4089                          withObject:nil];
4091   /* debugging: log all notifications */
4092   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4093                                          selector: @selector (logNotification:)
4094                                              name: nil object: nil]; */
4096   dpyinfo = xzalloc (sizeof *dpyinfo);
4098   ns_initialize_display_info (dpyinfo);
4099   terminal = ns_create_terminal (dpyinfo);
4101   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4102   init_kboard (terminal->kboard);
4103   kset_window_system (terminal->kboard, Qns);
4104   terminal->kboard->next_kboard = all_kboards;
4105   all_kboards = terminal->kboard;
4106   /* Don't let the initial kboard remain current longer than necessary.
4107      That would cause problems if a file loaded on startup tries to
4108      prompt in the mini-buffer.  */
4109   if (current_kboard == initial_kboard)
4110     current_kboard = terminal->kboard;
4111   terminal->kboard->reference_count++;
4113   dpyinfo->next = x_display_list;
4114   x_display_list = dpyinfo;
4116   /* Put it on ns_display_name_list */
4117   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4118                                 ns_display_name_list);
4119   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4121   terminal->name = xstrdup (SSDATA (display_name));
4123   unblock_input ();
4125   if (!inhibit_x_resources)
4126     {
4127       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4128                  Qt, Qnil, NO, NO);
4129       tmp = Qnil;
4130       /* this is a standard variable */
4131       ns_default ("AppleAntiAliasingThreshold", &tmp,
4132                  make_float (10.0), make_float (6.0), YES, NO);
4133       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4134     }
4136   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4137                          stringForKey: @"AppleHighlightColor"];
4138   if (ns_selection_color == nil)
4139     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4141   {
4142     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4144     if ( cl == nil )
4145       {
4146         Lisp_Object color_file, color_map, color;
4147         unsigned long c;
4148         char *name;
4150         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4151                          Fsymbol_value (intern ("data-directory")));
4153         color_map = Fx_load_color_file (color_file);
4154         if (NILP (color_map))
4155           fatal ("Could not read %s.\n", SDATA (color_file));
4157         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4158         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4159           {
4160             color = XCAR (color_map);
4161             name = SSDATA (XCAR (color));
4162             c = XINT (XCDR (color));
4163             [cl setColor:
4164                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4165                                             green: GREEN_FROM_ULONG (c) / 255.0
4166                                              blue: BLUE_FROM_ULONG (c) / 255.0
4167                                             alpha: 1.0]
4168                   forKey: [NSString stringWithUTF8String: name]];
4169           }
4170         [cl writeToFile: nil];
4171       }
4172   }
4174   {
4175 #ifdef NS_IMPL_GNUSTEP
4176     Vwindow_system_version = build_string (gnustep_base_version);
4177 #else
4178     /*PSnextrelease (128, c); */
4179     char c[DBL_BUFSIZE_BOUND];
4180     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4181     Vwindow_system_version = make_unibyte_string (c, len);
4182 #endif
4183   }
4185   delete_keyboard_wait_descriptor (0);
4187   ns_app_name = [[NSProcessInfo processInfo] processName];
4189 /* Set up OS X app menu */
4190 #ifdef NS_IMPL_COCOA
4191   {
4192     NSMenu *appMenu;
4193     NSMenuItem *item;
4194     /* set up the application menu */
4195     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4196     [svcsMenu setAutoenablesItems: NO];
4197     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4198     [appMenu setAutoenablesItems: NO];
4199     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4200     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4202     [appMenu insertItemWithTitle: @"About Emacs"
4203                           action: @selector (orderFrontStandardAboutPanel:)
4204                    keyEquivalent: @""
4205                          atIndex: 0];
4206     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4207     [appMenu insertItemWithTitle: @"Preferences..."
4208                           action: @selector (showPreferencesWindow:)
4209                    keyEquivalent: @","
4210                          atIndex: 2];
4211     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4212     item = [appMenu insertItemWithTitle: @"Services"
4213                                  action: @selector (menuDown:)
4214                           keyEquivalent: @""
4215                                 atIndex: 4];
4216     [appMenu setSubmenu: svcsMenu forItem: item];
4217     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4218     [appMenu insertItemWithTitle: @"Hide Emacs"
4219                           action: @selector (hide:)
4220                    keyEquivalent: @"h"
4221                          atIndex: 6];
4222     item =  [appMenu insertItemWithTitle: @"Hide Others"
4223                           action: @selector (hideOtherApplications:)
4224                    keyEquivalent: @"h"
4225                          atIndex: 7];
4226     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4227     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4228     [appMenu insertItemWithTitle: @"Quit Emacs"
4229                           action: @selector (terminate:)
4230                    keyEquivalent: @"q"
4231                          atIndex: 9];
4233     item = [mainMenu insertItemWithTitle: ns_app_name
4234                                   action: @selector (menuDown:)
4235                            keyEquivalent: @""
4236                                  atIndex: 0];
4237     [mainMenu setSubmenu: appMenu forItem: item];
4238     [dockMenu insertItemWithTitle: @"New Frame"
4239                            action: @selector (newFrame:)
4240                     keyEquivalent: @""
4241                           atIndex: 0];
4243     [NSApp setMainMenu: mainMenu];
4244     [NSApp setAppleMenu: appMenu];
4245     [NSApp setServicesMenu: svcsMenu];
4246     /* Needed at least on Cocoa, to get dock menu to show windows */
4247     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4249     [[NSNotificationCenter defaultCenter]
4250       addObserver: mainMenu
4251          selector: @selector (trackingNotification:)
4252              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4253     [[NSNotificationCenter defaultCenter]
4254       addObserver: mainMenu
4255          selector: @selector (trackingNotification:)
4256              name: NSMenuDidEndTrackingNotification object: mainMenu];
4257   }
4258 #endif /* MAC OS X menu setup */
4260   /* Register our external input/output types, used for determining
4261      applicable services and also drag/drop eligibility. */
4262   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4263   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4264                       retain];
4265   ns_drag_types = [[NSArray arrayWithObjects:
4266                             NSStringPboardType,
4267                             NSTabularTextPboardType,
4268                             NSFilenamesPboardType,
4269                             NSURLPboardType,
4270                             NSColorPboardType,
4271                             NSFontPboardType, nil] retain];
4273   /* If fullscreen is in init/default-frame-alist, focus isn't set
4274      right for fullscreen windows, so set this.  */
4275   [NSApp activateIgnoringOtherApps:YES];
4277   [NSApp run];
4278   ns_do_open_file = YES;
4279   return dpyinfo;
4283 void
4284 ns_term_shutdown (int sig)
4286   [[NSUserDefaults standardUserDefaults] synchronize];
4288   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4289   if (STRINGP (Vauto_save_list_file_name))
4290     unlink (SSDATA (Vauto_save_list_file_name));
4292   if (sig == 0 || sig == SIGTERM)
4293     {
4294       [NSApp terminate: NSApp];
4295     }
4296   else // force a stack trace to happen
4297     {
4298       emacs_abort ();
4299     }
4303 /* ==========================================================================
4305     EmacsApp implementation
4307    ========================================================================== */
4310 @implementation EmacsApp
4312 - (void)logNotification: (NSNotification *)notification
4314   const char *name = [[notification name] UTF8String];
4315   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4316       && !strstr (name, "WindowNumber"))
4317     NSLog (@"notification: '%@'", [notification name]);
4321 - (void)sendEvent: (NSEvent *)theEvent
4322 /* --------------------------------------------------------------------------
4323      Called when NSApp is running for each event received.  Used to stop
4324      the loop when we choose, since there's no way to just run one iteration.
4325    -------------------------------------------------------------------------- */
4327   int type = [theEvent type];
4328   NSWindow *window = [theEvent window];
4329 /*  NSTRACE (sendEvent); */
4330 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4332 #ifdef NS_IMPL_COCOA
4333   if (type == NSApplicationDefined
4334       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4335     {
4336       ns_run_ascript ();
4337       [self stop: self];
4338       return;
4339     }
4340 #endif
4342   if (type == NSCursorUpdate && window == nil)
4343     {
4344       fprintf (stderr, "Dropping external cursor update event.\n");
4345       return;
4346     }
4348   if (type == NSApplicationDefined)
4349     {
4350       /* Events posted by ns_send_appdefined interrupt the run loop here.
4351          But, if a modal window is up, an appdefined can still come through,
4352          (e.g., from a makeKeyWindow event) but stopping self also stops the
4353          modal loop. Just defer it until later. */
4354       if ([NSApp modalWindow] == nil)
4355         {
4356           last_appdefined_event_data = [theEvent data1];
4357           [self stop: self];
4358         }
4359       else
4360         {
4361           send_appdefined = YES;
4362         }
4363     }
4365   [super sendEvent: theEvent];
4369 - (void)showPreferencesWindow: (id)sender
4371   struct frame *emacsframe = SELECTED_FRAME ();
4372   NSEvent *theEvent = [NSApp currentEvent];
4374   if (!emacs_event)
4375     return;
4376   emacs_event->kind = NS_NONKEY_EVENT;
4377   emacs_event->code = KEY_NS_SHOW_PREFS;
4378   emacs_event->modifiers = 0;
4379   EV_TRAILER (theEvent);
4383 - (void)newFrame: (id)sender
4385   struct frame *emacsframe = SELECTED_FRAME ();
4386   NSEvent *theEvent = [NSApp currentEvent];
4388   if (!emacs_event)
4389     return;
4390   emacs_event->kind = NS_NONKEY_EVENT;
4391   emacs_event->code = KEY_NS_NEW_FRAME;
4392   emacs_event->modifiers = 0;
4393   EV_TRAILER (theEvent);
4397 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4398 - (BOOL) openFile: (NSString *)fileName
4400   struct frame *emacsframe = SELECTED_FRAME ();
4401   NSEvent *theEvent = [NSApp currentEvent];
4403   if (!emacs_event)
4404     return NO;
4406   emacs_event->kind = NS_NONKEY_EVENT;
4407   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4408   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4409   ns_input_line = Qnil; /* can be start or cons start,end */
4410   emacs_event->modifiers =0;
4411   EV_TRAILER (theEvent);
4413   return YES;
4417 /* **************************************************************************
4419       EmacsApp delegate implementation
4421    ************************************************************************** */
4423 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4424 /* --------------------------------------------------------------------------
4425      When application is loaded, terminate event loop in ns_term_init
4426    -------------------------------------------------------------------------- */
4428   NSTRACE (applicationDidFinishLaunching);
4429   [NSApp setServicesProvider: NSApp];
4430   ns_send_appdefined (-2);
4434 /* Termination sequences:
4435     C-x C-c:
4436     Cmd-Q:
4437     MenuBar | File | Exit:
4438     Select Quit from App menubar:
4439         -terminate
4440         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4441         ns_term_shutdown()
4443     Select Quit from Dock menu:
4444     Logout attempt:
4445         -appShouldTerminate
4446           Cancel -> Nothing else
4447           Accept ->
4449           -terminate
4450           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4451           ns_term_shutdown()
4455 - (void) terminate: (id)sender
4457   struct frame *emacsframe = SELECTED_FRAME ();
4459   if (!emacs_event)
4460     return;
4462   emacs_event->kind = NS_NONKEY_EVENT;
4463   emacs_event->code = KEY_NS_POWER_OFF;
4464   emacs_event->arg = Qt; /* mark as non-key event */
4465   EV_TRAILER ((id)nil);
4469 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4471   int ret;
4473   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4474     return NSTerminateNow;
4476     ret = NSRunAlertPanel(ns_app_name,
4477                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4478                           @"Save Buffers and Exit", @"Cancel", nil);
4480     if (ret == NSAlertDefaultReturn)
4481         return NSTerminateNow;
4482     else if (ret == NSAlertAlternateReturn)
4483         return NSTerminateCancel;
4484     return NSTerminateNow;  /* just in case */
4487 static int
4488 not_in_argv (NSString *arg)
4490   int k;
4491   const char *a = [arg UTF8String];
4492   for (k = 1; k < initial_argc; ++k)
4493     if (strcmp (a, initial_argv[k]) == 0) return 0;
4494   return 1;
4497 /*   Notification from the Workspace to open a file */
4498 - (BOOL)application: sender openFile: (NSString *)file
4500   if (ns_do_open_file || not_in_argv (file))
4501     [ns_pending_files addObject: file];
4502   return YES;
4506 /*   Open a file as a temporary file */
4507 - (BOOL)application: sender openTempFile: (NSString *)file
4509   if (ns_do_open_file || not_in_argv (file))
4510     [ns_pending_files addObject: file];
4511   return YES;
4515 /*   Notification from the Workspace to open a file noninteractively (?) */
4516 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4518   if (ns_do_open_file || not_in_argv (file))
4519     [ns_pending_files addObject: file];
4520   return YES;
4523 /*   Notification from the Workspace to open multiple files */
4524 - (void)application: sender openFiles: (NSArray *)fileList
4526   NSEnumerator *files = [fileList objectEnumerator];
4527   NSString *file;
4528   /* Don't open files from the command line unconditionally,
4529      Cocoa parses the command line wrong, --option value tries to open value
4530      if --option is the last option.  */
4531   while ((file = [files nextObject]) != nil)
4532     if (ns_do_open_file || not_in_argv (file))
4533       [ns_pending_files addObject: file];
4535   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4540 /* Handle dock menu requests.  */
4541 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4543   return dockMenu;
4547 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4548 - (void)applicationWillBecomeActive: (NSNotification *)notification
4550   //ns_app_active=YES;
4552 - (void)applicationDidBecomeActive: (NSNotification *)notification
4554   NSTRACE (applicationDidBecomeActive);
4556   //ns_app_active=YES;
4558   ns_update_auto_hide_menu_bar ();
4559   // No constraining takes place when the application is not active.
4560   ns_constrain_all_frames ();
4562 - (void)applicationDidResignActive: (NSNotification *)notification
4564   //ns_app_active=NO;
4565   ns_send_appdefined (-1);
4570 /* ==========================================================================
4572     EmacsApp aux handlers for managing event loop
4574    ========================================================================== */
4577 - (void)timeout_handler: (NSTimer *)timedEntry
4578 /* --------------------------------------------------------------------------
4579      The timeout specified to ns_select has passed.
4580    -------------------------------------------------------------------------- */
4582   /*NSTRACE (timeout_handler); */
4583   ns_send_appdefined (-2);
4586 - (void)fd_handler:(id)unused
4587 /* --------------------------------------------------------------------------
4588      Check data waiting on file descriptors and terminate if so
4589    -------------------------------------------------------------------------- */
4591   int result;
4592   int waiting = 1, nfds;
4593   char c;
4595   SELECT_TYPE readfds, writefds, *wfds;
4596   EMACS_TIME timeout, *tmo;
4597   NSAutoreleasePool *pool = nil;
4599   /* NSTRACE (fd_handler); */
4601   for (;;)
4602     {
4603       [pool release];
4604       pool = [[NSAutoreleasePool alloc] init];
4606       if (waiting)
4607         {
4608           SELECT_TYPE fds;
4609           FD_ZERO (&fds);
4610           FD_SET (selfds[0], &fds);
4611           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4612           if (result > 0 && read (selfds[0], &c, 1) == 1 && c == 'g')
4613             waiting = 0;
4614         }
4615       else
4616         {
4617           pthread_mutex_lock (&select_mutex);
4618           nfds = select_nfds;
4620           if (select_valid & SELECT_HAVE_READ)
4621             readfds = select_readfds;
4622           else
4623             FD_ZERO (&readfds);
4625           if (select_valid & SELECT_HAVE_WRITE)
4626             {
4627               writefds = select_writefds;
4628               wfds = &writefds;
4629             }
4630           else
4631             wfds = NULL;
4632           if (select_valid & SELECT_HAVE_TMO)
4633             {
4634               timeout = select_timeout;
4635               tmo = &timeout;
4636             }
4637           else
4638             tmo = NULL;
4640           pthread_mutex_unlock (&select_mutex);
4642           FD_SET (selfds[0], &readfds);
4643           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4645           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4647           if (result == 0)
4648             ns_send_appdefined (-2);
4649           else if (result > 0)
4650             {
4651               if (FD_ISSET (selfds[0], &readfds))
4652                 {
4653                   if (read (selfds[0], &c, 1) == 1 && c == 's')
4654                     waiting = 1;
4655                 }
4656               else
4657                 {
4658                   pthread_mutex_lock (&select_mutex);
4659                   if (select_valid & SELECT_HAVE_READ)
4660                     select_readfds = readfds;
4661                   if (select_valid & SELECT_HAVE_WRITE)
4662                     select_writefds = writefds;
4663                   if (select_valid & SELECT_HAVE_TMO)
4664                     select_timeout = timeout;
4665                   pthread_mutex_unlock (&select_mutex);
4667                   ns_send_appdefined (result);
4668                 }
4669             }
4670           waiting = 1;
4671         }
4672     }
4677 /* ==========================================================================
4679     Service provision
4681    ========================================================================== */
4683 /* called from system: queue for next pass through event loop */
4684 - (void)requestService: (NSPasteboard *)pboard
4685               userData: (NSString *)userData
4686                  error: (NSString **)error
4688   [ns_pending_service_names addObject: userData];
4689   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4690       SSDATA (ns_string_from_pasteboard (pboard))]];
4694 /* called from ns_read_socket to clear queue */
4695 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4697   struct frame *emacsframe = SELECTED_FRAME ();
4698   NSEvent *theEvent = [NSApp currentEvent];
4700   if (!emacs_event)
4701     return NO;
4703   emacs_event->kind = NS_NONKEY_EVENT;
4704   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4705   ns_input_spi_name = build_string ([name UTF8String]);
4706   ns_input_spi_arg = build_string ([arg UTF8String]);
4707   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4708   EV_TRAILER (theEvent);
4710   return YES;
4714 @end  /* EmacsApp */
4718 /* ==========================================================================
4720     EmacsView implementation
4722    ========================================================================== */
4725 @implementation EmacsView
4727 /* needed to inform when window closed from LISP */
4728 - (void) setWindowClosing: (BOOL)closing
4730   windowClosing = closing;
4734 - (void)dealloc
4736   NSTRACE (EmacsView_dealloc);
4737   [toolbar release];
4738   if (fs_state == FULLSCREEN_BOTH)
4739     [nonfs_window release];
4740   [super dealloc];
4744 /* called on font panel selection */
4745 - (void)changeFont: (id)sender
4747   NSEvent *e =[[self window] currentEvent];
4748   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4749   id newFont;
4750   float size;
4752   NSTRACE (changeFont);
4753   if (!emacs_event)
4754     return;
4756   if ((newFont = [sender convertFont:
4757                            ((struct nsfont_info *)face->font)->nsfont]))
4758     {
4759       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4761       emacs_event->kind = NS_NONKEY_EVENT;
4762       emacs_event->modifiers = 0;
4763       emacs_event->code = KEY_NS_CHANGE_FONT;
4765       size = [newFont pointSize];
4766       ns_input_fontsize = make_number (lrint (size));
4767       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4768       EV_TRAILER (e);
4769     }
4773 - (BOOL)acceptsFirstResponder
4775   NSTRACE (acceptsFirstResponder);
4776   return YES;
4780 - (void)resetCursorRects
4782   NSRect visible = [self visibleRect];
4783   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4784   NSTRACE (resetCursorRects);
4786   if (currentCursor == nil)
4787     currentCursor = [NSCursor arrowCursor];
4789   if (!NSIsEmptyRect (visible))
4790     [self addCursorRect: visible cursor: currentCursor];
4791   [currentCursor setOnMouseEntered: YES];
4796 /*****************************************************************************/
4797 /* Keyboard handling. */
4798 #define NS_KEYLOG 0
4800 - (void)keyDown: (NSEvent *)theEvent
4802   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4803   int code;
4804   unsigned fnKeysym = 0;
4805   static NSMutableArray *nsEvArray;
4806 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4807   static BOOL firstTime = YES;
4808 #endif
4809   int left_is_none;
4810   unsigned int flags = [theEvent modifierFlags];
4812   NSTRACE (keyDown);
4814   /* Rhapsody and OS X give up and down events for the arrow keys */
4815   if (ns_fake_keydown == YES)
4816     ns_fake_keydown = NO;
4817   else if ([theEvent type] != NSKeyDown)
4818     return;
4820   if (!emacs_event)
4821     return;
4823  if (![[self window] isKeyWindow]
4824      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4825      /* we must avoid an infinite loop here. */
4826      && (EmacsView *)[[theEvent window] delegate] != self)
4827    {
4828      /* XXX: There is an occasional condition in which, when Emacs display
4829          updates a different frame from the current one, and temporarily
4830          selects it, then processes some interrupt-driven input
4831          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4832          for some reason that window has its first responder set to the NSView
4833          most recently updated (I guess), which is not the correct one. */
4834      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4835      return;
4836    }
4838   if (nsEvArray == nil)
4839     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4841   [NSCursor setHiddenUntilMouseMoves: YES];
4843   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4844     {
4845       clear_mouse_face (hlinfo);
4846       hlinfo->mouse_face_hidden = 1;
4847     }
4849   if (!processingCompose)
4850     {
4851       /* When using screen sharing, no left or right information is sent,
4852          so use Left key in those cases.  */
4853       int is_left_key, is_right_key;
4855       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4856         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4858       /* (Carbon way: [theEvent keyCode]) */
4860       /* is it a "function key"? */
4861       fnKeysym = (code < 0x00ff && (flags&NSNumericPadKeyMask))
4862         ? ns_convert_key ([theEvent keyCode] | NSNumericPadKeyMask)
4863         : ns_convert_key (code);
4865       if (fnKeysym)
4866         {
4867           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4868              because Emacs treats Delete and KP-Delete same (in simple.el). */
4869           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4870             code = 0xFF08; /* backspace */
4871           else
4872             code = fnKeysym;
4873         }
4875       /* are there modifiers? */
4876       emacs_event->modifiers = 0;
4878       if (flags & NSHelpKeyMask)
4879           emacs_event->modifiers |= hyper_modifier;
4881       if (flags & NSShiftKeyMask)
4882         emacs_event->modifiers |= shift_modifier;
4884       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4885       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4886         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4888       if (is_right_key)
4889         emacs_event->modifiers |= parse_solitary_modifier
4890           (EQ (ns_right_command_modifier, Qleft)
4891            ? ns_command_modifier
4892            : ns_right_command_modifier);
4894       if (is_left_key)
4895         {
4896           emacs_event->modifiers |= parse_solitary_modifier
4897             (ns_command_modifier);
4899           /* if super (default), take input manager's word so things like
4900              dvorak / qwerty layout work */
4901           if (EQ (ns_command_modifier, Qsuper)
4902               && !fnKeysym
4903               && [[theEvent characters] length] != 0)
4904             {
4905               /* XXX: the code we get will be unshifted, so if we have
4906                  a shift modifier, must convert ourselves */
4907               if (!(flags & NSShiftKeyMask))
4908                 code = [[theEvent characters] characterAtIndex: 0];
4909 #if 0
4910               /* this is ugly and also requires linking w/Carbon framework
4911                  (for LMGetKbdType) so for now leave this rare (?) case
4912                  undealt with.. in future look into CGEvent methods */
4913               else
4914                 {
4915                   long smv = GetScriptManagerVariable (smKeyScript);
4916                   Handle uchrHandle = GetResource
4917                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4918                   UInt32 dummy = 0;
4919                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4920                                  [[theEvent characters] characterAtIndex: 0],
4921                                  kUCKeyActionDisplay,
4922                                  (flags & ~NSCommandKeyMask) >> 8,
4923                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4924                                  &dummy, 1, &dummy, &code);
4925                   code &= 0xFF;
4926                 }
4927 #endif
4928             }
4929         }
4931       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
4932       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
4933         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
4935       if (is_right_key)
4936           emacs_event->modifiers |= parse_solitary_modifier
4937               (EQ (ns_right_control_modifier, Qleft)
4938                ? ns_control_modifier
4939                : ns_right_control_modifier);
4941       if (is_left_key)
4942         emacs_event->modifiers |= parse_solitary_modifier
4943           (ns_control_modifier);
4945       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4946           emacs_event->modifiers |=
4947             parse_solitary_modifier (ns_function_modifier);
4949       left_is_none = NILP (ns_alternate_modifier)
4950         || EQ (ns_alternate_modifier, Qnone);
4952       is_right_key = (flags & NSRightAlternateKeyMask)
4953         == NSRightAlternateKeyMask;
4954       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
4955         || (! is_right_key
4956             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
4958       if (is_right_key)
4959         {
4960           if ((NILP (ns_right_alternate_modifier)
4961                || EQ (ns_right_alternate_modifier, Qnone)
4962                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4963               && !fnKeysym)
4964             {   /* accept pre-interp alt comb */
4965               if ([[theEvent characters] length] > 0)
4966                 code = [[theEvent characters] characterAtIndex: 0];
4967               /*HACK: clear lone shift modifier to stop next if from firing */
4968               if (emacs_event->modifiers == shift_modifier)
4969                 emacs_event->modifiers = 0;
4970             }
4971           else
4972             emacs_event->modifiers |= parse_solitary_modifier
4973               (EQ (ns_right_alternate_modifier, Qleft)
4974                ? ns_alternate_modifier
4975                : ns_right_alternate_modifier);
4976         }
4978       if (is_left_key) /* default = meta */
4979         {
4980           if (left_is_none && !fnKeysym)
4981             {   /* accept pre-interp alt comb */
4982               if ([[theEvent characters] length] > 0)
4983                 code = [[theEvent characters] characterAtIndex: 0];
4984               /*HACK: clear lone shift modifier to stop next if from firing */
4985               if (emacs_event->modifiers == shift_modifier)
4986                 emacs_event->modifiers = 0;
4987             }
4988           else
4989               emacs_event->modifiers |=
4990                 parse_solitary_modifier (ns_alternate_modifier);
4991         }
4993   if (NS_KEYLOG)
4994     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4995              code, fnKeysym, flags, emacs_event->modifiers);
4997       /* if it was a function key or had modifiers, pass it directly to emacs */
4998       if (fnKeysym || (emacs_event->modifiers
4999                        && (emacs_event->modifiers != shift_modifier)
5000                        && [[theEvent charactersIgnoringModifiers] length] > 0))
5001 /*[[theEvent characters] length] */
5002         {
5003           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5004           if (code < 0x20)
5005             code |= (1<<28)|(3<<16);
5006           else if (code == 0x7f)
5007             code |= (1<<28)|(3<<16);
5008           else if (!fnKeysym)
5009             emacs_event->kind = code > 0xFF
5010               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5012           emacs_event->code = code;
5013           EV_TRAILER (theEvent);
5014           processingCompose = NO;
5015           return;
5016         }
5017     }
5020 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
5021   /* if we get here we should send the key for input manager processing */
5022   if (firstTime && [[NSInputManager currentInputManager]
5023                      wantsToDelayTextChangeNotifications] == NO)
5024     fprintf (stderr,
5025           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
5026   firstTime = NO;
5027 #endif
5028   if (NS_KEYLOG && !processingCompose)
5029     fprintf (stderr, "keyDown: Begin compose sequence.\n");
5031   processingCompose = YES;
5032   [nsEvArray addObject: theEvent];
5033   [self interpretKeyEvents: nsEvArray];
5034   [nsEvArray removeObject: theEvent];
5038 #ifdef NS_IMPL_COCOA
5039 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
5040    decided not to send key-down for.
5041    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
5042    This only applies on Tiger and earlier.
5043    If it matches one of these, send it on to keyDown. */
5044 -(void)keyUp: (NSEvent *)theEvent
5046   int flags = [theEvent modifierFlags];
5047   int code = [theEvent keyCode];
5048   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
5049       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
5050     {
5051       if (NS_KEYLOG)
5052         fprintf (stderr, "keyUp: passed test");
5053       ns_fake_keydown = YES;
5054       [self keyDown: theEvent];
5055     }
5057 #endif
5060 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5063 /* <NSTextInput>: called when done composing;
5064    NOTE: also called when we delete over working text, followed immed.
5065          by doCommandBySelector: deleteBackward: */
5066 - (void)insertText: (id)aString
5068   int code;
5069   int len = [(NSString *)aString length];
5070   int i;
5072   if (NS_KEYLOG)
5073     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5074   processingCompose = NO;
5076   if (!emacs_event)
5077     return;
5079   /* first, clear any working text */
5080   if (workingText != nil)
5081     [self deleteWorkingText];
5083   /* now insert the string as keystrokes */
5084   for (i =0; i<len; i++)
5085     {
5086       code = [aString characterAtIndex: i];
5087       /* TODO: still need this? */
5088       if (code == 0x2DC)
5089         code = '~'; /* 0x7E */
5090       if (code != 32) /* Space */
5091         emacs_event->modifiers = 0;
5092       emacs_event->kind
5093         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5094       emacs_event->code = code;
5095       EV_TRAILER ((id)nil);
5096     }
5100 /* <NSTextInput>: inserts display of composing characters */
5101 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5103   NSString *str = [aString respondsToSelector: @selector (string)] ?
5104     [aString string] : aString;
5105   if (NS_KEYLOG)
5106     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5107            selRange.length, selRange.location);
5109   if (workingText != nil)
5110     [self deleteWorkingText];
5111   if ([str length] == 0)
5112     return;
5114   if (!emacs_event)
5115     return;
5117   processingCompose = YES;
5118   workingText = [str copy];
5119   ns_working_text = build_string ([workingText UTF8String]);
5121   emacs_event->kind = NS_TEXT_EVENT;
5122   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5123   EV_TRAILER ((id)nil);
5127 /* delete display of composing characters [not in <NSTextInput>] */
5128 - (void)deleteWorkingText
5130   if (workingText == nil)
5131     return;
5132   if (NS_KEYLOG)
5133     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5134   [workingText release];
5135   workingText = nil;
5136   processingCompose = NO;
5138   if (!emacs_event)
5139     return;
5141   emacs_event->kind = NS_TEXT_EVENT;
5142   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5143   EV_TRAILER ((id)nil);
5147 - (BOOL)hasMarkedText
5149   return workingText != nil;
5153 - (NSRange)markedRange
5155   NSRange rng = workingText != nil
5156     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5157   if (NS_KEYLOG)
5158     NSLog (@"markedRange request");
5159   return rng;
5163 - (void)unmarkText
5165   if (NS_KEYLOG)
5166     NSLog (@"unmark (accept) text");
5167   [self deleteWorkingText];
5168   processingCompose = NO;
5172 /* used to position char selection windows, etc. */
5173 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5175   NSRect rect;
5176   NSPoint pt;
5177   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5178   if (NS_KEYLOG)
5179     NSLog (@"firstRectForCharRange request");
5181   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5182   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5183   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5184   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5185                                        +FRAME_LINE_HEIGHT (emacsframe));
5187   pt = [self convertPoint: pt toView: nil];
5188   pt = [[self window] convertBaseToScreen: pt];
5189   rect.origin = pt;
5190   return rect;
5194 - (NSInteger)conversationIdentifier
5196   return (NSInteger)self;
5200 - (void)doCommandBySelector: (SEL)aSelector
5202   if (NS_KEYLOG)
5203     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5205   processingCompose = NO;
5206   if (aSelector == @selector (deleteBackward:))
5207     {
5208       /* happens when user backspaces over an ongoing composition:
5209          throw a 'delete' into the event queue */
5210       if (!emacs_event)
5211         return;
5212       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5213       emacs_event->code = 0xFF08;
5214       EV_TRAILER ((id)nil);
5215     }
5218 - (NSArray *)validAttributesForMarkedText
5220   static NSArray *arr = nil;
5221   if (arr == nil) arr = [NSArray new];
5222  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5223   return arr;
5226 - (NSRange)selectedRange
5228   if (NS_KEYLOG)
5229     NSLog (@"selectedRange request");
5230   return NSMakeRange (NSNotFound, 0);
5233 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5235   if (NS_KEYLOG)
5236     NSLog (@"characterIndexForPoint request");
5237   return 0;
5240 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5242   static NSAttributedString *str = nil;
5243   if (str == nil) str = [NSAttributedString new];
5244   if (NS_KEYLOG)
5245     NSLog (@"attributedSubstringFromRange request");
5246   return str;
5249 /* End <NSTextInput> impl. */
5250 /*****************************************************************************/
5253 /* This is what happens when the user presses a mouse button.  */
5254 - (void)mouseDown: (NSEvent *)theEvent
5256   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5258   NSTRACE (mouseDown);
5260   [self deleteWorkingText];
5262   if (!emacs_event)
5263     return;
5265   last_mouse_frame = emacsframe;
5266   /* appears to be needed to prevent spurious movement events generated on
5267      button clicks */
5268   last_mouse_frame->mouse_moved = 0;
5270   if ([theEvent type] == NSScrollWheel)
5271     {
5272       float delta = [theEvent deltaY];
5273       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5274       if (delta == 0)
5275         return;
5276       emacs_event->kind = WHEEL_EVENT;
5277       emacs_event->code = 0;
5278       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5279         ((delta > 0) ? up_modifier : down_modifier);
5280     }
5281   else
5282     {
5283       emacs_event->kind = MOUSE_CLICK_EVENT;
5284       emacs_event->code = EV_BUTTON (theEvent);
5285       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5286                              | EV_UDMODIFIERS (theEvent);
5287     }
5288   XSETINT (emacs_event->x, lrint (p.x));
5289   XSETINT (emacs_event->y, lrint (p.y));
5290   EV_TRAILER (theEvent);
5294 - (void)rightMouseDown: (NSEvent *)theEvent
5296   NSTRACE (rightMouseDown);
5297   [self mouseDown: theEvent];
5301 - (void)otherMouseDown: (NSEvent *)theEvent
5303   NSTRACE (otherMouseDown);
5304   [self mouseDown: theEvent];
5308 - (void)mouseUp: (NSEvent *)theEvent
5310   NSTRACE (mouseUp);
5311   [self mouseDown: theEvent];
5315 - (void)rightMouseUp: (NSEvent *)theEvent
5317   NSTRACE (rightMouseUp);
5318   [self mouseDown: theEvent];
5322 - (void)otherMouseUp: (NSEvent *)theEvent
5324   NSTRACE (otherMouseUp);
5325   [self mouseDown: theEvent];
5329 - (void) scrollWheel: (NSEvent *)theEvent
5331   NSTRACE (scrollWheel);
5332   [self mouseDown: theEvent];
5336 /* Tell emacs the mouse has moved. */
5337 - (void)mouseMoved: (NSEvent *)e
5339   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5340   Lisp_Object frame;
5342 //  NSTRACE (mouseMoved);
5344   last_mouse_movement_time = EV_TIMESTAMP (e);
5345   last_mouse_motion_position
5346     = [self convertPoint: [e locationInWindow] fromView: nil];
5348   /* update any mouse face */
5349   if (hlinfo->mouse_face_hidden)
5350     {
5351       hlinfo->mouse_face_hidden = 0;
5352       clear_mouse_face (hlinfo);
5353     }
5355   /* tooltip handling */
5356   previous_help_echo_string = help_echo_string;
5357   help_echo_string = Qnil;
5359   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5360                             last_mouse_motion_position.y))
5361     help_echo_string = previous_help_echo_string;
5363   XSETFRAME (frame, emacsframe);
5364   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5365     {
5366       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5367          (note_mouse_highlight), which is called through the
5368          note_mouse_movement () call above */
5369       gen_help_event (help_echo_string, frame, help_echo_window,
5370                       help_echo_object, help_echo_pos);
5371     }
5372   else
5373     {
5374       help_echo_string = Qnil;
5375       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5376     }
5378   if (emacsframe->mouse_moved && send_appdefined)
5379     ns_send_appdefined (-1);
5383 - (void)mouseDragged: (NSEvent *)e
5385   NSTRACE (mouseDragged);
5386   [self mouseMoved: e];
5390 - (void)rightMouseDragged: (NSEvent *)e
5392   NSTRACE (rightMouseDragged);
5393   [self mouseMoved: e];
5397 - (void)otherMouseDragged: (NSEvent *)e
5399   NSTRACE (otherMouseDragged);
5400   [self mouseMoved: e];
5404 - (BOOL)windowShouldClose: (id)sender
5406   NSEvent *e =[[self window] currentEvent];
5408   NSTRACE (windowShouldClose);
5409   windowClosing = YES;
5410   if (!emacs_event)
5411     return NO;
5412   emacs_event->kind = DELETE_WINDOW_EVENT;
5413   emacs_event->modifiers = 0;
5414   emacs_event->code = 0;
5415   EV_TRAILER (e);
5416   /* Don't close this window, let this be done from lisp code.  */
5417   return NO;
5420 - (void) updateFrameSize: (BOOL) delay;
5422   NSWindow *window = [self window];
5423   NSRect wr = [window frame];
5424   int extra = 0;
5425   int gsextra = 0;
5426 #ifdef NS_IMPL_GNUSTEP
5427   gsextra = 3;
5428 #endif
5430   int oldc = cols, oldr = rows;
5431   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5432     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5433   int neww, newh;
5435   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + gsextra);
5437   if (cols < MINWIDTH)
5438     cols = MINWIDTH;
5440   if (! [self isFullscreen])
5441     {
5442       extra = FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5443         + FRAME_TOOLBAR_HEIGHT (emacsframe) - gsextra;
5444     }
5446   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, wr.size.height - extra);
5448   if (rows < MINHEIGHT)
5449     rows = MINHEIGHT;
5451   neww = (int)wr.size.width - emacsframe->border_width;
5452   newh = (int)wr.size.height - extra;
5454   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5455     {
5456       struct frame *f = emacsframe;
5457       NSView *view = FRAME_NS_VIEW (emacsframe);
5458       NSWindow *win = [view window];
5459       NSSize sz = [win resizeIncrements];
5461       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5462       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5463       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5464       SET_FRAME_GARBAGED (emacsframe);
5465       cancel_mouse_face (emacsframe);
5467       // Did resize increments change because of a font change?
5468       if (sz.width != FRAME_COLUMN_WIDTH (emacsframe) ||
5469           sz.height != FRAME_LINE_HEIGHT (emacsframe))
5470         {
5471           sz.width = FRAME_COLUMN_WIDTH (emacsframe);
5472           sz.height = FRAME_LINE_HEIGHT (emacsframe);
5473           [win setResizeIncrements: sz];
5474         }
5476       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5477       [self windowDidMove:nil];   // Update top/left.
5478     }
5481 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5482 /* normalize frame to gridded text size */
5484   int extra = 0;
5485   int gsextra = 0;
5486 #ifdef NS_IMPL_GNUSTEP
5487   gsextra = 3;
5488 #endif
5489   
5490   NSTRACE (windowWillResize);
5491 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5493   if (fs_state == FULLSCREEN_MAXIMIZED
5494       && (maximized_width != (int)frameSize.width
5495           || maximized_height != (int)frameSize.height))
5496     [self setFSValue: FULLSCREEN_NONE];
5497   else if (fs_state == FULLSCREEN_WIDTH
5498            && maximized_width != (int)frameSize.width)
5499     [self setFSValue: FULLSCREEN_NONE];
5500   else if (fs_state == FULLSCREEN_HEIGHT
5501            && maximized_height != (int)frameSize.height)
5502     [self setFSValue: FULLSCREEN_NONE];
5503   if (fs_state == FULLSCREEN_NONE)
5504     maximized_width = maximized_height = -1;
5506   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5507                                          frameSize.width + gsextra);
5508   if (cols < MINWIDTH)
5509     cols = MINWIDTH;
5511   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe,
5512                                            frameSize.height - extra);
5513   if (rows < MINHEIGHT)
5514     rows = MINHEIGHT;
5515 #ifdef NS_IMPL_COCOA
5516   {
5517     /* this sets window title to have size in it; the wm does this under GS */
5518     NSRect r = [[self window] frame];
5519     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5520       {
5521         if (old_title != 0)
5522           {
5523             xfree (old_title);
5524             old_title = 0;
5525           }
5526       }
5527     else
5528       {
5529         char *size_title;
5530         NSWindow *window = [self window];
5531         if (old_title == 0)
5532           {
5533             const char *t = [[[self window] title] UTF8String];
5534             char *pos = strstr (t, "  â€”  ");
5535             if (pos)
5536               *pos = '\0';
5537             old_title = xstrdup (t);
5538           }
5539         size_title = xmalloc (strlen (old_title) + 40);
5540         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5541         [window setTitle: [NSString stringWithUTF8String: size_title]];
5542         [window display];
5543         xfree (size_title);
5544       }
5545   }
5546 #endif /* NS_IMPL_COCOA */
5547 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5549   return frameSize;
5553 - (void)windowDidResize: (NSNotification *)notification
5555   if (! [self fsIsNative]) 
5556     {
5557       NSWindow *theWindow = [notification object];
5558       /* We can get notification on the non-FS window when in
5559          fullscreen mode.  */
5560       if ([self window] != theWindow) return;
5561     }
5563 #ifdef NS_IMPL_GNUSTEP
5564   NSWindow *theWindow = [notification object];
5566    /* In GNUstep, at least currently, it's possible to get a didResize
5567       without getting a willResize.. therefore we need to act as if we got
5568       the willResize now */
5569   NSSize sz = [theWindow frame].size;
5570   sz = [self windowWillResize: theWindow toSize: sz];
5571 #endif /* NS_IMPL_GNUSTEP */
5573   NSTRACE (windowDidResize);
5574 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5576 #ifdef NS_IMPL_COCOA
5577   if (old_title != 0)
5578     {
5579       xfree (old_title);
5580       old_title = 0;
5581     }
5582 #endif /* NS_IMPL_COCOA */
5584   if (cols > 0 && rows > 0)
5585     {
5586       [self updateFrameSize: YES];
5587     }
5589   ns_send_appdefined (-1);
5593 - (void)windowDidBecomeKey: (NSNotification *)notification
5594 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5596   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5597   struct frame *old_focus = dpyinfo->x_focus_frame;
5599   NSTRACE (windowDidBecomeKey);
5601   if (emacsframe != old_focus)
5602     dpyinfo->x_focus_frame = emacsframe;
5604   ns_frame_rehighlight (emacsframe);
5606   if (emacs_event)
5607     {
5608       emacs_event->kind = FOCUS_IN_EVENT;
5609       EV_TRAILER ((id)nil);
5610     }
5614 - (void)windowDidResignKey: (NSNotification *)notification
5615 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5617   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5618   NSTRACE (windowDidResignKey);
5620   if (dpyinfo->x_focus_frame == emacsframe)
5621     dpyinfo->x_focus_frame = 0;
5623   ns_frame_rehighlight (emacsframe);
5625   /* FIXME: for some reason needed on second and subsequent clicks away
5626             from sole-frame Emacs to get hollow box to show */
5627   if (!windowClosing && [[self window] isVisible] == YES)
5628     {
5629       x_update_cursor (emacsframe, 1);
5630       x_set_frame_alpha (emacsframe);
5631     }
5633   if (emacs_event)
5634     {
5635       [self deleteWorkingText];
5636       emacs_event->kind = FOCUS_IN_EVENT;
5637       EV_TRAILER ((id)nil);
5638     }
5642 - (void)windowWillMiniaturize: sender
5644   NSTRACE (windowWillMiniaturize);
5648 - (BOOL)isFlipped
5650   return YES;
5654 - (BOOL)isOpaque
5656   return NO;
5660 - initFrameFromEmacs: (struct frame *)f
5662   NSRect r, wr;
5663   Lisp_Object tem;
5664   NSWindow *win;
5665   NSButton *toggleButton;
5666   NSSize sz;
5667   NSColor *col;
5668   NSString *name;
5670   NSTRACE (initFrameFromEmacs);
5672   windowClosing = NO;
5673   processingCompose = NO;
5674   scrollbarsNeedingUpdate = 0;
5675   fs_state = FULLSCREEN_NONE;
5676   fs_before_fs = next_maximized = -1;
5677 #ifdef HAVE_NATIVE_FS
5678   fs_is_native = ns_use_native_fullscreen;
5679 #else
5680   fs_is_native = NO;
5681 #endif
5682   maximized_width = maximized_height = -1;
5683   nonfs_window = nil;
5685 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5687   ns_userRect = NSMakeRect (0, 0, 0, 0);
5688   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5689                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5690   [self initWithFrame: r];
5691   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5693   FRAME_NS_VIEW (f) = self;
5694   emacsframe = f;
5695   old_title = 0;
5697   win = [[EmacsWindow alloc]
5698             initWithContentRect: r
5699                       styleMask: (NSResizableWindowMask |
5700 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5701                                   NSTitledWindowMask |
5702 #endif
5703                                   NSMiniaturizableWindowMask |
5704                                   NSClosableWindowMask)
5705                         backing: NSBackingStoreBuffered
5706                           defer: YES];
5708 #ifdef HAVE_NATIVE_FS
5709     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5710 #endif
5712   wr = [win frame];
5713   bwidth = f->border_width = wr.size.width - r.size.width;
5714   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5716   [win setAcceptsMouseMovedEvents: YES];
5717   [win setDelegate: self];
5718   [win useOptimizedDrawing: YES];
5720   sz.width = FRAME_COLUMN_WIDTH (f);
5721   sz.height = FRAME_LINE_HEIGHT (f);
5722   [win setResizeIncrements: sz];
5724   [[win contentView] addSubview: self];
5726   if (ns_drag_types)
5727     [self registerForDraggedTypes: ns_drag_types];
5729   tem = f->name;
5730   name = [NSString stringWithUTF8String:
5731                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5732   [win setTitle: name];
5734   /* toolbar support */
5735   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5736                          [NSString stringWithFormat: @"Emacs Frame %d",
5737                                    ns_window_num]];
5738   [win setToolbar: toolbar];
5739   [toolbar setVisible: NO];
5740 #ifdef NS_IMPL_COCOA
5741   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5742   [toggleButton setTarget: self];
5743   [toggleButton setAction: @selector (toggleToolbar: )];
5744 #endif
5745   FRAME_TOOLBAR_HEIGHT (f) = 0;
5747   tem = f->icon_name;
5748   if (!NILP (tem))
5749     [win setMiniwindowTitle:
5750            [NSString stringWithUTF8String: SSDATA (tem)]];
5752   {
5753     NSScreen *screen = [win screen];
5755     if (screen != 0)
5756       [win setFrameTopLeftPoint: NSMakePoint
5757            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5758             IN_BOUND (-SCREENMAX,
5759                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5760   }
5762   [win makeFirstResponder: self];
5764   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5765                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5766   [win setBackgroundColor: col];
5767   if ([col alphaComponent] != 1.0)
5768     [win setOpaque: NO];
5770   [self allocateGState];
5772   [NSApp registerServicesMenuSendTypes: ns_send_types
5773                            returnTypes: nil];
5775   ns_window_num++;
5776   return self;
5780 - (void)windowDidMove: sender
5782   NSWindow *win = [self window];
5783   NSRect r = [win frame];
5784   NSArray *screens = [NSScreen screens];
5785   NSScreen *screen = [screens objectAtIndex: 0];
5787   NSTRACE (windowDidMove);
5789   if (!emacsframe->output_data.ns)
5790     return;
5791   if (screen != nil)
5792     {
5793       emacsframe->left_pos = r.origin.x;
5794       emacsframe->top_pos =
5795         [screen frame].size.height - (r.origin.y + r.size.height);
5796     }
5800 /* Called AFTER method below, but before our windowWillResize call there leads
5801    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5802    location so set_window_size moves the frame. */
5803 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5805   emacsframe->output_data.ns->zooming = 1;
5806   return YES;
5810 /* Override to do something slightly nonstandard, but nice.  First click on
5811    zoom button will zoom vertically.  Second will zoom completely.  Third
5812    returns to original. */
5813 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5814                         defaultFrame:(NSRect)defaultFrame
5816   NSRect result = [sender frame];
5818   NSTRACE (windowWillUseStandardFrame);
5820   if (fs_before_fs != -1) /* Entering fullscreen */
5821       {
5822         result = defaultFrame;
5823       }
5824   else if (next_maximized == FULLSCREEN_HEIGHT
5825       || (next_maximized == -1
5826           && abs (defaultFrame.size.height - result.size.height)
5827           > FRAME_LINE_HEIGHT (emacsframe)))
5828     {
5829       /* first click */
5830       ns_userRect = result;
5831       maximized_height = result.size.height = defaultFrame.size.height;
5832       maximized_width = -1;
5833       result.origin.y = defaultFrame.origin.y;
5834       [self setFSValue: FULLSCREEN_HEIGHT];
5835     }
5836   else if (next_maximized == FULLSCREEN_WIDTH)
5837     {
5838       ns_userRect = result;
5839       maximized_width = result.size.width = defaultFrame.size.width;
5840       maximized_height = -1;
5841       result.origin.x = defaultFrame.origin.x;
5842       [self setFSValue: FULLSCREEN_WIDTH];
5843     }
5844   else if (next_maximized == FULLSCREEN_MAXIMIZED
5845            || (next_maximized == -1
5846                && abs (defaultFrame.size.width - result.size.width)
5847                > FRAME_COLUMN_WIDTH (emacsframe)))
5848     {
5849       result = defaultFrame;  /* second click */
5850       maximized_width = result.size.width;
5851       maximized_height = result.size.height;
5852       [self setFSValue: FULLSCREEN_MAXIMIZED];
5853     }
5854   else
5855     {
5856       /* restore */
5857       result = ns_userRect.size.height ? ns_userRect : result;
5858       ns_userRect = NSMakeRect (0, 0, 0, 0);
5859       [self setFSValue: FULLSCREEN_NONE];
5860       maximized_width = maximized_width = -1;
5861     }
5863   if (fs_before_fs == -1) next_maximized = -1;
5864   [self windowWillResize: sender toSize: result.size];
5865   return result;
5869 - (void)windowDidDeminiaturize: sender
5871   NSTRACE (windowDidDeminiaturize);
5872   if (!emacsframe->output_data.ns)
5873     return;
5875   SET_FRAME_ICONIFIED (emacsframe, 0);
5876   SET_FRAME_VISIBLE (emacsframe, 1);
5877   windows_or_buffers_changed++;
5879   if (emacs_event)
5880     {
5881       emacs_event->kind = DEICONIFY_EVENT;
5882       EV_TRAILER ((id)nil);
5883     }
5887 - (void)windowDidExpose: sender
5889   NSTRACE (windowDidExpose);
5890   if (!emacsframe->output_data.ns)
5891     return;
5893   SET_FRAME_VISIBLE (emacsframe, 1);
5894   SET_FRAME_GARBAGED (emacsframe);
5896   if (send_appdefined)
5897     ns_send_appdefined (-1);
5901 - (void)windowDidMiniaturize: sender
5903   NSTRACE (windowDidMiniaturize);
5904   if (!emacsframe->output_data.ns)
5905     return;
5907   SET_FRAME_ICONIFIED (emacsframe, 1);
5908   SET_FRAME_VISIBLE (emacsframe, 0);
5910   if (emacs_event)
5911     {
5912       emacs_event->kind = ICONIFY_EVENT;
5913       EV_TRAILER ((id)nil);
5914     }
5917 #ifdef HAVE_NATIVE_FS
5918 - (NSApplicationPresentationOptions)window:(NSWindow *)window
5919       willUseFullScreenPresentationOptions:
5920   (NSApplicationPresentationOptions)proposedOptions
5922   return proposedOptions|NSApplicationPresentationAutoHideToolbar;
5924 #endif
5926 - (void)windowWillEnterFullScreen:(NSNotification *)notification
5928   fs_before_fs = fs_state;
5931 - (void)windowDidEnterFullScreen:(NSNotification *)notification
5933   [self setFSValue: FULLSCREEN_BOTH];
5934   if (! [self fsIsNative])
5935     {
5936       [self windowDidBecomeKey:notification];
5937       [nonfs_window orderOut:self];
5938     }
5939   else if (! FRAME_EXTERNAL_TOOL_BAR (emacsframe))
5940     [toolbar setVisible:NO];
5943 - (void)windowWillExitFullScreen:(NSNotification *)notification
5945   if (next_maximized != -1)
5946     fs_before_fs = next_maximized;
5949 - (void)windowDidExitFullScreen:(NSNotification *)notification
5951   [self setFSValue: fs_before_fs];
5952   fs_before_fs = -1;
5953   [self updateCollectionBehaviour];
5954   if (FRAME_EXTERNAL_TOOL_BAR (emacsframe))
5955     {
5956       [toolbar setVisible:YES];
5957       update_frame_tool_bar (emacsframe);
5958       [self updateFrameSize:YES];
5959       [[self window] display];
5960     }
5961   else
5962     [toolbar setVisible:NO];
5964   if (next_maximized != -1)
5965     [[self window] performZoom:self];
5968 - (BOOL)fsIsNative
5970   return fs_is_native;
5973 - (BOOL)isFullscreen
5975   if (! fs_is_native) return nonfs_window != nil;
5976 #ifdef HAVE_NATIVE_FS
5977   return ([[self window] styleMask] & NSFullScreenWindowMask) != 0;
5978 #else
5979   return NO;
5980 #endif
5983 #ifdef HAVE_NATIVE_FS
5984 - (void)updateCollectionBehaviour
5986   if (! [self isFullscreen])
5987     {
5988       NSWindow *win = [self window];
5989       NSWindowCollectionBehavior b = [win collectionBehavior];
5990       if (ns_use_native_fullscreen)
5991         b |= NSWindowCollectionBehaviorFullScreenPrimary;
5992       else
5993         b &= ~NSWindowCollectionBehaviorFullScreenPrimary;
5995       [win setCollectionBehavior: b];
5996       fs_is_native = ns_use_native_fullscreen;
5997     }
5999 #endif
6001 - (void)toggleFullScreen: (id)sender
6003   NSWindow *w, *fw;
6004   BOOL onFirstScreen;
6005   struct frame *f;
6006   NSSize sz;
6007   NSRect r, wr;
6008   NSColor *col;
6010   if (fs_is_native)
6011     {
6012       [[self window] toggleFullScreen:sender];
6013       return;
6014     }
6016   w = [self window];
6017   onFirstScreen = [[w screen] isEqual:[[NSScreen screens] objectAtIndex:0]];
6018   f = emacsframe;
6019   wr = [w frame];
6020   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
6021                                  (FRAME_DEFAULT_FACE (f)),
6022                                  f);
6024   sz.width = FRAME_COLUMN_WIDTH (f);
6025   sz.height = FRAME_LINE_HEIGHT (f);
6027   if (fs_state != FULLSCREEN_BOTH)
6028     {
6029       /* Hide dock and menubar if we are on the primary screen.  */
6030       if (onFirstScreen)
6031         {
6032 #if defined (NS_IMPL_COCOA) && \
6033   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6034           NSApplicationPresentationOptions options
6035             = NSApplicationPresentationAutoHideDock
6036             | NSApplicationPresentationAutoHideMenuBar;
6038           [NSApp setPresentationOptions: options];
6039 #else
6040           [NSMenu setMenuBarVisible:NO];
6041 #endif
6042         }
6044       fw = [[EmacsFSWindow alloc]
6045                        initWithContentRect:[w contentRectForFrameRect:wr]
6046                                  styleMask:NSBorderlessWindowMask
6047                                    backing:NSBackingStoreBuffered
6048                                      defer:YES
6049                                     screen:[w screen]];
6051       [fw setContentView:[w contentView]];
6052       [fw setTitle:[w title]];
6053       [fw setDelegate:self];
6054       [fw setAcceptsMouseMovedEvents: YES];
6055       [fw useOptimizedDrawing: YES];
6056       [fw setResizeIncrements: sz];
6057       [fw setBackgroundColor: col];
6058       if ([col alphaComponent] != 1.0)
6059         [fw setOpaque: NO];
6061       f->border_width = 0;
6062       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
6063       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
6064       FRAME_TOOLBAR_HEIGHT (f) = 0;
6066       nonfs_window = w;
6068       [self windowWillEnterFullScreen:nil];
6069       [fw makeKeyAndOrderFront:NSApp];
6070       [fw makeFirstResponder:self];
6071       [w orderOut:self];
6072       r = [fw frameRectForContentRect:[[fw screen] frame]];
6073       [fw setFrame: r display:YES animate:YES];
6074       [self windowDidEnterFullScreen:nil];
6075       [fw display];
6076     }
6077   else
6078     {
6079       fw = w;
6080       w = nonfs_window;
6081       nonfs_window = nil;
6083       if (onFirstScreen)
6084         {
6085 #if defined (NS_IMPL_COCOA) && \
6086   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
6087           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
6088 #else
6089           [NSMenu setMenuBarVisible:YES];
6090 #endif
6091         }
6093       [w setContentView:[fw contentView]];
6094       [w setResizeIncrements: sz];
6095       [w setBackgroundColor: col];
6096       if ([col alphaComponent] != 1.0)
6097         [w setOpaque: NO];
6099       f->border_width = bwidth;
6100       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
6101       if (FRAME_EXTERNAL_TOOL_BAR (f))
6102         FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
6104       [self windowWillExitFullScreen:nil];
6105       [fw setFrame: [w frame] display:YES animate:YES];
6106       [fw close];
6107       [w makeKeyAndOrderFront:NSApp];
6108       [self windowDidExitFullScreen:nil];
6109       [self updateFrameSize:YES];
6110     }
6113 - (void)handleFS
6115   if (fs_state != emacsframe->want_fullscreen)
6116     {
6117       if (fs_state == FULLSCREEN_BOTH)
6118         {
6119           [self toggleFullScreen:self];
6120         }
6122       switch (emacsframe->want_fullscreen)
6123         {
6124         case FULLSCREEN_BOTH:
6125           [self toggleFullScreen:self];
6126           break;
6127         case FULLSCREEN_WIDTH:
6128           next_maximized = FULLSCREEN_WIDTH;
6129           if (fs_state != FULLSCREEN_BOTH)
6130             [[self window] performZoom:self];
6131           break;
6132         case FULLSCREEN_HEIGHT:
6133           next_maximized = FULLSCREEN_HEIGHT;
6134           if (fs_state != FULLSCREEN_BOTH)
6135             [[self window] performZoom:self];
6136           break;
6137         case FULLSCREEN_MAXIMIZED:
6138           next_maximized = FULLSCREEN_MAXIMIZED;
6139           if (fs_state != FULLSCREEN_BOTH)
6140             [[self window] performZoom:self];
6141           break;
6142         case FULLSCREEN_NONE:
6143           if (fs_state != FULLSCREEN_BOTH)
6144             {
6145               next_maximized = FULLSCREEN_NONE;
6146               [[self window] performZoom:self];
6147             }
6148           break;
6149         }
6151       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6152     }
6156 - (void) setFSValue: (int)value
6158   Lisp_Object lval = Qnil;
6159   switch (value)
6160     {
6161     case FULLSCREEN_BOTH:
6162       lval = Qfullboth;
6163       break;
6164     case FULLSCREEN_WIDTH:
6165       lval = Qfullwidth;
6166       break;
6167     case FULLSCREEN_HEIGHT:
6168       lval = Qfullheight;
6169       break;
6170     case FULLSCREEN_MAXIMIZED:
6171       lval = Qmaximized;
6172       break;
6173     }
6174   store_frame_param (emacsframe, Qfullscreen, lval);
6175   fs_state = value;
6178 - (void)mouseEntered: (NSEvent *)theEvent
6180   NSTRACE (mouseEntered);
6181   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6185 - (void)mouseExited: (NSEvent *)theEvent
6187   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6189   NSTRACE (mouseExited);
6191   if (!hlinfo)
6192     return;
6194   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6196   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6197     {
6198       clear_mouse_face (hlinfo);
6199       hlinfo->mouse_face_mouse_frame = 0;
6200     }
6204 - menuDown: sender
6206   NSTRACE (menuDown);
6207   if (context_menu_value == -1)
6208     context_menu_value = [sender tag];
6209   else
6210     {
6211       NSInteger tag = [sender tag];
6212       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6213                                     emacsframe->menu_bar_vector,
6214                                     (void *)tag);
6215     }
6217   ns_send_appdefined (-1);
6218   return self;
6222 - (EmacsToolbar *)toolbar
6224   return toolbar;
6228 /* this gets called on toolbar button click */
6229 - toolbarClicked: (id)item
6231   NSEvent *theEvent;
6232   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6234   NSTRACE (toolbarClicked);
6236   if (!emacs_event)
6237     return self;
6239   /* send first event (for some reason two needed) */
6240   theEvent = [[self window] currentEvent];
6241   emacs_event->kind = TOOL_BAR_EVENT;
6242   XSETFRAME (emacs_event->arg, emacsframe);
6243   EV_TRAILER (theEvent);
6245   emacs_event->kind = TOOL_BAR_EVENT;
6246 /*   XSETINT (emacs_event->code, 0); */
6247   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6248                            idx + TOOL_BAR_ITEM_KEY);
6249   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6250   EV_TRAILER (theEvent);
6251   return self;
6255 - toggleToolbar: (id)sender
6257   if (!emacs_event)
6258     return self;
6260   emacs_event->kind = NS_NONKEY_EVENT;
6261   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6262   EV_TRAILER ((id)nil);
6263   return self;
6267 - (void)drawRect: (NSRect)rect
6269   int x = NSMinX (rect), y = NSMinY (rect);
6270   int width = NSWidth (rect), height = NSHeight (rect);
6272   NSTRACE (drawRect);
6274   if (!emacsframe || !emacsframe->output_data.ns)
6275     return;
6277   ns_clear_frame_area (emacsframe, x, y, width, height);
6278   expose_frame (emacsframe, x, y, width, height);
6280   /*
6281     drawRect: may be called (at least in OS X 10.5) for invisible
6282     views as well for some reason.  Thus, do not infer visibility
6283     here.
6285     emacsframe->async_visible = 1;
6286     emacsframe->async_iconified = 0;
6287   */
6291 /* NSDraggingDestination protocol methods.  Actually this is not really a
6292    protocol, but a category of Object.  O well...  */
6294 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6296   NSTRACE (draggingEntered);
6297   return NSDragOperationGeneric;
6301 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6303   return YES;
6307 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6309   id pb;
6310   int x, y;
6311   NSString *type;
6312   NSEvent *theEvent = [[self window] currentEvent];
6313   NSPoint position;
6315   NSTRACE (performDragOperation);
6317   if (!emacs_event)
6318     return NO;
6320   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6321   x = lrint (position.x);  y = lrint (position.y);
6323   pb = [sender draggingPasteboard];
6324   type = [pb availableTypeFromArray: ns_drag_types];
6325   if (type == 0)
6326     {
6327       return NO;
6328     }
6329   else if ([type isEqualToString: NSFilenamesPboardType])
6330     {
6331       NSArray *files;
6332       NSEnumerator *fenum;
6333       NSString *file;
6335       if (!(files = [pb propertyListForType: type]))
6336         return NO;
6338       fenum = [files objectEnumerator];
6339       while ( (file = [fenum nextObject]) )
6340         {
6341           emacs_event->kind = NS_NONKEY_EVENT;
6342           emacs_event->code = KEY_NS_DRAG_FILE;
6343           XSETINT (emacs_event->x, x);
6344           XSETINT (emacs_event->y, y);
6345           ns_input_file = append2 (ns_input_file,
6346                                    build_string ([file UTF8String]));
6347           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6348           EV_TRAILER (theEvent);
6349         }
6350       return YES;
6351     }
6352   else if ([type isEqualToString: NSURLPboardType])
6353     {
6354       NSString *file;
6355       NSURL *fileURL;
6357       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6358           [fileURL isFileURL] == NO)
6359         return NO;
6361       file = [fileURL path];
6362       emacs_event->kind = NS_NONKEY_EVENT;
6363       emacs_event->code = KEY_NS_DRAG_FILE;
6364       XSETINT (emacs_event->x, x);
6365       XSETINT (emacs_event->y, y);
6366       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6367       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6368       EV_TRAILER (theEvent);
6369       return YES;
6370     }
6371   else if ([type isEqualToString: NSStringPboardType]
6372            || [type isEqualToString: NSTabularTextPboardType])
6373     {
6374       NSString *data;
6376       if (! (data = [pb stringForType: type]))
6377         return NO;
6379       emacs_event->kind = NS_NONKEY_EVENT;
6380       emacs_event->code = KEY_NS_DRAG_TEXT;
6381       XSETINT (emacs_event->x, x);
6382       XSETINT (emacs_event->y, y);
6383       ns_input_text = build_string ([data UTF8String]);
6384       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6385       EV_TRAILER (theEvent);
6386       return YES;
6387     }
6388   else if ([type isEqualToString: NSColorPboardType])
6389     {
6390       NSColor *c = [NSColor colorFromPasteboard: pb];
6391       emacs_event->kind = NS_NONKEY_EVENT;
6392       emacs_event->code = KEY_NS_DRAG_COLOR;
6393       XSETINT (emacs_event->x, x);
6394       XSETINT (emacs_event->y, y);
6395       ns_input_color = ns_color_to_lisp (c);
6396       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6397       EV_TRAILER (theEvent);
6398       return YES;
6399     }
6400   else if ([type isEqualToString: NSFontPboardType])
6401     {
6402       /* impl based on GNUstep NSTextView.m */
6403       NSData *data = [pb dataForType: NSFontPboardType];
6404       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6405       NSFont *font = [dict objectForKey: NSFontAttributeName];
6406       char fontSize[10];
6408       if (font == nil)
6409         return NO;
6411       emacs_event->kind = NS_NONKEY_EVENT;
6412       emacs_event->code = KEY_NS_CHANGE_FONT;
6413       XSETINT (emacs_event->x, x);
6414       XSETINT (emacs_event->y, y);
6415       ns_input_font = build_string ([[font fontName] UTF8String]);
6416       snprintf (fontSize, 10, "%f", [font pointSize]);
6417       ns_input_fontsize = build_string (fontSize);
6418       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6419       EV_TRAILER (theEvent);
6420       return YES;
6421     }
6422   else
6423     {
6424       error ("Invalid data type in dragging pasteboard.");
6425       return NO;
6426     }
6430 - (id) validRequestorForSendType: (NSString *)typeSent
6431                       returnType: (NSString *)typeReturned
6433   NSTRACE (validRequestorForSendType);
6434   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6435       && typeReturned == nil)
6436     {
6437       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6438         return self;
6439     }
6441   return [super validRequestorForSendType: typeSent
6442                                returnType: typeReturned];
6446 /* The next two methods are part of NSServicesRequests informal protocol,
6447    supposedly called when a services menu item is chosen from this app.
6448    But this should not happen because we override the services menu with our
6449    own entries which call ns-perform-service.
6450    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6451    So let's at least stub them out until further investigation can be done. */
6453 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6455   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6456      be written into the buffer in place of the existing selection..
6457      ordinary service calls go through functions defined in ns-win.el */
6458   return NO;
6461 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6463   NSArray *typesDeclared;
6464   Lisp_Object val;
6466   /* We only support NSStringPboardType */
6467   if ([types containsObject:NSStringPboardType] == NO) {
6468     return NO;
6469   }
6471   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6472   if (CONSP (val) && SYMBOLP (XCAR (val)))
6473     {
6474       val = XCDR (val);
6475       if (CONSP (val) && NILP (XCDR (val)))
6476         val = XCAR (val);
6477     }
6478   if (! STRINGP (val))
6479     return NO;
6481   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6482   [pb declareTypes:typesDeclared owner:nil];
6483   ns_string_to_pasteboard (pb, val);
6484   return YES;
6488 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6489    (gives a miniaturized version of the window); currently we use the latter for
6490    frames whose active buffer doesn't correspond to any file
6491    (e.g., '*scratch*') */
6492 - setMiniwindowImage: (BOOL) setMini
6494   id image = [[self window] miniwindowImage];
6495   NSTRACE (setMiniwindowImage);
6497   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6498      about "AppleDockIconEnabled" notwithstanding, however the set message
6499      below has its effect nonetheless. */
6500   if (image != emacsframe->output_data.ns->miniimage)
6501     {
6502       if (image && [image isKindOfClass: [EmacsImage class]])
6503         [image release];
6504       [[self window] setMiniwindowImage:
6505                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6506     }
6508   return self;
6512 - (void) setRows: (int) r andColumns: (int) c
6514   rows = r;
6515   cols = c;
6518 @end  /* EmacsView */
6522 /* ==========================================================================
6524     EmacsWindow implementation
6526    ========================================================================== */
6528 @implementation EmacsWindow
6530 #ifdef NS_IMPL_COCOA
6531 - (id)accessibilityAttributeValue:(NSString *)attribute
6533   Lisp_Object str = Qnil;
6534   struct frame *f = SELECTED_FRAME ();
6535   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->buffer);
6537   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6538     return NSAccessibilityTextFieldRole;
6540   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6541       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6542     {
6543       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6544     }
6545   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6546     {
6547       if (! NILP (BVAR (curbuf, mark_active)))
6548           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6550       if (NILP (str))
6551         {
6552           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6553           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6554           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6556           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6557             str = make_uninit_multibyte_string (range, byte_range);
6558           else
6559             str = make_uninit_string (range);
6560           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6561              Is this a problem?  */
6562           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6563         }
6564     }
6567   if (! NILP (str))
6568     {
6569       if (CONSP (str) && SYMBOLP (XCAR (str)))
6570         {
6571           str = XCDR (str);
6572           if (CONSP (str) && NILP (XCDR (str)))
6573             str = XCAR (str);
6574         }
6575       if (STRINGP (str))
6576         {
6577           const char *utfStr = SSDATA (str);
6578           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6579           return nsStr;
6580         }
6581     }
6583   return [super accessibilityAttributeValue:attribute];
6585 #endif /* NS_IMPL_COCOA */
6587 /* If we have multiple monitors, one above the other, we don't want to
6588    restrict the height to just one monitor.  So we override this.  */
6589 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6591   /* When making the frame visible for the first time or if there is just
6592      one screen, we want to constrain.  Other times not.  */
6593   NSUInteger nr_screens = [[NSScreen screens] count];
6594   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6595   NSTRACE (constrainFrameRect);
6597   if (nr_screens == 1)
6598     {
6599       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6600       return r;
6601     }
6603   if (f->output_data.ns->dont_constrain
6604       || ns_menu_bar_should_be_hidden ())
6605     return frameRect;
6607   f->output_data.ns->dont_constrain = 1;
6608   return [super constrainFrameRect:frameRect toScreen:screen];
6611 @end /* EmacsWindow */
6614 @implementation EmacsFSWindow
6616 - (BOOL)canBecomeKeyWindow
6618   return YES;
6621 - (BOOL)canBecomeMainWindow
6623   return YES;
6626 @end
6628 /* ==========================================================================
6630     EmacsScroller implementation
6632    ========================================================================== */
6635 @implementation EmacsScroller
6637 /* for repeat button push */
6638 #define SCROLL_BAR_FIRST_DELAY 0.5
6639 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6641 + (CGFloat) scrollerWidth
6643   /* TODO: if we want to allow variable widths, this is the place to do it,
6644            however neither GNUstep nor Cocoa support it very well */
6645   return [NSScroller scrollerWidth];
6649 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6651   NSTRACE (EmacsScroller_initFrame);
6653   r.size.width = [EmacsScroller scrollerWidth];
6654   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6655   [self setContinuous: YES];
6656   [self setEnabled: YES];
6658   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6659      locked against the top and bottom edges, and right edge on OS X, where
6660      scrollers are on right. */
6661 #ifdef NS_IMPL_GNUSTEP
6662   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6663 #else
6664   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6665 #endif
6667   win = nwin;
6668   condemned = NO;
6669   pixel_height = NSHeight (r);
6670   if (pixel_height == 0) pixel_height = 1;
6671   min_portion = 20 / pixel_height;
6673   frame = XFRAME (XWINDOW (win)->frame);
6674   if (FRAME_LIVE_P (frame))
6675     {
6676       int i;
6677       EmacsView *view = FRAME_NS_VIEW (frame);
6678       NSView *sview = [[view window] contentView];
6679       NSArray *subs = [sview subviews];
6681       /* disable optimization stopping redraw of other scrollbars */
6682       view->scrollbarsNeedingUpdate = 0;
6683       for (i =[subs count]-1; i >= 0; i--)
6684         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6685           view->scrollbarsNeedingUpdate++;
6686       [sview addSubview: self];
6687     }
6689 /*  [self setFrame: r]; */
6691   return self;
6695 - (void)setFrame: (NSRect)newRect
6697   NSTRACE (EmacsScroller_setFrame);
6698 /*  block_input (); */
6699   pixel_height = NSHeight (newRect);
6700   if (pixel_height == 0) pixel_height = 1;
6701   min_portion = 20 / pixel_height;
6702   [super setFrame: newRect];
6703   [self display];
6704 /*  unblock_input (); */
6708 - (void)dealloc
6710   NSTRACE (EmacsScroller_dealloc);
6711   if (!NILP (win))
6712     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6713   [super dealloc];
6717 - condemn
6719   NSTRACE (condemn);
6720   condemned =YES;
6721   return self;
6725 - reprieve
6727   NSTRACE (reprieve);
6728   condemned =NO;
6729   return self;
6733 - judge
6735   NSTRACE (judge);
6736   if (condemned)
6737     {
6738       EmacsView *view;
6739       block_input ();
6740       /* ensure other scrollbar updates after deletion */
6741       view = (EmacsView *)FRAME_NS_VIEW (frame);
6742       if (view != nil)
6743         view->scrollbarsNeedingUpdate++;
6744       [self removeFromSuperview];
6745       [self release];
6746       unblock_input ();
6747     }
6748   return self;
6752 - (void)resetCursorRects
6754   NSRect visible = [self visibleRect];
6755   NSTRACE (resetCursorRects);
6757   if (!NSIsEmptyRect (visible))
6758     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6759   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6763 - (int) checkSamePosition: (int) position portion: (int) portion
6764                     whole: (int) whole
6766   return em_position ==position && em_portion ==portion && em_whole ==whole
6767     && portion != whole; /* needed for resize empty buf */
6771 - setPosition: (int)position portion: (int)portion whole: (int)whole
6773   NSTRACE (setPosition);
6775   em_position = position;
6776   em_portion = portion;
6777   em_whole = whole;
6779   if (portion >= whole)
6780     {
6781 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6782       [self setKnobProportion: 1.0];
6783       [self setDoubleValue: 1.0];
6784 #else
6785       [self setFloatValue: 0.0 knobProportion: 1.0];
6786 #endif
6787     }
6788   else
6789     {
6790       float pos, por;
6791       portion = max ((float)whole*min_portion/pixel_height, portion);
6792       pos = (float)position / (whole - portion);
6793       por = (float)portion/whole;
6794 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6795       [self setKnobProportion: por];
6796       [self setDoubleValue: pos];
6797 #else
6798       [self setFloatValue: pos knobProportion: por];
6799 #endif
6800     }
6802   /* Events may come here even if the event loop is not running.
6803      If we don't enter the event loop, the scroll bar will not update.
6804      So send SIGIO to ourselves.  */
6805   if (apploopnr == 0) raise (SIGIO);
6807   return self;
6810 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6811      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6812 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6813                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6815   *part = last_hit_part;
6816   *window = win;
6817   XSETINT (*y, pixel_height);
6818   if ([self floatValue] > 0.999)
6819     XSETINT (*x, pixel_height);
6820   else
6821     XSETINT (*x, pixel_height * [self floatValue]);
6825 /* set up emacs_event */
6826 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6828   if (!emacs_event)
6829     return;
6831   emacs_event->part = last_hit_part;
6832   emacs_event->code = 0;
6833   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6834   emacs_event->frame_or_window = win;
6835   emacs_event->timestamp = EV_TIMESTAMP (e);
6836   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6837   emacs_event->arg = Qnil;
6838   XSETINT (emacs_event->x, loc * pixel_height);
6839   XSETINT (emacs_event->y, pixel_height-20);
6841   if (q_event_ptr)
6842     {
6843       n_emacs_events_pending++;
6844       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6845     }
6846   else
6847     hold_event (emacs_event);
6848   EVENT_INIT (*emacs_event);
6849   ns_send_appdefined (-1);
6853 /* called manually thru timer to implement repeated button action w/hold-down */
6854 - repeatScroll: (NSTimer *)scrollEntry
6856   NSEvent *e = [[self window] currentEvent];
6857   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6858   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6860   /* clear timer if need be */
6861   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6862     {
6863         [scroll_repeat_entry invalidate];
6864         [scroll_repeat_entry release];
6865         scroll_repeat_entry = nil;
6867         if (inKnob)
6868           return self;
6870         scroll_repeat_entry
6871           = [[NSTimer scheduledTimerWithTimeInterval:
6872                         SCROLL_BAR_CONTINUOUS_DELAY
6873                                             target: self
6874                                           selector: @selector (repeatScroll:)
6875                                           userInfo: 0
6876                                            repeats: YES]
6877               retain];
6878     }
6880   [self sendScrollEventAtLoc: 0 fromEvent: e];
6881   return self;
6885 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6886    mouseDragged events without going into a modal loop. */
6887 - (void)mouseDown: (NSEvent *)e
6889   NSRect sr, kr;
6890   /* hitPart is only updated AFTER event is passed on */
6891   NSScrollerPart part = [self testPart: [e locationInWindow]];
6892   double inc = 0.0, loc, kloc, pos;
6893   int edge = 0;
6895   NSTRACE (EmacsScroller_mouseDown);
6897   switch (part)
6898     {
6899     case NSScrollerDecrementPage:
6900         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6901     case NSScrollerIncrementPage:
6902         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6903     case NSScrollerDecrementLine:
6904       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6905     case NSScrollerIncrementLine:
6906       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6907     case NSScrollerKnob:
6908       last_hit_part = scroll_bar_handle; break;
6909     case NSScrollerKnobSlot:  /* GNUstep-only */
6910       last_hit_part = scroll_bar_move_ratio; break;
6911     default:  /* NSScrollerNoPart? */
6912       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6913                (long) part);
6914       return;
6915     }
6917   if (inc != 0.0)
6918     {
6919       pos = 0;      /* ignored */
6921       /* set a timer to repeat, as we can't let superclass do this modally */
6922       scroll_repeat_entry
6923         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6924                                             target: self
6925                                           selector: @selector (repeatScroll:)
6926                                           userInfo: 0
6927                                            repeats: YES]
6928             retain];
6929     }
6930   else
6931     {
6932       /* handle, or on GNUstep possibly slot */
6933       NSEvent *fake_event;
6935       /* compute float loc in slot and mouse offset on knob */
6936       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6937                       toView: nil];
6938       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6939       if (loc <= 0.0)
6940         {
6941           loc = 0.0;
6942           edge = -1;
6943         }
6944       else if (loc >= NSHeight (sr))
6945         {
6946           loc = NSHeight (sr);
6947           edge = 1;
6948         }
6950       if (edge)
6951         kloc = 0.5 * edge;
6952       else
6953         {
6954           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6955                           toView: nil];
6956           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6957         }
6958       last_mouse_offset = kloc;
6960       /* if knob, tell emacs a location offset by knob pos
6961          (to indicate top of handle) */
6962       if (part == NSScrollerKnob)
6963           pos = (loc - last_mouse_offset) / NSHeight (sr);
6964       else
6965         /* else this is a slot click on GNUstep: go straight there */
6966         pos = loc / NSHeight (sr);
6968       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6969       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6970                                       location: [e locationInWindow]
6971                                  modifierFlags: [e modifierFlags]
6972                                      timestamp: [e timestamp]
6973                                   windowNumber: [e windowNumber]
6974                                        context: [e context]
6975                                    eventNumber: [e eventNumber]
6976                                     clickCount: [e clickCount]
6977                                       pressure: [e pressure]];
6978       [super mouseUp: fake_event];
6979     }
6981   if (part != NSScrollerKnob)
6982     [self sendScrollEventAtLoc: pos fromEvent: e];
6986 /* Called as we manually track scroller drags, rather than superclass. */
6987 - (void)mouseDragged: (NSEvent *)e
6989     NSRect sr;
6990     double loc, pos;
6991     int edge = 0;
6993     NSTRACE (EmacsScroller_mouseDragged);
6995       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6996                       toView: nil];
6997       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6999       if (loc <= 0.0)
7000         {
7001           loc = 0.0;
7002           edge = -1;
7003         }
7004       else if (loc >= NSHeight (sr) + last_mouse_offset)
7005         {
7006           loc = NSHeight (sr) + last_mouse_offset;
7007           edge = 1;
7008         }
7010       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
7011       [self sendScrollEventAtLoc: pos fromEvent: e];
7015 - (void)mouseUp: (NSEvent *)e
7017   if (scroll_repeat_entry)
7018     {
7019       [scroll_repeat_entry invalidate];
7020       [scroll_repeat_entry release];
7021       scroll_repeat_entry = nil;
7022     }
7023   last_hit_part = 0;
7027 /* treat scrollwheel events in the bar as though they were in the main window */
7028 - (void) scrollWheel: (NSEvent *)theEvent
7030   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
7031   [view mouseDown: theEvent];
7034 @end  /* EmacsScroller */
7039 /* ==========================================================================
7041    Font-related functions; these used to be in nsfaces.m
7043    ========================================================================== */
7046 Lisp_Object
7047 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
7049   struct font *font = XFONT_OBJECT (font_object);
7051   if (fontset < 0)
7052     fontset = fontset_from_font (font_object);
7053   FRAME_FONTSET (f) = fontset;
7055   if (FRAME_FONT (f) == font)
7056     /* This font is already set in frame F.  There's nothing more to
7057        do.  */
7058     return font_object;
7060   FRAME_FONT (f) = font;
7062   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
7063   FRAME_COLUMN_WIDTH (f) = font->average_width;
7064   FRAME_LINE_HEIGHT (f) = font->height;
7066   compute_fringe_widths (f, 1);
7068   /* Compute the scroll bar width in character columns.  */
7069   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
7070     {
7071       int wid = FRAME_COLUMN_WIDTH (f);
7072       FRAME_CONFIG_SCROLL_BAR_COLS (f)
7073         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
7074     }
7075   else
7076     {
7077       int wid = FRAME_COLUMN_WIDTH (f);
7078       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
7079     }
7081   /* Now make the frame display the given font.  */
7082   if (FRAME_NS_WINDOW (f) != 0)
7083         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
7085   return font_object;
7089 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
7090 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
7091          in 1.43. */
7093 const char *
7094 ns_xlfd_to_fontname (const char *xlfd)
7095 /* --------------------------------------------------------------------------
7096     Convert an X font name (XLFD) to an NS font name.
7097     Only family is used.
7098     The string returned is temporarily allocated.
7099    -------------------------------------------------------------------------- */
7101   char *name = xmalloc (180);
7102   int i, len;
7103   const char *ret;
7105   if (!strncmp (xlfd, "--", 2))
7106     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
7107   else
7108     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
7110   /* stopgap for malformed XLFD input */
7111   if (strlen (name) == 0)
7112     strcpy (name, "Monaco");
7114   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
7115      also uppercase after '-' or ' ' */
7116   name[0] = c_toupper (name[0]);
7117   for (len =strlen (name), i =0; i<len; i++)
7118     {
7119       if (name[i] == '$')
7120         {
7121           name[i] = '-';
7122           if (i+1<len)
7123             name[i+1] = c_toupper (name[i+1]);
7124         }
7125       else if (name[i] == '_')
7126         {
7127           name[i] = ' ';
7128           if (i+1<len)
7129             name[i+1] = c_toupper (name[i+1]);
7130         }
7131     }
7132 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7133   ret = [[NSString stringWithUTF8String: name] UTF8String];
7134   xfree (name);
7135   return ret;
7139 void
7140 syms_of_nsterm (void)
7142   NSTRACE (syms_of_nsterm);
7144   ns_antialias_threshold = 10.0;
7146   /* from 23+ we need to tell emacs what modifiers there are.. */
7147   DEFSYM (Qmodifier_value, "modifier-value");
7148   DEFSYM (Qalt, "alt");
7149   DEFSYM (Qhyper, "hyper");
7150   DEFSYM (Qmeta, "meta");
7151   DEFSYM (Qsuper, "super");
7152   DEFSYM (Qcontrol, "control");
7153   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7155   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7156   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7157   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7158   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7159   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7161   DEFVAR_LISP ("ns-input-file", ns_input_file,
7162               "The file specified in the last NS event.");
7163   ns_input_file =Qnil;
7165   DEFVAR_LISP ("ns-input-text", ns_input_text,
7166               "The data received in the last NS text drag event.");
7167   ns_input_text =Qnil;
7169   DEFVAR_LISP ("ns-working-text", ns_working_text,
7170               "String for visualizing working composition sequence.");
7171   ns_working_text =Qnil;
7173   DEFVAR_LISP ("ns-input-font", ns_input_font,
7174               "The font specified in the last NS event.");
7175   ns_input_font =Qnil;
7177   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7178               "The fontsize specified in the last NS event.");
7179   ns_input_fontsize =Qnil;
7181   DEFVAR_LISP ("ns-input-line", ns_input_line,
7182                "The line specified in the last NS event.");
7183   ns_input_line =Qnil;
7185   DEFVAR_LISP ("ns-input-color", ns_input_color,
7186                "The color specified in the last NS event.");
7187   ns_input_color =Qnil;
7189   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7190                "The service name specified in the last NS event.");
7191   ns_input_spi_name =Qnil;
7193   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7194                "The service argument specified in the last NS event.");
7195   ns_input_spi_arg =Qnil;
7197   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7198                "This variable describes the behavior of the alternate or option key.\n\
7199 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7200 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7201 at all, allowing it to be used at a lower level for accented character entry.");
7202   ns_alternate_modifier = Qmeta;
7204   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7205                "This variable describes the behavior of the right alternate or option key.\n\
7206 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7207 Set to left means be the same key as `ns-alternate-modifier'.\n\
7208 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7209 at all, allowing it to be used at a lower level for accented character entry.");
7210   ns_right_alternate_modifier = Qleft;
7212   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7213                "This variable describes the behavior of the command key.\n\
7214 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7215   ns_command_modifier = Qsuper;
7217   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7218                "This variable describes the behavior of the right command key.\n\
7219 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7220 Set to left means be the same key as `ns-command-modifier'.\n\
7221 Set to none means that the command / option key is not interpreted by Emacs\n\
7222 at all, allowing it to be used at a lower level for accented character entry.");
7223   ns_right_command_modifier = Qleft;
7225   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7226                "This variable describes the behavior of the control key.\n\
7227 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7228   ns_control_modifier = Qcontrol;
7230   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7231                "This variable describes the behavior of the right control key.\n\
7232 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7233 Set to left means be the same key as `ns-control-modifier'.\n\
7234 Set to none means that the control / option key is not interpreted by Emacs\n\
7235 at all, allowing it to be used at a lower level for accented character entry.");
7236   ns_right_control_modifier = Qleft;
7238   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7239                "This variable describes the behavior of the function key (on laptops).\n\
7240 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7241 Set to none means that the function key is not interpreted by Emacs at all,\n\
7242 allowing it to be used at a lower level for accented character entry.");
7243   ns_function_modifier = Qnone;
7245   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7246                "Non-nil (the default) means to render text antialiased.");
7247   ns_antialias_text = Qt;
7249   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7250                "Whether to confirm application quit using dialog.");
7251   ns_confirm_quit = Qnil;
7253   staticpro (&ns_display_name_list);
7254   ns_display_name_list = Qnil;
7256   staticpro (&last_mouse_motion_frame);
7257   last_mouse_motion_frame = Qnil;
7259   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7260                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7261 Only works on OSX 10.6 or later.  */);
7262   ns_auto_hide_menu_bar = Qnil;
7264   DEFVAR_BOOL ("ns-use-native-fullscreen", ns_use_native_fullscreen,
7265      doc: /*Non-nil means to use native fullscreen on OSX >= 10.7.
7266 Nil means use fullscreen the old (< 10.7) way.  The old way works better with
7267 multiple monitors, but lacks tool bar.  This variable is ignored on OSX < 10.7.
7268 Default is t for OSX >= 10.7, nil otherwise. */);
7269 #ifdef HAVE_NATIVE_FS
7270   ns_use_native_fullscreen = YES;
7271 #else
7272   ns_use_native_fullscreen = NO;
7273 #endif
7274   ns_last_use_native_fullscreen = ns_use_native_fullscreen;
7276   /* TODO: move to common code */
7277   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7278                doc: /* Which toolkit scroll bars Emacs uses, if any.
7279 A value of nil means Emacs doesn't use toolkit scroll bars.
7280 With the X Window system, the value is a symbol describing the
7281 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7282 With MS Windows or Nextstep, the value is t.  */);
7283   Vx_toolkit_scroll_bars = Qt;
7285   DEFVAR_BOOL ("x-use-underline-position-properties",
7286                x_use_underline_position_properties,
7287      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7288 A value of nil means ignore them.  If you encounter fonts with bogus
7289 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7290 to 4.1, set this to nil. */);
7291   x_use_underline_position_properties = 0;
7293   DEFVAR_BOOL ("x-underline-at-descent-line",
7294                x_underline_at_descent_line,
7295      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7296 A value of nil means to draw the underline according to the value of the
7297 variable `x-use-underline-position-properties', which is usually at the
7298 baseline level.  The default value is nil.  */);
7299   x_underline_at_descent_line = 0;
7301   /* Tell emacs about this window system. */
7302   Fprovide (intern ("ns"), Qnil);