Load term/internal from loadup.el.
[emacs.git] / src / nsterm.m
blob9b2e544c75baa8a9f0c9bc02f9e3e951cfa01f7c
1 /* NeXT/Open/GNUstep / MacOSX communication module.
3 Copyright (C) 1989, 1993-1994, 2005-2006, 2008-2012
4   Free Software 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 <math.h>
34 #include <sys/types.h>
35 #include <time.h>
36 #include <signal.h>
37 #include <unistd.h>
39 #include <c-ctype.h>
40 #include <c-strcase.h>
41 #include <ftoastr.h>
43 #ifdef HAVE_FCNTL_H
44 #include <fcntl.h>
45 #endif
47 #include "lisp.h"
48 #include "blockinput.h"
49 #include "sysselect.h"
50 #include "nsterm.h"
51 #include "systime.h"
52 #include "character.h"
53 #include "fontset.h"
54 #include "composite.h"
55 #include "ccl.h"
57 #include "termhooks.h"
58 #include "termchar.h"
60 #include "window.h"
61 #include "keyboard.h"
62 #include "buffer.h"
63 #include "font.h"
65 /* call tracing */
66 #if 0
67 int term_trace_num = 0;
68 #define NSTRACE(x)        fprintf (stderr, "%s:%d: [%d] " #x "\n",         \
69                                 __FILE__, __LINE__, ++term_trace_num)
70 #else
71 #define NSTRACE(x)
72 #endif
74 #if defined (NS_IMPL_COCOA) && \
75   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
76 #define NEW_STYLE_FS
77 #endif
79 extern NSString *NSMenuDidBeginTrackingNotification;
81 /* ==========================================================================
83     Local declarations
85    ========================================================================== */
87 /* Convert a symbol indexed with an NSxxx value to a value as defined
88    in keyboard.c (lispy_function_key). I hope this is a correct way
89    of doing things... */
90 static unsigned convert_ns_to_X_keysym[] =
92   NSHomeFunctionKey,            0x50,
93   NSLeftArrowFunctionKey,       0x51,
94   NSUpArrowFunctionKey,         0x52,
95   NSRightArrowFunctionKey,      0x53,
96   NSDownArrowFunctionKey,       0x54,
97   NSPageUpFunctionKey,          0x55,
98   NSPageDownFunctionKey,        0x56,
99   NSEndFunctionKey,             0x57,
100   NSBeginFunctionKey,           0x58,
101   NSSelectFunctionKey,          0x60,
102   NSPrintFunctionKey,           0x61,
103   NSExecuteFunctionKey,         0x62,
104   NSInsertFunctionKey,          0x63,
105   NSUndoFunctionKey,            0x65,
106   NSRedoFunctionKey,            0x66,
107   NSMenuFunctionKey,            0x67,
108   NSFindFunctionKey,            0x68,
109   NSHelpFunctionKey,            0x6A,
110   NSBreakFunctionKey,           0x6B,
112   NSF1FunctionKey,              0xBE,
113   NSF2FunctionKey,              0xBF,
114   NSF3FunctionKey,              0xC0,
115   NSF4FunctionKey,              0xC1,
116   NSF5FunctionKey,              0xC2,
117   NSF6FunctionKey,              0xC3,
118   NSF7FunctionKey,              0xC4,
119   NSF8FunctionKey,              0xC5,
120   NSF9FunctionKey,              0xC6,
121   NSF10FunctionKey,             0xC7,
122   NSF11FunctionKey,             0xC8,
123   NSF12FunctionKey,             0xC9,
124   NSF13FunctionKey,             0xCA,
125   NSF14FunctionKey,             0xCB,
126   NSF15FunctionKey,             0xCC,
127   NSF16FunctionKey,             0xCD,
128   NSF17FunctionKey,             0xCE,
129   NSF18FunctionKey,             0xCF,
130   NSF19FunctionKey,             0xD0,
131   NSF20FunctionKey,             0xD1,
132   NSF21FunctionKey,             0xD2,
133   NSF22FunctionKey,             0xD3,
134   NSF23FunctionKey,             0xD4,
135   NSF24FunctionKey,             0xD5,
137   NSBackspaceCharacter,         0x08,  /* 8: Not on some KBs. */
138   NSDeleteCharacter,            0xFF,  /* 127: Big 'delete' key upper right. */
139   NSDeleteFunctionKey,          0x9F,  /* 63272: Del forw key off main array. */
141   NSTabCharacter,               0x09,
142   0x19,                         0x09,  /* left tab->regular since pass shift */
143   NSCarriageReturnCharacter,    0x0D,
144   NSNewlineCharacter,           0x0D,
145   NSEnterCharacter,             0x8D,
147   0x1B,                         0x1B   /* escape */
150 static Lisp_Object Qmodifier_value;
151 Lisp_Object Qalt, Qcontrol, Qhyper, Qmeta, Qsuper;
152 extern Lisp_Object Qcursor_color, Qcursor_type, Qns, Qleft;
154 static Lisp_Object QUTF8_STRING;
156 /* On OS X picks up the default NSGlobalDomain AppleAntiAliasingThreshold,
157    the maximum font size to NOT antialias.  On GNUstep there is currently
158    no way to control this behavior. */
159 float ns_antialias_threshold;
161 /* Used to pick up AppleHighlightColor on OS X */
162 NSString *ns_selection_color;
164 NSArray *ns_send_types =0, *ns_return_types =0, *ns_drag_types =0;
165 NSString *ns_app_name = @"Emacs";  /* default changed later */
167 /* Display variables */
168 struct ns_display_info *x_display_list; /* Chain of existing displays */
169 Lisp_Object ns_display_name_list;
170 long context_menu_value = 0;
172 /* display update */
173 NSPoint last_mouse_motion_position;
174 static NSRect last_mouse_glyph;
175 static Time last_mouse_movement_time = 0;
176 static Lisp_Object last_mouse_motion_frame;
177 static EmacsScroller *last_mouse_scroll_bar = nil;
178 static struct frame *ns_updating_frame;
179 static NSView *focus_view = NULL;
180 static int ns_window_num = 0;
181 #ifdef NS_IMPL_GNUSTEP
182 static NSRect uRect;
183 #endif
184 static BOOL gsaved = NO;
185 static BOOL ns_fake_keydown = NO;
186 int ns_tmp_flags; /* FIXME */
187 struct nsfont_info *ns_tmp_font; /* FIXME */
188 static BOOL ns_menu_bar_is_hidden = NO;
189 /*static int debug_lock = 0; */
191 /* event loop */
192 static BOOL send_appdefined = YES;
193 #define NO_APPDEFINED_DATA (-8)
194 static int last_appdefined_event_data = NO_APPDEFINED_DATA;
195 static NSTimer *timed_entry = 0;
196 static NSTimer *scroll_repeat_entry = nil;
197 static fd_set select_readfds, select_writefds;
198 enum { SELECT_HAVE_READ = 1, SELECT_HAVE_WRITE = 2, SELECT_HAVE_TMO = 4 };
199 static int select_nfds = 0, select_valid = 0;
200 static EMACS_TIME select_timeout = { 0, 0 };
201 static int selfds[2] = { -1, -1 };
202 static pthread_mutex_t select_mutex;
203 static int apploopnr = 0;
204 static NSAutoreleasePool *outerpool;
205 static struct input_event *emacs_event = NULL;
206 static struct input_event *q_event_ptr = NULL;
207 static int n_emacs_events_pending = 0;
208 static NSMutableArray *ns_pending_files, *ns_pending_service_names,
209   *ns_pending_service_args;
210 static BOOL ns_do_open_file = NO;
212 static struct {
213   struct input_event *q;
214   int nr, cap;
215 } hold_event_q = {
216   NULL, 0, 0
219 /* Convert modifiers in a NeXTstep event to emacs style modifiers.  */
220 #define NS_FUNCTION_KEY_MASK 0x800000
221 #define NSLeftControlKeyMask    (0x000001 | NSControlKeyMask)
222 #define NSRightControlKeyMask   (0x002000 | NSControlKeyMask)
223 #define NSLeftCommandKeyMask    (0x000008 | NSCommandKeyMask)
224 #define NSRightCommandKeyMask   (0x000010 | NSCommandKeyMask)
225 #define NSLeftAlternateKeyMask  (0x000020 | NSAlternateKeyMask)
226 #define NSRightAlternateKeyMask (0x000040 | NSAlternateKeyMask)
227 #define EV_MODIFIERS(e)                               \
228     ((([e modifierFlags] & NSHelpKeyMask) ?           \
229            hyper_modifier : 0)                        \
230      | (!EQ (ns_right_alternate_modifier, Qleft) && \
231         (([e modifierFlags] & NSRightAlternateKeyMask) \
232          == NSRightAlternateKeyMask) ? \
233            parse_solitary_modifier (ns_right_alternate_modifier) : 0) \
234      | (([e modifierFlags] & NSAlternateKeyMask) ?                 \
235            parse_solitary_modifier (ns_alternate_modifier) : 0)   \
236      | (([e modifierFlags] & NSShiftKeyMask) ?     \
237            shift_modifier : 0)                        \
238      | (!EQ (ns_right_control_modifier, Qleft) && \
239         (([e modifierFlags] & NSRightControlKeyMask) \
240          == NSRightControlKeyMask) ? \
241            parse_solitary_modifier (ns_right_control_modifier) : 0) \
242      | (([e modifierFlags] & NSControlKeyMask) ?      \
243            parse_solitary_modifier (ns_control_modifier) : 0)     \
244      | (([e modifierFlags] & NS_FUNCTION_KEY_MASK) ?  \
245            parse_solitary_modifier (ns_function_modifier) : 0)    \
246      | (!EQ (ns_right_command_modifier, Qleft) && \
247         (([e modifierFlags] & NSRightCommandKeyMask) \
248          == NSRightCommandKeyMask) ? \
249            parse_solitary_modifier (ns_right_command_modifier) : 0) \
250      | (([e modifierFlags] & NSCommandKeyMask) ?      \
251            parse_solitary_modifier (ns_command_modifier):0))
253 #define EV_UDMODIFIERS(e)                                      \
254     ((([e type] == NSLeftMouseDown) ? down_modifier : 0)       \
255      | (([e type] == NSRightMouseDown) ? down_modifier : 0)    \
256      | (([e type] == NSOtherMouseDown) ? down_modifier : 0)    \
257      | (([e type] == NSLeftMouseDragged) ? down_modifier : 0)  \
258      | (([e type] == NSRightMouseDragged) ? down_modifier : 0) \
259      | (([e type] == NSOtherMouseDragged) ? down_modifier : 0) \
260      | (([e type] == NSLeftMouseUp)   ? up_modifier   : 0)     \
261      | (([e type] == NSRightMouseUp)   ? up_modifier   : 0)    \
262      | (([e type] == NSOtherMouseUp)   ? up_modifier   : 0))
264 #define EV_BUTTON(e)                                                         \
265     ((([e type] == NSLeftMouseDown) || ([e type] == NSLeftMouseUp)) ? 0 :    \
266       (([e type] == NSRightMouseDown) || ([e type] == NSRightMouseUp)) ? 2 : \
267      [e buttonNumber] - 1)
269 /* Convert the time field to a timestamp in milliseconds. */
270 #define EV_TIMESTAMP(e) ([e timestamp] * 1000)
272 /* This is a piece of code which is common to all the event handling
273    methods.  Maybe it should even be a function.  */
274 #define EV_TRAILER(e)                                                   \
275     {                                                                   \
276       XSETFRAME (emacs_event->frame_or_window, emacsframe);             \
277       if (e) emacs_event->timestamp = EV_TIMESTAMP (e);                 \
278       if (q_event_ptr)                                                  \
279         {                                                               \
280           n_emacs_events_pending++;                                     \
281           kbd_buffer_store_event_hold (emacs_event, q_event_ptr);       \
282         }                                                               \
283       else                                                              \
284         hold_event (emacs_event);                                       \
285       EVENT_INIT (*emacs_event);                                        \
286       ns_send_appdefined (-1);                                          \
287     }
289 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
291 /* TODO: get rid of need for these forward declarations */
292 static void ns_condemn_scroll_bars (struct frame *f);
293 static void ns_judge_scroll_bars (struct frame *f);
294 void x_set_frame_alpha (struct frame *f);
297 /* ==========================================================================
299     Utilities
301    ========================================================================== */
303 static void
304 hold_event (struct input_event *event)
306   if (hold_event_q.nr == hold_event_q.cap)
307     {
308       if (hold_event_q.cap == 0) hold_event_q.cap = 10;
309       else hold_event_q.cap *= 2;
310       hold_event_q.q = (struct input_event *)
311         xrealloc (hold_event_q.q, hold_event_q.cap * sizeof (*hold_event_q.q));
312     }
314   hold_event_q.q[hold_event_q.nr++] = *event;
317 static Lisp_Object
318 append2 (Lisp_Object list, Lisp_Object item)
319 /* --------------------------------------------------------------------------
320    Utility to append to a list
321    -------------------------------------------------------------------------- */
323   Lisp_Object array[2];
324   array[0] = list;
325   array[1] = Fcons (item, Qnil);
326   return Fnconc (2, &array[0]);
330 const char *
331 ns_etc_directory (void)
332 /* If running as a self-contained app bundle, return as a string the
333    filename of the etc directory, if present; else nil.  */
335   NSBundle *bundle = [NSBundle mainBundle];
336   NSString *resourceDir = [bundle resourcePath];
337   NSString *resourcePath;
338   NSFileManager *fileManager = [NSFileManager defaultManager];
339   BOOL isDir;
341   resourcePath = [resourceDir stringByAppendingPathComponent: @"etc"];
342   if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
343     {
344       if (isDir) return [resourcePath UTF8String];
345     }
346   return NULL;
350 const char *
351 ns_exec_path (void)
352 /* If running as a self-contained app bundle, return as a path string
353    the filenames of the libexec and bin directories, ie libexec:bin.
354    Otherwise, return nil.
355    Normally, Emacs does not add its own bin/ directory to the PATH.
356    However, a self-contained NS build has a different layout, with
357    bin/ and libexec/ subdirectories in the directory that contains
358    Emacs.app itself.
359    We put libexec first, because init_callproc_1 uses the first
360    element to initialize exec-directory.  An alternative would be
361    for init_callproc to check for invocation-directory/libexec.
364   NSBundle *bundle = [NSBundle mainBundle];
365   NSString *resourceDir = [bundle resourcePath];
366   NSString *binDir = [bundle bundlePath];
367   NSString *resourcePath, *resourcePaths;
368   NSRange range;
369   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
370   NSFileManager *fileManager = [NSFileManager defaultManager];
371   NSArray *paths;
372   NSEnumerator *pathEnum;
373   BOOL isDir;
375   range = [resourceDir rangeOfString: @"Contents"];
376   if (range.location != NSNotFound)
377     {
378       binDir = [binDir stringByAppendingPathComponent: @"Contents"];
379 #ifdef NS_IMPL_COCOA
380       binDir = [binDir stringByAppendingPathComponent: @"MacOS"];
381 #endif
382     }
384   paths = [binDir stringsByAppendingPaths:
385                 [NSArray arrayWithObjects: @"libexec", @"bin", nil]];
386   pathEnum = [paths objectEnumerator];
387   resourcePaths = @"";
389   while ((resourcePath = [pathEnum nextObject]))
390     {
391       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
392         if (isDir)
393           {
394             if ([resourcePaths length] > 0)
395               resourcePaths
396                 = [resourcePaths stringByAppendingString: pathSeparator];
397             resourcePaths
398               = [resourcePaths stringByAppendingString: resourcePath];
399           }
400     }
401   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
403   return NULL;
407 const char *
408 ns_load_path (void)
409 /* If running as a self-contained app bundle, return as a path string
410    the filenames of the site-lisp, lisp and leim directories.
411    Ie, site-lisp:lisp:leim.  Otherwise, return nil.  */
413   NSBundle *bundle = [NSBundle mainBundle];
414   NSString *resourceDir = [bundle resourcePath];
415   NSString *resourcePath, *resourcePaths;
416   NSString *pathSeparator = [NSString stringWithFormat: @"%c", SEPCHAR];
417   NSFileManager *fileManager = [NSFileManager defaultManager];
418   BOOL isDir;
419   NSArray *paths = [resourceDir stringsByAppendingPaths:
420                               [NSArray arrayWithObjects:
421                                          @"site-lisp", @"lisp", @"leim", nil]];
422   NSEnumerator *pathEnum = [paths objectEnumerator];
423   resourcePaths = @"";
425   /* Hack to skip site-lisp.  */
426   if (no_site_lisp) resourcePath = [pathEnum nextObject];
428   while ((resourcePath = [pathEnum nextObject]))
429     {
430       if ([fileManager fileExistsAtPath: resourcePath isDirectory: &isDir])
431         if (isDir)
432           {
433             if ([resourcePaths length] > 0)
434               resourcePaths
435                 = [resourcePaths stringByAppendingString: pathSeparator];
436             resourcePaths
437               = [resourcePaths stringByAppendingString: resourcePath];
438           }
439     }
440   if ([resourcePaths length] > 0) return [resourcePaths UTF8String];
442   return NULL;
445 static void
446 ns_timeout (int usecs)
447 /* --------------------------------------------------------------------------
448      Blocking timer utility used by ns_ring_bell
449    -------------------------------------------------------------------------- */
451   EMACS_TIME wakeup = add_emacs_time (current_emacs_time (),
452                                       make_emacs_time (0, usecs * 1000));
454   /* Keep waiting until past the time wakeup.  */
455   while (1)
456     {
457       EMACS_TIME timeout, now = current_emacs_time ();
458       if (EMACS_TIME_LE (wakeup, now))
459         break;
460       timeout = sub_emacs_time (wakeup, now);
462       /* Try to wait that long--but we might wake up sooner.  */
463       pselect (0, NULL, NULL, NULL, &timeout, NULL);
464     }
468 void
469 ns_release_object (void *obj)
470 /* --------------------------------------------------------------------------
471     Release an object (callable from C)
472    -------------------------------------------------------------------------- */
474     [(id)obj release];
478 void
479 ns_retain_object (void *obj)
480 /* --------------------------------------------------------------------------
481     Retain an object (callable from C)
482    -------------------------------------------------------------------------- */
484     [(id)obj retain];
488 void *
489 ns_alloc_autorelease_pool (void)
490 /* --------------------------------------------------------------------------
491      Allocate a pool for temporary objects (callable from C)
492    -------------------------------------------------------------------------- */
494   return [[NSAutoreleasePool alloc] init];
498 void
499 ns_release_autorelease_pool (void *pool)
500 /* --------------------------------------------------------------------------
501      Free a pool and temporary objects it refers to (callable from C)
502    -------------------------------------------------------------------------- */
504   ns_release_object (pool);
509 /* ==========================================================================
511     Focus (clipping) and screen update
513    ========================================================================== */
516 // Window constraining
517 // -------------------
519 // To ensure that the windows are not placed under the menu bar, they
520 // are typically moved by the call-back constrainFrameRect. However,
521 // by overriding it, it's possible to inhibit this, leaving the window
522 // in it's original position.
524 // It's possible to hide the menu bar. However, technically, it's only
525 // possible to hide it when the application is active. To ensure that
526 // this work properly, the menu bar and window constraining are
527 // deferred until the application becomes active.
529 // Even though it's not possible to manually move a window above the
530 // top of the screen, it is allowed if it's done programmatically,
531 // when the menu is hidden. This allows the editable area to cover the
532 // full screen height.
534 // Test cases
535 // ----------
537 // Use the following extra files:
539 //    init.el:
540 //       ;; Hide menu and place frame slightly above the top of the screen.
541 //       (setq ns-auto-hide-menu-bar t)
542 //       (set-frame-position (selected-frame) 0 -20)
544 // Test 1:
546 //    emacs -Q -l init.el
548 //    Result: No menu bar, and the title bar should be above the screen.
550 // Test 2:
552 //    emacs -Q
554 //    Result: Menu bar visible, frame placed immediately below the menu.
557 static void
558 ns_constrain_all_frames (void)
560   Lisp_Object tail, frame;
562   FOR_EACH_FRAME (tail, frame)
563     {
564       struct frame *f = XFRAME (frame);
565       if (FRAME_NS_P (f))
566         {
567           NSView *view = FRAME_NS_VIEW (f);
568           /* This no-op will trigger the default window placing
569            * constraint system. */
570           f->output_data.ns->dont_constrain = 0;
571           [[view window] setFrameOrigin:[[view window] frame].origin];
572         }
573     }
577 /* True, if the menu bar should be hidden.  */
579 static BOOL
580 ns_menu_bar_should_be_hidden (void)
582   return !NILP (ns_auto_hide_menu_bar)
583     && [NSApp respondsToSelector:@selector(setPresentationOptions:)];
587 /* Show or hide the menu bar, based on user setting.  */
589 static void
590 ns_update_auto_hide_menu_bar (void)
592 #ifdef NS_IMPL_COCOA
593 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
594   block_input ();
596   NSTRACE (ns_update_auto_hide_menu_bar);
598   if (NSApp != nil
599       && [NSApp isActive]
600       && [NSApp respondsToSelector:@selector(setPresentationOptions:)])
601     {
602       // Note, "setPresentationOptions" triggers an error unless the
603       // application is active.
604       BOOL menu_bar_should_be_hidden = ns_menu_bar_should_be_hidden ();
606       if (menu_bar_should_be_hidden != ns_menu_bar_is_hidden)
607         {
608           NSApplicationPresentationOptions options
609             = NSApplicationPresentationAutoHideDock;
611           if (menu_bar_should_be_hidden)
612             options |= NSApplicationPresentationAutoHideMenuBar;
614           [NSApp setPresentationOptions: options];
616           ns_menu_bar_is_hidden = menu_bar_should_be_hidden;
618           if (!ns_menu_bar_is_hidden)
619             {
620               ns_constrain_all_frames ();
621             }
622         }
623     }
625   unblock_input ();
626 #endif
627 #endif
631 static void
632 ns_update_begin (struct frame *f)
633 /* --------------------------------------------------------------------------
634    Prepare for a grouped sequence of drawing calls
635    external (RIF) call; whole frame, called before update_window_begin
636    -------------------------------------------------------------------------- */
638   NSView *view = FRAME_NS_VIEW (f);
639   NSRect r = [view frame];
640   NSBezierPath *bp;
641   NSTRACE (ns_update_begin);
643   ns_update_auto_hide_menu_bar ();
645   ns_updating_frame = f;
646   [view lockFocus];
648   /* drawRect may have been called for say the minibuffer, and then clip path
649      is for the minibuffer.  But the display engine may draw more because
650      we have set the frame as garbaged.  So reset clip path to the whole
651      view.  */
652   bp = [[NSBezierPath bezierPathWithRect: r] retain];
653   [bp setClip];
654   [bp release];
656 #ifdef NS_IMPL_GNUSTEP
657   uRect = NSMakeRect (0, 0, 0, 0);
658 #endif
662 static void
663 ns_update_window_begin (struct window *w)
664 /* --------------------------------------------------------------------------
665    Prepare for a grouped sequence of drawing calls
666    external (RIF) call; for one window, called after update_begin
667    -------------------------------------------------------------------------- */
669   struct frame *f = XFRAME (WINDOW_FRAME (w));
670  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
671   NSTRACE (ns_update_window_begin);
672   updated_window = w;
673   set_output_cursor (&w->cursor);
675   block_input ();
677   if (f == hlinfo->mouse_face_mouse_frame)
678     {
679       /* Don't do highlighting for mouse motion during the update.  */
680       hlinfo->mouse_face_defer = 1;
682         /* If the frame needs to be redrawn,
683            simply forget about any prior mouse highlighting.  */
684       if (FRAME_GARBAGED_P (f))
685         hlinfo->mouse_face_window = Qnil;
687       /* (further code for mouse faces ifdef'd out in other terms elided) */
688     }
690   unblock_input ();
694 static void
695 ns_update_window_end (struct window *w, int cursor_on_p,
696                       int mouse_face_overwritten_p)
697 /* --------------------------------------------------------------------------
698    Finished a grouped sequence of drawing calls
699    external (RIF) call; for one window called before update_end
700    -------------------------------------------------------------------------- */
702   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (XFRAME (w->frame));
704   /* note: this fn is nearly identical in all terms */
705   if (!w->pseudo_window_p)
706     {
707       block_input ();
709       if (cursor_on_p)
710         display_and_set_cursor (w, 1,
711                                 output_cursor.hpos, output_cursor.vpos,
712                                 output_cursor.x, output_cursor.y);
714       if (draw_window_fringes (w, 1))
715         x_draw_vertical_border (w);
717       unblock_input ();
718     }
720   /* If a row with mouse-face was overwritten, arrange for
721      frame_up_to_date to redisplay the mouse highlight.  */
722   if (mouse_face_overwritten_p)
723     {
724       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
725       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
726       hlinfo->mouse_face_window = Qnil;
727     }
729   updated_window = NULL;
730   NSTRACE (update_window_end);
734 static void
735 ns_update_end (struct frame *f)
736 /* --------------------------------------------------------------------------
737    Finished a grouped sequence of drawing calls
738    external (RIF) call; for whole frame, called after update_window_end
739    -------------------------------------------------------------------------- */
741   NSView *view = FRAME_NS_VIEW (f);
743 /*   if (f == MOUSE_HL_INFO (f)->mouse_face_mouse_frame) */
744     MOUSE_HL_INFO (f)->mouse_face_defer = 0;
746     block_input ();
748 #ifdef NS_IMPL_GNUSTEP
749   /* trigger flush only in the rectangle we tracked as being drawn */
750   [view unlockFocusNeedsFlush: NO];
751 /*fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", uRect.origin.x, uRect.origin.y, uRect.size.width, uRect.size.height); */
752   [view lockFocusInRect: uRect];
753 #endif
755   [view unlockFocus];
756   [[view window] flushWindow];
758   unblock_input ();
759   ns_updating_frame = NULL;
760   NSTRACE (ns_update_end);
764 static void
765 ns_flush (struct frame *f)
766 /* --------------------------------------------------------------------------
767    external (RIF) call
768    NS impl is no-op since currently we flush in ns_update_end and elsewhere
769    -------------------------------------------------------------------------- */
771     NSTRACE (ns_flush);
775 static void
776 ns_focus (struct frame *f, NSRect *r, int n)
777 /* --------------------------------------------------------------------------
778    Internal: Focus on given frame.  During small local updates this is used to
779      draw, however during large updates, ns_update_begin and ns_update_end are
780      called to wrap the whole thing, in which case these calls are stubbed out.
781      Except, on GNUstep, we accumulate the rectangle being drawn into, because
782      the back end won't do this automatically, and will just end up flushing
783      the entire window.
784    -------------------------------------------------------------------------- */
786 //  NSTRACE (ns_focus);
787 #ifdef NS_IMPL_GNUSTEP
788   NSRect u;
789     if (n == 2)
790       u = NSUnionRect (r[0], r[1]);
791     else if (r)
792       u = *r;
793 #endif
794 /* static int c =0;
795    fprintf (stderr, "focus: %d", c++);
796    if (r) fprintf (stderr, " (%.0f, %.0f : %.0f x %.0f)", r->origin.x, r->origin.y, r->size.width, r->size.height);
797    fprintf (stderr, "\n"); */
799   if (f != ns_updating_frame)
800     {
801       NSView *view = FRAME_NS_VIEW (f);
802       if (view != focus_view)
803         {
804           if (focus_view != NULL)
805             {
806               [focus_view unlockFocus];
807               [[focus_view window] flushWindow];
808 /*debug_lock--; */
809             }
811           if (view)
812 #ifdef NS_IMPL_GNUSTEP
813             r ? [view lockFocusInRect: u] : [view lockFocus];
814 #else
815             [view lockFocus];
816 #endif
817           focus_view = view;
818 /*if (view) debug_lock++; */
819         }
820 #ifdef NS_IMPL_GNUSTEP
821       else
822         {
823           /* more than one rect being drawn into */
824           if (view && r)
825             {
826               [view unlockFocus]; /* add prev rect to redraw list */
827               [view lockFocusInRect: u]; /* focus for draw in new rect */
828             }
829         }
830 #endif
831     }
832 #ifdef NS_IMPL_GNUSTEP
833   else
834     {
835       /* in batch mode, but in GNUstep must still track rectangles explicitly */
836       uRect = (r ? NSUnionRect (uRect, u) : [FRAME_NS_VIEW (f) visibleRect]);
837     }
838 #endif
840   /* clipping */
841   if (r)
842     {
843       [[NSGraphicsContext currentContext] saveGraphicsState];
844       if (n == 2)
845         NSRectClipList (r, 2);
846       else
847         NSRectClip (*r);
848       gsaved = YES;
849     }
853 static void
854 ns_unfocus (struct frame *f)
855 /* --------------------------------------------------------------------------
856      Internal: Remove focus on given frame
857    -------------------------------------------------------------------------- */
859 //  NSTRACE (ns_unfocus);
861   if (gsaved)
862     {
863       [[NSGraphicsContext currentContext] restoreGraphicsState];
864       gsaved = NO;
865     }
867   if (f != ns_updating_frame)
868     {
869       if (focus_view != NULL)
870         {
871           [focus_view unlockFocus];
872           [[focus_view window] flushWindow];
873           focus_view = NULL;
874 /*debug_lock--; */
875         }
876     }
880 static void
881 ns_clip_to_row (struct window *w, struct glyph_row *row, int area, BOOL gc)
882 /* --------------------------------------------------------------------------
883      Internal (but parallels other terms): Focus drawing on given row
884    -------------------------------------------------------------------------- */
886   struct frame *f = XFRAME (WINDOW_FRAME (w));
887   NSRect clip_rect;
888   int window_x, window_y, window_width;
890   window_box (w, area, &window_x, &window_y, &window_width, 0);
892   clip_rect.origin.x = window_x;
893   clip_rect.origin.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
894   clip_rect.origin.y = max (clip_rect.origin.y, window_y);
895   clip_rect.size.width = window_width;
896   clip_rect.size.height = row->visible_height;
898   ns_focus (f, &clip_rect, 1);
902 static void
903 ns_ring_bell (struct frame *f)
904 /* --------------------------------------------------------------------------
905      "Beep" routine
906    -------------------------------------------------------------------------- */
908   NSTRACE (ns_ring_bell);
909   if (visible_bell)
910     {
911       NSAutoreleasePool *pool;
912       struct frame *frame = SELECTED_FRAME ();
913       NSView *view;
915       block_input ();
916       pool = [[NSAutoreleasePool alloc] init];
918       view = FRAME_NS_VIEW (frame);
919       if (view != nil)
920         {
921           NSRect r, surr;
922           NSPoint dim = NSMakePoint (128, 128);
924           r = [view bounds];
925           r.origin.x += (r.size.width - dim.x) / 2;
926           r.origin.y += (r.size.height - dim.y) / 2;
927           r.size.width = dim.x;
928           r.size.height = dim.y;
929           surr = NSInsetRect (r, -2, -2);
930           ns_focus (frame, &surr, 1);
931           [[view window] cacheImageInRect: [view convertRect: surr toView:nil]];
932           [ns_lookup_indexed_color (NS_FACE_FOREGROUND
933                                       (FRAME_DEFAULT_FACE (frame)), frame) set];
934           NSRectFill (r);
935           [[view window] flushWindow];
936           ns_timeout (150000);
937           [[view window] restoreCachedImage];
938           [[view window] flushWindow];
939           ns_unfocus (frame);
940         }
941       [pool release];
942       unblock_input ();
943     }
944   else
945     {
946       NSBeep ();
947     }
951 static void
952 ns_reset_terminal_modes (struct terminal *terminal)
953 /*  Externally called as hook */
955   NSTRACE (ns_reset_terminal_modes);
959 static void
960 ns_set_terminal_modes (struct terminal *terminal)
961 /*  Externally called as hook */
963   NSTRACE (ns_set_terminal_modes);
968 /* ==========================================================================
970     Frame / window manager related functions
972    ========================================================================== */
975 static void
976 ns_raise_frame (struct frame *f)
977 /* --------------------------------------------------------------------------
978      Bring window to foreground and make it active
979    -------------------------------------------------------------------------- */
981   NSView *view = FRAME_NS_VIEW (f);
982   check_ns ();
983   block_input ();
984   FRAME_SAMPLE_VISIBILITY (f);
985   if (FRAME_VISIBLE_P (f))
986     {
987       [[view window] makeKeyAndOrderFront: NSApp];
988     }
989   unblock_input ();
993 static void
994 ns_lower_frame (struct frame *f)
995 /* --------------------------------------------------------------------------
996      Send window to back
997    -------------------------------------------------------------------------- */
999   NSView *view = FRAME_NS_VIEW (f);
1000   check_ns ();
1001   block_input ();
1002   [[view window] orderBack: NSApp];
1003   unblock_input ();
1007 static void
1008 ns_frame_raise_lower (struct frame *f, int raise)
1009 /* --------------------------------------------------------------------------
1010      External (hook)
1011    -------------------------------------------------------------------------- */
1013   NSTRACE (ns_frame_raise_lower);
1015   if (raise)
1016     ns_raise_frame (f);
1017   else
1018     ns_lower_frame (f);
1022 static void
1023 ns_frame_rehighlight (struct frame *frame)
1024 /* --------------------------------------------------------------------------
1025      External (hook): called on things like window switching within frame
1026    -------------------------------------------------------------------------- */
1028   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (frame);
1029   struct frame *old_highlight = dpyinfo->x_highlight_frame;
1031   NSTRACE (ns_frame_rehighlight);
1032   if (dpyinfo->x_focus_frame)
1033     {
1034       dpyinfo->x_highlight_frame
1035         = (FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1036            ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
1037            : dpyinfo->x_focus_frame);
1038       if (!FRAME_LIVE_P (dpyinfo->x_highlight_frame))
1039         {
1040           fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
1041           dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame;
1042         }
1043     }
1044   else
1045       dpyinfo->x_highlight_frame = 0;
1047   if (dpyinfo->x_highlight_frame &&
1048          dpyinfo->x_highlight_frame != old_highlight)
1049     {
1050       if (old_highlight)
1051         {
1052           x_update_cursor (old_highlight, 1);
1053           x_set_frame_alpha (old_highlight);
1054         }
1055       if (dpyinfo->x_highlight_frame)
1056         {
1057           x_update_cursor (dpyinfo->x_highlight_frame, 1);
1058           x_set_frame_alpha (dpyinfo->x_highlight_frame);
1059         }
1060     }
1064 void
1065 x_make_frame_visible (struct frame *f)
1066 /* --------------------------------------------------------------------------
1067      External: Show the window (X11 semantics)
1068    -------------------------------------------------------------------------- */
1070   NSTRACE (x_make_frame_visible);
1071   /* XXX: at some points in past this was not needed, as the only place that
1072      called this (frame.c:Fraise_frame ()) also called raise_lower;
1073      if this ends up the case again, comment this out again. */
1074   if (!FRAME_VISIBLE_P (f))
1075     {
1076       EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1077       f->async_visible = 1;
1078       ns_raise_frame (f);
1080 #ifdef NEW_STYLE_FS
1081       /* Making a new frame from a fullscreen frame will make the new frame
1082          fullscreen also.  So skip handleFS as this will print an error.  */
1083       if (f->want_fullscreen == FULLSCREEN_BOTH
1084           && ([[view window] styleMask] & NSFullScreenWindowMask) != 0)
1085         return;
1086 #endif
1087       if (f->want_fullscreen != FULLSCREEN_NONE)
1088         {
1089           block_input ();
1090           [view handleFS];
1091           unblock_input ();
1092         }
1093     }
1097 void
1098 x_make_frame_invisible (struct frame *f)
1099 /* --------------------------------------------------------------------------
1100      External: Hide the window (X11 semantics)
1101    -------------------------------------------------------------------------- */
1103   NSView * view = FRAME_NS_VIEW (f);
1104   NSTRACE (x_make_frame_invisible);
1105   check_ns ();
1106   [[view window] orderOut: NSApp];
1107   f->async_visible = 0;
1108   f->async_iconified = 0;
1112 void
1113 x_iconify_frame (struct frame *f)
1114 /* --------------------------------------------------------------------------
1115      External: Iconify window
1116    -------------------------------------------------------------------------- */
1118   NSView * view = FRAME_NS_VIEW (f);
1119   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1120   NSTRACE (x_iconify_frame);
1121   check_ns ();
1123   if (dpyinfo->x_highlight_frame == f)
1124     dpyinfo->x_highlight_frame = 0;
1126   if ([[view window] windowNumber] <= 0)
1127     {
1128       /* the window is still deferred.  Make it very small, bring it
1129          on screen and order it out. */
1130       NSRect s = { { 100, 100}, {0, 0} };
1131       NSRect t;
1132       t = [[view window] frame];
1133       [[view window] setFrame: s display: NO];
1134       [[view window] orderBack: NSApp];
1135       [[view window] orderOut: NSApp];
1136       [[view window] setFrame: t display: NO];
1137     }
1138   [[view window] miniaturize: NSApp];
1141 /* Free X resources of frame F.  */
1143 void
1144 x_free_frame_resources (struct frame *f)
1146   NSView *view = FRAME_NS_VIEW (f);
1147   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1148   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1149   NSTRACE (x_free_frame_resources);
1150   check_ns ();
1152   [(EmacsView *)view setWindowClosing: YES]; /* may not have been informed */
1154   block_input ();
1156   free_frame_menubar (f);
1158   if (FRAME_FACE_CACHE (f))
1159     free_frame_faces (f);
1161   if (f == dpyinfo->x_focus_frame)
1162     dpyinfo->x_focus_frame = 0;
1163   if (f == dpyinfo->x_highlight_frame)
1164     dpyinfo->x_highlight_frame = 0;
1165   if (f == hlinfo->mouse_face_mouse_frame)
1166     {
1167       hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
1168       hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
1169       hlinfo->mouse_face_window = Qnil;
1170       hlinfo->mouse_face_deferred_gc = 0;
1171       hlinfo->mouse_face_mouse_frame = 0;
1172     }
1174   if (f->output_data.ns->miniimage != nil)
1175     [f->output_data.ns->miniimage release];
1177   [[view window] close];
1178   [view release];
1180   xfree (f->output_data.ns);
1182   unblock_input ();
1185 void
1186 x_destroy_window (struct frame *f)
1187 /* --------------------------------------------------------------------------
1188      External: Delete the window
1189    -------------------------------------------------------------------------- */
1191   NSTRACE (x_destroy_window);
1192   check_ns ();
1193   x_free_frame_resources (f);
1194   ns_window_num--;
1198 void
1199 x_set_offset (struct frame *f, int xoff, int yoff, int change_grav)
1200 /* --------------------------------------------------------------------------
1201      External: Position the window
1202    -------------------------------------------------------------------------- */
1204   NSView *view = FRAME_NS_VIEW (f);
1205   NSArray *screens = [NSScreen screens];
1206   NSScreen *fscreen = [screens objectAtIndex: 0];
1207   NSScreen *screen = [[view window] screen];
1209   NSTRACE (x_set_offset);
1211   block_input ();
1213   f->left_pos = xoff;
1214   f->top_pos = yoff;
1216   if (view != nil && screen && fscreen)
1217     {
1218       f->left_pos = f->size_hint_flags & XNegative
1219         ? [screen visibleFrame].size.width + f->left_pos - FRAME_PIXEL_WIDTH (f)
1220         : f->left_pos;
1221       /* We use visibleFrame here to take menu bar into account.
1222          Ideally we should also adjust left/top with visibleFrame.origin.  */
1224       f->top_pos = f->size_hint_flags & YNegative
1225         ? ([screen visibleFrame].size.height + f->top_pos
1226            - FRAME_PIXEL_HEIGHT (f) - FRAME_NS_TITLEBAR_HEIGHT (f)
1227            - FRAME_TOOLBAR_HEIGHT (f))
1228         : f->top_pos;
1229 #ifdef NS_IMPL_GNUSTEP
1230       if (f->left_pos < 100)
1231         f->left_pos = 100;  /* don't overlap menu */
1232 #endif
1233       /* Constrain the setFrameTopLeftPoint so we don't move behind the
1234          menu bar.  */
1235       f->output_data.ns->dont_constrain = 0;
1236       [[view window] setFrameTopLeftPoint:
1237                        NSMakePoint (SCREENMAXBOUND (f->left_pos),
1238                                     SCREENMAXBOUND ([fscreen frame].size.height
1239                                                     - NS_TOP_POS (f)))];
1240       f->size_hint_flags &= ~(XNegative|YNegative);
1241     }
1243   unblock_input ();
1247 void
1248 x_set_window_size (struct frame *f, int change_grav, int cols, int rows)
1249 /* --------------------------------------------------------------------------
1250      Adjust window pixel size based on given character grid size
1251      Impl is a bit more complex than other terms, need to do some
1252      internal clipping.
1253    -------------------------------------------------------------------------- */
1255   EmacsView *view = FRAME_NS_VIEW (f);
1256   NSWindow *window = [view window];
1257   NSRect wr = [window frame];
1258   int tb = FRAME_EXTERNAL_TOOL_BAR (f);
1259   int pixelwidth, pixelheight;
1261   NSTRACE (x_set_window_size);
1263   if (view == nil)
1264     return;
1266 /*fprintf (stderr, "\tsetWindowSize: %d x %d, font size %d x %d\n", cols, rows, FRAME_COLUMN_WIDTH (f), FRAME_LINE_HEIGHT (f)); */
1268   block_input ();
1270   check_frame_size (f, &rows, &cols);
1272   f->scroll_bar_actual_width = NS_SCROLL_BAR_WIDTH (f);
1273   compute_fringe_widths (f, 0);
1275   pixelwidth =  FRAME_TEXT_COLS_TO_PIXEL_WIDTH   (f, cols);
1276   pixelheight = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, rows);
1278   /* If we have a toolbar, take its height into account. */
1279   if (tb)
1280     /* NOTE: previously this would generate wrong result if toolbar not
1281              yet displayed and fixing toolbar_height=32 helped, but
1282              now (200903) seems no longer needed */
1283     FRAME_TOOLBAR_HEIGHT (f) =
1284       NSHeight ([window frameRectForContentRect: NSMakeRect (0, 0, 0, 0)])
1285         - FRAME_NS_TITLEBAR_HEIGHT (f);
1286   else
1287     FRAME_TOOLBAR_HEIGHT (f) = 0;
1289   wr.size.width = pixelwidth + f->border_width;
1290   wr.size.height = pixelheight + FRAME_NS_TITLEBAR_HEIGHT (f)
1291                   + FRAME_TOOLBAR_HEIGHT (f);
1293   /* Do not try to constrain to this screen.  We may have multiple
1294      screens, and want Emacs to span those.  Constraining to screen
1295      prevents that, and that is not nice to the user.  */
1296  if (f->output_data.ns->zooming)
1297    f->output_data.ns->zooming = 0;
1298  else
1299    wr.origin.y += FRAME_PIXEL_HEIGHT (f) - pixelheight;
1301   [view setRows: rows andColumns: cols];
1302   [window setFrame: wr display: YES];
1304 /*fprintf (stderr, "\tx_set_window_size %d, %d\t%d, %d\n", cols, rows, pixelwidth, pixelheight); */
1306   /* This is a trick to compensate for Emacs' managing the scrollbar area
1307      as a fixed number of standard character columns.  Instead of leaving
1308      blank space for the extra, we chopped it off above.  Now for
1309      left-hand scrollbars, we shift all rendering to the left by the
1310      difference between the real width and Emacs' imagined one.  For
1311      right-hand bars, don't worry about it since the extra is never used.
1312      (Obviously doesn't work for vertically split windows tho..) */
1313   {
1314     NSPoint origin = FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f)
1315       ? NSMakePoint (FRAME_SCROLL_BAR_COLS (f) * FRAME_COLUMN_WIDTH (f)
1316                      - NS_SCROLL_BAR_WIDTH (f), 0)
1317       : NSMakePoint (0, 0);
1318     [view setFrame: NSMakeRect (0, 0, pixelwidth, pixelheight)];
1319     [view setBoundsOrigin: origin];
1320   }
1322   change_frame_size (f, rows, cols, 0, 1, 0); /* pretend, delay, safe */
1323   FRAME_PIXEL_WIDTH (f) = pixelwidth;
1324   FRAME_PIXEL_HEIGHT (f) = pixelheight;
1325 /*  SET_FRAME_GARBAGED (f); // this short-circuits expose call in drawRect */
1327   mark_window_cursors_off (XWINDOW (f->root_window));
1328   cancel_mouse_face (f);
1330   unblock_input ();
1334 static void
1335 ns_fullscreen_hook (FRAME_PTR f)
1337   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (f);
1339   if (! f->async_visible) return;
1340 #ifndef NEW_STYLE_FS
1341   if (f->want_fullscreen == FULLSCREEN_BOTH)
1342     {
1343       /* Old style fs don't initiate correctly if created from
1344          init/default-frame alist, so use a timer (not nice...).
1345       */
1346       [NSTimer scheduledTimerWithTimeInterval: 0.5 target: view
1347                                      selector: @selector (handleFS)
1348                                      userInfo: nil repeats: NO];
1349       return;
1350     }
1351 #endif
1353   block_input ();
1354   [view handleFS];
1355   unblock_input ();
1358 /* ==========================================================================
1360     Color management
1362    ========================================================================== */
1365 NSColor *
1366 ns_lookup_indexed_color (unsigned long idx, struct frame *f)
1368   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1369   if (idx < 1 || idx >= color_table->avail)
1370     return nil;
1371   return color_table->colors[idx];
1375 unsigned long
1376 ns_index_color (NSColor *color, struct frame *f)
1378   struct ns_color_table *color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1379   ptrdiff_t idx;
1380   ptrdiff_t i;
1382   if (!color_table->colors)
1383     {
1384       color_table->size = NS_COLOR_CAPACITY;
1385       color_table->avail = 1; /* skip idx=0 as marker */
1386       color_table->colors = xmalloc (color_table->size * sizeof (NSColor *));
1387       color_table->colors[0] = nil;
1388       color_table->empty_indices = [[NSMutableSet alloc] init];
1389     }
1391   /* do we already have this color ? */
1392   for (i = 1; i < color_table->avail; i++)
1393     if (color_table->colors[i] && [color_table->colors[i] isEqual: color])
1394       return i;
1396   if ([color_table->empty_indices count] > 0)
1397     {
1398       NSNumber *index = [color_table->empty_indices anyObject];
1399       [color_table->empty_indices removeObject: index];
1400       idx = [index unsignedLongValue];
1401     }
1402   else
1403     {
1404       if (color_table->avail == color_table->size)
1405         color_table->colors =
1406           xpalloc (color_table->colors, &color_table->size, 1,
1407                    min (ULONG_MAX, PTRDIFF_MAX), sizeof *color_table->colors);
1408       idx = color_table->avail++;
1409     }
1411   color_table->colors[idx] = color;
1412   [color retain];
1413 /*fprintf(stderr, "color_table: allocated %d\n",idx);*/
1414   return idx;
1418 void
1419 ns_free_indexed_color (unsigned long idx, struct frame *f)
1421   struct ns_color_table *color_table;
1422   NSColor *color;
1423   NSNumber *index;
1425   if (!f)
1426     return;
1428   color_table = FRAME_NS_DISPLAY_INFO (f)->color_table;
1430   if (idx <= 0 || idx >= color_table->size) {
1431     message1 ("ns_free_indexed_color: Color index out of range.\n");
1432     return;
1433   }
1435   index = [NSNumber numberWithUnsignedInt: idx];
1436   if ([color_table->empty_indices containsObject: index]) {
1437     message1 ("ns_free_indexed_color: attempt to free already freed color.\n");
1438     return;
1439   }
1441   color = color_table->colors[idx];
1442   [color release];
1443   color_table->colors[idx] = nil;
1444   [color_table->empty_indices addObject: index];
1445 /*fprintf(stderr, "color_table: FREED %d\n",idx);*/
1449 static int
1450 ns_get_color (const char *name, NSColor **col)
1451 /* --------------------------------------------------------------------------
1452      Parse a color name
1453    -------------------------------------------------------------------------- */
1454 /* On *Step, we attempt to mimic the X11 platform here, down to installing an
1455    X11 rgb.txt-compatible color list in Emacs.clr (see ns_term_init()).
1456    See: http://thread.gmane.org/gmane.emacs.devel/113050/focus=113272). */
1458   NSColor *new = nil;
1459   static char hex[20];
1460   int scaling;
1461   float r = -1.0, g, b;
1462   NSString *nsname = [NSString stringWithUTF8String: name];
1464 /*fprintf (stderr, "ns_get_color: '%s'\n", name); */
1465   block_input ();
1467   if ([nsname isEqualToString: @"ns_selection_color"])
1468     {
1469       nsname = ns_selection_color;
1470       name = [ns_selection_color UTF8String];
1471     }
1473   /* First, check for some sort of numeric specification. */
1474   hex[0] = '\0';
1476   if (name[0] == '0' || name[0] == '1' || name[0] == '.')  /* RGB decimal */
1477     {
1478       NSScanner *scanner = [NSScanner scannerWithString: nsname];
1479       [scanner scanFloat: &r];
1480       [scanner scanFloat: &g];
1481       [scanner scanFloat: &b];
1482     }
1483   else if (!strncmp(name, "rgb:", 4))  /* A newer X11 format -- rgb:r/g/b */
1484     scaling = (snprintf (hex, sizeof hex, "%s", name + 4) - 2) / 3;
1485   else if (name[0] == '#')        /* An old X11 format; convert to newer */
1486     {
1487       int len = (strlen(name) - 1);
1488       int start = (len % 3 == 0) ? 1 : len / 4 + 1;
1489       int i;
1490       scaling = strlen(name+start) / 3;
1491       for (i = 0; i < 3; i++)
1492         sprintf (hex + i * (scaling + 1), "%.*s/", scaling,
1493                  name + start + i * scaling);
1494       hex[3 * (scaling + 1) - 1] = '\0';
1495     }
1497   if (hex[0])
1498     {
1499       int rr, gg, bb;
1500       float fscale = scaling == 4 ? 65535.0 : (scaling == 2 ? 255.0 : 15.0);
1501       if (sscanf (hex, "%x/%x/%x", &rr, &gg, &bb))
1502         {
1503           r = rr / fscale;
1504           g = gg / fscale;
1505           b = bb / fscale;
1506         }
1507     }
1509   if (r >= 0.0)
1510     {
1511       *col = [NSColor colorWithCalibratedRed: r green: g blue: b alpha: 1.0];
1512       unblock_input ();
1513       return 0;
1514     }
1516   /* Otherwise, color is expected to be from a list */
1517   {
1518     NSEnumerator *lenum, *cenum;
1519     NSString *name;
1520     NSColorList *clist;
1522 #ifdef NS_IMPL_GNUSTEP
1523     /* XXX: who is wrong, the requestor or the implementation? */
1524     if ([nsname compare: @"Highlight" options: NSCaseInsensitiveSearch]
1525         == NSOrderedSame)
1526       nsname = @"highlightColor";
1527 #endif
1529     lenum = [[NSColorList availableColorLists] objectEnumerator];
1530     while ( (clist = [lenum nextObject]) && new == nil)
1531       {
1532         cenum = [[clist allKeys] objectEnumerator];
1533         while ( (name = [cenum nextObject]) && new == nil )
1534           {
1535             if ([name compare: nsname
1536                       options: NSCaseInsensitiveSearch] == NSOrderedSame )
1537               new = [clist colorWithKey: name];
1538           }
1539       }
1540   }
1542   if (new)
1543     *col = [new colorUsingColorSpaceName: NSCalibratedRGBColorSpace];
1544   unblock_input ();
1545   return new ? 0 : 1;
1550 ns_lisp_to_color (Lisp_Object color, NSColor **col)
1551 /* --------------------------------------------------------------------------
1552      Convert a Lisp string object to a NS color
1553    -------------------------------------------------------------------------- */
1555   NSTRACE (ns_lisp_to_color);
1556   if (STRINGP (color))
1557     return ns_get_color (SSDATA (color), col);
1558   else if (SYMBOLP (color))
1559     return ns_get_color (SSDATA (SYMBOL_NAME (color)), col);
1560   return 1;
1564 Lisp_Object
1565 ns_color_to_lisp (NSColor *col)
1566 /* --------------------------------------------------------------------------
1567      Convert a color to a lisp string with the RGB equivalent
1568    -------------------------------------------------------------------------- */
1570   CGFloat red, green, blue, alpha, gray;
1571   char buf[1024];
1572   const char *str;
1573   NSTRACE (ns_color_to_lisp);
1575   block_input ();
1576   if ([[col colorSpaceName] isEqualToString: NSNamedColorSpace])
1578       if ((str =[[col colorNameComponent] UTF8String]))
1579         {
1580           unblock_input ();
1581           return build_string ((char *)str);
1582         }
1584     [[col colorUsingColorSpaceName: NSCalibratedRGBColorSpace]
1585         getRed: &red green: &green blue: &blue alpha: &alpha];
1586   if (red ==green && red ==blue)
1587     {
1588       [[col colorUsingColorSpaceName: NSCalibratedWhiteColorSpace]
1589             getWhite: &gray alpha: &alpha];
1590       snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1591                 lrint (gray * 0xff), lrint (gray * 0xff), lrint (gray * 0xff));
1592       unblock_input ();
1593       return build_string (buf);
1594     }
1596   snprintf (buf, sizeof (buf), "#%2.2lx%2.2lx%2.2lx",
1597             lrint (red*0xff), lrint (green*0xff), lrint (blue*0xff));
1599   unblock_input ();
1600   return build_string (buf);
1604 void
1605 ns_query_color(void *col, XColor *color_def, int setPixel)
1606 /* --------------------------------------------------------------------------
1607          Get ARGB values out of NSColor col and put them into color_def.
1608          If setPixel, set the pixel to a concatenated version.
1609          and set color_def pixel to the resulting index.
1610    -------------------------------------------------------------------------- */
1612   CGFloat r, g, b, a;
1614   [((NSColor *)col) getRed: &r green: &g blue: &b alpha: &a];
1615   color_def->red   = r * 65535;
1616   color_def->green = g * 65535;
1617   color_def->blue  = b * 65535;
1619   if (setPixel == YES)
1620     color_def->pixel
1621       = ARGB_TO_ULONG((int)(a*255),
1622                       (int)(r*255), (int)(g*255), (int)(b*255));
1626 bool
1627 ns_defined_color (struct frame *f,
1628                   const char *name,
1629                   XColor *color_def,
1630                   bool alloc,
1631                   bool makeIndex)
1632 /* --------------------------------------------------------------------------
1633          Return true if named color found, and set color_def rgb accordingly.
1634          If makeIndex and alloc are nonzero put the color in the color_table,
1635          and set color_def pixel to the resulting index.
1636          If makeIndex is zero, set color_def pixel to ARGB.
1637          Return false if not found
1638    -------------------------------------------------------------------------- */
1640   NSColor *col;
1641   NSTRACE (ns_defined_color);
1643   block_input ();
1644   if (ns_get_color (name, &col) != 0) /* Color not found  */
1645     {
1646       unblock_input ();
1647       return 0;
1648     }
1649   if (makeIndex && alloc)
1650     color_def->pixel = ns_index_color (col, f);
1651   ns_query_color (col, color_def, !makeIndex);
1652   unblock_input ();
1653   return 1;
1657 unsigned long
1658 ns_get_rgb_color (struct frame *f, float r, float g, float b, float a)
1659 /* --------------------------------------------------------------------------
1660     return an autoreleased RGB color
1661    -------------------------------------------------------------------------- */
1663 /*static int c = 1; fprintf (stderr, "color request %d\n", c++); */
1664   if (r < 0.0) r = 0.0;
1665   else if (r > 1.0) r = 1.0;
1666   if (g < 0.0) g = 0.0;
1667   else if (g > 1.0) g = 1.0;
1668   if (b < 0.0) b = 0.0;
1669   else if (b > 1.0) b = 1.0;
1670   if (a < 0.0) a = 0.0;
1671   else if (a > 1.0) a = 1.0;
1672   return (unsigned long) ns_index_color(
1673     [NSColor colorWithCalibratedRed: r green: g blue: b alpha: a], f);
1677 void
1678 x_set_frame_alpha (struct frame *f)
1679 /* --------------------------------------------------------------------------
1680      change the entire-frame transparency
1681    -------------------------------------------------------------------------- */
1683   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (f);
1684   EmacsView *view = FRAME_NS_VIEW (f);
1685   double alpha = 1.0;
1686   double alpha_min = 1.0;
1688   if (dpyinfo->x_highlight_frame == f)
1689     alpha = f->alpha[0];
1690   else
1691     alpha = f->alpha[1];
1693   if (FLOATP (Vframe_alpha_lower_limit))
1694     alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
1695   else if (INTEGERP (Vframe_alpha_lower_limit))
1696     alpha_min = (XINT (Vframe_alpha_lower_limit)) / 100.0;
1698   if (alpha < 0.0)
1699     return;
1700   else if (1.0 < alpha)
1701     alpha = 1.0;
1702   else if (0.0 <= alpha && alpha < alpha_min && alpha_min <= 1.0)
1703     alpha = alpha_min;
1705 #ifdef NS_IMPL_COCOA
1706   [[view window] setAlphaValue: alpha];
1707 #endif
1711 /* ==========================================================================
1713     Mouse handling
1715    ========================================================================== */
1718 void
1719 x_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
1720 /* --------------------------------------------------------------------------
1721      Programmatically reposition mouse pointer in pixel coordinates
1722    -------------------------------------------------------------------------- */
1724   NSTRACE (x_set_mouse_pixel_position);
1725   ns_raise_frame (f);
1726 #if 0
1727   /* FIXME: this does not work, and what about GNUstep? */
1728 #ifdef NS_IMPL_COCOA
1729   [FRAME_NS_VIEW (f) lockFocus];
1730   PSsetmouse ((float)pix_x, (float)pix_y);
1731   [FRAME_NS_VIEW (f) unlockFocus];
1732 #endif
1733 #endif
1737 void
1738 x_set_mouse_position (struct frame *f, int h, int v)
1739 /* --------------------------------------------------------------------------
1740      Programmatically reposition mouse pointer in character coordinates
1741    -------------------------------------------------------------------------- */
1743   int pix_x, pix_y;
1745   pix_x = FRAME_COL_TO_PIXEL_X (f, h) + FRAME_COLUMN_WIDTH (f) / 2;
1746   pix_y = FRAME_LINE_TO_PIXEL_Y (f, v) + FRAME_LINE_HEIGHT (f) / 2;
1748   if (pix_x < 0) pix_x = 0;
1749   if (pix_x > FRAME_PIXEL_WIDTH (f)) pix_x = FRAME_PIXEL_WIDTH (f);
1751   if (pix_y < 0) pix_y = 0;
1752   if (pix_y > FRAME_PIXEL_HEIGHT (f)) pix_y = FRAME_PIXEL_HEIGHT (f);
1754   x_set_mouse_pixel_position (f, pix_x, pix_y);
1758 static int
1759 note_mouse_movement (struct frame *frame, float x, float y)
1760 /*   ------------------------------------------------------------------------
1761      Called by EmacsView on mouseMovement events.  Passes on
1762      to emacs mainstream code if we moved off of a rect of interest
1763      known as last_mouse_glyph.
1764      ------------------------------------------------------------------------ */
1766 //  NSTRACE (note_mouse_movement);
1768   XSETFRAME (last_mouse_motion_frame, frame);
1770   /* Note, this doesn't get called for enter/leave, since we don't have a
1771      position.  Those are taken care of in the corresponding NSView methods. */
1773   /* has movement gone beyond last rect we were tracking? */
1774   if (x < last_mouse_glyph.origin.x ||
1775       x >= (last_mouse_glyph.origin.x + last_mouse_glyph.size.width) ||
1776       y < last_mouse_glyph.origin.y ||
1777       y >= (last_mouse_glyph.origin.y + last_mouse_glyph.size.height))
1778     {
1779       ns_update_begin(frame);
1780       frame->mouse_moved = 1;
1781       note_mouse_highlight (frame, x, y);
1782       remember_mouse_glyph (frame, x, y, &last_mouse_glyph);
1783       ns_update_end(frame);
1784       return 1;
1785     }
1787   return 0;
1791 static void
1792 ns_mouse_position (struct frame **fp, int insist, Lisp_Object *bar_window,
1793                    enum scroll_bar_part *part, Lisp_Object *x, Lisp_Object *y,
1794                    Time *time)
1795 /* --------------------------------------------------------------------------
1796     External (hook): inform emacs about mouse position and hit parts.
1797     If a scrollbar is being dragged, set bar_window, part, x, y, time.
1798     x & y should be position in the scrollbar (the whole bar, not the handle)
1799     and length of scrollbar respectively
1800    -------------------------------------------------------------------------- */
1802   id view;
1803   NSPoint position;
1804   Lisp_Object frame, tail;
1805   struct frame *f;
1806   struct ns_display_info *dpyinfo;
1808   NSTRACE (ns_mouse_position);
1810   if (*fp == NULL)
1811     {
1812       fprintf (stderr, "Warning: ns_mouse_position () called with null *fp.\n");
1813       return;
1814     }
1816   dpyinfo = FRAME_NS_DISPLAY_INFO (*fp);
1818   block_input ();
1820   if (last_mouse_scroll_bar != nil && insist == 0)
1821     {
1822       /* TODO: we do not use this path at the moment because drag events will
1823            go directly to the EmacsScroller.  Leaving code in for now. */
1824       [last_mouse_scroll_bar getMouseMotionPart: (int *)part window: bar_window
1825                                               x: x y: y];
1826       if (time) *time = last_mouse_movement_time;
1827       last_mouse_scroll_bar = nil;
1828     }
1829   else
1830     {
1831       /* Clear the mouse-moved flag for every frame on this display.  */
1832       FOR_EACH_FRAME (tail, frame)
1833         if (FRAME_NS_P (XFRAME (frame))
1834             && FRAME_NS_DISPLAY (XFRAME (frame)) == FRAME_NS_DISPLAY (*fp))
1835           XFRAME (frame)->mouse_moved = 0;
1837       last_mouse_scroll_bar = nil;
1838       if (last_mouse_frame && FRAME_LIVE_P (last_mouse_frame))
1839         f = last_mouse_frame;
1840       else
1841         f = dpyinfo->x_focus_frame ? dpyinfo->x_focus_frame
1842                                     : SELECTED_FRAME ();
1844       if (f && f->output_data.ns)  /* TODO: 2nd check no longer needed? */
1845         {
1846           view = FRAME_NS_VIEW (*fp);
1848           position = [[view window] mouseLocationOutsideOfEventStream];
1849           position = [view convertPoint: position fromView: nil];
1850           remember_mouse_glyph (f, position.x, position.y, &last_mouse_glyph);
1851 /*fprintf (stderr, "ns_mouse_position: %.0f, %.0f\n", position.x, position.y); */
1853           if (bar_window) *bar_window = Qnil;
1854           if (part) *part = 0; /*scroll_bar_handle; */
1856           if (x) XSETINT (*x, lrint (position.x));
1857           if (y) XSETINT (*y, lrint (position.y));
1858           if (time) *time = last_mouse_movement_time;
1859           *fp = f;
1860         }
1861     }
1863   unblock_input ();
1867 static void
1868 ns_frame_up_to_date (struct frame *f)
1869 /* --------------------------------------------------------------------------
1870     External (hook): Fix up mouse highlighting right after a full update.
1871     Some highlighting was deferred if GC was happening during
1872     note_mouse_highlight (), while other highlighting was deferred for update.
1873    -------------------------------------------------------------------------- */
1875   NSTRACE (ns_frame_up_to_date);
1877   if (FRAME_NS_P (f))
1878     {
1879       Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
1880       if ((hlinfo->mouse_face_deferred_gc || f ==hlinfo->mouse_face_mouse_frame)
1881       /*&& hlinfo->mouse_face_mouse_frame*/)
1882         {
1883           block_input ();
1884           ns_update_begin(f);
1885           if (hlinfo->mouse_face_mouse_frame)
1886             note_mouse_highlight (hlinfo->mouse_face_mouse_frame,
1887                                   hlinfo->mouse_face_mouse_x,
1888                                   hlinfo->mouse_face_mouse_y);
1889           hlinfo->mouse_face_deferred_gc = 0;
1890           ns_update_end(f);
1891           unblock_input ();
1892         }
1893     }
1897 static void
1898 ns_define_frame_cursor (struct frame *f, Cursor cursor)
1899 /* --------------------------------------------------------------------------
1900     External (RIF): set frame mouse pointer type.
1901    -------------------------------------------------------------------------- */
1903   NSTRACE (ns_define_frame_cursor);
1904   if (FRAME_POINTER_TYPE (f) != cursor)
1905     {
1906       EmacsView *view = FRAME_NS_VIEW (f);
1907       FRAME_POINTER_TYPE (f) = cursor;
1908       [[view window] invalidateCursorRectsForView: view];
1909       /* Redisplay assumes this function also draws the changed frame
1910          cursor, but this function doesn't, so do it explicitly.  */
1911       x_update_cursor (f, 1);
1912     }
1917 /* ==========================================================================
1919     Keyboard handling
1921    ========================================================================== */
1924 static unsigned
1925 ns_convert_key (unsigned code)
1926 /* --------------------------------------------------------------------------
1927     Internal call used by NSView-keyDown.
1928    -------------------------------------------------------------------------- */
1930   const unsigned last_keysym = (sizeof (convert_ns_to_X_keysym)
1931                                 / sizeof (convert_ns_to_X_keysym[0]));
1932   unsigned keysym;
1933   /* An array would be faster, but less easy to read. */
1934   for (keysym = 0; keysym < last_keysym; keysym += 2)
1935     if (code == convert_ns_to_X_keysym[keysym])
1936       return 0xFF00 | convert_ns_to_X_keysym[keysym+1];
1937   return 0;
1938 /* if decide to use keyCode and Carbon table, use this line:
1939      return code > 0xff ? 0 : 0xFF00 | ns_keycode_to_xkeysym_table[code]; */
1943 char *
1944 x_get_keysym_name (int keysym)
1945 /* --------------------------------------------------------------------------
1946     Called by keyboard.c.  Not sure if the return val is important, except
1947     that it be unique.
1948    -------------------------------------------------------------------------- */
1950   static char value[16];
1951   NSTRACE (x_get_keysym_name);
1952   sprintf (value, "%d", keysym);
1953   return value;
1958 /* ==========================================================================
1960     Block drawing operations
1962    ========================================================================== */
1965 static void
1966 ns_redraw_scroll_bars (struct frame *f)
1968   int i;
1969   id view;
1970   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
1971   NSTRACE (ns_redraw_scroll_bars);
1972   for (i =[subviews count]-1; i >= 0; i--)
1973     {
1974       view = [subviews objectAtIndex: i];
1975       if (![view isKindOfClass: [EmacsScroller class]]) continue;
1976       [view display];
1977     }
1981 void
1982 ns_clear_frame (struct frame *f)
1983 /* --------------------------------------------------------------------------
1984       External (hook): Erase the entire frame
1985    -------------------------------------------------------------------------- */
1987   NSView *view = FRAME_NS_VIEW (f);
1988   NSRect r;
1990   NSTRACE (ns_clear_frame);
1992  /* comes on initial frame because we have
1993     after-make-frame-functions = select-frame */
1994  if (!FRAME_DEFAULT_FACE (f))
1995    return;
1997   mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
1999   output_cursor.hpos = output_cursor.vpos = 0;
2000   output_cursor.x = -1;
2002   r = [view bounds];
2004   block_input ();
2005   ns_focus (f, &r, 1);
2006   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (FRAME_DEFAULT_FACE (f)), f) set];
2007   NSRectFill (r);
2008   ns_unfocus (f);
2010   /* as of 2006/11 or so this is now needed */
2011   ns_redraw_scroll_bars (f);
2012   unblock_input ();
2016 static void
2017 ns_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2018 /* --------------------------------------------------------------------------
2019     External (RIF):  Clear section of frame
2020    -------------------------------------------------------------------------- */
2022   NSRect r = NSMakeRect (x, y, width, height);
2023   NSView *view = FRAME_NS_VIEW (f);
2024   struct face *face = FRAME_DEFAULT_FACE (f);
2026   if (!view || !face)
2027     return;
2029   NSTRACE (ns_clear_frame_area);
2031   r = NSIntersectionRect (r, [view frame]);
2032   ns_focus (f, &r, 1);
2033   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), f) set];
2035   NSRectFill (r);
2037   ns_unfocus (f);
2038   return;
2042 static void
2043 ns_scroll_run (struct window *w, struct run *run)
2044 /* --------------------------------------------------------------------------
2045     External (RIF):  Insert or delete n lines at line vpos
2046    -------------------------------------------------------------------------- */
2048   struct frame *f = XFRAME (w->frame);
2049   int x, y, width, height, from_y, to_y, bottom_y;
2051   NSTRACE (ns_scroll_run);
2053   /* begin copy from other terms */
2054   /* Get frame-relative bounding box of the text display area of W,
2055      without mode lines.  Include in this box the left and right
2056      fringe of W.  */
2057   window_box (w, -1, &x, &y, &width, &height);
2059   from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
2060   to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
2061   bottom_y = y + height;
2063   if (to_y < from_y)
2064     {
2065       /* Scrolling up.  Make sure we don't copy part of the mode
2066          line at the bottom.  */
2067       if (from_y + run->height > bottom_y)
2068         height = bottom_y - from_y;
2069       else
2070         height = run->height;
2071     }
2072   else
2073     {
2074       /* Scrolling down.  Make sure we don't copy over the mode line.
2075          at the bottom.  */
2076       if (to_y + run->height > bottom_y)
2077         height = bottom_y - to_y;
2078       else
2079         height = run->height;
2080     }
2081   /* end copy from other terms */
2083   if (height == 0)
2084       return;
2086   block_input ();
2088   updated_window = w;
2089   x_clear_cursor (w);
2091   {
2092     NSRect srcRect = NSMakeRect (x, from_y, width, height);
2093     NSRect dstRect = NSMakeRect (x, to_y, width, height);
2094     NSPoint dstOrigin = NSMakePoint (x, to_y);
2096     ns_focus (f, &dstRect, 1);
2097     NSCopyBits (0, srcRect , dstOrigin);
2098     ns_unfocus (f);
2099   }
2101   unblock_input ();
2105 static void
2106 ns_after_update_window_line (struct glyph_row *desired_row)
2107 /* --------------------------------------------------------------------------
2108     External (RIF): preparatory to fringe update after text was updated
2109    -------------------------------------------------------------------------- */
2111   struct window *w = updated_window;
2112   struct frame *f;
2113   int width, height;
2115   NSTRACE (ns_after_update_window_line);
2117   /* begin copy from other terms */
2118   eassert (w);
2120   if (!desired_row->mode_line_p && !w->pseudo_window_p)
2121     desired_row->redraw_fringe_bitmaps_p = 1;
2123   /* When a window has disappeared, make sure that no rest of
2124      full-width rows stays visible in the internal border.  */
2125   if (windows_or_buffers_changed
2126       && desired_row->full_width_p
2127       && (f = XFRAME (w->frame),
2128           width = FRAME_INTERNAL_BORDER_WIDTH (f),
2129           width != 0)
2130       && (height = desired_row->visible_height,
2131           height > 0))
2132     {
2133       int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2135       block_input ();
2136       ns_clear_frame_area (f, 0, y, width, height);
2137       ns_clear_frame_area (f,
2138                            FRAME_PIXEL_WIDTH (f) - width,
2139                            y, width, height);
2140       unblock_input ();
2141     }
2145 static void
2146 ns_shift_glyphs_for_insert (struct frame *f,
2147                            int x, int y, int width, int height,
2148                            int shift_by)
2149 /* --------------------------------------------------------------------------
2150     External (RIF): copy an area horizontally, don't worry about clearing src
2151    -------------------------------------------------------------------------- */
2153   NSRect srcRect = NSMakeRect (x, y, width, height);
2154   NSRect dstRect = NSMakeRect (x+shift_by, y, width, height);
2155   NSPoint dstOrigin = dstRect.origin;
2157   NSTRACE (ns_shift_glyphs_for_insert);
2159   ns_focus (f, &dstRect, 1);
2160   NSCopyBits (0, srcRect, dstOrigin);
2161   ns_unfocus (f);
2166 /* ==========================================================================
2168     Character encoding and metrics
2170    ========================================================================== */
2173 static void
2174 ns_compute_glyph_string_overhangs (struct glyph_string *s)
2175 /* --------------------------------------------------------------------------
2176      External (RIF); compute left/right overhang of whole string and set in s
2177    -------------------------------------------------------------------------- */
2179   struct font *font = s->font;
2181   if (s->char2b)
2182     {
2183       struct font_metrics metrics;
2184       unsigned int codes[2];
2185       codes[0] = *(s->char2b);
2186       codes[1] = *(s->char2b + s->nchars - 1);
2188       font->driver->text_extents (font, codes, 2, &metrics);
2189       s->left_overhang = -metrics.lbearing;
2190       s->right_overhang
2191         = metrics.rbearing > metrics.width
2192         ? metrics.rbearing - metrics.width : 0;
2193     }
2194   else
2195     {
2196       s->left_overhang = 0;
2197       s->right_overhang = ((struct nsfont_info *)font)->ital ?
2198         FONT_HEIGHT (font) * 0.2 : 0;
2199     }
2204 /* ==========================================================================
2206     Fringe and cursor drawing
2208    ========================================================================== */
2211 extern int max_used_fringe_bitmap;
2212 static void
2213 ns_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
2214                       struct draw_fringe_bitmap_params *p)
2215 /* --------------------------------------------------------------------------
2216     External (RIF); fringe-related
2217    -------------------------------------------------------------------------- */
2219   struct frame *f = XFRAME (WINDOW_FRAME (w));
2220   struct face *face = p->face;
2221   int rowY;
2222   static EmacsImage **bimgs = NULL;
2223   static int nBimgs = 0;
2225   /* grow bimgs if needed */
2226   if (nBimgs < max_used_fringe_bitmap)
2227     {
2228       bimgs = xrealloc (bimgs, max_used_fringe_bitmap * sizeof *bimgs);
2229       memset (bimgs + nBimgs, 0,
2230               (max_used_fringe_bitmap - nBimgs) * sizeof *bimgs);
2231       nBimgs = max_used_fringe_bitmap;
2232     }
2234   /* Must clip because of partially visible lines.  */
2235   rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
2236   ns_clip_to_row (w, row, -1, YES);
2238   if (!p->overlay_p)
2239     {
2240       int bx = p->bx, by = p->by, nx = p->nx, ny = p->ny;
2242       /* If the fringe is adjacent to the left (right) scroll bar of a
2243          leftmost (rightmost, respectively) window, then extend its
2244          background to the gap between the fringe and the bar.  */
2245       if ((WINDOW_LEFTMOST_P (w)
2246            && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (w))
2247           || (WINDOW_RIGHTMOST_P (w)
2248               && WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)))
2249         {
2250           int sb_width = WINDOW_CONFIG_SCROLL_BAR_WIDTH (w);
2252           if (sb_width > 0)
2253             {
2254               int bar_area_x = WINDOW_SCROLL_BAR_AREA_X (w);
2255               int bar_area_width = (WINDOW_CONFIG_SCROLL_BAR_COLS (w)
2256                                     * FRAME_COLUMN_WIDTH (f));
2258               if (bx < 0)
2259                 {
2260                   /* Bitmap fills the fringe.  */
2261                   if (bar_area_x + bar_area_width == p->x)
2262                     bx = bar_area_x + sb_width;
2263                   else if (p->x + p->wd == bar_area_x)
2264                     bx = bar_area_x;
2265                   if (bx >= 0)
2266                     {
2267                       int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
2269                       nx = bar_area_width - sb_width;
2270                       by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height,
2271                                                             row->y));
2272                       ny = row->visible_height;
2273                     }
2274                 }
2275               else
2276                 {
2277                   if (bar_area_x + bar_area_width == bx)
2278                     {
2279                       bx = bar_area_x + sb_width;
2280                       nx += bar_area_width - sb_width;
2281                     }
2282                   else if (bx + nx == bar_area_x)
2283                     nx += bar_area_width - sb_width;
2284                 }
2285             }
2286         }
2288       if (bx >= 0 && nx > 0)
2289         {
2290           NSRect r = NSMakeRect (bx, by, nx, ny);
2291           NSRectClip (r);
2292           [ns_lookup_indexed_color (face->background, f) set];
2293           NSRectFill (r);
2294         }
2295     }
2297   if (p->which)
2298     {
2299       NSRect r = NSMakeRect (p->x, p->y, p->wd, p->h);
2300       EmacsImage *img = bimgs[p->which - 1];
2302       if (!img)
2303         {
2304           unsigned short *bits = p->bits + p->dh;
2305           int len = p->h;
2306           int i;
2307           unsigned char *cbits = xmalloc (len);
2309           for (i = 0; i < len; i++)
2310             cbits[i] = ~(bits[i] & 0xff);
2311           img = [[EmacsImage alloc] initFromXBM: cbits width: 8 height: p->h
2312                                            flip: NO];
2313           bimgs[p->which - 1] = img;
2314           xfree (cbits);
2315         }
2317       NSRectClip (r);
2318       /* Since we composite the bitmap instead of just blitting it, we need
2319          to erase the whole background. */
2320       [ns_lookup_indexed_color(face->background, f) set];
2321       NSRectFill (r);
2322       [img setXBMColor: ns_lookup_indexed_color(face->foreground, f)];
2323 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2324       [img drawInRect: r
2325               fromRect: NSZeroRect
2326              operation: NSCompositeSourceOver
2327               fraction: 1.0
2328            respectFlipped: YES
2329                 hints: nil];
2330 #else
2331       {
2332         NSPoint pt = r.origin;
2333         pt.y += p->h;
2334         [img compositeToPoint: pt operation: NSCompositeSourceOver];
2335       }
2336 #endif
2337     }
2338   ns_unfocus (f);
2342 static void
2343 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
2344                        int x, int y, int cursor_type, int cursor_width,
2345                        int on_p, int active_p)
2346 /* --------------------------------------------------------------------------
2347      External call (RIF): draw cursor.
2348      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
2349    -------------------------------------------------------------------------- */
2351   NSRect r, s;
2352   int fx, fy, h, cursor_height;
2353   struct frame *f = WINDOW_XFRAME (w);
2354   struct glyph *phys_cursor_glyph;
2355   int overspill;
2356   struct glyph *cursor_glyph;
2357   struct face *face;
2358   NSColor *hollow_color = FRAME_BACKGROUND_COLOR (f);
2360   /* If cursor is out of bounds, don't draw garbage.  This can happen
2361      in mini-buffer windows when switching between echo area glyphs
2362      and mini-buffer.  */
2364   NSTRACE (dumpcursor);
2366   if (!on_p)
2367     return;
2369   w->phys_cursor_type = cursor_type;
2370   w->phys_cursor_on_p = on_p;
2372   if (cursor_type == NO_CURSOR)
2373     {
2374       w->phys_cursor_width = 0;
2375       return;
2376     }
2378   if ((phys_cursor_glyph = get_phys_cursor_glyph (w)) == NULL)
2379     {
2380       if (glyph_row->exact_window_width_line_p
2381           && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
2382         {
2383           glyph_row->cursor_in_fringe_p = 1;
2384           draw_fringe_bitmap (w, glyph_row, 0);
2385         }
2386       return;
2387     }
2389   /* We draw the cursor (with NSRectFill), then draw the glyph on top
2390      (other terminals do it the other way round).  We must set
2391      w->phys_cursor_width to the cursor width.  For bar cursors, that
2392      is CURSOR_WIDTH; for box cursors, it is the glyph width.  */
2393   get_phys_cursor_geometry (w, glyph_row, phys_cursor_glyph, &fx, &fy, &h);
2395   /* The above get_phys_cursor_geometry call set w->phys_cursor_width
2396      to the glyph width; replace with CURSOR_WIDTH for (V)BAR cursors. */
2397   if (cursor_type == BAR_CURSOR)
2398     {
2399       if (cursor_width < 1)
2400         cursor_width = max (FRAME_CURSOR_WIDTH (f), 1);
2401       w->phys_cursor_width = cursor_width;
2402     }
2403   /* If we have an HBAR, "cursor_width" MAY specify height. */
2404   else if (cursor_type == HBAR_CURSOR)
2405     {
2406       cursor_height = (cursor_width < 1) ? lrint (0.25 * h) : cursor_width;
2407       fy += h - cursor_height;
2408       h = cursor_height;
2409     }
2411   r.origin.x = fx, r.origin.y = fy;
2412   r.size.height = h;
2413   r.size.width = w->phys_cursor_width;
2415   /* TODO: only needed in rare cases with last-resort font in HELLO..
2416      should we do this more efficiently? */
2417   ns_clip_to_row (w, glyph_row, -1, NO); /* do ns_focus(f, &r, 1); if remove */
2420   face = FACE_FROM_ID (f, phys_cursor_glyph->face_id);
2421   if (face && NS_FACE_BACKGROUND (face)
2422       == ns_index_color (FRAME_CURSOR_COLOR (f), f))
2423     {
2424       [ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), f) set];
2425       hollow_color = FRAME_CURSOR_COLOR (f);
2426     }
2427   else
2428     [FRAME_CURSOR_COLOR (f) set];
2430 #ifdef NS_IMPL_COCOA
2431   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
2432            atomic.  Cleaner ways of doing this should be investigated.
2433            One way would be to set a global variable DRAWING_CURSOR
2434            when making the call to draw_phys..(), don't focus in that
2435            case, then move the ns_unfocus() here after that call. */
2436   NSDisableScreenUpdates ();
2437 #endif
2439   switch (cursor_type)
2440     {
2441     case NO_CURSOR:
2442       break;
2443     case FILLED_BOX_CURSOR:
2444       NSRectFill (r);
2445       break;
2446     case HOLLOW_BOX_CURSOR:
2447       NSRectFill (r);
2448       [hollow_color set];
2449       NSRectFill (NSInsetRect (r, 1, 1));
2450       [FRAME_CURSOR_COLOR (f) set];
2451       break;
2452     case HBAR_CURSOR:
2453       NSRectFill (r);
2454       break;
2455     case BAR_CURSOR:
2456       s = r;
2457       /* If the character under cursor is R2L, draw the bar cursor
2458          on the right of its glyph, rather than on the left.  */
2459       cursor_glyph = get_phys_cursor_glyph (w);
2460       if ((cursor_glyph->resolved_level & 1) != 0)
2461         s.origin.x += cursor_glyph->pixel_width - s.size.width;
2463       NSRectFill (s);
2464       break;
2465     }
2466   ns_unfocus (f);
2468   /* draw the character under the cursor */
2469   if (cursor_type != NO_CURSOR)
2470     draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2472 #ifdef NS_IMPL_COCOA
2473   NSEnableScreenUpdates ();
2474 #endif
2479 static void
2480 ns_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
2481 /* --------------------------------------------------------------------------
2482      External (RIF): Draw a vertical line.
2483    -------------------------------------------------------------------------- */
2485   struct frame *f = XFRAME (WINDOW_FRAME (w));
2486   struct face *face;
2487   NSRect r = NSMakeRect (x, y0, 1, y1-y0);
2489   NSTRACE (ns_draw_vertical_window_border);
2491   face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID);
2492   if (face)
2493       [ns_lookup_indexed_color(face->foreground, f) set];
2495   ns_focus (f, &r, 1);
2496   NSRectFill(r);
2497   ns_unfocus (f);
2501 void
2502 show_hourglass (struct atimer *timer)
2504   if (hourglass_shown_p)
2505     return;
2507   block_input ();
2509   /* TODO: add NSProgressIndicator to selected frame (see macfns.c) */
2511   hourglass_shown_p = 1;
2512   unblock_input ();
2516 void
2517 hide_hourglass (void)
2519   if (!hourglass_shown_p)
2520     return;
2522   block_input ();
2524   /* TODO: remove NSProgressIndicator from all frames */
2526   hourglass_shown_p = 0;
2527   unblock_input ();
2532 /* ==========================================================================
2534     Glyph drawing operations
2536    ========================================================================== */
2538 static int
2539 ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr)
2540 /* --------------------------------------------------------------------------
2541     Wrapper utility to account for internal border width on full-width lines,
2542     and allow top full-width rows to hit the frame top.  nr should be pointer
2543     to two successive NSRects.  Number of rects actually used is returned.
2544    -------------------------------------------------------------------------- */
2546   int n = get_glyph_string_clip_rects (s, nr, 2);
2547   return n;
2550 /* --------------------------------------------------------------------
2551    Draw a wavy line under glyph string s. The wave fills wave_height
2552    pixels from y.
2554                     x          wave_length = 3
2555                                  --
2556                 y    *   *   *   *   *
2557                      |* * * * * * * * *
2558     wave_height = 3  | *   *   *   *
2559   --------------------------------------------------------------------- */
2561 static void
2562 ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2564   int wave_height = 3, wave_length = 3;
2565   int y, dx, dy, odd, xmax;
2566   NSPoint a, b;
2567   NSRect waveClip;
2569   dx = wave_length;
2570   dy = wave_height - 1;
2571   y =  s->ybase + 1;
2572   xmax = x + width;
2574   /* Find and set clipping rectangle */
2575   waveClip = NSMakeRect (x, y, width, wave_height);
2576   [[NSGraphicsContext currentContext] saveGraphicsState];
2577   NSRectClip (waveClip);
2579   /* Draw the waves */
2580   a.x = x - ((int)(x) % dx);
2581   b.x = a.x + dx;
2582   odd = (int)(a.x/dx) % 2;
2583   a.y = b.y = y;
2585   if (odd)
2586     a.y += dy;
2587   else
2588     b.y += dy;
2590   while (a.x <= xmax)
2591     {
2592       [NSBezierPath strokeLineFromPoint:a toPoint:b];
2593       a.x = b.x, a.y = b.y;
2594       b.x += dx, b.y = y + odd*dy;
2595       odd = !odd;
2596     }
2598   /* Restore previous clipping rectangle(s) */
2599   [[NSGraphicsContext currentContext] restoreGraphicsState];
2604 void
2605 ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2606                          NSColor *defaultCol, CGFloat width, CGFloat x)
2607 /* --------------------------------------------------------------------------
2608    Draw underline, overline, and strike-through on glyph string s.
2609    -------------------------------------------------------------------------- */
2611   if (s->for_overlaps)
2612     return;
2614   /* Do underline. */
2615   if (face->underline_p)
2616     {
2617       if (s->face->underline_type == FACE_UNDER_WAVE)
2618         {
2619           if (face->underline_defaulted_p)
2620             [defaultCol set];
2621           else
2622             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2624           ns_draw_underwave (s, width, x);
2625         }
2626       else if (s->face->underline_type == FACE_UNDER_LINE)
2627         {
2629           NSRect r;
2630           unsigned long thickness, position;
2632           /* If the prev was underlined, match its appearance. */
2633           if (s->prev && s->prev->face->underline_p
2634               && s->prev->underline_thickness > 0)
2635             {
2636               thickness = s->prev->underline_thickness;
2637               position = s->prev->underline_position;
2638             }
2639           else
2640             {
2641               struct font *font;
2642               unsigned long descent;
2644               font=s->font;
2645               descent = s->y + s->height - s->ybase;
2647               /* Use underline thickness of font, defaulting to 1. */
2648               thickness = (font && font->underline_thickness > 0)
2649                 ? font->underline_thickness : 1;
2651               /* Determine the offset of underlining from the baseline. */
2652               if (x_underline_at_descent_line)
2653                 position = descent - thickness;
2654               else if (x_use_underline_position_properties
2655                        && font && font->underline_position >= 0)
2656                 position = font->underline_position;
2657               else if (font)
2658                 position = lround (font->descent / 2);
2659               else
2660                 position = underline_minimum_offset;
2662               position = max (position, underline_minimum_offset);
2664               /* Ensure underlining is not cropped. */
2665               if (descent <= position)
2666                 {
2667                   position = descent - 1;
2668                   thickness = 1;
2669                 }
2670               else if (descent < position + thickness)
2671                 thickness = 1;
2672             }
2674           s->underline_thickness = thickness;
2675           s->underline_position = position;
2677           r = NSMakeRect (x, s->ybase + position, width, thickness);
2679           if (face->underline_defaulted_p)
2680             [defaultCol set];
2681           else
2682             [ns_lookup_indexed_color (face->underline_color, s->f) set];
2683           NSRectFill (r);
2684         }
2685     }
2686   /* Do overline. We follow other terms in using a thickness of 1
2687      and ignoring overline_margin. */
2688   if (face->overline_p)
2689     {
2690       NSRect r;
2691       r = NSMakeRect (x, s->y, width, 1);
2693       if (face->overline_color_defaulted_p)
2694         [defaultCol set];
2695       else
2696         [ns_lookup_indexed_color (face->overline_color, s->f) set];
2697       NSRectFill (r);
2698     }
2700   /* Do strike-through.  We follow other terms for thickness and
2701      vertical position.*/
2702   if (face->strike_through_p)
2703     {
2704       NSRect r;
2705       unsigned long dy;
2707       dy = lrint ((s->height - 1) / 2);
2708       r = NSMakeRect (x, s->y + dy, width, 1);
2710       if (face->strike_through_color_defaulted_p)
2711         [defaultCol set];
2712       else
2713         [ns_lookup_indexed_color (face->strike_through_color, s->f) set];
2714       NSRectFill (r);
2715     }
2718 static void
2719 ns_draw_box (NSRect r, float thickness, NSColor *col, char left_p, char right_p)
2720 /* --------------------------------------------------------------------------
2721     Draw an unfilled rect inside r, optionally leaving left and/or right open.
2722     Note we can't just use an NSDrawRect command, because of the possibility
2723     of some sides not being drawn, and because the rect will be filled.
2724    -------------------------------------------------------------------------- */
2726   NSRect s = r;
2727   [col set];
2729   /* top, bottom */
2730   s.size.height = thickness;
2731   NSRectFill (s);
2732   s.origin.y += r.size.height - thickness;
2733   NSRectFill (s);
2735   s.size.height = r.size.height;
2736   s.origin.y = r.origin.y;
2738   /* left, right (optional) */
2739   s.size.width = thickness;
2740   if (left_p)
2741     NSRectFill (s);
2742   if (right_p)
2743     {
2744       s.origin.x += r.size.width - thickness;
2745       NSRectFill (s);
2746     }
2750 static void
2751 ns_draw_relief (NSRect r, int thickness, char raised_p,
2752                char top_p, char bottom_p, char left_p, char right_p,
2753                struct glyph_string *s)
2754 /* --------------------------------------------------------------------------
2755     Draw a relief rect inside r, optionally leaving some sides open.
2756     Note we can't just use an NSDrawBezel command, because of the possibility
2757     of some sides not being drawn, and because the rect will be filled.
2758    -------------------------------------------------------------------------- */
2760   static NSColor *baseCol = nil, *lightCol = nil, *darkCol = nil;
2761   NSColor *newBaseCol = nil;
2762   NSRect sr = r;
2764   NSTRACE (ns_draw_relief);
2766   /* set up colors */
2768   if (s->face->use_box_color_for_shadows_p)
2769     {
2770       newBaseCol = ns_lookup_indexed_color (s->face->box_color, s->f);
2771     }
2772 /*     else if (s->first_glyph->type == IMAGE_GLYPH
2773            && s->img->pixmap
2774            && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
2775        {
2776          newBaseCol = IMAGE_BACKGROUND  (s->img, s->f, 0);
2777        } */
2778   else
2779     {
2780       newBaseCol = ns_lookup_indexed_color (s->face->background, s->f);
2781     }
2783   if (newBaseCol == nil)
2784     newBaseCol = [NSColor grayColor];
2786   if (newBaseCol != baseCol)  /* TODO: better check */
2787     {
2788       [baseCol release];
2789       baseCol = [newBaseCol retain];
2790       [lightCol release];
2791       lightCol = [[baseCol highlightWithLevel: 0.2] retain];
2792       [darkCol release];
2793       darkCol = [[baseCol shadowWithLevel: 0.3] retain];
2794     }
2796   [(raised_p ? lightCol : darkCol) set];
2798   /* TODO: mitering. Using NSBezierPath doesn't work because of color switch. */
2800   /* top */
2801   sr.size.height = thickness;
2802   if (top_p) NSRectFill (sr);
2804   /* left */
2805   sr.size.height = r.size.height;
2806   sr.size.width = thickness;
2807   if (left_p) NSRectFill (sr);
2809   [(raised_p ? darkCol : lightCol) set];
2811   /* bottom */
2812   sr.size.width = r.size.width;
2813   sr.size.height = thickness;
2814   sr.origin.y += r.size.height - thickness;
2815   if (bottom_p) NSRectFill (sr);
2817   /* right */
2818   sr.size.height = r.size.height;
2819   sr.origin.y = r.origin.y;
2820   sr.size.width = thickness;
2821   sr.origin.x += r.size.width - thickness;
2822   if (right_p) NSRectFill (sr);
2826 static void
2827 ns_dumpglyphs_box_or_relief (struct glyph_string *s)
2828 /* --------------------------------------------------------------------------
2829       Function modeled after x_draw_glyph_string_box ().
2830       Sets up parameters for drawing.
2831    -------------------------------------------------------------------------- */
2833   int right_x, last_x;
2834   char left_p, right_p;
2835   struct glyph *last_glyph;
2836   NSRect r;
2837   int thickness;
2838   struct face *face;
2840   if (s->hl == DRAW_MOUSE_FACE)
2841     {
2842       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2843       if (!face)
2844         face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2845     }
2846   else
2847     face = s->face;
2849   thickness = face->box_line_width;
2851   NSTRACE (ns_dumpglyphs_box_or_relief);
2853   last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
2854             ? WINDOW_RIGHT_EDGE_X (s->w)
2855             : window_box_right (s->w, s->area));
2856   last_glyph = (s->cmp || s->img
2857                 ? s->first_glyph : s->first_glyph + s->nchars-1);
2859   right_x = ((s->row->full_width_p && s->extends_to_end_of_line_p
2860               ? last_x - 1 : min (last_x, s->x + s->background_width) - 1));
2862   left_p = (s->first_glyph->left_box_line_p
2863             || (s->hl == DRAW_MOUSE_FACE
2864                 && (s->prev == NULL || s->prev->hl != s->hl)));
2865   right_p = (last_glyph->right_box_line_p
2866              || (s->hl == DRAW_MOUSE_FACE
2867                  && (s->next == NULL || s->next->hl != s->hl)));
2869   r = NSMakeRect (s->x, s->y, right_x - s->x + 1, s->height);
2871   /* TODO: Sometimes box_color is 0 and this seems wrong; should investigate. */
2872   if (s->face->box == FACE_SIMPLE_BOX && s->face->box_color)
2873     {
2874       ns_draw_box (r, abs (thickness),
2875                    ns_lookup_indexed_color (face->box_color, s->f),
2876                   left_p, right_p);
2877     }
2878   else
2879     {
2880       ns_draw_relief (r, abs (thickness), s->face->box == FACE_RAISED_BOX,
2881                      1, 1, left_p, right_p, s);
2882     }
2886 static void
2887 ns_maybe_dumpglyphs_background (struct glyph_string *s, char force_p)
2888 /* --------------------------------------------------------------------------
2889       Modeled after x_draw_glyph_string_background, which draws BG in
2890       certain cases.  Others are left to the text rendering routine.
2891    -------------------------------------------------------------------------- */
2893   NSTRACE (ns_maybe_dumpglyphs_background);
2895   if (!s->background_filled_p/* || s->hl == DRAW_MOUSE_FACE*/)
2896     {
2897       int box_line_width = max (s->face->box_line_width, 0);
2898       if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
2899           || s->font_not_found_p || s->extends_to_end_of_line_p || force_p)
2900         {
2901           struct face *face;
2902           if (s->hl == DRAW_MOUSE_FACE)
2903             {
2904               face = FACE_FROM_ID (s->f,
2905                                    MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2906               if (!face)
2907                 face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2908             }
2909           else
2910             face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2911           if (!face->stipple)
2912             [(NS_FACE_BACKGROUND (face) != 0
2913               ? ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f)
2914               : FRAME_BACKGROUND_COLOR (s->f)) set];
2915           else
2916             {
2917               struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (s->f);
2918               [[dpyinfo->bitmaps[face->stipple-1].img stippleMask] set];
2919             }
2921           if (s->hl != DRAW_CURSOR)
2922             {
2923               NSRect r = NSMakeRect (s->x, s->y + box_line_width,
2924                                     s->background_width,
2925                                     s->height-2*box_line_width);
2926               NSRectFill (r);
2927             }
2929           s->background_filled_p = 1;
2930         }
2931     }
2935 static void
2936 ns_dumpglyphs_image (struct glyph_string *s, NSRect r)
2937 /* --------------------------------------------------------------------------
2938       Renders an image and associated borders.
2939    -------------------------------------------------------------------------- */
2941   EmacsImage *img = s->img->pixmap;
2942   int box_line_vwidth = max (s->face->box_line_width, 0);
2943   int x = s->x, y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2944   int bg_x, bg_y, bg_height;
2945   int th;
2946   char raised_p;
2947   NSRect br;
2948   struct face *face;
2949   NSColor *tdCol;
2951   NSTRACE (ns_dumpglyphs_image);
2953   if (s->face->box != FACE_NO_BOX
2954       && s->first_glyph->left_box_line_p && s->slice.x == 0)
2955     x += abs (s->face->box_line_width);
2957   bg_x = x;
2958   bg_y =  s->slice.y == 0 ? s->y : s->y + box_line_vwidth;
2959   bg_height = s->height;
2960   /* other terms have this, but was causing problems w/tabbar mode */
2961   /* - 2 * box_line_vwidth; */
2963   if (s->slice.x == 0) x += s->img->hmargin;
2964   if (s->slice.y == 0) y += s->img->vmargin;
2966   /* Draw BG: if we need larger area than image itself cleared, do that,
2967      otherwise, since we composite the image under NS (instead of mucking
2968      with its background color), we must clear just the image area. */
2969   if (s->hl == DRAW_MOUSE_FACE)
2970     {
2971       face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
2972       if (!face)
2973        face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
2974     }
2975   else
2976     face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
2978   [ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f) set];
2980   if (bg_height > s->slice.height || s->img->hmargin || s->img->vmargin
2981       || s->img->mask || s->img->pixmap == 0 || s->width != s->background_width)
2982     {
2983       br = NSMakeRect (bg_x, bg_y, s->background_width, bg_height);
2984       s->background_filled_p = 1;
2985     }
2986   else
2987     {
2988       br = NSMakeRect (x, y, s->slice.width, s->slice.height);
2989     }
2991   NSRectFill (br);
2993   /* Draw the image.. do we need to draw placeholder if img ==nil? */
2994   if (img != nil)
2995     {
2996 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
2997       NSRect dr = NSMakeRect (x, y, s->slice.width, s->slice.height);
2998       NSRect ir = NSMakeRect (s->slice.x, s->slice.y,
2999                               s->slice.width, s->slice.height);
3000       [img drawInRect: dr
3001              fromRect: ir
3002              operation: NSCompositeSourceOver
3003               fraction: 1.0
3004            respectFlipped: YES
3005                 hints: nil];
3006 #else
3007       [img compositeToPoint: NSMakePoint (x, y + s->slice.height)
3008                   operation: NSCompositeSourceOver];
3009 #endif
3010     }
3012   if (s->hl == DRAW_CURSOR)
3013     {
3014     [FRAME_CURSOR_COLOR (s->f) set];
3015     if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3016       tdCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3017     else
3018       /* Currently on NS img->mask is always 0. Since
3019          get_window_cursor_type specifies a hollow box cursor when on
3020          a non-masked image we never reach this clause. But we put it
3021          in in anticipation of better support for image masks on
3022          NS. */
3023       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3024     }
3025   else
3026     {
3027       tdCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3028     }
3030   /* Draw underline, overline, strike-through. */
3031   ns_draw_text_decoration (s, face, tdCol, br.size.width, br.origin.x);
3033   /* Draw relief, if requested */
3034   if (s->img->relief || s->hl ==DRAW_IMAGE_RAISED || s->hl ==DRAW_IMAGE_SUNKEN)
3035     {
3036       if (s->hl == DRAW_IMAGE_SUNKEN || s->hl == DRAW_IMAGE_RAISED)
3037         {
3038           th = tool_bar_button_relief >= 0 ?
3039             tool_bar_button_relief : DEFAULT_TOOL_BAR_BUTTON_RELIEF;
3040           raised_p = (s->hl == DRAW_IMAGE_RAISED);
3041         }
3042       else
3043         {
3044           th = abs (s->img->relief);
3045           raised_p = (s->img->relief > 0);
3046         }
3048       r.origin.x = x - th;
3049       r.origin.y = y - th;
3050       r.size.width = s->slice.width + 2*th-1;
3051       r.size.height = s->slice.height + 2*th-1;
3052       ns_draw_relief (r, th, raised_p,
3053                       s->slice.y == 0,
3054                       s->slice.y + s->slice.height == s->img->height,
3055                       s->slice.x == 0,
3056                       s->slice.x + s->slice.width == s->img->width, s);
3057     }
3059   /* If there is no mask, the background won't be seen,
3060      so draw a rectangle on the image for the cursor.
3061      Do this for all images, getting transparency right is not reliable.  */
3062   if (s->hl == DRAW_CURSOR)
3063     {
3064       int thickness = abs (s->img->relief);
3065       if (thickness == 0) thickness = 1;
3066       ns_draw_box (br, thickness, FRAME_CURSOR_COLOR (s->f), 1, 1);
3067     }
3071 static void
3072 ns_dumpglyphs_stretch (struct glyph_string *s)
3074   NSRect r[2];
3075   int n, i;
3076   struct face *face;
3077   NSColor *fgCol, *bgCol;
3079   if (!s->background_filled_p)
3080     {
3081       n = ns_get_glyph_string_clip_rect (s, r);
3082       *r = NSMakeRect (s->x, s->y, s->background_width, s->height);
3084       ns_focus (s->f, r, n);
3086       if (s->hl == DRAW_MOUSE_FACE)
3087        {
3088          face = FACE_FROM_ID (s->f, MOUSE_HL_INFO (s->f)->mouse_face_face_id);
3089          if (!face)
3090            face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
3091        }
3092       else
3093        face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
3095       bgCol = ns_lookup_indexed_color (NS_FACE_BACKGROUND (face), s->f);
3096       fgCol = ns_lookup_indexed_color (NS_FACE_FOREGROUND (face), s->f);
3098       for (i = 0; i < n; ++i)
3099         {
3100           if (!s->row->full_width_p)
3101             {
3102               int overrun, leftoverrun;
3104               /* truncate to avoid overwriting fringe and/or scrollbar */
3105               overrun = max (0, (s->x + s->background_width)
3106                              - (WINDOW_BOX_RIGHT_EDGE_X (s->w)
3107                                 - WINDOW_RIGHT_FRINGE_WIDTH (s->w)));
3108               r[i].size.width -= overrun;
3110               /* truncate to avoid overwriting to left of the window box */
3111               leftoverrun = (WINDOW_BOX_LEFT_EDGE_X (s->w)
3112                              + WINDOW_LEFT_FRINGE_WIDTH (s->w)) - s->x;
3114               if (leftoverrun > 0)
3115                 {
3116                   r[i].origin.x += leftoverrun;
3117                   r[i].size.width -= leftoverrun;
3118                 }
3120               /* XXX: Try to work between problem where a stretch glyph on
3121                  a partially-visible bottom row will clear part of the
3122                  modeline, and another where list-buffers headers and similar
3123                  rows erroneously have visible_height set to 0.  Not sure
3124                  where this is coming from as other terms seem not to show. */
3125               r[i].size.height = min (s->height, s->row->visible_height);
3126             }
3128           [bgCol set];
3130           /* NOTE: under NS this is NOT used to draw cursors, but we must avoid
3131              overwriting cursor (usually when cursor on a tab) */
3132           if (s->hl == DRAW_CURSOR)
3133             {
3134               CGFloat x, width;
3136               x = r[i].origin.x;
3137               width = s->w->phys_cursor_width;
3138               r[i].size.width -= width;
3139               r[i].origin.x += width;
3141               NSRectFill (r[i]);
3143               /* Draw overlining, etc. on the cursor. */
3144               if (s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3145                 ns_draw_text_decoration (s, face, bgCol, width, x);
3146               else
3147                 ns_draw_text_decoration (s, face, fgCol, width, x);
3148             }
3149           else
3150             {
3151               NSRectFill (r[i]);
3152             }
3154           /* Draw overlining, etc. on the stretch glyph (or the part
3155              of the stretch glyph after the cursor). */
3156           ns_draw_text_decoration (s, face, fgCol, r[i].size.width,
3157                                    r[i].origin.x);
3158         }
3159       ns_unfocus (s->f);
3160       s->background_filled_p = 1;
3161     }
3165 static void
3166 ns_draw_glyph_string (struct glyph_string *s)
3167 /* --------------------------------------------------------------------------
3168       External (RIF): Main draw-text call.
3169    -------------------------------------------------------------------------- */
3171   /* TODO (optimize): focus for box and contents draw */
3172   NSRect r[2];
3173   int n;
3174   char box_drawn_p = 0;
3176   NSTRACE (ns_draw_glyph_string);
3178   if (s->next && s->right_overhang && !s->for_overlaps/*&&s->hl!=DRAW_CURSOR*/)
3179     {
3180       int width;
3181       struct glyph_string *next;
3183       for (width = 0, next = s->next;
3184            next && width < s->right_overhang;
3185            width += next->width, next = next->next)
3186         if (next->first_glyph->type != IMAGE_GLYPH)
3187           {
3188             if (next->first_glyph->type != STRETCH_GLYPH)
3189               {
3190                 n = ns_get_glyph_string_clip_rect (s->next, r);
3191                 ns_focus (s->f, r, n);
3192                 ns_maybe_dumpglyphs_background (s->next, 1);
3193                 ns_unfocus (s->f);
3194               }
3195             else
3196               {
3197                 ns_dumpglyphs_stretch (s->next);
3198               }
3199             next->num_clips = 0;
3200           }
3201     }
3203   if (!s->for_overlaps && s->face->box != FACE_NO_BOX
3204         && (s->first_glyph->type == CHAR_GLYPH
3205             || s->first_glyph->type == COMPOSITE_GLYPH))
3206     {
3207       n = ns_get_glyph_string_clip_rect (s, r);
3208       ns_focus (s->f, r, n);
3209       ns_maybe_dumpglyphs_background (s, 1);
3210       ns_dumpglyphs_box_or_relief (s);
3211       ns_unfocus (s->f);
3212       box_drawn_p = 1;
3213     }
3215   switch (s->first_glyph->type)
3216     {
3218     case IMAGE_GLYPH:
3219       n = ns_get_glyph_string_clip_rect (s, r);
3220       ns_focus (s->f, r, n);
3221       ns_dumpglyphs_image (s, r[0]);
3222       ns_unfocus (s->f);
3223       break;
3225     case STRETCH_GLYPH:
3226       ns_dumpglyphs_stretch (s);
3227       break;
3229     case CHAR_GLYPH:
3230     case COMPOSITE_GLYPH:
3231       n = ns_get_glyph_string_clip_rect (s, r);
3232       ns_focus (s->f, r, n);
3234       if (s->for_overlaps || (s->cmp_from > 0
3235                               && ! s->first_glyph->u.cmp.automatic))
3236         s->background_filled_p = 1;
3237       else
3238         ns_maybe_dumpglyphs_background
3239           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3241       ns_tmp_flags = s->hl == DRAW_CURSOR ? NS_DUMPGLYPH_CURSOR :
3242                     (s->hl == DRAW_MOUSE_FACE ? NS_DUMPGLYPH_MOUSEFACE :
3243                      (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
3244                       NS_DUMPGLYPH_NORMAL));
3245       ns_tmp_font = (struct nsfont_info *)s->face->font;
3246       if (ns_tmp_font == NULL)
3247           ns_tmp_font = (struct nsfont_info *)FRAME_FONT (s->f);
3249       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3250         {
3251           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3252           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3253           NS_FACE_FOREGROUND (s->face) = tmp;
3254         }
3256       ns_tmp_font->font.driver->draw
3257         (s, 0, s->nchars, s->x, s->y,
3258          (ns_tmp_flags == NS_DUMPGLYPH_NORMAL && !s->background_filled_p)
3259          || ns_tmp_flags == NS_DUMPGLYPH_MOUSEFACE);
3261       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
3262         {
3263           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
3264           NS_FACE_BACKGROUND (s->face) = NS_FACE_FOREGROUND (s->face);
3265           NS_FACE_FOREGROUND (s->face) = tmp;
3266         }
3268       ns_unfocus (s->f);
3269       break;
3271     case GLYPHLESS_GLYPH:
3272       n = ns_get_glyph_string_clip_rect (s, r);
3273       ns_focus (s->f, r, n);
3275       if (s->for_overlaps || (s->cmp_from > 0
3276                               && ! s->first_glyph->u.cmp.automatic))
3277         s->background_filled_p = 1;
3278       else
3279         ns_maybe_dumpglyphs_background
3280           (s, s->first_glyph->type == COMPOSITE_GLYPH);
3281       /* ... */
3282       /* Not yet implemented.  */
3283       /* ... */
3284       ns_unfocus (s->f);
3285       break;
3287     default:
3288       emacs_abort ();
3289     }
3291   /* Draw box if not done already. */
3292   if (!s->for_overlaps && !box_drawn_p && s->face->box != FACE_NO_BOX)
3293     {
3294       n = ns_get_glyph_string_clip_rect (s, r);
3295       ns_focus (s->f, r, n);
3296       ns_dumpglyphs_box_or_relief (s);
3297       ns_unfocus (s->f);
3298     }
3300   s->num_clips = 0;
3305 /* ==========================================================================
3307     Event loop
3309    ========================================================================== */
3312 static void
3313 ns_send_appdefined (int value)
3314 /* --------------------------------------------------------------------------
3315     Internal: post an appdefined event which EmacsApp-sendEvent will
3316               recognize and take as a command to halt the event loop.
3317    -------------------------------------------------------------------------- */
3319   /*NSTRACE (ns_send_appdefined); */
3321   /* Only post this event if we haven't already posted one.  This will end
3322        the [NXApp run] main loop after having processed all events queued at
3323        this moment.  */
3324   if (send_appdefined)
3325     {
3326       NSEvent *nxev;
3328       /* We only need one NX_APPDEFINED event to stop NXApp from running.  */
3329       send_appdefined = NO;
3331       /* Don't need wakeup timer any more */
3332       if (timed_entry)
3333         {
3334           [timed_entry invalidate];
3335           [timed_entry release];
3336           timed_entry = nil;
3337         }
3339       nxev = [NSEvent otherEventWithType: NSApplicationDefined
3340                                 location: NSMakePoint (0, 0)
3341                            modifierFlags: 0
3342                                timestamp: 0
3343                             windowNumber: [[NSApp mainWindow] windowNumber]
3344                                  context: [NSApp context]
3345                                  subtype: 0
3346                                    data1: value
3347                                    data2: 0];
3349       /* Post an application defined event on the event queue.  When this is
3350          received the [NXApp run] will return, thus having processed all
3351          events which are currently queued.  */
3352       [NSApp postEvent: nxev atStart: NO];
3353     }
3356 static int
3357 ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3358 /* --------------------------------------------------------------------------
3359      External (hook): Post an event to ourself and keep reading events until
3360      we read it back again.  In effect process all events which were waiting.
3361      From 21+ we have to manage the event buffer ourselves.
3362    -------------------------------------------------------------------------- */
3364   struct input_event ev;
3365   int nevents;
3367 /* NSTRACE (ns_read_socket); */
3369   if ([NSApp modalWindow] != nil)
3370     return -1;
3372   if (hold_event_q.nr > 0) 
3373     {
3374       int i;
3375       for (i = 0; i < hold_event_q.nr; ++i)
3376         kbd_buffer_store_event_hold (&hold_event_q.q[i], hold_quit);
3377       hold_event_q.nr = 0;
3378       return i;
3379     }
3381   block_input ();
3382   n_emacs_events_pending = 0;
3383   EVENT_INIT (ev);
3384   emacs_event = &ev;
3385   q_event_ptr = hold_quit;
3387   /* we manage autorelease pools by allocate/reallocate each time around
3388      the loop; strict nesting is occasionally violated but seems not to
3389      matter.. earlier methods using full nesting caused major memory leaks */
3390   [outerpool release];
3391   outerpool = [[NSAutoreleasePool alloc] init];
3393   /* If have pending open-file requests, attend to the next one of those. */
3394   if (ns_pending_files && [ns_pending_files count] != 0
3395       && [(EmacsApp *)NSApp openFile: [ns_pending_files objectAtIndex: 0]])
3396     {
3397       [ns_pending_files removeObjectAtIndex: 0];
3398     }
3399   /* Deal with pending service requests. */
3400   else if (ns_pending_service_names && [ns_pending_service_names count] != 0
3401     && [(EmacsApp *)
3402          NSApp fulfillService: [ns_pending_service_names objectAtIndex: 0]
3403                       withArg: [ns_pending_service_args objectAtIndex: 0]])
3404     {
3405       [ns_pending_service_names removeObjectAtIndex: 0];
3406       [ns_pending_service_args removeObjectAtIndex: 0];
3407     }
3408   else
3409     {
3410       /* Run and wait for events.  We must always send one NX_APPDEFINED event
3411          to ourself, otherwise [NXApp run] will never exit.  */
3412       send_appdefined = YES;
3413       ns_send_appdefined (-1);
3415       if (++apploopnr != 1)
3416         {
3417           emacs_abort ();
3418         }
3419       [NSApp run];
3420       --apploopnr;
3421     }
3423   nevents = n_emacs_events_pending;
3424   n_emacs_events_pending = 0;
3425   emacs_event = q_event_ptr = NULL;
3426   unblock_input ();
3428   return nevents;
3433 ns_select (int nfds, fd_set *readfds, fd_set *writefds,
3434            fd_set *exceptfds, EMACS_TIME *timeout, sigset_t *sigmask)
3435 /* --------------------------------------------------------------------------
3436      Replacement for select, checking for events
3437    -------------------------------------------------------------------------- */
3439   int result;
3440   int t, k, nr = 0;
3441   struct input_event event;
3442   char c;
3444 /*  NSTRACE (ns_select); */
3446   for (k = 0; k < nfds+1; k++)
3447     {
3448       if (readfds && FD_ISSET(k, readfds)) ++nr;
3449       if (writefds && FD_ISSET(k, writefds)) ++nr;
3450     }
3452   if (NSApp == nil
3453       || (timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0))
3454     return pselect (nfds, readfds, writefds, exceptfds, timeout, sigmask);
3456   [outerpool release];
3457   outerpool = [[NSAutoreleasePool alloc] init];
3460   send_appdefined = YES;
3461   if (nr > 0)
3462     {
3463       pthread_mutex_lock (&select_mutex);
3464       select_nfds = nfds;
3465       select_valid = 0;
3466       if (readfds)
3467         {
3468           select_readfds = *readfds;
3469           select_valid += SELECT_HAVE_READ;
3470         }
3471       if (writefds)
3472         {
3473           select_writefds = *writefds;
3474           select_valid += SELECT_HAVE_WRITE;
3475         }
3477       if (timeout)
3478         {
3479           select_timeout = *timeout;
3480           select_valid += SELECT_HAVE_TMO;
3481         }
3483       pthread_mutex_unlock (&select_mutex);
3485       /* Inform fd_handler that select should be called */
3486       c = 'g';
3487       write (selfds[1], &c, 1);
3488     }
3489   else if (nr == 0 && timeout)
3490     {
3491       /* No file descriptor, just a timeout, no need to wake fd_handler  */
3492       double time = EMACS_TIME_TO_DOUBLE (*timeout);
3493       timed_entry = [[NSTimer scheduledTimerWithTimeInterval: time
3494                                                       target: NSApp
3495                                                     selector:
3496                                   @selector (timeout_handler:)
3497                                                     userInfo: 0
3498                                                      repeats: NO]
3499                       retain];
3500     }
3501   else /* No timeout and no file descriptors, can this happen?  */
3502     {
3503       /* Send appdefined so we exit from the loop */
3504       ns_send_appdefined (-1);
3505     }
3507   EVENT_INIT (event);
3508   block_input ();
3509   emacs_event = &event;
3510   if (++apploopnr != 1)
3511     {
3512       emacs_abort ();
3513     }
3514   [NSApp run];
3515   --apploopnr;
3516   emacs_event = NULL;
3517   if (nr > 0 && readfds)
3518     {
3519       c = 's';
3520       write (selfds[1], &c, 1);
3521     }
3522   unblock_input ();
3524   t = last_appdefined_event_data;
3526   if (t != NO_APPDEFINED_DATA)
3527     {
3528       last_appdefined_event_data = NO_APPDEFINED_DATA;
3530       if (t == -2)
3531         {
3532           /* The NX_APPDEFINED event we received was a timeout. */
3533           result = 0;
3534         }
3535       else if (t == -1)
3536         {
3537           /* The NX_APPDEFINED event we received was the result of
3538              at least one real input event arriving.  */
3539           errno = EINTR;
3540           result = -1;
3541         }
3542       else
3543         {
3544           /* Received back from select () in fd_handler; copy the results */
3545           pthread_mutex_lock (&select_mutex);
3546           if (readfds) *readfds = select_readfds;
3547           if (writefds) *writefds = select_writefds;
3548           if (timeout) *timeout = select_timeout;
3549           pthread_mutex_unlock (&select_mutex);
3550           result = t;
3551         }
3552     }
3554   return result;
3559 /* ==========================================================================
3561     Scrollbar handling
3563    ========================================================================== */
3566 static void
3567 ns_set_vertical_scroll_bar (struct window *window,
3568                            int portion, int whole, int position)
3569 /* --------------------------------------------------------------------------
3570       External (hook): Update or add scrollbar
3571    -------------------------------------------------------------------------- */
3573   Lisp_Object win;
3574   NSRect r, v;
3575   struct frame *f = XFRAME (WINDOW_FRAME (window));
3576   EmacsView *view = FRAME_NS_VIEW (f);
3577   int window_y, window_height;
3578   int top, left, height, width, sb_width, sb_left;
3579   EmacsScroller *bar;
3580   BOOL fringe_extended_p;
3582   /* optimization; display engine sends WAY too many of these.. */
3583   if (!NILP (window->vertical_scroll_bar))
3584     {
3585       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3586       if ([bar checkSamePosition: position portion: portion whole: whole])
3587         {
3588           if (view->scrollbarsNeedingUpdate == 0)
3589             {
3590               if (!windows_or_buffers_changed)
3591                   return;
3592             }
3593           else
3594             view->scrollbarsNeedingUpdate--;
3595         }
3596     }
3598   NSTRACE (ns_set_vertical_scroll_bar);
3600   /* Get dimensions.  */
3601   window_box (window, -1, 0, &window_y, 0, &window_height);
3602   top = window_y;
3603   height = window_height;
3604   width = WINDOW_CONFIG_SCROLL_BAR_COLS (window) * FRAME_COLUMN_WIDTH (f);
3605   left = WINDOW_SCROLL_BAR_AREA_X (window);
3607   /* allow for displaying a skinnier scrollbar than char area allotted */
3608   sb_width = (WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) > 0) ?
3609     WINDOW_CONFIG_SCROLL_BAR_WIDTH (window) : width;
3610   sb_left = left;
3612   r = NSMakeRect (sb_left, top, sb_width, height);
3613   /* the parent view is flipped, so we need to flip y value */
3614   v = [view frame];
3615   r.origin.y = (v.size.height - r.size.height - r.origin.y);
3617   if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_LEFT (window))
3618     fringe_extended_p = (WINDOW_LEFTMOST_P (window)
3619                          && WINDOW_LEFT_FRINGE_WIDTH (window)
3620                          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3621                              || WINDOW_LEFT_MARGIN_COLS (window) == 0));
3622   else
3623     fringe_extended_p = (WINDOW_RIGHTMOST_P (window)
3624                          && WINDOW_RIGHT_FRINGE_WIDTH (window)
3625                          && (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (window)
3626                              || WINDOW_RIGHT_MARGIN_COLS (window) == 0));
3628   XSETWINDOW (win, window);
3629   block_input ();
3631   /* we want at least 5 lines to display a scrollbar */
3632   if (WINDOW_TOTAL_LINES (window) < 5)
3633     {
3634       if (!NILP (window->vertical_scroll_bar))
3635         {
3636           bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3637           [bar removeFromSuperview];
3638           wset_vertical_scroll_bar (window, Qnil);
3639         }
3640       ns_clear_frame_area (f, sb_left, top, width, height);
3641       unblock_input ();
3642       return;
3643     }
3645   if (NILP (window->vertical_scroll_bar))
3646     {
3647       if (width > 0 && height > 0)
3648         {
3649           if (fringe_extended_p)
3650             ns_clear_frame_area (f, sb_left, top, sb_width, height);
3651           else
3652             ns_clear_frame_area (f, left, top, width, height);
3653         }
3655       bar = [[EmacsScroller alloc] initFrame: r window: win];
3656       wset_vertical_scroll_bar (window, make_save_value (bar, 0));
3657     }
3658   else
3659     {
3660       NSRect oldRect;
3661       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3662       oldRect = [bar frame];
3663       r.size.width = oldRect.size.width;
3664       if (FRAME_LIVE_P (f) && !NSEqualRects (oldRect, r))
3665         {
3666           if (oldRect.origin.x != r.origin.x)
3667               ns_clear_frame_area (f, sb_left, top, width, height);
3668           [bar setFrame: r];
3669         }
3670     }
3672   [bar setPosition: position portion: portion whole: whole];
3673   unblock_input ();
3677 static void
3678 ns_condemn_scroll_bars (struct frame *f)
3679 /* --------------------------------------------------------------------------
3680      External (hook): arrange for all frame's scrollbars to be removed
3681      at next call to judge_scroll_bars, except for those redeemed.
3682    -------------------------------------------------------------------------- */
3684   int i;
3685   id view;
3686   NSArray *subviews = [[FRAME_NS_VIEW (f) superview] subviews];
3688   NSTRACE (ns_condemn_scroll_bars);
3690   for (i =[subviews count]-1; i >= 0; i--)
3691     {
3692       view = [subviews objectAtIndex: i];
3693       if ([view isKindOfClass: [EmacsScroller class]])
3694         [view condemn];
3695     }
3699 static void
3700 ns_redeem_scroll_bar (struct window *window)
3701 /* --------------------------------------------------------------------------
3702      External (hook): arrange to spare this window's scrollbar
3703      at next call to judge_scroll_bars.
3704    -------------------------------------------------------------------------- */
3706   id bar;
3707   NSTRACE (ns_redeem_scroll_bar);
3708   if (!NILP (window->vertical_scroll_bar))
3709     {
3710       bar = XNS_SCROLL_BAR (window->vertical_scroll_bar);
3711       [bar reprieve];
3712     }
3716 static void
3717 ns_judge_scroll_bars (struct frame *f)
3718 /* --------------------------------------------------------------------------
3719      External (hook): destroy all scrollbars on frame that weren't
3720      redeemed after call to condemn_scroll_bars.
3721    -------------------------------------------------------------------------- */
3723   int i;
3724   id view;
3725   EmacsView *eview = FRAME_NS_VIEW (f);
3726   NSArray *subviews = [[eview superview] subviews];
3727   BOOL removed = NO;
3729   NSTRACE (ns_judge_scroll_bars);
3730   for (i = [subviews count]-1; i >= 0; --i)
3731     {
3732       view = [subviews objectAtIndex: i];
3733       if (![view isKindOfClass: [EmacsScroller class]]) continue;
3734       [view judge];
3735       removed = YES;
3736     }
3738   if (removed)
3739     [eview updateFrameSize: NO];
3743 void
3744 x_wm_set_icon_position (struct frame *f, int icon_x, int icon_y)
3746   /* XXX irrelevant under NS */
3751 /* ==========================================================================
3753     Initialization
3755    ========================================================================== */
3758 x_display_pixel_height (struct ns_display_info *dpyinfo)
3760   NSScreen *screen = [NSScreen mainScreen];
3761   return [screen frame].size.height;
3765 x_display_pixel_width (struct ns_display_info *dpyinfo)
3767   NSScreen *screen = [NSScreen mainScreen];
3768   return [screen frame].size.width;
3772 static Lisp_Object ns_string_to_lispmod (const char *s)
3773 /* --------------------------------------------------------------------------
3774      Convert modifier name to lisp symbol
3775    -------------------------------------------------------------------------- */
3777   if (!strncmp (SSDATA (SYMBOL_NAME (Qmeta)), s, 10))
3778     return Qmeta;
3779   else if (!strncmp (SSDATA (SYMBOL_NAME (Qsuper)), s, 10))
3780     return Qsuper;
3781   else if (!strncmp (SSDATA (SYMBOL_NAME (Qcontrol)), s, 10))
3782     return Qcontrol;
3783   else if (!strncmp (SSDATA (SYMBOL_NAME (Qalt)), s, 10))
3784     return Qalt;
3785   else if (!strncmp (SSDATA (SYMBOL_NAME (Qhyper)), s, 10))
3786     return Qhyper;
3787   else if (!strncmp (SSDATA (SYMBOL_NAME (Qnone)), s, 10))
3788     return Qnone;
3789   else
3790     return Qnil;
3794 static void
3795 ns_default (const char *parameter, Lisp_Object *result,
3796            Lisp_Object yesval, Lisp_Object noval,
3797            BOOL is_float, BOOL is_modstring)
3798 /* --------------------------------------------------------------------------
3799       Check a parameter value in user's preferences
3800    -------------------------------------------------------------------------- */
3802   const char *value = ns_get_defaults_value (parameter);
3804   if (value)
3805     {
3806       double f;
3807       char *pos;
3808       if (c_strcasecmp (value, "YES") == 0)
3809         *result = yesval;
3810       else if (c_strcasecmp (value, "NO") == 0)
3811         *result = noval;
3812       else if (is_float && (f = strtod (value, &pos), pos != value))
3813         *result = make_float (f);
3814       else if (is_modstring && value)
3815         *result = ns_string_to_lispmod (value);
3816       else fprintf (stderr,
3817                    "Bad value for default \"%s\": \"%s\"\n", parameter, value);
3818     }
3822 static void
3823 ns_initialize_display_info (struct ns_display_info *dpyinfo)
3824 /* --------------------------------------------------------------------------
3825       Initialize global info and storage for display.
3826    -------------------------------------------------------------------------- */
3828     NSScreen *screen = [NSScreen mainScreen];
3829     NSWindowDepth depth = [screen depth];
3830     Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
3832     dpyinfo->resx = 72.27; /* used 75.0, but this makes pt == pixel, expected */
3833     dpyinfo->resy = 72.27;
3834     dpyinfo->color_p = ![NSDeviceWhiteColorSpace isEqualToString:
3835                                                   NSColorSpaceFromDepth (depth)]
3836                 && ![NSCalibratedWhiteColorSpace isEqualToString:
3837                                                  NSColorSpaceFromDepth (depth)];
3838     dpyinfo->n_planes = NSBitsPerPixelFromDepth (depth);
3839     dpyinfo->image_cache = make_image_cache ();
3840     dpyinfo->color_table = xmalloc (sizeof *dpyinfo->color_table);
3841     dpyinfo->color_table->colors = NULL;
3842     dpyinfo->root_window = 42; /* a placeholder.. */
3844     hlinfo->mouse_face_mouse_frame = NULL;
3845     hlinfo->mouse_face_deferred_gc = 0;
3846     hlinfo->mouse_face_beg_row = hlinfo->mouse_face_beg_col = -1;
3847     hlinfo->mouse_face_end_row = hlinfo->mouse_face_end_col = -1;
3848     hlinfo->mouse_face_face_id = DEFAULT_FACE_ID;
3849     hlinfo->mouse_face_window = hlinfo->mouse_face_overlay = Qnil;
3850     hlinfo->mouse_face_hidden = 0;
3852     hlinfo->mouse_face_mouse_x = hlinfo->mouse_face_mouse_y = 0;
3853     hlinfo->mouse_face_defer = 0;
3855     dpyinfo->x_highlight_frame = dpyinfo->x_focus_frame = NULL;
3857     dpyinfo->n_fonts = 0;
3858     dpyinfo->smallest_font_height = 1;
3859     dpyinfo->smallest_char_width = 1;
3863 /* This and next define (many of the) public functions in this file. */
3864 /* x_... are generic versions in xdisp.c that we, and other terms, get away
3865          with using despite presence in the "system dependent" redisplay
3866          interface.  In addition, many of the ns_ methods have code that is
3867          shared with all terms, indicating need for further refactoring. */
3868 extern frame_parm_handler ns_frame_parm_handlers[];
3869 static struct redisplay_interface ns_redisplay_interface =
3871   ns_frame_parm_handlers,
3872   x_produce_glyphs,
3873   x_write_glyphs,
3874   x_insert_glyphs,
3875   x_clear_end_of_line,
3876   ns_scroll_run,
3877   ns_after_update_window_line,
3878   ns_update_window_begin,
3879   ns_update_window_end,
3880   x_cursor_to,
3881   ns_flush,
3882   0, /* flush_display_optional */
3883   x_clear_window_mouse_face,
3884   x_get_glyph_overhangs,
3885   x_fix_overlapping_area,
3886   ns_draw_fringe_bitmap,
3887   0, /* define_fringe_bitmap */ /* FIXME: simplify ns_draw_fringe_bitmap */
3888   0, /* destroy_fringe_bitmap */
3889   ns_compute_glyph_string_overhangs,
3890   ns_draw_glyph_string, /* interface to nsfont.m */
3891   ns_define_frame_cursor,
3892   ns_clear_frame_area,
3893   ns_draw_window_cursor,
3894   ns_draw_vertical_window_border,
3895   ns_shift_glyphs_for_insert
3899 static void
3900 ns_delete_display (struct ns_display_info *dpyinfo)
3902   /* TODO... */
3906 /* This function is called when the last frame on a display is deleted. */
3907 static void
3908 ns_delete_terminal (struct terminal *terminal)
3910   struct ns_display_info *dpyinfo = terminal->display_info.ns;
3912   /* Protect against recursive calls.  delete_frame in
3913      delete_terminal calls us back when it deletes our last frame.  */
3914   if (!terminal->name)
3915     return;
3917   block_input ();
3919   x_destroy_all_bitmaps (dpyinfo);
3920   ns_delete_display (dpyinfo);
3921   unblock_input ();
3925 static struct terminal *
3926 ns_create_terminal (struct ns_display_info *dpyinfo)
3927 /* --------------------------------------------------------------------------
3928       Set up use of NS before we make the first connection.
3929    -------------------------------------------------------------------------- */
3931   struct terminal *terminal;
3933   NSTRACE (ns_create_terminal);
3935   terminal = create_terminal ();
3937   terminal->type = output_ns;
3938   terminal->display_info.ns = dpyinfo;
3939   dpyinfo->terminal = terminal;
3941   terminal->rif = &ns_redisplay_interface;
3943   terminal->clear_frame_hook = ns_clear_frame;
3944   terminal->ins_del_lines_hook = 0; /* XXX vestigial? */
3945   terminal->delete_glyphs_hook = 0; /* XXX vestigial? */
3946   terminal->ring_bell_hook = ns_ring_bell;
3947   terminal->reset_terminal_modes_hook = ns_reset_terminal_modes;
3948   terminal->set_terminal_modes_hook = ns_set_terminal_modes;
3949   terminal->update_begin_hook = ns_update_begin;
3950   terminal->update_end_hook = ns_update_end;
3951   terminal->set_terminal_window_hook = NULL; /* XXX vestigial? */
3952   terminal->read_socket_hook = ns_read_socket;
3953   terminal->frame_up_to_date_hook = ns_frame_up_to_date;
3954   terminal->mouse_position_hook = ns_mouse_position;
3955   terminal->frame_rehighlight_hook = ns_frame_rehighlight;
3956   terminal->frame_raise_lower_hook = ns_frame_raise_lower;
3958   terminal->fullscreen_hook = ns_fullscreen_hook;
3960   terminal->set_vertical_scroll_bar_hook = ns_set_vertical_scroll_bar;
3961   terminal->condemn_scroll_bars_hook = ns_condemn_scroll_bars;
3962   terminal->redeem_scroll_bar_hook = ns_redeem_scroll_bar;
3963   terminal->judge_scroll_bars_hook = ns_judge_scroll_bars;
3965   terminal->delete_frame_hook = x_destroy_window;
3966   terminal->delete_terminal_hook = ns_delete_terminal;
3968   terminal->scroll_region_ok = 1;
3969   terminal->char_ins_del_ok = 1;
3970   terminal->line_ins_del_ok = 1;
3971   terminal->fast_clear_end_of_line = 1;
3972   terminal->memory_below_frame = 0;
3974   return terminal;
3978 struct ns_display_info *
3979 ns_term_init (Lisp_Object display_name)
3980 /* --------------------------------------------------------------------------
3981      Start the Application and get things rolling.
3982    -------------------------------------------------------------------------- */
3984   struct terminal *terminal;
3985   struct ns_display_info *dpyinfo;
3986   static int ns_initialized = 0;
3987   Lisp_Object tmp;
3989   if (ns_initialized) return x_display_list;
3990   ns_initialized = 1;
3992   NSTRACE (ns_term_init);
3994   [outerpool release];
3995   outerpool = [[NSAutoreleasePool alloc] init];
3997   /* count object allocs (About, click icon); on OS X use ObjectAlloc tool */
3998   /*GSDebugAllocationActive (YES); */
3999   block_input ();
4001   baud_rate = 38400;
4002   Fset_input_interrupt_mode (Qnil);
4004   if (selfds[0] == -1)
4005     {
4006       if (pipe (selfds) == -1)
4007         {
4008           fprintf (stderr, "Failed to create pipe: %s\n",
4009                    emacs_strerror (errno));
4010           emacs_abort ();
4011         }
4013       fcntl (selfds[0], F_SETFL, O_NONBLOCK|fcntl (selfds[0], F_GETFL));
4014       FD_ZERO (&select_readfds);
4015       FD_ZERO (&select_writefds);
4016       pthread_mutex_init (&select_mutex, NULL);
4017     }
4019   ns_pending_files = [[NSMutableArray alloc] init];
4020   ns_pending_service_names = [[NSMutableArray alloc] init];
4021   ns_pending_service_args = [[NSMutableArray alloc] init];
4023 /* Start app and create the main menu, window, view.
4024      Needs to be here because ns_initialize_display_info () uses AppKit classes.
4025      The view will then ask the NSApp to stop and return to Emacs. */
4026   [EmacsApp sharedApplication];
4027   if (NSApp == nil)
4028     return NULL;
4029   [NSApp setDelegate: NSApp];
4031   /* Start the select thread.  */
4032   [NSThread detachNewThreadSelector:@selector (fd_handler:)
4033                            toTarget:NSApp
4034                          withObject:nil];
4036   /* debugging: log all notifications */
4037   /*   [[NSNotificationCenter defaultCenter] addObserver: NSApp
4038                                          selector: @selector (logNotification:)
4039                                              name: nil object: nil]; */
4041   dpyinfo = xzalloc (sizeof *dpyinfo);
4043   ns_initialize_display_info (dpyinfo);
4044   terminal = ns_create_terminal (dpyinfo);
4046   terminal->kboard = xmalloc (sizeof *terminal->kboard);
4047   init_kboard (terminal->kboard);
4048   kset_window_system (terminal->kboard, Qns);
4049   terminal->kboard->next_kboard = all_kboards;
4050   all_kboards = terminal->kboard;
4051   /* Don't let the initial kboard remain current longer than necessary.
4052      That would cause problems if a file loaded on startup tries to
4053      prompt in the mini-buffer.  */
4054   if (current_kboard == initial_kboard)
4055     current_kboard = terminal->kboard;
4056   terminal->kboard->reference_count++;
4058   dpyinfo->next = x_display_list;
4059   x_display_list = dpyinfo;
4061   /* Put it on ns_display_name_list */
4062   ns_display_name_list = Fcons (Fcons (display_name, Qnil),
4063                                 ns_display_name_list);
4064   dpyinfo->name_list_element = XCAR (ns_display_name_list);
4066   terminal->name = xstrdup (SSDATA (display_name));
4068   unblock_input ();
4070   if (!inhibit_x_resources)
4071     {
4072       ns_default ("GSFontAntiAlias", &ns_antialias_text,
4073                  Qt, Qnil, NO, NO);
4074       tmp = Qnil;
4075       /* this is a standard variable */
4076       ns_default ("AppleAntiAliasingThreshold", &tmp,
4077                  make_float (10.0), make_float (6.0), YES, NO);
4078       ns_antialias_threshold = NILP (tmp) ? 10.0 : XFLOATINT (tmp);
4079     }
4081   ns_selection_color = [[NSUserDefaults standardUserDefaults]
4082                          stringForKey: @"AppleHighlightColor"];
4083   if (ns_selection_color == nil)
4084     ns_selection_color = NS_SELECTION_COLOR_DEFAULT;
4086   {
4087     NSColorList *cl = [NSColorList colorListNamed: @"Emacs"];
4089     if ( cl == nil )
4090       {
4091         Lisp_Object color_file, color_map, color;
4092         unsigned long c;
4093         char *name;
4095         color_file = Fexpand_file_name (build_string ("rgb.txt"),
4096                          Fsymbol_value (intern ("data-directory")));
4097         if (NILP (Ffile_readable_p (color_file)))
4098           fatal ("Could not find %s.\n", SDATA (color_file));
4100         color_map = Fx_load_color_file (color_file);
4101         if (NILP (color_map))
4102           fatal ("Could not read %s.\n", SDATA (color_file));
4104         cl = [[NSColorList alloc] initWithName: @"Emacs"];
4105         for ( ; CONSP (color_map); color_map = XCDR (color_map))
4106           {
4107             color = XCAR (color_map);
4108             name = SSDATA (XCAR (color));
4109             c = XINT (XCDR (color));
4110             [cl setColor:
4111                   [NSColor colorWithCalibratedRed: RED_FROM_ULONG (c) / 255.0
4112                                             green: GREEN_FROM_ULONG (c) / 255.0
4113                                              blue: BLUE_FROM_ULONG (c) / 255.0
4114                                             alpha: 1.0]
4115                   forKey: [NSString stringWithUTF8String: name]];
4116           }
4117         [cl writeToFile: nil];
4118       }
4119   }
4121   {
4122 #ifdef NS_IMPL_GNUSTEP
4123     Vwindow_system_version = build_string (gnustep_base_version);
4124 #else
4125     /*PSnextrelease (128, c); */
4126     char c[DBL_BUFSIZE_BOUND];
4127     int len = dtoastr (c, sizeof c, 0, 0, NSAppKitVersionNumber);
4128     Vwindow_system_version = make_unibyte_string (c, len);
4129 #endif
4130   }
4132   delete_keyboard_wait_descriptor (0);
4134   ns_app_name = [[NSProcessInfo processInfo] processName];
4136 /* Set up OS X app menu */
4137 #ifdef NS_IMPL_COCOA
4138   {
4139     NSMenu *appMenu;
4140     NSMenuItem *item;
4141     /* set up the application menu */
4142     svcsMenu = [[EmacsMenu alloc] initWithTitle: @"Services"];
4143     [svcsMenu setAutoenablesItems: NO];
4144     appMenu = [[EmacsMenu alloc] initWithTitle: @"Emacs"];
4145     [appMenu setAutoenablesItems: NO];
4146     mainMenu = [[EmacsMenu alloc] initWithTitle: @""];
4147     dockMenu = [[EmacsMenu alloc] initWithTitle: @""];
4149     [appMenu insertItemWithTitle: @"About Emacs"
4150                           action: @selector (orderFrontStandardAboutPanel:)
4151                    keyEquivalent: @""
4152                          atIndex: 0];
4153     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 1];
4154     [appMenu insertItemWithTitle: @"Preferences..."
4155                           action: @selector (showPreferencesWindow:)
4156                    keyEquivalent: @","
4157                          atIndex: 2];
4158     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
4159     item = [appMenu insertItemWithTitle: @"Services"
4160                                  action: @selector (menuDown:)
4161                           keyEquivalent: @""
4162                                 atIndex: 4];
4163     [appMenu setSubmenu: svcsMenu forItem: item];
4164     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
4165     [appMenu insertItemWithTitle: @"Hide Emacs"
4166                           action: @selector (hide:)
4167                    keyEquivalent: @"h"
4168                          atIndex: 6];
4169     item =  [appMenu insertItemWithTitle: @"Hide Others"
4170                           action: @selector (hideOtherApplications:)
4171                    keyEquivalent: @"h"
4172                          atIndex: 7];
4173     [item setKeyEquivalentModifierMask: NSCommandKeyMask | NSAlternateKeyMask];
4174     [appMenu insertItem: [NSMenuItem separatorItem] atIndex: 8];
4175     [appMenu insertItemWithTitle: @"Quit Emacs"
4176                           action: @selector (terminate:)
4177                    keyEquivalent: @"q"
4178                          atIndex: 9];
4180     item = [mainMenu insertItemWithTitle: ns_app_name
4181                                   action: @selector (menuDown:)
4182                            keyEquivalent: @""
4183                                  atIndex: 0];
4184     [mainMenu setSubmenu: appMenu forItem: item];
4185     [dockMenu insertItemWithTitle: @"New Frame"
4186                            action: @selector (newFrame:)
4187                     keyEquivalent: @""
4188                           atIndex: 0];
4190     [NSApp setMainMenu: mainMenu];
4191     [NSApp setAppleMenu: appMenu];
4192     [NSApp setServicesMenu: svcsMenu];
4193     /* Needed at least on Cocoa, to get dock menu to show windows */
4194     [NSApp setWindowsMenu: [[NSMenu alloc] init]];
4196     [[NSNotificationCenter defaultCenter]
4197       addObserver: mainMenu
4198          selector: @selector (trackingNotification:)
4199              name: NSMenuDidBeginTrackingNotification object: mainMenu];
4200     [[NSNotificationCenter defaultCenter]
4201       addObserver: mainMenu
4202          selector: @selector (trackingNotification:)
4203              name: NSMenuDidEndTrackingNotification object: mainMenu];
4204   }
4205 #endif /* MAC OS X menu setup */
4207   /* Register our external input/output types, used for determining
4208      applicable services and also drag/drop eligibility. */
4209   ns_send_types = [[NSArray arrayWithObjects: NSStringPboardType, nil] retain];
4210   ns_return_types = [[NSArray arrayWithObjects: NSStringPboardType, nil]
4211                       retain];
4212   ns_drag_types = [[NSArray arrayWithObjects:
4213                             NSStringPboardType,
4214                             NSTabularTextPboardType,
4215                             NSFilenamesPboardType,
4216                             NSURLPboardType,
4217                             NSColorPboardType,
4218                             NSFontPboardType, nil] retain];
4220 #ifndef NEW_STYLE_FS
4221   /* If fullscreen is in init/default-frame-alist, focus isn't set
4222      right for fullscreen windows, so set this.  */
4223   [NSApp activateIgnoringOtherApps:YES];
4224 #endif
4226   [NSApp run];
4227   ns_do_open_file = YES;
4228   return dpyinfo;
4232 void
4233 ns_term_shutdown (int sig)
4235   [[NSUserDefaults standardUserDefaults] synchronize];
4237   /* code not reached in emacs.c after this is called by shut_down_emacs: */
4238   if (STRINGP (Vauto_save_list_file_name))
4239     unlink (SSDATA (Vauto_save_list_file_name));
4241   if (sig == 0 || sig == SIGTERM)
4242     {
4243       [NSApp terminate: NSApp];
4244     }
4245   else // force a stack trace to happen
4246     {
4247       emacs_abort ();
4248     }
4252 /* ==========================================================================
4254     EmacsApp implementation
4256    ========================================================================== */
4259 @implementation EmacsApp
4261 - (void)logNotification: (NSNotification *)notification
4263   const char *name = [[notification name] UTF8String];
4264   if (!strstr (name, "Update") && !strstr (name, "NSMenu")
4265       && !strstr (name, "WindowNumber"))
4266     NSLog (@"notification: '%@'", [notification name]);
4270 - (void)sendEvent: (NSEvent *)theEvent
4271 /* --------------------------------------------------------------------------
4272      Called when NSApp is running for each event received.  Used to stop
4273      the loop when we choose, since there's no way to just run one iteration.
4274    -------------------------------------------------------------------------- */
4276   int type = [theEvent type];
4277   NSWindow *window = [theEvent window];
4278 /*  NSTRACE (sendEvent); */
4279 /*fprintf (stderr, "received event of type %d\t%d\n", type);*/
4281 #ifdef NS_IMPL_COCOA
4282   if (type == NSApplicationDefined
4283       && [theEvent data2] == NSAPP_DATA2_RUNASSCRIPT)
4284     {
4285       ns_run_ascript ();
4286       [self stop: self];
4287       return;
4288     }
4289 #endif
4291   if (type == NSCursorUpdate && window == nil)
4292     {
4293       fprintf (stderr, "Dropping external cursor update event.\n");
4294       return;
4295     }
4297   if (type == NSApplicationDefined)
4298     {
4299       /* Events posted by ns_send_appdefined interrupt the run loop here.
4300          But, if a modal window is up, an appdefined can still come through,
4301          (e.g., from a makeKeyWindow event) but stopping self also stops the
4302          modal loop. Just defer it until later. */
4303       if ([NSApp modalWindow] == nil)
4304         {
4305           last_appdefined_event_data = [theEvent data1];
4306           [self stop: self];
4307         }
4308       else
4309         {
4310           send_appdefined = YES;
4311         }
4312     }
4314   [super sendEvent: theEvent];
4318 - (void)showPreferencesWindow: (id)sender
4320   struct frame *emacsframe = SELECTED_FRAME ();
4321   NSEvent *theEvent = [NSApp currentEvent];
4323   if (!emacs_event)
4324     return;
4325   emacs_event->kind = NS_NONKEY_EVENT;
4326   emacs_event->code = KEY_NS_SHOW_PREFS;
4327   emacs_event->modifiers = 0;
4328   EV_TRAILER (theEvent);
4332 - (void)newFrame: (id)sender
4334   struct frame *emacsframe = SELECTED_FRAME ();
4335   NSEvent *theEvent = [NSApp currentEvent];
4337   if (!emacs_event)
4338     return;
4339   emacs_event->kind = NS_NONKEY_EVENT;
4340   emacs_event->code = KEY_NS_NEW_FRAME;
4341   emacs_event->modifiers = 0;
4342   EV_TRAILER (theEvent);
4346 /* Open a file (used by below, after going into queue read by ns_read_socket) */
4347 - (BOOL) openFile: (NSString *)fileName
4349   struct frame *emacsframe = SELECTED_FRAME ();
4350   NSEvent *theEvent = [NSApp currentEvent];
4352   if (!emacs_event)
4353     return NO;
4355   emacs_event->kind = NS_NONKEY_EVENT;
4356   emacs_event->code = KEY_NS_OPEN_FILE_LINE;
4357   ns_input_file = append2 (ns_input_file, build_string ([fileName UTF8String]));
4358   ns_input_line = Qnil; /* can be start or cons start,end */
4359   emacs_event->modifiers =0;
4360   EV_TRAILER (theEvent);
4362   return YES;
4366 /* **************************************************************************
4368       EmacsApp delegate implementation
4370    ************************************************************************** */
4372 - (void)applicationDidFinishLaunching: (NSNotification *)notification
4373 /* --------------------------------------------------------------------------
4374      When application is loaded, terminate event loop in ns_term_init
4375    -------------------------------------------------------------------------- */
4377   NSTRACE (applicationDidFinishLaunching);
4378   [NSApp setServicesProvider: NSApp];
4379   ns_send_appdefined (-2);
4383 /* Termination sequences:
4384     C-x C-c:
4385     Cmd-Q:
4386     MenuBar | File | Exit:
4387     Select Quit from App menubar:
4388         -terminate
4389         KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4390         ns_term_shutdown()
4392     Select Quit from Dock menu:
4393     Logout attempt:
4394         -appShouldTerminate
4395           Cancel -> Nothing else
4396           Accept ->
4398           -terminate
4399           KEY_NS_POWER_OFF, (save-buffers-kill-emacs)
4400           ns_term_shutdown()
4404 - (void) terminate: (id)sender
4406   struct frame *emacsframe = SELECTED_FRAME ();
4408   if (!emacs_event)
4409     return;
4411   emacs_event->kind = NS_NONKEY_EVENT;
4412   emacs_event->code = KEY_NS_POWER_OFF;
4413   emacs_event->arg = Qt; /* mark as non-key event */
4414   EV_TRAILER ((id)nil);
4418 - (NSApplicationTerminateReply)applicationShouldTerminate: (id)sender
4420   int ret;
4422   if (NILP (ns_confirm_quit)) //   || ns_shutdown_properly  --> TO DO
4423     return NSTerminateNow;
4425     ret = NSRunAlertPanel(ns_app_name,
4426                           @"Exit requested.  Would you like to Save Buffers and Exit, or Cancel the request?",
4427                           @"Save Buffers and Exit", @"Cancel", nil);
4429     if (ret == NSAlertDefaultReturn)
4430         return NSTerminateNow;
4431     else if (ret == NSAlertAlternateReturn)
4432         return NSTerminateCancel;
4433     return NSTerminateNow;  /* just in case */
4436 static int
4437 not_in_argv (NSString *arg)
4439   int k;
4440   const char *a = [arg UTF8String];
4441   for (k = 1; k < initial_argc; ++k)
4442     if (strcmp (a, initial_argv[k]) == 0) return 0;
4443   return 1;
4446 /*   Notification from the Workspace to open a file */
4447 - (BOOL)application: sender openFile: (NSString *)file
4449   if (ns_do_open_file || not_in_argv (file))
4450     [ns_pending_files addObject: file];
4451   return YES;
4455 /*   Open a file as a temporary file */
4456 - (BOOL)application: sender openTempFile: (NSString *)file
4458   if (ns_do_open_file || not_in_argv (file))
4459     [ns_pending_files addObject: file];
4460   return YES;
4464 /*   Notification from the Workspace to open a file noninteractively (?) */
4465 - (BOOL)application: sender openFileWithoutUI: (NSString *)file
4467   if (ns_do_open_file || not_in_argv (file))
4468     [ns_pending_files addObject: file];
4469   return YES;
4472 /*   Notification from the Workspace to open multiple files */
4473 - (void)application: sender openFiles: (NSArray *)fileList
4475   NSEnumerator *files = [fileList objectEnumerator];
4476   NSString *file;
4477   /* Don't open files from the command line unconditionally,
4478      Cocoa parses the command line wrong, --option value tries to open value
4479      if --option is the last option.  */
4480   while ((file = [files nextObject]) != nil)
4481     if (ns_do_open_file || not_in_argv (file))
4482       [ns_pending_files addObject: file];
4484   [self replyToOpenOrPrint: NSApplicationDelegateReplySuccess];
4489 /* Handle dock menu requests.  */
4490 - (NSMenu *)applicationDockMenu: (NSApplication *) sender
4492   return dockMenu;
4496 /* TODO: these may help w/IO switching btwn terminal and NSApp */
4497 - (void)applicationWillBecomeActive: (NSNotification *)notification
4499   //ns_app_active=YES;
4501 - (void)applicationDidBecomeActive: (NSNotification *)notification
4503   NSTRACE (applicationDidBecomeActive);
4505   //ns_app_active=YES;
4507   ns_update_auto_hide_menu_bar ();
4508   // No constraining takes place when the application is not active.
4509   ns_constrain_all_frames ();
4511 - (void)applicationDidResignActive: (NSNotification *)notification
4513   //ns_app_active=NO;
4514   ns_send_appdefined (-1);
4519 /* ==========================================================================
4521     EmacsApp aux handlers for managing event loop
4523    ========================================================================== */
4526 - (void)timeout_handler: (NSTimer *)timedEntry
4527 /* --------------------------------------------------------------------------
4528      The timeout specified to ns_select has passed.
4529    -------------------------------------------------------------------------- */
4531   /*NSTRACE (timeout_handler); */
4532   ns_send_appdefined (-2);
4535 - (void)fd_handler:(id)unused
4536 /* --------------------------------------------------------------------------
4537      Check data waiting on file descriptors and terminate if so
4538    -------------------------------------------------------------------------- */
4540   int result;
4541   int waiting = 1, nfds;
4542   char c;
4544   SELECT_TYPE readfds, writefds, *wfds;
4545   EMACS_TIME timeout, *tmo;
4546   NSAutoreleasePool *pool = nil;
4548   /* NSTRACE (fd_handler); */
4550   for (;;)
4551     {
4552       [pool release];
4553       pool = [[NSAutoreleasePool alloc] init];
4555       if (waiting)
4556         {
4557           SELECT_TYPE fds;
4559           FD_SET (selfds[0], &fds);
4560           result = select (selfds[0]+1, &fds, NULL, NULL, NULL);
4561           if (result > 0)
4562             {
4563               read (selfds[0], &c, 1);
4564               if (c == 'g') waiting = 0;
4565             }
4566         }
4567       else
4568         {
4569           pthread_mutex_lock (&select_mutex);
4570           nfds = select_nfds;
4572           if (select_valid & SELECT_HAVE_READ)
4573             readfds = select_readfds;
4574           else
4575             FD_ZERO (&readfds);
4577           if (select_valid & SELECT_HAVE_WRITE)
4578             {
4579               writefds = select_writefds;
4580               wfds = &writefds;
4581             }
4582           else
4583             wfds = NULL;
4584           if (select_valid & SELECT_HAVE_TMO)
4585             {
4586               timeout = select_timeout;
4587               tmo = &timeout;
4588             }
4589           else
4590             tmo = NULL;
4592           pthread_mutex_unlock (&select_mutex);
4594           FD_SET (selfds[0], &readfds);
4595           if (selfds[0] >= nfds) nfds = selfds[0]+1;
4597           result = pselect (nfds, &readfds, wfds, NULL, tmo, NULL);
4599           if (result == 0)
4600             ns_send_appdefined (-2);
4601           else if (result > 0)
4602             {
4603               if (FD_ISSET (selfds[0], &readfds))
4604                 {
4605                   read (selfds[0], &c, 1);
4606                   if (c == 's') waiting = 1;
4607                 }
4608               else
4609                 {
4610                   pthread_mutex_lock (&select_mutex);
4611                   if (select_valid & SELECT_HAVE_READ)
4612                     select_readfds = readfds;
4613                   if (select_valid & SELECT_HAVE_WRITE)
4614                     select_writefds = writefds;
4615                   if (select_valid & SELECT_HAVE_TMO)
4616                     select_timeout = timeout;
4617                   pthread_mutex_unlock (&select_mutex);
4619                   ns_send_appdefined (result);
4620                 }
4621             }
4622           waiting = 1;
4623         }
4624     }
4629 /* ==========================================================================
4631     Service provision
4633    ========================================================================== */
4635 /* called from system: queue for next pass through event loop */
4636 - (void)requestService: (NSPasteboard *)pboard
4637               userData: (NSString *)userData
4638                  error: (NSString **)error
4640   [ns_pending_service_names addObject: userData];
4641   [ns_pending_service_args addObject: [NSString stringWithUTF8String:
4642       SSDATA (ns_string_from_pasteboard (pboard))]];
4646 /* called from ns_read_socket to clear queue */
4647 - (BOOL)fulfillService: (NSString *)name withArg: (NSString *)arg
4649   struct frame *emacsframe = SELECTED_FRAME ();
4650   NSEvent *theEvent = [NSApp currentEvent];
4652   if (!emacs_event)
4653     return NO;
4655   emacs_event->kind = NS_NONKEY_EVENT;
4656   emacs_event->code = KEY_NS_SPI_SERVICE_CALL;
4657   ns_input_spi_name = build_string ([name UTF8String]);
4658   ns_input_spi_arg = build_string ([arg UTF8String]);
4659   emacs_event->modifiers = EV_MODIFIERS (theEvent);
4660   EV_TRAILER (theEvent);
4662   return YES;
4666 @end  /* EmacsApp */
4670 /* ==========================================================================
4672     EmacsView implementation
4674    ========================================================================== */
4677 @implementation EmacsView
4679 /* needed to inform when window closed from LISP */
4680 - (void) setWindowClosing: (BOOL)closing
4682   windowClosing = closing;
4686 - (void)dealloc
4688   NSTRACE (EmacsView_dealloc);
4689   [toolbar release];
4690   if (fs_state == FULLSCREEN_BOTH)
4691     [nonfs_window release];
4692   [super dealloc];
4696 /* called on font panel selection */
4697 - (void)changeFont: (id)sender
4699   NSEvent *e =[[self window] currentEvent];
4700   struct face *face =FRAME_DEFAULT_FACE (emacsframe);
4701   id newFont;
4702   float size;
4704   NSTRACE (changeFont);
4705   if (!emacs_event)
4706     return;
4708   if ((newFont = [sender convertFont:
4709                            ((struct nsfont_info *)face->font)->nsfont]))
4710     {
4711       SET_FRAME_GARBAGED (emacsframe); /* now needed as of 2008/10 */
4713       emacs_event->kind = NS_NONKEY_EVENT;
4714       emacs_event->modifiers = 0;
4715       emacs_event->code = KEY_NS_CHANGE_FONT;
4717       size = [newFont pointSize];
4718       ns_input_fontsize = make_number (lrint (size));
4719       ns_input_font = build_string ([[newFont familyName] UTF8String]);
4720       EV_TRAILER (e);
4721     }
4725 - (BOOL)acceptsFirstResponder
4727   NSTRACE (acceptsFirstResponder);
4728   return YES;
4732 - (void)resetCursorRects
4734   NSRect visible = [self visibleRect];
4735   NSCursor *currentCursor = FRAME_POINTER_TYPE (emacsframe);
4736   NSTRACE (resetCursorRects);
4738   if (currentCursor == nil)
4739     currentCursor = [NSCursor arrowCursor];
4741   if (!NSIsEmptyRect (visible))
4742     [self addCursorRect: visible cursor: currentCursor];
4743   [currentCursor setOnMouseEntered: YES];
4748 /*****************************************************************************/
4749 /* Keyboard handling. */
4750 #define NS_KEYLOG 0
4752 - (void)keyDown: (NSEvent *)theEvent
4754   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
4755   int code;
4756   unsigned fnKeysym = 0;
4757   int flags;
4758   static NSMutableArray *nsEvArray;
4759 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4760   static BOOL firstTime = YES;
4761 #endif
4762   int left_is_none;
4764   NSTRACE (keyDown);
4766   /* Rhapsody and OS X give up and down events for the arrow keys */
4767   if (ns_fake_keydown == YES)
4768     ns_fake_keydown = NO;
4769   else if ([theEvent type] != NSKeyDown)
4770     return;
4772   if (!emacs_event)
4773     return;
4775  if (![[self window] isKeyWindow]
4776      && [[theEvent window] isKindOfClass: [EmacsWindow class]]
4777      /* we must avoid an infinite loop here. */
4778      && (EmacsView *)[[theEvent window] delegate] != self)
4779    {
4780      /* XXX: There is an occasional condition in which, when Emacs display
4781          updates a different frame from the current one, and temporarily
4782          selects it, then processes some interrupt-driven input
4783          (dispnew.c:3878), OS will send the event to the correct NSWindow, but
4784          for some reason that window has its first responder set to the NSView
4785          most recently updated (I guess), which is not the correct one. */
4786      [(EmacsView *)[[theEvent window] delegate] keyDown: theEvent];
4787      return;
4788    }
4790   if (nsEvArray == nil)
4791     nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
4793   [NSCursor setHiddenUntilMouseMoves: YES];
4795   if (hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
4796     {
4797       clear_mouse_face (hlinfo);
4798       hlinfo->mouse_face_hidden = 1;
4799     }
4801   if (!processingCompose)
4802     {
4803       /* When using screen sharing, no left or right information is sent,
4804          so use Left key in those cases.  */
4805       int is_left_key, is_right_key;
4807       code = ([[theEvent charactersIgnoringModifiers] length] == 0) ?
4808         0 : [[theEvent charactersIgnoringModifiers] characterAtIndex: 0];
4810       /* (Carbon way: [theEvent keyCode]) */
4812       /* is it a "function key"? */
4813       fnKeysym = ns_convert_key (code);
4814       if (fnKeysym)
4815         {
4816           /* COUNTERHACK: map 'Delete' on upper-right main KB to 'Backspace',
4817              because Emacs treats Delete and KP-Delete same (in simple.el). */
4818           if (fnKeysym == 0xFFFF && [theEvent keyCode] == 0x33)
4819             code = 0xFF08; /* backspace */
4820           else
4821             code = fnKeysym;
4822         }
4824       /* are there modifiers? */
4825       emacs_event->modifiers = 0;
4826       flags = [theEvent modifierFlags];
4828       if (flags & NSHelpKeyMask)
4829           emacs_event->modifiers |= hyper_modifier;
4831       if (flags & NSShiftKeyMask)
4832         emacs_event->modifiers |= shift_modifier;
4834       is_right_key = (flags & NSRightCommandKeyMask) == NSRightCommandKeyMask;
4835       is_left_key = (flags & NSLeftCommandKeyMask) == NSLeftCommandKeyMask
4836         || (! is_right_key && (flags & NSCommandKeyMask) == NSCommandKeyMask);
4838       if (is_right_key)
4839         emacs_event->modifiers |= parse_solitary_modifier
4840           (EQ (ns_right_command_modifier, Qleft)
4841            ? ns_command_modifier
4842            : ns_right_command_modifier);
4844       if (is_left_key)
4845         {
4846           emacs_event->modifiers |= parse_solitary_modifier
4847             (ns_command_modifier);
4849           /* if super (default), take input manager's word so things like
4850              dvorak / qwerty layout work */
4851           if (EQ (ns_command_modifier, Qsuper)
4852               && !fnKeysym
4853               && [[theEvent characters] length] != 0)
4854             {
4855               /* XXX: the code we get will be unshifted, so if we have
4856                  a shift modifier, must convert ourselves */
4857               if (!(flags & NSShiftKeyMask))
4858                 code = [[theEvent characters] characterAtIndex: 0];
4859 #if 0
4860               /* this is ugly and also requires linking w/Carbon framework
4861                  (for LMGetKbdType) so for now leave this rare (?) case
4862                  undealt with.. in future look into CGEvent methods */
4863               else
4864                 {
4865                   long smv = GetScriptManagerVariable (smKeyScript);
4866                   Handle uchrHandle = GetResource
4867                     ('uchr', GetScriptVariable (smv, smScriptKeys));
4868                   UInt32 dummy = 0;
4869                   UCKeyTranslate ((UCKeyboardLayout*)*uchrHandle,
4870                                  [[theEvent characters] characterAtIndex: 0],
4871                                  kUCKeyActionDisplay,
4872                                  (flags & ~NSCommandKeyMask) >> 8,
4873                                  LMGetKbdType (), kUCKeyTranslateNoDeadKeysMask,
4874                                  &dummy, 1, &dummy, &code);
4875                   code &= 0xFF;
4876                 }
4877 #endif
4878             }
4879         }
4881       is_right_key = (flags & NSRightControlKeyMask) == NSRightControlKeyMask;
4882       is_left_key = (flags & NSLeftControlKeyMask) == NSLeftControlKeyMask
4883         || (! is_right_key && (flags & NSControlKeyMask) == NSControlKeyMask);
4885       if (is_right_key)
4886           emacs_event->modifiers |= parse_solitary_modifier
4887               (EQ (ns_right_control_modifier, Qleft)
4888                ? ns_control_modifier
4889                : ns_right_control_modifier);
4891       if (is_left_key)
4892         emacs_event->modifiers |= parse_solitary_modifier
4893           (ns_control_modifier);
4895       if (flags & NS_FUNCTION_KEY_MASK && !fnKeysym)
4896           emacs_event->modifiers |=
4897             parse_solitary_modifier (ns_function_modifier);
4899       left_is_none = NILP (ns_alternate_modifier)
4900         || EQ (ns_alternate_modifier, Qnone);
4902       is_right_key = (flags & NSRightAlternateKeyMask)
4903         == NSRightAlternateKeyMask;
4904       is_left_key = (flags & NSLeftAlternateKeyMask) == NSLeftAlternateKeyMask
4905         || (! is_right_key
4906             && (flags & NSAlternateKeyMask) == NSAlternateKeyMask);
4908       if (is_right_key)
4909         {
4910           if ((NILP (ns_right_alternate_modifier)
4911                || EQ (ns_right_alternate_modifier, Qnone)
4912                || (EQ (ns_right_alternate_modifier, Qleft) && left_is_none))
4913               && !fnKeysym)
4914             {   /* accept pre-interp alt comb */
4915               if ([[theEvent characters] length] > 0)
4916                 code = [[theEvent characters] characterAtIndex: 0];
4917               /*HACK: clear lone shift modifier to stop next if from firing */
4918               if (emacs_event->modifiers == shift_modifier)
4919                 emacs_event->modifiers = 0;
4920             }
4921           else
4922             emacs_event->modifiers |= parse_solitary_modifier
4923               (EQ (ns_right_alternate_modifier, Qleft)
4924                ? ns_alternate_modifier
4925                : ns_right_alternate_modifier);
4926         }
4928       if (is_left_key) /* default = meta */
4929         {
4930           if (left_is_none && !fnKeysym)
4931             {   /* accept pre-interp alt comb */
4932               if ([[theEvent characters] length] > 0)
4933                 code = [[theEvent characters] characterAtIndex: 0];
4934               /*HACK: clear lone shift modifier to stop next if from firing */
4935               if (emacs_event->modifiers == shift_modifier)
4936                 emacs_event->modifiers = 0;
4937             }
4938           else
4939               emacs_event->modifiers |=
4940                 parse_solitary_modifier (ns_alternate_modifier);
4941         }
4943   if (NS_KEYLOG)
4944     fprintf (stderr, "keyDown: code =%x\tfnKey =%x\tflags = %x\tmods = %x\n",
4945              code, fnKeysym, flags, emacs_event->modifiers);
4947       /* if it was a function key or had modifiers, pass it directly to emacs */
4948       if (fnKeysym || (emacs_event->modifiers
4949                        && (emacs_event->modifiers != shift_modifier)
4950                        && [[theEvent charactersIgnoringModifiers] length] > 0))
4951 /*[[theEvent characters] length] */
4952         {
4953           emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
4954           if (code < 0x20)
4955             code |= (1<<28)|(3<<16);
4956           else if (code == 0x7f)
4957             code |= (1<<28)|(3<<16);
4958           else if (!fnKeysym)
4959             emacs_event->kind = code > 0xFF
4960               ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
4962           emacs_event->code = code;
4963           EV_TRAILER (theEvent);
4964           return;
4965         }
4966     }
4969 #if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
4970   /* if we get here we should send the key for input manager processing */
4971   if (firstTime && [[NSInputManager currentInputManager]
4972                      wantsToDelayTextChangeNotifications] == NO)
4973     fprintf (stderr,
4974           "Emacs: WARNING: TextInput mgr wants marked text to be permanent!\n");
4975   firstTime = NO;
4976 #endif
4977   if (NS_KEYLOG && !processingCompose)
4978     fprintf (stderr, "keyDown: Begin compose sequence.\n");
4980   processingCompose = YES;
4981   [nsEvArray addObject: theEvent];
4982   [self interpretKeyEvents: nsEvArray];
4983   [nsEvArray removeObject: theEvent];
4987 #ifdef NS_IMPL_COCOA
4988 /* Needed to pick up Ctrl-tab and possibly other events that OS X has
4989    decided not to send key-down for.
4990    See http://osdir.com/ml/editors.vim.mac/2007-10/msg00141.html
4991    This only applies on Tiger and earlier.
4992    If it matches one of these, send it on to keyDown. */
4993 -(void)keyUp: (NSEvent *)theEvent
4995   int flags = [theEvent modifierFlags];
4996   int code = [theEvent keyCode];
4997   if (floor (NSAppKitVersionNumber) <= 824 /*NSAppKitVersionNumber10_4*/ &&
4998       code == 0x30 && (flags & NSControlKeyMask) && !(flags & NSCommandKeyMask))
4999     {
5000       if (NS_KEYLOG)
5001         fprintf (stderr, "keyUp: passed test");
5002       ns_fake_keydown = YES;
5003       [self keyDown: theEvent];
5004     }
5006 #endif
5009 /* <NSTextInput> implementation (called through super interpretKeyEvents:]). */
5012 /* <NSTextInput>: called when done composing;
5013    NOTE: also called when we delete over working text, followed immed.
5014          by doCommandBySelector: deleteBackward: */
5015 - (void)insertText: (id)aString
5017   int code;
5018   int len = [(NSString *)aString length];
5019   int i;
5021   if (NS_KEYLOG)
5022     NSLog (@"insertText '%@'\tlen = %d", aString, len);
5023   processingCompose = NO;
5025   if (!emacs_event)
5026     return;
5028   /* first, clear any working text */
5029   if (workingText != nil)
5030     [self deleteWorkingText];
5032   /* now insert the string as keystrokes */
5033   for (i =0; i<len; i++)
5034     {
5035       code = [aString characterAtIndex: i];
5036       /* TODO: still need this? */
5037       if (code == 0x2DC)
5038         code = '~'; /* 0x7E */
5039       if (code != 32) /* Space */
5040         emacs_event->modifiers = 0;
5041       emacs_event->kind
5042         = code > 0xFF ? MULTIBYTE_CHAR_KEYSTROKE_EVENT : ASCII_KEYSTROKE_EVENT;
5043       emacs_event->code = code;
5044       EV_TRAILER ((id)nil);
5045     }
5049 /* <NSTextInput>: inserts display of composing characters */
5050 - (void)setMarkedText: (id)aString selectedRange: (NSRange)selRange
5052   NSString *str = [aString respondsToSelector: @selector (string)] ?
5053     [aString string] : aString;
5054   if (NS_KEYLOG)
5055     NSLog (@"setMarkedText '%@' len =%d range %d from %d", str, [str length],
5056            selRange.length, selRange.location);
5058   if (workingText != nil)
5059     [self deleteWorkingText];
5060   if ([str length] == 0)
5061     return;
5063   if (!emacs_event)
5064     return;
5066   processingCompose = YES;
5067   workingText = [str copy];
5068   ns_working_text = build_string ([workingText UTF8String]);
5070   emacs_event->kind = NS_TEXT_EVENT;
5071   emacs_event->code = KEY_NS_PUT_WORKING_TEXT;
5072   EV_TRAILER ((id)nil);
5076 /* delete display of composing characters [not in <NSTextInput>] */
5077 - (void)deleteWorkingText
5079   if (workingText == nil)
5080     return;
5081   if (NS_KEYLOG)
5082     NSLog(@"deleteWorkingText len =%d\n", [workingText length]);
5083   [workingText release];
5084   workingText = nil;
5085   processingCompose = NO;
5087   if (!emacs_event)
5088     return;
5090   emacs_event->kind = NS_TEXT_EVENT;
5091   emacs_event->code = KEY_NS_UNPUT_WORKING_TEXT;
5092   EV_TRAILER ((id)nil);
5096 - (BOOL)hasMarkedText
5098   return workingText != nil;
5102 - (NSRange)markedRange
5104   NSRange rng = workingText != nil
5105     ? NSMakeRange (0, [workingText length]) : NSMakeRange (NSNotFound, 0);
5106   if (NS_KEYLOG)
5107     NSLog (@"markedRange request");
5108   return rng;
5112 - (void)unmarkText
5114   if (NS_KEYLOG)
5115     NSLog (@"unmark (accept) text");
5116   [self deleteWorkingText];
5117   processingCompose = NO;
5121 /* used to position char selection windows, etc. */
5122 - (NSRect)firstRectForCharacterRange: (NSRange)theRange
5124   NSRect rect;
5125   NSPoint pt;
5126   struct window *win = XWINDOW (FRAME_SELECTED_WINDOW (emacsframe));
5127   if (NS_KEYLOG)
5128     NSLog (@"firstRectForCharRange request");
5130   rect.size.width = theRange.length * FRAME_COLUMN_WIDTH (emacsframe);
5131   rect.size.height = FRAME_LINE_HEIGHT (emacsframe);
5132   pt.x = WINDOW_TEXT_TO_FRAME_PIXEL_X (win, win->phys_cursor.x);
5133   pt.y = WINDOW_TO_FRAME_PIXEL_Y (win, win->phys_cursor.y
5134                                        +FRAME_LINE_HEIGHT (emacsframe));
5136   pt = [self convertPoint: pt toView: nil];
5137   pt = [[self window] convertBaseToScreen: pt];
5138   rect.origin = pt;
5139   return rect;
5143 - (NSInteger)conversationIdentifier
5145   return (NSInteger)self;
5149 - (void)doCommandBySelector: (SEL)aSelector
5151   if (NS_KEYLOG)
5152     NSLog (@"doCommandBySelector: %@", NSStringFromSelector (aSelector));
5154   if (aSelector == @selector (deleteBackward:))
5155     {
5156       /* happens when user backspaces over an ongoing composition:
5157          throw a 'delete' into the event queue */
5158       if (!emacs_event)
5159         return;
5160       emacs_event->kind = NON_ASCII_KEYSTROKE_EVENT;
5161       emacs_event->code = 0xFF08;
5162       EV_TRAILER ((id)nil);
5163     }
5166 - (NSArray *)validAttributesForMarkedText
5168   static NSArray *arr = nil;
5169   if (arr == nil) arr = [NSArray new];
5170  /* [[NSArray arrayWithObject: NSUnderlineStyleAttributeName] retain]; */
5171   return arr;
5174 - (NSRange)selectedRange
5176   if (NS_KEYLOG)
5177     NSLog (@"selectedRange request");
5178   return NSMakeRange (NSNotFound, 0);
5181 - (NSUInteger)characterIndexForPoint: (NSPoint)thePoint
5183   if (NS_KEYLOG)
5184     NSLog (@"characterIndexForPoint request");
5185   return 0;
5188 - (NSAttributedString *)attributedSubstringFromRange: (NSRange)theRange
5190   static NSAttributedString *str = nil;
5191   if (str == nil) str = [NSAttributedString new];
5192   if (NS_KEYLOG)
5193     NSLog (@"attributedSubstringFromRange request");
5194   return str;
5197 /* End <NSTextInput> impl. */
5198 /*****************************************************************************/
5201 /* This is what happens when the user presses a mouse button.  */
5202 - (void)mouseDown: (NSEvent *)theEvent
5204   NSPoint p = [self convertPoint: [theEvent locationInWindow] fromView: nil];
5206   NSTRACE (mouseDown);
5208   [self deleteWorkingText];
5210   if (!emacs_event)
5211     return;
5213   last_mouse_frame = emacsframe;
5214   /* appears to be needed to prevent spurious movement events generated on
5215      button clicks */
5216   last_mouse_frame->mouse_moved = 0;
5218   if ([theEvent type] == NSScrollWheel)
5219     {
5220       float delta = [theEvent deltaY];
5221       /* Mac notebooks send wheel events w/delta =0 when trackpad scrolling */
5222       if (delta == 0)
5223         return;
5224       emacs_event->kind = WHEEL_EVENT;
5225       emacs_event->code = 0;
5226       emacs_event->modifiers = EV_MODIFIERS (theEvent) |
5227         ((delta > 0) ? up_modifier : down_modifier);
5228     }
5229   else
5230     {
5231       emacs_event->kind = MOUSE_CLICK_EVENT;
5232       emacs_event->code = EV_BUTTON (theEvent);
5233       emacs_event->modifiers = EV_MODIFIERS (theEvent)
5234                              | EV_UDMODIFIERS (theEvent);
5235     }
5236   XSETINT (emacs_event->x, lrint (p.x));
5237   XSETINT (emacs_event->y, lrint (p.y));
5238   EV_TRAILER (theEvent);
5242 - (void)rightMouseDown: (NSEvent *)theEvent
5244   NSTRACE (rightMouseDown);
5245   [self mouseDown: theEvent];
5249 - (void)otherMouseDown: (NSEvent *)theEvent
5251   NSTRACE (otherMouseDown);
5252   [self mouseDown: theEvent];
5256 - (void)mouseUp: (NSEvent *)theEvent
5258   NSTRACE (mouseUp);
5259   [self mouseDown: theEvent];
5263 - (void)rightMouseUp: (NSEvent *)theEvent
5265   NSTRACE (rightMouseUp);
5266   [self mouseDown: theEvent];
5270 - (void)otherMouseUp: (NSEvent *)theEvent
5272   NSTRACE (otherMouseUp);
5273   [self mouseDown: theEvent];
5277 - (void) scrollWheel: (NSEvent *)theEvent
5279   NSTRACE (scrollWheel);
5280   [self mouseDown: theEvent];
5284 /* Tell emacs the mouse has moved. */
5285 - (void)mouseMoved: (NSEvent *)e
5287   Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (emacsframe);
5288   Lisp_Object frame;
5290 //  NSTRACE (mouseMoved);
5292   last_mouse_movement_time = EV_TIMESTAMP (e);
5293   last_mouse_motion_position
5294     = [self convertPoint: [e locationInWindow] fromView: nil];
5296   /* update any mouse face */
5297   if (hlinfo->mouse_face_hidden)
5298     {
5299       hlinfo->mouse_face_hidden = 0;
5300       clear_mouse_face (hlinfo);
5301     }
5303   /* tooltip handling */
5304   previous_help_echo_string = help_echo_string;
5305   help_echo_string = Qnil;
5307   if (!note_mouse_movement (emacsframe, last_mouse_motion_position.x,
5308                             last_mouse_motion_position.y))
5309     help_echo_string = previous_help_echo_string;
5311   XSETFRAME (frame, emacsframe);
5312   if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5313     {
5314       /* NOTE: help_echo_{window,pos,object} are set in xdisp.c
5315          (note_mouse_highlight), which is called through the
5316          note_mouse_movement () call above */
5317       gen_help_event (help_echo_string, frame, help_echo_window,
5318                       help_echo_object, help_echo_pos);
5319     }
5320   else
5321     {
5322       help_echo_string = Qnil;
5323       gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5324     }
5326   if (emacsframe->mouse_moved && send_appdefined)
5327     ns_send_appdefined (-1);
5331 - (void)mouseDragged: (NSEvent *)e
5333   NSTRACE (mouseDragged);
5334   [self mouseMoved: e];
5338 - (void)rightMouseDragged: (NSEvent *)e
5340   NSTRACE (rightMouseDragged);
5341   [self mouseMoved: e];
5345 - (void)otherMouseDragged: (NSEvent *)e
5347   NSTRACE (otherMouseDragged);
5348   [self mouseMoved: e];
5352 - (BOOL)windowShouldClose: (id)sender
5354   NSEvent *e =[[self window] currentEvent];
5356   NSTRACE (windowShouldClose);
5357   windowClosing = YES;
5358   if (!emacs_event)
5359     return NO;
5360   emacs_event->kind = DELETE_WINDOW_EVENT;
5361   emacs_event->modifiers = 0;
5362   emacs_event->code = 0;
5363   EV_TRAILER (e);
5364   /* Don't close this window, let this be done from lisp code.  */
5365   return NO;
5368 - (void) updateFrameSize: (BOOL) delay;
5370   NSWindow *window = [self window];
5371   NSRect wr = [window frame];
5372 #ifdef NS_IMPL_GNUSTEP
5373   int extra = 3;
5374 #else
5375   int extra = 0;
5376 #endif
5378   int oldc = cols, oldr = rows;
5379   int oldw = FRAME_PIXEL_WIDTH (emacsframe),
5380     oldh = FRAME_PIXEL_HEIGHT (emacsframe);
5381   int neww, newh;
5383   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe, wr.size.width + extra);
5385   if (cols < MINWIDTH)
5386     cols = MINWIDTH;
5388   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES
5389     (emacsframe, wr.size.height
5390      - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + extra
5391      - FRAME_TOOLBAR_HEIGHT (emacsframe));
5393   if (rows < MINHEIGHT)
5394     rows = MINHEIGHT;
5396   neww = (int)wr.size.width - emacsframe->border_width;
5397   newh = ((int)wr.size.height
5398           - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5399           - FRAME_TOOLBAR_HEIGHT (emacsframe));
5401   if (oldr != rows || oldc != cols || neww != oldw || newh != oldh)
5402     {
5403       NSView *view = FRAME_NS_VIEW (emacsframe);
5404       FRAME_PIXEL_WIDTH (emacsframe) = neww;
5405       FRAME_PIXEL_HEIGHT (emacsframe) = newh;
5406       change_frame_size (emacsframe, rows, cols, 0, delay, 0);
5407       SET_FRAME_GARBAGED (emacsframe);
5408       cancel_mouse_face (emacsframe);
5409       [view setFrame: NSMakeRect (0, 0, neww, newh)];
5410       [self windowDidMove:nil];   // Update top/left.
5411     }
5414 - (NSSize)windowWillResize: (NSWindow *)sender toSize: (NSSize)frameSize
5415 /* normalize frame to gridded text size */
5417   NSTRACE (windowWillResize);
5418 /*fprintf (stderr,"Window will resize: %.0f x %.0f\n",frameSize.width,frameSize.height); */
5420   if (fs_state == FULLSCREEN_MAXIMIZED
5421       && (maximized_width != (int)frameSize.width
5422           || maximized_height != (int)frameSize.height))
5423     [self setFSValue: FULLSCREEN_NONE];
5424   else if (fs_state == FULLSCREEN_WIDTH
5425            && maximized_width != (int)frameSize.width)
5426     [self setFSValue: FULLSCREEN_NONE];
5427   else if (fs_state == FULLSCREEN_HEIGHT
5428            && maximized_height != (int)frameSize.height)
5429     [self setFSValue: FULLSCREEN_NONE];
5430   if (fs_state == FULLSCREEN_NONE)
5431     maximized_width = maximized_height = -1;
5433   cols = FRAME_PIXEL_WIDTH_TO_TEXT_COLS (emacsframe,
5434 #ifdef NS_IMPL_GNUSTEP
5435                                         frameSize.width + 3);
5436 #else
5437                                         frameSize.width);
5438 #endif
5439   if (cols < MINWIDTH)
5440     cols = MINWIDTH;
5442   rows = FRAME_PIXEL_HEIGHT_TO_TEXT_LINES (emacsframe, frameSize.height
5443 #ifdef NS_IMPL_GNUSTEP
5444       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe) + 3
5445         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5446 #else
5447       - FRAME_NS_TITLEBAR_HEIGHT (emacsframe)
5448         - FRAME_TOOLBAR_HEIGHT (emacsframe));
5449 #endif
5450   if (rows < MINHEIGHT)
5451     rows = MINHEIGHT;
5452 #ifdef NS_IMPL_COCOA
5453   {
5454     /* this sets window title to have size in it; the wm does this under GS */
5455     NSRect r = [[self window] frame];
5456     if (r.size.height == frameSize.height && r.size.width == frameSize.width)
5457       {
5458         if (old_title != 0)
5459           {
5460             xfree (old_title);
5461             old_title = 0;
5462           }
5463       }
5464     else
5465       {
5466         char *size_title;
5467         NSWindow *window = [self window];
5468         if (old_title == 0)
5469           {
5470             const char *t = [[[self window] title] UTF8String];
5471             char *pos = strstr (t, "  â€”  ");
5472             if (pos)
5473               *pos = '\0';
5474             old_title = xstrdup (t);
5475           }
5476         size_title = xmalloc (strlen (old_title) + 40);
5477         esprintf (size_title, "%s  â€”  (%d x %d)", old_title, cols, rows);
5478         [window setTitle: [NSString stringWithUTF8String: size_title]];
5479         [window display];
5480         xfree (size_title);
5481       }
5482   }
5483 #endif /* NS_IMPL_COCOA */
5484 /*fprintf (stderr,"    ...size became %.0f x %.0f  (%d x %d)\n",frameSize.width,frameSize.height,cols,rows); */
5486   return frameSize;
5490 - (void)windowDidResize: (NSNotification *)notification
5493 #if !defined (NEW_STYLE_FS) && ! defined (NS_IMPL_GNUSTEP)
5494   NSWindow *theWindow = [notification object];
5495   /* We can get notification on the non-FS window when in fullscreen mode.  */
5496   if ([self window] != theWindow) return;
5497 #endif
5499 #ifdef NS_IMPL_GNUSTEP
5500   NSWindow *theWindow = [notification object];
5502    /* In GNUstep, at least currently, it's possible to get a didResize
5503       without getting a willResize.. therefore we need to act as if we got
5504       the willResize now */
5505   NSSize sz = [theWindow frame].size;
5506   sz = [self windowWillResize: theWindow toSize: sz];
5507 #endif /* NS_IMPL_GNUSTEP */
5509   NSTRACE (windowDidResize);
5510 /*fprintf (stderr,"windowDidResize: %.0f\n",[theWindow frame].size.height); */
5512 #ifdef NS_IMPL_COCOA
5513   if (old_title != 0)
5514     {
5515       xfree (old_title);
5516       old_title = 0;
5517     }
5518 #endif /* NS_IMPL_COCOA */
5520   if (cols > 0 && rows > 0)
5521     {
5522       [self updateFrameSize: YES];
5523     }
5525   ns_send_appdefined (-1);
5529 - (void)windowDidBecomeKey: (NSNotification *)notification
5530 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5532   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5533   struct frame *old_focus = dpyinfo->x_focus_frame;
5535   NSTRACE (windowDidBecomeKey);
5537   if (emacsframe != old_focus)
5538     dpyinfo->x_focus_frame = emacsframe;
5540   ns_frame_rehighlight (emacsframe);
5542   if (emacs_event)
5543     {
5544       emacs_event->kind = FOCUS_IN_EVENT;
5545       EV_TRAILER ((id)nil);
5546     }
5550 - (void)windowDidResignKey: (NSNotification *)notification
5551 /* cf. x_detect_focus_change(), x_focus_changed(), x_new_focus_frame() */
5553   struct ns_display_info *dpyinfo = FRAME_NS_DISPLAY_INFO (emacsframe);
5554   NSTRACE (windowDidResignKey);
5556   if (dpyinfo->x_focus_frame == emacsframe)
5557     dpyinfo->x_focus_frame = 0;
5559   ns_frame_rehighlight (emacsframe);
5561   /* FIXME: for some reason needed on second and subsequent clicks away
5562             from sole-frame Emacs to get hollow box to show */
5563   if (!windowClosing && [[self window] isVisible] == YES)
5564     {
5565       x_update_cursor (emacsframe, 1);
5566       x_set_frame_alpha (emacsframe);
5567     }
5569   if (emacs_event)
5570     {
5571       [self deleteWorkingText];
5572       emacs_event->kind = FOCUS_IN_EVENT;
5573       EV_TRAILER ((id)nil);
5574     }
5578 - (void)windowWillMiniaturize: sender
5580   NSTRACE (windowWillMiniaturize);
5584 - (BOOL)isFlipped
5586   return YES;
5590 - (BOOL)isOpaque
5592   return NO;
5596 - initFrameFromEmacs: (struct frame *)f
5598   NSRect r, wr;
5599   Lisp_Object tem;
5600   NSWindow *win;
5601   NSButton *toggleButton;
5602   NSSize sz;
5603   NSColor *col;
5604   NSString *name;
5606   NSTRACE (initFrameFromEmacs);
5608   windowClosing = NO;
5609   processingCompose = NO;
5610   scrollbarsNeedingUpdate = 0;
5611   fs_state = FULLSCREEN_NONE;
5612   fs_before_fs = next_maximized = -1;
5613   maximized_width = maximized_height = -1;
5614   nonfs_window = nil;
5616 /*fprintf (stderr,"init with %d, %d\n",f->text_cols, f->text_lines); */
5618   ns_userRect = NSMakeRect (0, 0, 0, 0);
5619   r = NSMakeRect (0, 0, FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, f->text_cols),
5620                  FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, f->text_lines));
5621   [self initWithFrame: r];
5622   [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
5624   FRAME_NS_VIEW (f) = self;
5625   emacsframe = f;
5626   old_title = 0;
5628   win = [[EmacsWindow alloc]
5629             initWithContentRect: r
5630                       styleMask: (NSResizableWindowMask |
5631 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
5632                                   NSTitledWindowMask |
5633 #endif
5634                                   NSMiniaturizableWindowMask |
5635                                   NSClosableWindowMask)
5636                         backing: NSBackingStoreBuffered
5637                           defer: YES];
5639 #ifdef NEW_STYLE_FS
5640     [win setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
5641 #endif
5643   wr = [win frame];
5644   bwidth = f->border_width = wr.size.width - r.size.width;
5645   tibar_height = FRAME_NS_TITLEBAR_HEIGHT (f) = wr.size.height - r.size.height;
5647   [win setAcceptsMouseMovedEvents: YES];
5648   [win setDelegate: self];
5649   [win useOptimizedDrawing: YES];
5651   sz.width = FRAME_COLUMN_WIDTH (f);
5652   sz.height = FRAME_LINE_HEIGHT (f);
5653   [win setResizeIncrements: sz];
5655   [[win contentView] addSubview: self];
5657   if (ns_drag_types)
5658     [self registerForDraggedTypes: ns_drag_types];
5660   tem = f->name;
5661   name = [NSString stringWithUTF8String:
5662                    NILP (tem) ? "Emacs" : SSDATA (tem)];
5663   [win setTitle: name];
5665   /* toolbar support */
5666   toolbar = [[EmacsToolbar alloc] initForView: self withIdentifier:
5667                          [NSString stringWithFormat: @"Emacs Frame %d",
5668                                    ns_window_num]];
5669   [win setToolbar: toolbar];
5670   [toolbar setVisible: NO];
5671 #ifdef NS_IMPL_COCOA
5672   toggleButton = [win standardWindowButton: NSWindowToolbarButton];
5673   [toggleButton setTarget: self];
5674   [toggleButton setAction: @selector (toggleToolbar: )];
5675 #endif
5676   FRAME_TOOLBAR_HEIGHT (f) = 0;
5678   tem = f->icon_name;
5679   if (!NILP (tem))
5680     [win setMiniwindowTitle:
5681            [NSString stringWithUTF8String: SSDATA (tem)]];
5683   {
5684     NSScreen *screen = [win screen];
5686     if (screen != 0)
5687       [win setFrameTopLeftPoint: NSMakePoint
5688            (IN_BOUND (-SCREENMAX, f->left_pos, SCREENMAX),
5689             IN_BOUND (-SCREENMAX,
5690                      [screen frame].size.height - NS_TOP_POS (f), SCREENMAX))];
5691   }
5693   [win makeFirstResponder: self];
5695   col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5696                                   (FRAME_DEFAULT_FACE (emacsframe)), emacsframe);
5697   [win setBackgroundColor: col];
5698   if ([col alphaComponent] != 1.0)
5699     [win setOpaque: NO];
5701   [self allocateGState];
5703   [NSApp registerServicesMenuSendTypes: ns_send_types
5704                            returnTypes: nil];
5706   ns_window_num++;
5707   return self;
5711 - (void)windowDidMove: sender
5713   NSWindow *win = [self window];
5714   NSRect r = [win frame];
5715   NSArray *screens = [NSScreen screens];
5716   NSScreen *screen = [screens objectAtIndex: 0];
5718   NSTRACE (windowDidMove);
5720   if (!emacsframe->output_data.ns)
5721     return;
5722   if (screen != nil)
5723     {
5724       emacsframe->left_pos = r.origin.x;
5725       emacsframe->top_pos =
5726         [screen frame].size.height - (r.origin.y + r.size.height);
5727     }
5731 /* Called AFTER method below, but before our windowWillResize call there leads
5732    to windowDidResize -> x_set_window_size.  Update emacs' notion of frame
5733    location so set_window_size moves the frame. */
5734 - (BOOL)windowShouldZoom: (NSWindow *)sender toFrame: (NSRect)newFrame
5736   emacsframe->output_data.ns->zooming = 1;
5737   return YES;
5741 /* Override to do something slightly nonstandard, but nice.  First click on
5742    zoom button will zoom vertically.  Second will zoom completely.  Third
5743    returns to original. */
5744 - (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
5745                         defaultFrame:(NSRect)defaultFrame
5747   NSRect result = [sender frame];
5749   NSTRACE (windowWillUseStandardFrame);
5751   if (fs_before_fs != -1) /* Entering fullscreen */
5752       {
5753         result = defaultFrame;
5754       }
5755   else if (next_maximized == FULLSCREEN_HEIGHT
5756       || (next_maximized == -1
5757           && abs (defaultFrame.size.height - result.size.height)
5758           > FRAME_LINE_HEIGHT (emacsframe)))
5759     {
5760       /* first click */
5761       ns_userRect = result;
5762       maximized_height = result.size.height = defaultFrame.size.height;
5763       maximized_width = -1;
5764       result.origin.y = defaultFrame.origin.y;
5765       [self setFSValue: FULLSCREEN_HEIGHT];
5766     }
5767   else if (next_maximized == FULLSCREEN_WIDTH)
5768     {
5769       ns_userRect = result;
5770       maximized_width = result.size.width = defaultFrame.size.width;
5771       maximized_height = -1;
5772       result.origin.x = defaultFrame.origin.x;
5773       [self setFSValue: FULLSCREEN_WIDTH];
5774     }
5775   else if (next_maximized == FULLSCREEN_MAXIMIZED
5776            || (next_maximized == -1
5777                && abs (defaultFrame.size.width - result.size.width)
5778                > FRAME_COLUMN_WIDTH (emacsframe)))
5779     {
5780       result = defaultFrame;  /* second click */
5781       maximized_width = result.size.width;
5782       maximized_height = result.size.height;
5783       [self setFSValue: FULLSCREEN_MAXIMIZED];
5784     }
5785   else
5786     {
5787       /* restore */
5788       result = ns_userRect.size.height ? ns_userRect : result;
5789       ns_userRect = NSMakeRect (0, 0, 0, 0);
5790       [self setFSValue: FULLSCREEN_NONE];
5791       maximized_width = maximized_width = -1;
5792     }
5794   if (fs_before_fs == -1) next_maximized = -1;
5795   [self windowWillResize: sender toSize: result.size];
5796   return result;
5800 - (void)windowDidDeminiaturize: sender
5802   NSTRACE (windowDidDeminiaturize);
5803   if (!emacsframe->output_data.ns)
5804     return;
5805   emacsframe->async_iconified = 0;
5806   emacsframe->async_visible   = 1;
5807   windows_or_buffers_changed++;
5809   if (emacs_event)
5810     {
5811       emacs_event->kind = ICONIFY_EVENT;
5812       EV_TRAILER ((id)nil);
5813     }
5817 - (void)windowDidExpose: sender
5819   NSTRACE (windowDidExpose);
5820   if (!emacsframe->output_data.ns)
5821     return;
5822   emacsframe->async_visible = 1;
5823   SET_FRAME_GARBAGED (emacsframe);
5825   if (send_appdefined)
5826     ns_send_appdefined (-1);
5830 - (void)windowDidMiniaturize: sender
5832   NSTRACE (windowDidMiniaturize);
5833   if (!emacsframe->output_data.ns)
5834     return;
5836   emacsframe->async_iconified = 1;
5837   emacsframe->async_visible = 0;
5839   if (emacs_event)
5840     {
5841       emacs_event->kind = ICONIFY_EVENT;
5842       EV_TRAILER ((id)nil);
5843     }
5846 - (void)windowWillEnterFullScreen:(NSNotification *)notification
5848   fs_before_fs = fs_state;
5851 - (void)windowDidEnterFullScreen:(NSNotification *)notification
5853   [self setFSValue: FULLSCREEN_BOTH];
5854 #ifdef NEW_STYLE_FS
5855   // Fix bad background.
5856   if ([toolbar isVisible])
5857     {
5858       [toolbar setVisible:NO];
5859       [toolbar setVisible:YES];
5860     }
5861 #else
5862   [self windowDidBecomeKey:notification];
5863   [nonfs_window orderOut:self];
5864 #endif
5867 - (void)windowWillExitFullScreen:(NSNotification *)notification
5869   if (next_maximized != -1)
5870     fs_before_fs = next_maximized;
5873 - (void)windowDidExitFullScreen:(NSNotification *)notification
5875   [self setFSValue: fs_before_fs];
5876   fs_before_fs = -1;
5877   if (next_maximized != -1)
5878     [[self window] performZoom:self];
5881 - (void)toggleFullScreen: (id)sender
5883 #ifdef NEW_STYLE_FS
5884   [[self window] toggleFullScreen:sender];
5885 #else
5886   NSWindow *w = [self window], *fw;
5887   BOOL onFirstScreen = [[w screen]
5888                          isEqual:[[NSScreen screens] objectAtIndex:0]];
5889   struct frame *f = emacsframe;
5890   NSSize sz;
5891   NSRect r, wr = [w frame];
5892   NSColor *col = ns_lookup_indexed_color (NS_FACE_BACKGROUND
5893                                           (FRAME_DEFAULT_FACE (f)),
5894                                           f);
5896   sz.width = FRAME_COLUMN_WIDTH (f);
5897   sz.height = FRAME_LINE_HEIGHT (f);
5899   if (fs_state != FULLSCREEN_BOTH)
5900     {
5901       /* Hide dock and menubar if we are on the primary screen.  */
5902       if (onFirstScreen)
5903         {
5904 #if defined (NS_IMPL_COCOA) && \
5905   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
5906           NSApplicationPresentationOptions options
5907             = NSApplicationPresentationAutoHideDock
5908             | NSApplicationPresentationAutoHideMenuBar;
5910           [NSApp setPresentationOptions: options];
5911 #else
5912           [NSMenu setMenuBarVisible:NO];
5913 #endif
5914         }
5916       fw = [[EmacsFSWindow alloc]
5917                        initWithContentRect:[w contentRectForFrameRect:wr]
5918                                  styleMask:NSBorderlessWindowMask
5919                                    backing:NSBackingStoreBuffered
5920                                      defer:YES
5921                                     screen:[w screen]];
5923       [fw setContentView:[w contentView]];
5924       [fw setTitle:[w title]];
5925       [fw setDelegate:self];
5926       [fw setAcceptsMouseMovedEvents: YES];
5927       [fw useOptimizedDrawing: YES];
5928       [fw setResizeIncrements: sz];
5929       [fw setBackgroundColor: col];
5930       if ([col alphaComponent] != 1.0)
5931         [fw setOpaque: NO];
5933       f->border_width = 0;
5934       FRAME_NS_TITLEBAR_HEIGHT (f) = 0;
5935       tobar_height = FRAME_TOOLBAR_HEIGHT (f);
5936       FRAME_TOOLBAR_HEIGHT (f) = 0;
5937       FRAME_EXTERNAL_TOOL_BAR (f) = 0;
5939       nonfs_window = w;
5941       [self windowWillEnterFullScreen:nil];
5942       [fw makeKeyAndOrderFront:NSApp];
5943       [fw makeFirstResponder:self];
5944       [w orderOut:self];
5945       r = [fw frameRectForContentRect:[[fw screen] frame]];
5946       [fw setFrame: r display:YES animate:YES];
5947       [self windowDidEnterFullScreen:nil];
5948       [fw display];
5949     }
5950   else
5951     {
5952       fw = w;
5953       w = nonfs_window;
5954       nonfs_window = nil;
5956       if (onFirstScreen)
5957         {
5958 #if defined (NS_IMPL_COCOA) && \
5959   MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
5960           [NSApp setPresentationOptions: NSApplicationPresentationDefault];
5961 #else
5962           [NSMenu setMenuBarVisible:YES];
5963 #endif
5964         }
5966       [w setContentView:[fw contentView]];
5967       [w setResizeIncrements: sz];
5968       [w setBackgroundColor: col];
5969       if ([col alphaComponent] != 1.0)
5970         [w setOpaque: NO];
5972       f->border_width = bwidth;
5973       FRAME_NS_TITLEBAR_HEIGHT (f) = tibar_height;
5974       FRAME_TOOLBAR_HEIGHT (f) = tobar_height;
5975       if (tobar_height)
5976         FRAME_EXTERNAL_TOOL_BAR (f) = 1;
5978       [self windowWillExitFullScreen:nil];
5979       [fw setFrame: [w frame] display:YES animate:YES];
5980       [fw close];
5981       [w makeKeyAndOrderFront:NSApp];
5982       [self windowDidExitFullScreen:nil];
5983     }
5984 #endif
5987 - (void)handleFS
5989   if (fs_state != emacsframe->want_fullscreen)
5990     {
5991       if (fs_state == FULLSCREEN_BOTH)
5992         {
5993           [self toggleFullScreen:self];
5994         }
5996       switch (emacsframe->want_fullscreen)
5997         {
5998         case FULLSCREEN_BOTH:
5999           [self toggleFullScreen:self];
6000           break;
6001         case FULLSCREEN_WIDTH:
6002           next_maximized = FULLSCREEN_WIDTH;
6003           if (fs_state != FULLSCREEN_BOTH)
6004             [[self window] performZoom:self];
6005           break;
6006         case FULLSCREEN_HEIGHT:
6007           next_maximized = FULLSCREEN_HEIGHT;
6008           if (fs_state != FULLSCREEN_BOTH)
6009             [[self window] performZoom:self];
6010           break;
6011         case FULLSCREEN_MAXIMIZED:
6012           next_maximized = FULLSCREEN_MAXIMIZED;
6013           if (fs_state != FULLSCREEN_BOTH)
6014             [[self window] performZoom:self];
6015           break;
6016         case FULLSCREEN_NONE:
6017           if (fs_state != FULLSCREEN_BOTH)
6018             {
6019               next_maximized = FULLSCREEN_NONE;
6020               [[self window] performZoom:self];
6021             }
6022           break;
6023         }
6025       emacsframe->want_fullscreen = FULLSCREEN_NONE;
6026     }
6030 - (void) setFSValue: (int)value
6032   Lisp_Object lval = Qnil;
6033   switch (value)
6034     {
6035     case FULLSCREEN_BOTH:
6036       lval = Qfullboth;
6037       break;
6038     case FULLSCREEN_WIDTH:
6039       lval = Qfullwidth;
6040       break;
6041     case FULLSCREEN_HEIGHT:
6042       lval = Qfullheight;
6043       break;
6044     case FULLSCREEN_MAXIMIZED:
6045       lval = Qmaximized;
6046       break;
6047     }
6048   store_frame_param (emacsframe, Qfullscreen, lval);
6049   fs_state = value;
6052 - (void)mouseEntered: (NSEvent *)theEvent
6054   NSTRACE (mouseEntered);
6055   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6059 - (void)mouseExited: (NSEvent *)theEvent
6061   Mouse_HLInfo *hlinfo = emacsframe ? MOUSE_HL_INFO (emacsframe) : NULL;
6063   NSTRACE (mouseExited);
6065   if (!hlinfo)
6066     return;
6068   last_mouse_movement_time = EV_TIMESTAMP (theEvent);
6070   if (emacsframe == hlinfo->mouse_face_mouse_frame)
6071     {
6072       clear_mouse_face (hlinfo);
6073       hlinfo->mouse_face_mouse_frame = 0;
6074     }
6078 - menuDown: sender
6080   NSTRACE (menuDown);
6081   if (context_menu_value == -1)
6082     context_menu_value = [sender tag];
6083   else
6084     {
6085       NSInteger tag = [sender tag];
6086       find_and_call_menu_selection (emacsframe, emacsframe->menu_bar_items_used,
6087                                     emacsframe->menu_bar_vector,
6088                                     (void *)tag);
6089     }
6091   ns_send_appdefined (-1);
6092   return self;
6096 - (EmacsToolbar *)toolbar
6098   return toolbar;
6102 /* this gets called on toolbar button click */
6103 - toolbarClicked: (id)item
6105   NSEvent *theEvent;
6106   int idx = [item tag] * TOOL_BAR_ITEM_NSLOTS;
6108   NSTRACE (toolbarClicked);
6110   if (!emacs_event)
6111     return self;
6113   /* send first event (for some reason two needed) */
6114   theEvent = [[self window] currentEvent];
6115   emacs_event->kind = TOOL_BAR_EVENT;
6116   XSETFRAME (emacs_event->arg, emacsframe);
6117   EV_TRAILER (theEvent);
6119   emacs_event->kind = TOOL_BAR_EVENT;
6120 /*   XSETINT (emacs_event->code, 0); */
6121   emacs_event->arg = AREF (emacsframe->tool_bar_items,
6122                            idx + TOOL_BAR_ITEM_KEY);
6123   emacs_event->modifiers = EV_MODIFIERS (theEvent);
6124   EV_TRAILER (theEvent);
6125   return self;
6129 - toggleToolbar: (id)sender
6131   if (!emacs_event)
6132     return self;
6134   emacs_event->kind = NS_NONKEY_EVENT;
6135   emacs_event->code = KEY_NS_TOGGLE_TOOLBAR;
6136   EV_TRAILER ((id)nil);
6137   return self;
6141 - (void)drawRect: (NSRect)rect
6143   int x = NSMinX (rect), y = NSMinY (rect);
6144   int width = NSWidth (rect), height = NSHeight (rect);
6146   NSTRACE (drawRect);
6148   if (!emacsframe || !emacsframe->output_data.ns)
6149     return;
6151   ns_clear_frame_area (emacsframe, x, y, width, height);
6152   expose_frame (emacsframe, x, y, width, height);
6154   /*
6155     drawRect: may be called (at least in OS X 10.5) for invisible
6156     views as well for some reason.  Thus, do not infer visibility
6157     here.
6159     emacsframe->async_visible = 1;
6160     emacsframe->async_iconified = 0;
6161   */
6165 /* NSDraggingDestination protocol methods.  Actually this is not really a
6166    protocol, but a category of Object.  O well...  */
6168 -(NSUInteger) draggingEntered: (id <NSDraggingInfo>) sender
6170   NSTRACE (draggingEntered);
6171   return NSDragOperationGeneric;
6175 -(BOOL)prepareForDragOperation: (id <NSDraggingInfo>) sender
6177   return YES;
6181 -(BOOL)performDragOperation: (id <NSDraggingInfo>) sender
6183   id pb;
6184   int x, y;
6185   NSString *type;
6186   NSEvent *theEvent = [[self window] currentEvent];
6187   NSPoint position;
6189   NSTRACE (performDragOperation);
6191   if (!emacs_event)
6192     return NO;
6194   position = [self convertPoint: [sender draggingLocation] fromView: nil];
6195   x = lrint (position.x);  y = lrint (position.y);
6197   pb = [sender draggingPasteboard];
6198   type = [pb availableTypeFromArray: ns_drag_types];
6199   if (type == 0)
6200     {
6201       return NO;
6202     }
6203   else if ([type isEqualToString: NSFilenamesPboardType])
6204     {
6205       NSArray *files;
6206       NSEnumerator *fenum;
6207       NSString *file;
6209       if (!(files = [pb propertyListForType: type]))
6210         return NO;
6212       fenum = [files objectEnumerator];
6213       while ( (file = [fenum nextObject]) )
6214         {
6215           emacs_event->kind = NS_NONKEY_EVENT;
6216           emacs_event->code = KEY_NS_DRAG_FILE;
6217           XSETINT (emacs_event->x, x);
6218           XSETINT (emacs_event->y, y);
6219           ns_input_file = append2 (ns_input_file,
6220                                    build_string ([file UTF8String]));
6221           emacs_event->modifiers = EV_MODIFIERS (theEvent);
6222           EV_TRAILER (theEvent);
6223         }
6224       return YES;
6225     }
6226   else if ([type isEqualToString: NSURLPboardType])
6227     {
6228       NSString *file;
6229       NSURL *fileURL;
6231       if (!(fileURL = [NSURL URLFromPasteboard: pb]) ||
6232           [fileURL isFileURL] == NO)
6233         return NO;
6235       file = [fileURL path];
6236       emacs_event->kind = NS_NONKEY_EVENT;
6237       emacs_event->code = KEY_NS_DRAG_FILE;
6238       XSETINT (emacs_event->x, x);
6239       XSETINT (emacs_event->y, y);
6240       ns_input_file = append2 (ns_input_file, build_string ([file UTF8String]));
6241       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6242       EV_TRAILER (theEvent);
6243       return YES;
6244     }
6245   else if ([type isEqualToString: NSStringPboardType]
6246            || [type isEqualToString: NSTabularTextPboardType])
6247     {
6248       NSString *data;
6250       if (! (data = [pb stringForType: type]))
6251         return NO;
6253       emacs_event->kind = NS_NONKEY_EVENT;
6254       emacs_event->code = KEY_NS_DRAG_TEXT;
6255       XSETINT (emacs_event->x, x);
6256       XSETINT (emacs_event->y, y);
6257       ns_input_text = build_string ([data UTF8String]);
6258       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6259       EV_TRAILER (theEvent);
6260       return YES;
6261     }
6262   else if ([type isEqualToString: NSColorPboardType])
6263     {
6264       NSColor *c = [NSColor colorFromPasteboard: pb];
6265       emacs_event->kind = NS_NONKEY_EVENT;
6266       emacs_event->code = KEY_NS_DRAG_COLOR;
6267       XSETINT (emacs_event->x, x);
6268       XSETINT (emacs_event->y, y);
6269       ns_input_color = ns_color_to_lisp (c);
6270       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6271       EV_TRAILER (theEvent);
6272       return YES;
6273     }
6274   else if ([type isEqualToString: NSFontPboardType])
6275     {
6276       /* impl based on GNUstep NSTextView.m */
6277       NSData *data = [pb dataForType: NSFontPboardType];
6278       NSDictionary *dict = [NSUnarchiver unarchiveObjectWithData: data];
6279       NSFont *font = [dict objectForKey: NSFontAttributeName];
6280       char fontSize[10];
6282       if (font == nil)
6283         return NO;
6285       emacs_event->kind = NS_NONKEY_EVENT;
6286       emacs_event->code = KEY_NS_CHANGE_FONT;
6287       XSETINT (emacs_event->x, x);
6288       XSETINT (emacs_event->y, y);
6289       ns_input_font = build_string ([[font fontName] UTF8String]);
6290       snprintf (fontSize, 10, "%f", [font pointSize]);
6291       ns_input_fontsize = build_string (fontSize);
6292       emacs_event->modifiers = EV_MODIFIERS (theEvent);
6293       EV_TRAILER (theEvent);
6294       return YES;
6295     }
6296   else
6297     {
6298       error ("Invalid data type in dragging pasteboard.");
6299       return NO;
6300     }
6304 - (id) validRequestorForSendType: (NSString *)typeSent
6305                       returnType: (NSString *)typeReturned
6307   NSTRACE (validRequestorForSendType);
6308   if (typeSent != nil && [ns_send_types indexOfObject: typeSent] != NSNotFound
6309       && typeReturned == nil)
6310     {
6311       if (! NILP (ns_get_local_selection (QPRIMARY, QUTF8_STRING)))
6312         return self;
6313     }
6315   return [super validRequestorForSendType: typeSent
6316                                returnType: typeReturned];
6320 /* The next two methods are part of NSServicesRequests informal protocol,
6321    supposedly called when a services menu item is chosen from this app.
6322    But this should not happen because we override the services menu with our
6323    own entries which call ns-perform-service.
6324    Nonetheless, it appeared to happen (under strange circumstances): bug#1435.
6325    So let's at least stub them out until further investigation can be done. */
6327 - (BOOL) readSelectionFromPasteboard: (NSPasteboard *)pb
6329   /* we could call ns_string_from_pasteboard(pboard) here but then it should
6330      be written into the buffer in place of the existing selection..
6331      ordinary service calls go through functions defined in ns-win.el */
6332   return NO;
6335 - (BOOL) writeSelectionToPasteboard: (NSPasteboard *)pb types: (NSArray *)types
6337   NSArray *typesDeclared;
6338   Lisp_Object val;
6340   /* We only support NSStringPboardType */
6341   if ([types containsObject:NSStringPboardType] == NO) {
6342     return NO;
6343   }
6345   val = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6346   if (CONSP (val) && SYMBOLP (XCAR (val)))
6347     {
6348       val = XCDR (val);
6349       if (CONSP (val) && NILP (XCDR (val)))
6350         val = XCAR (val);
6351     }
6352   if (! STRINGP (val))
6353     return NO;
6355   typesDeclared = [NSArray arrayWithObject:NSStringPboardType];
6356   [pb declareTypes:typesDeclared owner:nil];
6357   ns_string_to_pasteboard (pb, val);
6358   return YES;
6362 /* setMini =YES means set from internal (gives a finder icon), NO means set nil
6363    (gives a miniaturized version of the window); currently we use the latter for
6364    frames whose active buffer doesn't correspond to any file
6365    (e.g., '*scratch*') */
6366 - setMiniwindowImage: (BOOL) setMini
6368   id image = [[self window] miniwindowImage];
6369   NSTRACE (setMiniwindowImage);
6371   /* NOTE: under Cocoa miniwindowImage always returns nil, documentation
6372      about "AppleDockIconEnabled" notwithstanding, however the set message
6373      below has its effect nonetheless. */
6374   if (image != emacsframe->output_data.ns->miniimage)
6375     {
6376       if (image && [image isKindOfClass: [EmacsImage class]])
6377         [image release];
6378       [[self window] setMiniwindowImage:
6379                        setMini ? emacsframe->output_data.ns->miniimage : nil];
6380     }
6382   return self;
6386 - (void) setRows: (int) r andColumns: (int) c
6388   rows = r;
6389   cols = c;
6392 @end  /* EmacsView */
6396 /* ==========================================================================
6398     EmacsWindow implementation
6400    ========================================================================== */
6402 @implementation EmacsWindow
6404 #ifdef NS_IMPL_COCOA
6405 - (id)accessibilityAttributeValue:(NSString *)attribute
6407   Lisp_Object str = Qnil;
6408   struct frame *f = SELECTED_FRAME ();
6409   struct buffer *curbuf = XBUFFER (XWINDOW (f->selected_window)->buffer);
6411   if ([attribute isEqualToString:NSAccessibilityRoleAttribute])
6412     return NSAccessibilityTextFieldRole;
6414   if ([attribute isEqualToString:NSAccessibilitySelectedTextAttribute]
6415       && curbuf && ! NILP (BVAR (curbuf, mark_active)))
6416     {
6417       str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6418     }
6419   else if (curbuf && [attribute isEqualToString:NSAccessibilityValueAttribute])
6420     {
6421       if (! NILP (BVAR (curbuf, mark_active)))
6422           str = ns_get_local_selection (QPRIMARY, QUTF8_STRING);
6424       if (NILP (str))
6425         {
6426           ptrdiff_t start_byte = BUF_BEGV_BYTE (curbuf);
6427           ptrdiff_t byte_range = BUF_ZV_BYTE (curbuf) - start_byte;
6428           ptrdiff_t range = BUF_ZV (curbuf) - BUF_BEGV (curbuf);
6430           if (! NILP (BVAR (curbuf, enable_multibyte_characters)))
6431             str = make_uninit_multibyte_string (range, byte_range);
6432           else
6433             str = make_uninit_string (range);
6434           /* To check: This returns emacs-utf-8, which is a superset of utf-8.
6435              Is this a problem?  */
6436           memcpy (SDATA (str), BYTE_POS_ADDR (start_byte), byte_range);
6437         }
6438     }
6441   if (! NILP (str))
6442     {
6443       if (CONSP (str) && SYMBOLP (XCAR (str)))
6444         {
6445           str = XCDR (str);
6446           if (CONSP (str) && NILP (XCDR (str)))
6447             str = XCAR (str);
6448         }
6449       if (STRINGP (str))
6450         {
6451           const char *utfStr = SSDATA (str);
6452           NSString *nsStr = [NSString stringWithUTF8String: utfStr];
6453           return nsStr;
6454         }
6455     }
6457   return [super accessibilityAttributeValue:attribute];
6459 #endif /* NS_IMPL_COCOA */
6461 /* If we have multiple monitors, one above the other, we don't want to
6462    restrict the height to just one monitor.  So we override this.  */
6463 - (NSRect)constrainFrameRect:(NSRect)frameRect toScreen:(NSScreen *)screen
6465   /* When making the frame visible for the first time or if there is just
6466      one screen, we want to constrain.  Other times not.  */
6467   NSUInteger nr_screens = [[NSScreen screens] count];
6468   struct frame *f = ((EmacsView *)[self delegate])->emacsframe;
6469   NSTRACE (constrainFrameRect);
6471   if (nr_screens == 1)
6472     {
6473       NSRect r = [super constrainFrameRect:frameRect toScreen:screen];
6474       return r;
6475     }
6477   if (f->output_data.ns->dont_constrain
6478       || ns_menu_bar_should_be_hidden ())
6479     return frameRect;
6481   f->output_data.ns->dont_constrain = 1;
6482   return [super constrainFrameRect:frameRect toScreen:screen];
6485 @end /* EmacsWindow */
6488 @implementation EmacsFSWindow
6490 - (BOOL)canBecomeKeyWindow
6492   return YES;
6495 - (BOOL)canBecomeMainWindow
6497   return YES;
6500 @end
6502 /* ==========================================================================
6504     EmacsScroller implementation
6506    ========================================================================== */
6509 @implementation EmacsScroller
6511 /* for repeat button push */
6512 #define SCROLL_BAR_FIRST_DELAY 0.5
6513 #define SCROLL_BAR_CONTINUOUS_DELAY (1.0 / 15)
6515 + (CGFloat) scrollerWidth
6517   /* TODO: if we want to allow variable widths, this is the place to do it,
6518            however neither GNUstep nor Cocoa support it very well */
6519   return [NSScroller scrollerWidth];
6523 - initFrame: (NSRect )r window: (Lisp_Object)nwin
6525   NSTRACE (EmacsScroller_initFrame);
6527   r.size.width = [EmacsScroller scrollerWidth];
6528   [super initWithFrame: r/*NSMakeRect (0, 0, 0, 0)*/];
6529   [self setContinuous: YES];
6530   [self setEnabled: YES];
6532   /* Ensure auto resizing of scrollbars occurs within the emacs frame's view
6533      locked against the top and bottom edges, and right edge on OS X, where
6534      scrollers are on right. */
6535 #ifdef NS_IMPL_GNUSTEP
6536   [self setAutoresizingMask: NSViewMaxXMargin | NSViewHeightSizable];
6537 #else
6538   [self setAutoresizingMask: NSViewMinXMargin | NSViewHeightSizable];
6539 #endif
6541   win = nwin;
6542   condemned = NO;
6543   pixel_height = NSHeight (r);
6544   if (pixel_height == 0) pixel_height = 1;
6545   min_portion = 20 / pixel_height;
6547   frame = XFRAME (XWINDOW (win)->frame);
6548   if (FRAME_LIVE_P (frame))
6549     {
6550       int i;
6551       EmacsView *view = FRAME_NS_VIEW (frame);
6552       NSView *sview = [[view window] contentView];
6553       NSArray *subs = [sview subviews];
6555       /* disable optimization stopping redraw of other scrollbars */
6556       view->scrollbarsNeedingUpdate = 0;
6557       for (i =[subs count]-1; i >= 0; i--)
6558         if ([[subs objectAtIndex: i] isKindOfClass: [EmacsScroller class]])
6559           view->scrollbarsNeedingUpdate++;
6560       [sview addSubview: self];
6561     }
6563 /*  [self setFrame: r]; */
6565   return self;
6569 - (void)setFrame: (NSRect)newRect
6571   NSTRACE (EmacsScroller_setFrame);
6572 /*  block_input (); */
6573   pixel_height = NSHeight (newRect);
6574   if (pixel_height == 0) pixel_height = 1;
6575   min_portion = 20 / pixel_height;
6576   [super setFrame: newRect];
6577   [self display];
6578 /*  unblock_input (); */
6582 - (void)dealloc
6584   NSTRACE (EmacsScroller_dealloc);
6585   if (!NILP (win))
6586     wset_vertical_scroll_bar (XWINDOW (win), Qnil);
6587   [super dealloc];
6591 - condemn
6593   NSTRACE (condemn);
6594   condemned =YES;
6595   return self;
6599 - reprieve
6601   NSTRACE (reprieve);
6602   condemned =NO;
6603   return self;
6607 - judge
6609   NSTRACE (judge);
6610   if (condemned)
6611     {
6612       EmacsView *view;
6613       block_input ();
6614       /* ensure other scrollbar updates after deletion */
6615       view = (EmacsView *)FRAME_NS_VIEW (frame);
6616       if (view != nil)
6617         view->scrollbarsNeedingUpdate++;
6618       [self removeFromSuperview];
6619       [self release];
6620       unblock_input ();
6621     }
6622   return self;
6626 - (void)resetCursorRects
6628   NSRect visible = [self visibleRect];
6629   NSTRACE (resetCursorRects);
6631   if (!NSIsEmptyRect (visible))
6632     [self addCursorRect: visible cursor: [NSCursor arrowCursor]];
6633   [[NSCursor arrowCursor] setOnMouseEntered: YES];
6637 - (int) checkSamePosition: (int) position portion: (int) portion
6638                     whole: (int) whole
6640   return em_position ==position && em_portion ==portion && em_whole ==whole
6641     && portion != whole; /* needed for resize empty buf */
6645 - setPosition: (int)position portion: (int)portion whole: (int)whole
6647   NSTRACE (setPosition);
6649   em_position = position;
6650   em_portion = portion;
6651   em_whole = whole;
6653   if (portion >= whole)
6654     {
6655 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6656       [self setKnobProportion: 1.0];
6657       [self setDoubleValue: 1.0];
6658 #else
6659       [self setFloatValue: 0.0 knobProportion: 1.0];
6660 #endif
6661     }
6662   else
6663     {
6664       float pos, por;
6665       portion = max ((float)whole*min_portion/pixel_height, portion);
6666       pos = (float)position / (whole - portion);
6667       por = (float)portion/whole;
6668 #if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
6669       [self setKnobProportion: por];
6670       [self setDoubleValue: pos];
6671 #else
6672       [self setFloatValue: pos knobProportion: por];
6673 #endif
6674     }
6676   /* Events may come here even if the event loop is not running.
6677      If we don't enter the event loop, the scroll bar will not update.
6678      So send SIGIO to ourselves.  */
6679   if (apploopnr == 0) kill (0, SIGIO);
6681   return self;
6684 /* FIXME: unused at moment (see ns_mouse_position) at the moment because
6685      drag events will go directly to the EmacsScroller.  Leaving in for now. */
6686 -(void)getMouseMotionPart: (int *)part window: (Lisp_Object *)window
6687                         x: (Lisp_Object *)x y: ( Lisp_Object *)y
6689   *part = last_hit_part;
6690   *window = win;
6691   XSETINT (*y, pixel_height);
6692   if ([self floatValue] > 0.999)
6693     XSETINT (*x, pixel_height);
6694   else
6695     XSETINT (*x, pixel_height * [self floatValue]);
6699 /* set up emacs_event */
6700 - (void) sendScrollEventAtLoc: (float)loc fromEvent: (NSEvent *)e
6702   if (!emacs_event)
6703     return;
6705   emacs_event->part = last_hit_part;
6706   emacs_event->code = 0;
6707   emacs_event->modifiers = EV_MODIFIERS (e) | down_modifier;
6708   emacs_event->frame_or_window = win;
6709   emacs_event->timestamp = EV_TIMESTAMP (e);
6710   emacs_event->kind = SCROLL_BAR_CLICK_EVENT;
6711   emacs_event->arg = Qnil;
6712   XSETINT (emacs_event->x, loc * pixel_height);
6713   XSETINT (emacs_event->y, pixel_height-20);
6715   if (q_event_ptr)
6716     {
6717       n_emacs_events_pending++;
6718       kbd_buffer_store_event_hold (emacs_event, q_event_ptr);
6719     }
6720   else
6721     hold_event (emacs_event);
6722   EVENT_INIT (*emacs_event);
6723   ns_send_appdefined (-1);
6727 /* called manually thru timer to implement repeated button action w/hold-down */
6728 - repeatScroll: (NSTimer *)scrollEntry
6730   NSEvent *e = [[self window] currentEvent];
6731   NSPoint p =  [[self window] mouseLocationOutsideOfEventStream];
6732   BOOL inKnob = [self testPart: p] == NSScrollerKnob;
6734   /* clear timer if need be */
6735   if (inKnob || [scroll_repeat_entry timeInterval] == SCROLL_BAR_FIRST_DELAY)
6736     {
6737         [scroll_repeat_entry invalidate];
6738         [scroll_repeat_entry release];
6739         scroll_repeat_entry = nil;
6741         if (inKnob)
6742           return self;
6744         scroll_repeat_entry
6745           = [[NSTimer scheduledTimerWithTimeInterval:
6746                         SCROLL_BAR_CONTINUOUS_DELAY
6747                                             target: self
6748                                           selector: @selector (repeatScroll:)
6749                                           userInfo: 0
6750                                            repeats: YES]
6751               retain];
6752     }
6754   [self sendScrollEventAtLoc: 0 fromEvent: e];
6755   return self;
6759 /* Asynchronous mouse tracking for scroller.  This allows us to dispatch
6760    mouseDragged events without going into a modal loop. */
6761 - (void)mouseDown: (NSEvent *)e
6763   NSRect sr, kr;
6764   /* hitPart is only updated AFTER event is passed on */
6765   NSScrollerPart part = [self testPart: [e locationInWindow]];
6766   double inc = 0.0, loc, kloc, pos;
6767   int edge = 0;
6769   NSTRACE (EmacsScroller_mouseDown);
6771   switch (part)
6772     {
6773     case NSScrollerDecrementPage:
6774         last_hit_part = scroll_bar_above_handle; inc = -1.0; break;
6775     case NSScrollerIncrementPage:
6776         last_hit_part = scroll_bar_below_handle; inc = 1.0; break;
6777     case NSScrollerDecrementLine:
6778       last_hit_part = scroll_bar_up_arrow; inc = -0.1; break;
6779     case NSScrollerIncrementLine:
6780       last_hit_part = scroll_bar_down_arrow; inc = 0.1; break;
6781     case NSScrollerKnob:
6782       last_hit_part = scroll_bar_handle; break;
6783     case NSScrollerKnobSlot:  /* GNUstep-only */
6784       last_hit_part = scroll_bar_move_ratio; break;
6785     default:  /* NSScrollerNoPart? */
6786       fprintf (stderr, "EmacsScoller-mouseDown: unexpected part %ld\n",
6787                (long) part);
6788       return;
6789     }
6791   if (inc != 0.0)
6792     {
6793       pos = 0;      /* ignored */
6795       /* set a timer to repeat, as we can't let superclass do this modally */
6796       scroll_repeat_entry
6797         = [[NSTimer scheduledTimerWithTimeInterval: SCROLL_BAR_FIRST_DELAY
6798                                             target: self
6799                                           selector: @selector (repeatScroll:)
6800                                           userInfo: 0
6801                                            repeats: YES]
6802             retain];
6803     }
6804   else
6805     {
6806       /* handle, or on GNUstep possibly slot */
6807       NSEvent *fake_event;
6809       /* compute float loc in slot and mouse offset on knob */
6810       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6811                       toView: nil];
6812       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6813       if (loc <= 0.0)
6814         {
6815           loc = 0.0;
6816           edge = -1;
6817         }
6818       else if (loc >= NSHeight (sr))
6819         {
6820           loc = NSHeight (sr);
6821           edge = 1;
6822         }
6824       if (edge)
6825         kloc = 0.5 * edge;
6826       else
6827         {
6828           kr = [self convertRect: [self rectForPart: NSScrollerKnob]
6829                           toView: nil];
6830           kloc = NSHeight (kr) - ([e locationInWindow].y - NSMinY (kr));
6831         }
6832       last_mouse_offset = kloc;
6834       /* if knob, tell emacs a location offset by knob pos
6835          (to indicate top of handle) */
6836       if (part == NSScrollerKnob)
6837           pos = (loc - last_mouse_offset) / NSHeight (sr);
6838       else
6839         /* else this is a slot click on GNUstep: go straight there */
6840         pos = loc / NSHeight (sr);
6842       /* send a fake mouse-up to super to preempt modal -trackKnob: mode */
6843       fake_event = [NSEvent mouseEventWithType: NSLeftMouseUp
6844                                       location: [e locationInWindow]
6845                                  modifierFlags: [e modifierFlags]
6846                                      timestamp: [e timestamp]
6847                                   windowNumber: [e windowNumber]
6848                                        context: [e context]
6849                                    eventNumber: [e eventNumber]
6850                                     clickCount: [e clickCount]
6851                                       pressure: [e pressure]];
6852       [super mouseUp: fake_event];
6853     }
6855   if (part != NSScrollerKnob)
6856     [self sendScrollEventAtLoc: pos fromEvent: e];
6860 /* Called as we manually track scroller drags, rather than superclass. */
6861 - (void)mouseDragged: (NSEvent *)e
6863     NSRect sr;
6864     double loc, pos;
6865     int edge = 0;
6867     NSTRACE (EmacsScroller_mouseDragged);
6869       sr = [self convertRect: [self rectForPart: NSScrollerKnobSlot]
6870                       toView: nil];
6871       loc = NSHeight (sr) - ([e locationInWindow].y - NSMinY (sr));
6873       if (loc <= 0.0)
6874         {
6875           loc = 0.0;
6876           edge = -1;
6877         }
6878       else if (loc >= NSHeight (sr) + last_mouse_offset)
6879         {
6880           loc = NSHeight (sr) + last_mouse_offset;
6881           edge = 1;
6882         }
6884       pos = /*(edge ? loc :*/ (loc - last_mouse_offset) / NSHeight (sr);
6885       [self sendScrollEventAtLoc: pos fromEvent: e];
6889 - (void)mouseUp: (NSEvent *)e
6891   if (scroll_repeat_entry)
6892     {
6893       [scroll_repeat_entry invalidate];
6894       [scroll_repeat_entry release];
6895       scroll_repeat_entry = nil;
6896     }
6897   last_hit_part = 0;
6901 /* treat scrollwheel events in the bar as though they were in the main window */
6902 - (void) scrollWheel: (NSEvent *)theEvent
6904   EmacsView *view = (EmacsView *)FRAME_NS_VIEW (frame);
6905   [view mouseDown: theEvent];
6908 @end  /* EmacsScroller */
6913 /* ==========================================================================
6915    Font-related functions; these used to be in nsfaces.m
6917    ========================================================================== */
6920 Lisp_Object
6921 x_new_font (struct frame *f, Lisp_Object font_object, int fontset)
6923   struct font *font = XFONT_OBJECT (font_object);
6925   if (fontset < 0)
6926     fontset = fontset_from_font (font_object);
6927   FRAME_FONTSET (f) = fontset;
6929   if (FRAME_FONT (f) == font)
6930     /* This font is already set in frame F.  There's nothing more to
6931        do.  */
6932     return font_object;
6934   FRAME_FONT (f) = font;
6936   FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
6937   FRAME_COLUMN_WIDTH (f) = font->average_width;
6938   FRAME_SPACE_WIDTH (f) = font->space_width;
6939   FRAME_LINE_HEIGHT (f) = font->height;
6941   compute_fringe_widths (f, 1);
6943   /* Compute the scroll bar width in character columns.  */
6944   if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
6945     {
6946       int wid = FRAME_COLUMN_WIDTH (f);
6947       FRAME_CONFIG_SCROLL_BAR_COLS (f)
6948         = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
6949     }
6950   else
6951     {
6952       int wid = FRAME_COLUMN_WIDTH (f);
6953       FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
6954     }
6956   /* Now make the frame display the given font.  */
6957   if (FRAME_NS_WINDOW (f) != 0)
6958         x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
6960   return font_object;
6964 /* XLFD: -foundry-family-weight-slant-swidth-adstyle-pxlsz-ptSz-resx-resy-spc-avgWidth-rgstry-encoding */
6965 /* Note: ns_font_to_xlfd and ns_fontname_to_xlfd no longer needed, removed
6966          in 1.43. */
6968 const char *
6969 ns_xlfd_to_fontname (const char *xlfd)
6970 /* --------------------------------------------------------------------------
6971     Convert an X font name (XLFD) to an NS font name.
6972     Only family is used.
6973     The string returned is temporarily allocated.
6974    -------------------------------------------------------------------------- */
6976   char *name = xmalloc (180);
6977   int i, len;
6978   const char *ret;
6980   if (!strncmp (xlfd, "--", 2))
6981     sscanf (xlfd, "--%*[^-]-%[^-]179-", name);
6982   else
6983     sscanf (xlfd, "-%*[^-]-%[^-]179-", name);
6985   /* stopgap for malformed XLFD input */
6986   if (strlen (name) == 0)
6987     strcpy (name, "Monaco");
6989   /* undo hack in ns_fontname_to_xlfd, converting '$' to '-', '_' to ' '
6990      also uppercase after '-' or ' ' */
6991   name[0] = c_toupper (name[0]);
6992   for (len =strlen (name), i =0; i<len; i++)
6993     {
6994       if (name[i] == '$')
6995         {
6996           name[i] = '-';
6997           if (i+1<len)
6998             name[i+1] = c_toupper (name[i+1]);
6999         }
7000       else if (name[i] == '_')
7001         {
7002           name[i] = ' ';
7003           if (i+1<len)
7004             name[i+1] = c_toupper (name[i+1]);
7005         }
7006     }
7007 /*fprintf (stderr, "converted '%s' to '%s'\n",xlfd,name);  */
7008   ret = [[NSString stringWithUTF8String: name] UTF8String];
7009   xfree (name);
7010   return ret;
7014 void
7015 syms_of_nsterm (void)
7017   NSTRACE (syms_of_nsterm);
7019   ns_antialias_threshold = 10.0;
7021   /* from 23+ we need to tell emacs what modifiers there are.. */
7022   DEFSYM (Qmodifier_value, "modifier-value");
7023   DEFSYM (Qalt, "alt");
7024   DEFSYM (Qhyper, "hyper");
7025   DEFSYM (Qmeta, "meta");
7026   DEFSYM (Qsuper, "super");
7027   DEFSYM (Qcontrol, "control");
7028   DEFSYM (QUTF8_STRING, "UTF8_STRING");
7030   Fput (Qalt, Qmodifier_value, make_number (alt_modifier));
7031   Fput (Qhyper, Qmodifier_value, make_number (hyper_modifier));
7032   Fput (Qmeta, Qmodifier_value, make_number (meta_modifier));
7033   Fput (Qsuper, Qmodifier_value, make_number (super_modifier));
7034   Fput (Qcontrol, Qmodifier_value, make_number (ctrl_modifier));
7036   DEFVAR_LISP ("ns-input-file", ns_input_file,
7037               "The file specified in the last NS event.");
7038   ns_input_file =Qnil;
7040   DEFVAR_LISP ("ns-input-text", ns_input_text,
7041               "The data received in the last NS text drag event.");
7042   ns_input_text =Qnil;
7044   DEFVAR_LISP ("ns-working-text", ns_working_text,
7045               "String for visualizing working composition sequence.");
7046   ns_working_text =Qnil;
7048   DEFVAR_LISP ("ns-input-font", ns_input_font,
7049               "The font specified in the last NS event.");
7050   ns_input_font =Qnil;
7052   DEFVAR_LISP ("ns-input-fontsize", ns_input_fontsize,
7053               "The fontsize specified in the last NS event.");
7054   ns_input_fontsize =Qnil;
7056   DEFVAR_LISP ("ns-input-line", ns_input_line,
7057                "The line specified in the last NS event.");
7058   ns_input_line =Qnil;
7060   DEFVAR_LISP ("ns-input-color", ns_input_color,
7061                "The color specified in the last NS event.");
7062   ns_input_color =Qnil;
7064   DEFVAR_LISP ("ns-input-spi-name", ns_input_spi_name,
7065                "The service name specified in the last NS event.");
7066   ns_input_spi_name =Qnil;
7068   DEFVAR_LISP ("ns-input-spi-arg", ns_input_spi_arg,
7069                "The service argument specified in the last NS event.");
7070   ns_input_spi_arg =Qnil;
7072   DEFVAR_LISP ("ns-alternate-modifier", ns_alternate_modifier,
7073                "This variable describes the behavior of the alternate or option key.\n\
7074 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7075 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7076 at all, allowing it to be used at a lower level for accented character entry.");
7077   ns_alternate_modifier = Qmeta;
7079   DEFVAR_LISP ("ns-right-alternate-modifier", ns_right_alternate_modifier,
7080                "This variable describes the behavior of the right alternate or option key.\n\
7081 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7082 Set to left means be the same key as `ns-alternate-modifier'.\n\
7083 Set to none means that the alternate / option key is not interpreted by Emacs\n\
7084 at all, allowing it to be used at a lower level for accented character entry.");
7085   ns_right_alternate_modifier = Qleft;
7087   DEFVAR_LISP ("ns-command-modifier", ns_command_modifier,
7088                "This variable describes the behavior of the command key.\n\
7089 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7090   ns_command_modifier = Qsuper;
7092   DEFVAR_LISP ("ns-right-command-modifier", ns_right_command_modifier,
7093                "This variable describes the behavior of the right command key.\n\
7094 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7095 Set to left means be the same key as `ns-command-modifier'.\n\
7096 Set to none means that the command / option key is not interpreted by Emacs\n\
7097 at all, allowing it to be used at a lower level for accented character entry.");
7098   ns_right_command_modifier = Qleft;
7100   DEFVAR_LISP ("ns-control-modifier", ns_control_modifier,
7101                "This variable describes the behavior of the control key.\n\
7102 Set to control, meta, alt, super, or hyper means it is taken to be that key.");
7103   ns_control_modifier = Qcontrol;
7105   DEFVAR_LISP ("ns-right-control-modifier", ns_right_control_modifier,
7106                "This variable describes the behavior of the right control key.\n\
7107 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7108 Set to left means be the same key as `ns-control-modifier'.\n\
7109 Set to none means that the control / option key is not interpreted by Emacs\n\
7110 at all, allowing it to be used at a lower level for accented character entry.");
7111   ns_right_control_modifier = Qleft;
7113   DEFVAR_LISP ("ns-function-modifier", ns_function_modifier,
7114                "This variable describes the behavior of the function key (on laptops).\n\
7115 Set to control, meta, alt, super, or hyper means it is taken to be that key.\n\
7116 Set to none means that the function key is not interpreted by Emacs at all,\n\
7117 allowing it to be used at a lower level for accented character entry.");
7118   ns_function_modifier = Qnone;
7120   DEFVAR_LISP ("ns-antialias-text", ns_antialias_text,
7121                "Non-nil (the default) means to render text antialiased.");
7122   ns_antialias_text = Qt;
7124   DEFVAR_LISP ("ns-confirm-quit", ns_confirm_quit,
7125                "Whether to confirm application quit using dialog.");
7126   ns_confirm_quit = Qnil;
7128   staticpro (&ns_display_name_list);
7129   ns_display_name_list = Qnil;
7131   staticpro (&last_mouse_motion_frame);
7132   last_mouse_motion_frame = Qnil;
7134   DEFVAR_LISP ("ns-auto-hide-menu-bar", ns_auto_hide_menu_bar,
7135                doc: /* Non-nil means that the menu bar is hidden, but appears when the mouse is near.
7136 Only works on OSX 10.6 or later.  */);
7137   ns_auto_hide_menu_bar = Qnil;
7139   /* TODO: move to common code */
7140   DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7141                doc: /* Which toolkit scroll bars Emacs uses, if any.
7142 A value of nil means Emacs doesn't use toolkit scroll bars.
7143 With the X Window system, the value is a symbol describing the
7144 X toolkit.  Possible values are: gtk, motif, xaw, or xaw3d.
7145 With MS Windows or Nextstep, the value is t.  */);
7146   Vx_toolkit_scroll_bars = Qt;
7148   DEFVAR_BOOL ("x-use-underline-position-properties",
7149                x_use_underline_position_properties,
7150      doc: /*Non-nil means make use of UNDERLINE_POSITION font properties.
7151 A value of nil means ignore them.  If you encounter fonts with bogus
7152 UNDERLINE_POSITION font properties, for example 7x13 on XFree prior
7153 to 4.1, set this to nil. */);
7154   x_use_underline_position_properties = 0;
7156   DEFVAR_BOOL ("x-underline-at-descent-line",
7157                x_underline_at_descent_line,
7158      doc: /* Non-nil means to draw the underline at the same place as the descent line.
7159 A value of nil means to draw the underline according to the value of the
7160 variable `x-use-underline-position-properties', which is usually at the
7161 baseline level.  The default value is nil.  */);
7162   x_underline_at_descent_line = 0;
7164   /* Tell emacs about this window system. */
7165   Fprovide (intern ("ns"), Qnil);